Projects
A project is an organizational workspace in your Korely account that groups your API keys. For an agent builder, projects answer a concrete ops question: how do you run a staging environment and a production environment under one account, with separate keys and a clear promotion path, without risking a staging write leaking into the production memory your end users see? The answer is two projects, one key each. Every account starts with a Default project created automatically; you mint additional projects in the dashboard as your deployment topology grows.
Projects are an organizational layer on top of your keys. They do not change how your agents call Korely, and they are not something an agent ever sees. A project is resolved on the server from the key that authenticates the request.
flowchart TD
ACC["Your account"]
P1["Project: Staging"]
P2["Project: Production"]
K1["Staging key (kor_live_...)"]
K2["Production key (kor_live_...)"]
A1["agent_id: support-bot-staging"]
A2["agent_id: support-bot"]
U1["user_id: test-customer-001"]
U2["user_id: customer-4812"]
ACC --> P1
ACC --> P2
P1 --> K1
P2 --> K2
K1 --> A1
K2 --> A2
A1 --> U1
A2 --> U2
style ACC fill:#1e293b,color:#e2e8f0,stroke:#6366f1
style P1 fill:#374151,color:#d1d5db,stroke:#4b5563
style P2 fill:#374151,color:#d1d5db,stroke:#4b5563
style K1 fill:#1e293b,color:#a5b4fc,stroke:#6366f1
style K2 fill:#1e293b,color:#a5b4fc,stroke:#6366f1
style A1 fill:#0f172a,color:#94a3b8,stroke:#334155
style A2 fill:#0f172a,color:#94a3b8,stroke:#334155
style U1 fill:#0f172a,color:#94a3b8,stroke:#334155
style U2 fill:#0f172a,color:#94a3b8,stroke:#334155
Managed from the dashboard
Projects are managed from the dashboard, or with an admin-scope key
through the /admin API (the Python SDK's
projects(), create_project(),
move_key()...). The /v1 calls your agents make
never name a project: it is resolved from the key. From the dashboard you:
- Create, rename, archive, and delete projects.
- Create API keys inside a specific project, reading and writing or read only or write only.
- Move a key from one project to another. This is the staging → production path: promote a key once it is ready instead of minting a new one and re-deploying.
Deleting a project moves its API keys to the Default project, where they keep working. Apps connected over OAuth are disconnected instead (their grant covered only that project) and must connect again. By default its memories and facts move to the Default project with them, so nothing is lost. If you choose to erase them instead, they are deleted for good, with an audit record, and each end user the project held is erased as by Forget a user: what stays of them, in the audit trail and the erasure records, names them by a pseudonym only.
Project vs agent_id vs user_id
Three different things group your data, at three different levels. They stack; they do not compete.
| Concept | Groups | Set where | Use it for |
|---|---|---|---|
| Project | Your API keys | Dashboard or /admin API | Environment and product: staging vs production, one product vs another. |
agent_id | One application, within a project | API call | The app itself, e.g. support-bot. One project runs many agents. |
user_id | The memory of one end customer | API call | The person your agent serves. Unlimited on every tier. |
Read it top to bottom: a project is the environment or
product container that holds your keys; agent_id is the
application within that project; user_id is the end
user that application is serving. Use projects for environment and product,
agent_id for the app, and user_id for the end
user.
What a project isolates
A project groups your keys, lets you promote a key from staging to
production, and
walls off the data. Every memory and fact carries the
project of the key that wrote it, and on /v1 a key reads, searches, assembles
context from, corrects, forgets and erases only what belongs to its own
project. A staging key never sees production memory, and a fact in
another project answers 404, the same answer as an id that
never existed.
The one exception is a key with the admin scope, which is not
in the default set: through the /admin API it reads, corrects,
forgets and erases the memories and facts of every project of the account.
Keep admin keys out of anything your agents run.
Erasing an end user is per project too. DELETE /v1/users/{end_user}/memories erases that end
user in the key's project. If the same end user lives in several
projects, call it once per project, with that project's key.
Usage, quotas and the agent cap are account-wide. Usage
and quotas are counted for the whole account: staging and
production share one write pool and one read pool; there is no
per-project budget. The agent cap counts agent_id names
across the account: a name used in two projects holds one slot, and
GET /v1/agents lists the names of the key's project while
its used count covers the whole account.
The public API is unchanged
Projects do not touch the /v1 contract. There is no project
field in any request body, and there is nothing new to send. The project a
request belongs to is resolved server-side from the authenticating
key; agents stay exactly as they are.
# The same call from a staging key and a production key.# The project is resolved from the key: nothing changes in the request.curl https://api.korely.ai/v1/memories \ -H "Authorization: Bearer kor_live_..." \ -H "Content-Type: application/json" \ -d '{"content": "User prefers email follow-ups", "user_id": "customer-4812"}'Because the project is carried by the key, you get isolation simply by minting keys in different projects. Mint a staging key in a Staging project and a production key in a Production project, point each environment at its own key, and the separation follows automatically with no code change: separate keys, separate memory, and the staging → production promotion path.
Worked example: staging to production
The following shows the full lifecycle an agent builder goes through when moving a support bot from staging to production. The API calls are identical in both environments; only the key changes.
import os
from korely_memory import Korely
# ── Staging environment ─────────────────────────────────────────────────────# Key is scoped to the "Staging" project in the dashboard.staging = Korely(api_key=os.environ["KORELY_STAGING_KEY"]) # a key of the Staging project
staging.add( "Test user verified the support-bot correctly recalled meal preference.", user_id="test-customer-001", agent_id="support-bot-staging",)
results = staging.search( "meal preference", user_id="test-customer-001", agent_id="support-bot-staging",)# results[0].snippet => "Test user verified the support-bot correctly..."
# ── Production environment ───────────────────────────────────────────────────# When staging tests pass, swap the key for the one in the "Production" project.# No code change required, the project is resolved server-side from the key.production = Korely(api_key=os.environ["KORELY_PRODUCTION_KEY"]) # a key of the Production project
production.add( "Customer-4812 prefers vegetarian meals. Mentioned nut allergy.", user_id="customer-4812", agent_id="support-bot",)
# Later, once extraction has run (a few seconds after the write):facts = production.get_facts( user_id="customer-4812", agent_id="support-bot",)# get_facts returns a flat list, freshest confirmation first. Access fields by attribute.if facts: print(facts[0].subject, facts[0].predicate, facts[0].object)# facts[0].subject == "customer-4812"# facts[0].predicate == "prefers" # the relation as stored; predicate_raw is the phrase as extracted# facts[0].predicate_raw == "prefers"# facts[0].object == "vegetarian meals"# facts[0].invalid_at is None # still live (None == active)# facts[1].predicate == "allergic_to", facts[1].object == "nuts"
When the staging tests pass, the only change is in the environment variable
that holds the key. The same agent_id and user_id
values that worked in staging work in production with no modification, and
memories written by the staging key are invisible to the production key.
A distinct agent_id such as support-bot-staging
is optional; keep in mind that each distinct name holds one slot of the
account-wide agent cap.
See also
- The memory model, the three-layer architecture (managed store, session memory, cross-session facts) that sits underneath every key and project.
- The knowledge graph,
how typed facts are extracted automatically from every
add()call and whyagent_idkeeps graph namespaces clean. - API reference, full
parameter docs for
POST /v1/memories,GET /v1/facts, and the rest of the/v1contract your agents call.