Korely

Concepts

Projects

A project groups API keys and walls off the memories and facts those keys write.

Use one project per environment or product, such as Staging and Production.

Your calls never name a project: Korely finds it from the key. GET /v1/ping shows the project's region (processing_region), never its name.

This page is for developers who run several environments or products on one account.

Terms

The Glossary defines the words used across the docs. These are the ones this page relies on.

  • Default project: the project every account starts with, and where a key goes when you do not choose one.
  • Admin key: a key with the admin permission. It can manage projects and keys.
  • Move: putting an existing key into another project of the account.
  • Archive: hiding a project without deleting what it holds.

Quick start

You need a Korely account: Quickstart gets you one, free. Install with pip install korely-memory (Python 3.9 or later) or npm install korely-memory (Node.js 18 or later). Checked with SDK 0.1.28 (Python) and 0.1.17 (Node.js).

In the dashboard, create two projects, Staging and Production, on the Projects page. On the API Keys page, create one key in each: a new key goes to the project picked in the switcher at the top left. Export them as KORELY_STAGING_KEY and KORELY_PRODUCTION_KEY.

The code saves one memory with the staging key, then runs the same search with each key for one end user.

import os
from korely_memory import Korely
staging = Korely(api_key=os.environ["KORELY_STAGING_KEY"])
production = Korely(api_key=os.environ["KORELY_PRODUCTION_KEY"])
staging.add("Prefers email follow-ups.", user_id="test-user-1")
for name, korely in {"staging": staging, "production": production}.items():
hits = korely.search("email follow-ups", user_id="test-user-1")
print(name, [hit.snippet for hit in hits])

The staging search lists the memory. The production search does not: the staging memory is not visible to the production key.

If production lists it too, both keys are in the same project, most often Default: the API Keys page lists each key under its project. If staging lists nothing, check that both calls use the same user_id (case counts).

What a project isolates

Every memory and fact carries the project of the key that wrote it. On /v1, a key reads and changes memories and facts only in its own project, except DELETE /v1/account: with confirm=true it erases the whole account with an unconfined key that has the admin permission, whatever its project (see Delete the account). Forgetting or correcting a fact of another project answers 404, as for an id that does not exist.

An admin key can also manage projects and keys outside the dashboard and reach every project's data. On /v1 it stays in its own project. Keep admin keys out of anything your agents run.

The wall holds only between different projects, and not for DELETE /v1/account. Watch three cases:

  • Keys in Default. Two keys created without choosing a project both go to Default and share one memory. Pick the project when you create each key.
  • Deleting a project. Unless you erase them, its memories and facts move into Default (see Delete a project).
  • Webhooks. A webhook endpoint is an address of yours that Korely calls when something happens, such as a new memory with its user_id. Unless you bind it to one project, it receives the calls of every project.

Erasing an end user

The wall applies to erasing too. DELETE /v1/users/{end_user}/memories works in the key's project only. If the same end user lives in several projects, call it once per project, with that project's key.

The region of a project

Each project has a region, eu or global. Your data is stored on Korely's servers in Helsinki in both. The region decides which model reads the project's memories to write the facts: global (the default) uses a model from Google, outside the EU; eu uses Scaleway in Paris. Data governance lists the model of each region and where it runs.

  • The region belongs to the project, not to the key. A key moved to a project with another region has its next writes read there.
  • You set it on the Projects page, at creation or later. Default and new projects start as global, unless an agent created the account and chose a region.
  • A change applies to the next memories, including those still waiting for their facts. Facts already written stay as they are.
  • To read a new memory, the model also gets that end user's earlier memories and facts as context. After a change, that context goes to the company that runs the new region's model.

Give staging and production the same region, or staging uses a different model than production.

Project, agent_id and end user

ConceptWhat it isSet where
Project Keys and the wall around the data they write: one environment or product. Dashboard
agent_id A name you choose for the app that writes. It does not belong to a key and counts toward your plan's agent limit. Each call
user_id The end user your app serves. Unlimited on every plan. Each call

The memory of an end user is shared by every agent of the project.

What the dashboard shows

The switcher at the top left names the project the dashboard looks at. Since 1.0.12 the data pages show only that project: Memory Graph, Memories, Facts, Agents, Requests, the Audit log and the numbers on the Home page. A line under each title says which project it is. Before 1.0.12 the switcher named a project, but these pages read every project of the account.

  • Choose another project and the page loads that project's data. Filters and the selection start over. The choice is kept when you reload the page.
  • All projects is the first choice in the list. It shows every project of the account together, and the switcher's button says "All projects" while it is chosen. The choice is kept per account in the browser: another account signed in on the same browser keeps its own choice, and starts on its Default project if it never chose one.
  • The Audit log lists some events only under All projects, because they belong to no project: sign-ins and sign-outs, the model settings, a webhook for every project, an erasure of an end user in every project, a project's deletion, and the reads made with All projects chosen.
  • Some numbers stay the account's. Model calls are not counted by project, and neither are the plan's writes. The model calls (the Home page card, the sidebar and the Usage page) and the writes of this month (the Home page card and the sidebar) are the whole account's. Those cards say "account".

