Skip to content

Projects and scope

This page explains the two levels at which Alvia organizes memories, and when to use each: projects, which are the access boundary, and scope, which organizes memories inside one project.

A project is a separate set of memories. Each API key belongs to one project, and a request with that key reaches only that project’s memories.

Use separate projects for things that must never share memories:

  • your production and staging environments
  • separate products
  • customers whose data must be kept apart

You create projects and API keys in the dashboard. The Free plan allows three projects; paid plans have no project limit. The Demo Project a new account starts with does not count toward it. See Limits and allowances.

A project also owns its memory policy: all keys and scopes in that project share the same keyword and meaning exclusions on new writes. Give each set of rules its own project, for example when a support service must exclude health disclosures while another application has a different memory purpose. See Memory policies.

Scope labels each memory with who or what it is about. It has five optional fields:

Field Use it for
organization_id A customer organization or tenant in your app
user_id One end user
application_id One of your applications
agent_id One agent
team_id A team inside an organization

Each value is a string you choose, such as your own database ID for that user. Your application owns these IDs, and Alvia stores them as you send them.

A write stores its memories under exactly the scope fields you send. The same text sent with two different scopes becomes two separate memories, and formation compares a new fact only with memories in the same scope.

POST /v1/memories
{
"content": "Prefers invoices in euros.",
"scope": { "organization_id": "acme", "user_id": "u_4821" }
}

A write with no scope stores its memories in the project’s unscoped space.

A read returns memories that match every scope field you send. Fields you leave out match anything.

Read scope Returns
{ "organization_id": "acme", "user_id": "u_4821" } Only memories about that user at Acme
{ "organization_id": "acme" } Every memory for Acme, for any user, agent or team
None Every memory in the project, including unscoped memories

Use the same IDs on every write and read. A read with a different ID finds nothing.

  • In request bodies (store, import, search, recall and context), send scope as a nested scope object. Top-level fields such as "user_id" are refused.
  • On GET /v1/memories, send scope fields as query parameters: /v1/memories?organization_id=acme&user_id=u_4821. That request has no body, so a scope object in a body is ignored.
  • MCP tools take the five fields as separate arguments.

Alvia trims each value, collapses any run of whitespace to one space, changes it to lowercase and applies Unicode NFC normalization before it stores or compares it. Acme and acme are the same value, and responses return the lowercase form. An empty value counts as not sent.

Each value can be up to 128 characters. Values that start and end with two underscores, such as __all__, are reserved and refused.