Outside the dashboard, an admin key can call the same reads on /admin. Since 1.0.12 the ones that list memories, their categories, namespaces, requests and the audit log take an optional project_id, as the facts and the memory search already did. With it, they return one project of the account: the same rows a key of that project sees (the Audit log also keeps meta.operator, which a key does not see). Left out, they read the whole account, as before. A project that is not the account's answers 404. The usage read has no project_id, because a model call is not counted by project. New in 1.0.12, GET /admin/memories/count counts the memories (with the same optional project_id) without reading one.

An empty project_id is a 422. Up to 1.0.11 an empty project_id= in a query meant the whole account. Now it is refused. An empty "project_id": "" in a request body is refused the same way in POST /admin/keys, a key's move (POST /admin/keys/{key_id}/move) and POST /admin/aliases. A script that sent an empty one must leave the field out or send null: both do what the empty one did (a new key goes to the Default project). POST /admin/webhooks and an OAuth consent already refused an empty one, with a 404; the answer is now a 422.

Create and manage projects

A dashboard login creates projects and keys, and so does an admin key. The key of an account that an agent created with POST /v1/agents/init is an admin key since 1.0.5, so it can do both without the dashboard. A key issued before 1.0.5 cannot: that account has only Default until you sign in to the dashboard and paste the key on the Account page (how to link the key to a dashboard login).

Move a key

On the API Keys page you can move a key to another project. From its next call it reads and writes there and no longer sees the old project; what it wrote before stays behind. Everything that still uses the key moves with it.

To promote staging, do not move its key: put a new Production key in the environment variable your production app reads.

Archive a project

Archiving is refused while the project holds a live key, one neither revoked nor expired. An archived project accepts no new keys. Default can be neither archived nor deleted.

Only an admin key undoes an archive (unarchive_project in the Python SDK); the dashboard cannot.

Delete a project

  • Its keys move to Default and keep working. A connected app, an app such as Claude or ChatGPT that you connected to Korely with OAuth (a sign-in standard), is disconnected and must connect again.
  • By default its memories and facts move to Default.
  • Deleting a project never changes the region its keys and data are written in. When the Default project writes in another region than the deleted one, and live keys would move, or, without erasing, any memory, fact or batch job would, DELETE /admin/projects/{id} answers 409 project_region_differs and nothing is deleted. The message names both regions, what would have moved and the two ways on: give the two projects the same region first (edit the project, or PATCH /admin/projects/{id} with region; it applies from the next write), or revoke the project's keys and erase it. The answer of a deletion has a field region: the Default project's region, where what moved is written from now on. The refusal exists because the Cloud's Default project is Global: before 1.0.19 deleting an EU project without erasing it moved its keys and its queued memories into Default, where the Global provider wrote them, and nothing said so. Measured with the release's tests on a local database with faked providers; not tried on the Cloud.
  • Its webhook endpoints are deleted.
  • If you choose to erase, memories and facts are deleted for good. Each end user is erased as in Forget a user, and a confined key whose end users were all erased is revoked. Encrypted backups keep a copy for up to 35 days.

What the whole account shares

Staging and production share one pool of writes, one of reads, and the same per-minute, per-hour and per-day rate limits.

The agent limit counts an agent_id once per project: a name used in two projects takes two places, and the free Hobby plan holds 2 agents. Whether a name is new is asked of the key's own project only, so the answer is the same whether or not another project uses the name. GET /v1/agents lists only the key's project, while used counts the account: a key can list 3 names while used says 7, because 4 agents live in other projects. It tells how many agents the account holds, never which.

Quotas, plan rate limits and the agent limit belong to the Cloud; a Self-hosted install counts none of them.

Reference

CaseLimit or answer
Projects per account100, Default and archived ones included. Deleting a project frees a place; archiving does not.
API keys per account100 not revoked, across all projects. An expired key counts until you revoke it; the key of a connected app does not.
Past either limit409 too_many_projects or too_many_keys. Nothing else changes.
Sending a project field in the body of a /v1 request (calls do not take one)422 invalid_request. Nothing is written.
Other refusals, all 409project_archived (a key into an archived project), project_has_live_keys, project_region_differs (deleting a project, see above), cannot_archive_default, cannot_delete_default, connected_app_key (moving a connected app's key).

Details

  • A read without user_id covers every end user of the key's project.

See also