Skip to Content
PlatformAgent access
Raw

Agent access

An agent lives in one workspace: the one where it runs, which decides its deploy regions, its secrets, where its new collections go (AETHERFY_WORKSPACE_ID) and its starting level. It can access the collections of other workspaces you grant it, each at a level. The level decides what the agent’s code may do there. This page is the reference for the levels, protected collections and the switch that lets an agent write its own secrets. Only you can change any of them, never the agent.

Who the rules apply to

The levels and protection apply to an agent’s key only: the key an agent receives when it runs. Your own API key, whether you use it from the SDKs, the CLI or plain HTTP, and the dashboard are never limited by a level or by protection. You can do everything an agent is refused.

The checks add no database query beyond the ones a request already makes. Protection rides the lookup the edge makes to resolve the collection, which is answered from a Redis-backed cache that holds the collection’s flag for up to 60 seconds (a change of protection tells the cache to forget it at once). A request that is forwarded to another region re-reads the collection by its id there. The agent’s levels are an in-memory copy refreshed within 60 seconds. The one place a check reads the database again is changing an alias, a rare administrative action, where an agent’s change reads the alias’s target once more.

The model: lives in, can access

  • Lives in: exactly one workspace. Where it lives is not a grant, so it cannot be removed; to change it, move the agent.
  • Can access: any other workspace you grant it. A grant belongs to the agent, names a workspace and carries a level. A workspace you did not grant is refused to the agent (403 AGENT_KEY_WORKSPACE_FORBIDDEN), and so is one that does not exist, so an agent cannot find out which workspace names exist.

The three access levels

In words (the dashboard and the CLI say the same):

  • Read access: can search, query, retrieve and count points, and read a collection’s information and schema.
  • Read and write access: everything read access can do, plus add, change and delete points, and create collections and indexes.
  • Full access: everything read and write access can do, plus delete collections, delete indexes and change their structure (schema, aliases), which changes them for everyone who uses them.

A request needs one level and any higher level passes. The next table lists every operation and the level it needs.

OperationNeeds
Search, query, scroll, retrieve and count points; read a collection, its schema and its aliases; list collections and aliases; analyze a schemaRead access
Add or update points (upsert), set a payload, overwrite a payload, update vectorsRead and write access
Delete points, delete vectors, delete payload fields or clear a payload, by id or by filterRead and write access, and refused on a protected collection
Create a collectionRead and write access
Create a payload indexRead and write access
Delete a payload indexFull access
Set or delete a schemaFull access
Change a collection’s descriptionFull access
Create, rename or delete an aliasFull access, and refused when the alias points at a protected collection
Delete a collectionFull access, and refused on a protected collection
Rename a collectionNever an agent: a person’s change (403 AUTH_AGENT_KEY_OUT_OF_SCOPE)

Creating adds something and removes nothing, which is why creating a collection or an index needs read and write access while deleting either does not.

How an agent’s level in a workspace is decided

An agent holds one level in each workspace it reaches, decided in this order:

  1. In the workspace where it lives: the agent’s own setting if it has one, otherwise that workspace’s default for the agents living there. The default is read and write access.
  2. In a workspace it can access: the grant’s level, and nothing else. The agent’s own setting and the home workspace’s default never apply there. A new grant is read access.

Worked examples. Two workspaces: support, whose default for its agents is read and write access, and research, whose default is read access.

AgentLives inOwn settingGrantsLevel in supportLevel in research
support-botsupportnoneresearch: readRead and write (the default of support)Read (the grant)
analystresearchfullnoneNot reachableFull (its own setting; the default of research is read)
triagesupportreadresearch: fullRead (its own setting is lower than the default, and wins)Full (the grant is higher than its level at home, and applies only there)
nightlysupportnoneresearch: read and writeRead and write (follows the default)Read and write (the grant)

Two more rules that follow:

  • Changing a workspace’s default changes every agent living there that has no setting of its own, and leaves an agent with a setting of its own unchanged.
  • Full at home never carries over. An agent at full access in its own workspace is not at full access in a workspace it can only access: there it holds the level of its grant. A high level where an agent lives never raises what it can do somewhere else.

An agent’s key cannot change a level, a grant or a default, its own or another’s, and aetherfy.yaml has no field for one.

What a change does and how fast

A change takes effect within 60 seconds on the Aetherfy vector API. So does lowering a level or removing a grant. When you lower a level or revoke a grant the dashboard and the CLI say it plainly and do not ask for a confirmation:

Takes effect within 60 seconds; requests above the new level are refused.

A change that lets the agent’s code do more asks first: raising a level, adding a grant, turning the secrets switch on, turning protection off.

What happens when an agent tries more than its level

A request above the agent’s level is refused 403 AGENT_ACCESS_LEVEL_INSUFFICIENT and nothing is applied. An agent at read access that tries to write gets:

{ "error": { "code": "AGENT_ACCESS_LEVEL_INSUFFICIENT", "message": "This agent's key holds read access in workspace \"research\", and this request needs read and write access. Ask the account owner to raise this agent's access there (the agent's ACCESS tab in the dashboard, or afy access).", "workspace": "research", "level": "read", "required_level": "read_write", "documentation_url": "https://docs.aetherfy.com/platform/agent-access" } }

The message says the levels in words; level and required_level carry the machine values (read, read_write, full). It is decided on the workspace the request addresses, before anything is forwarded or read, and it is not retryable until you change the level.

What the agent’s own log shows

A refusal is also written into the agent’s own log, so the person reading the agent’s logs sees what its key was refused without reading a response body. Each refusal of an agent’s request (its access, a protected collection or the plan’s collection limit) and each time the agent deleted a collection or points is one line on the system stream, in the same plain sentences as the refusal itself and never the raw level names:

afy logs invoice-bot --stream system --json

Every line has stream system and level SYSTEM. Examples:

What happenedThe line
The agent tried to delete a collection with read and write accessRefused DELETE /api/v1/workspaces/research/collections/kb: This agent's key holds read and write access in workspace "research", and this request needs full access. …
The agent tried to delete points of a protected collection, three timesRefused POST /api/v1/workspaces/research/collections/kb/points/delete: Collection "kb" is protected: … (3 times)
The agent created a collection past the plan’s limitRefused POST /api/v1/workspaces/research/collections: Collection limit reached. Your free plan allows 3 collections.
The agent deleted 12 pointsDeleted 12 points from collection "kb" in workspace "research".
The agent deleted a collectionDeleted collection "kb" in workspace "research".

A delete says how many points it removed; a delete by filter counts the points the filter selected. The same refusal of the same kind of request repeated within a minute is one line ending (3 times), and deletes from one collection within a minute add up to one line ((4 requests)). An agent that refuses itself in a loop cannot flood its own log: past 50 distinct lines in a minute, one further line says how many were not listed. The lines appear within about a minute of the event, from any region, in the order of the logs. Reading data, and anything your own key does, writes no line. In the dashboard they are on the agent’s LOGS tab with the stream system. The full list of streams is in runs and logs.

Memories and collections follow the same rules

A memory namespace is a collection, so the levels apply to it exactly as to any other collection. This is the whole mapping, for the Python and the JavaScript memory SDKs alike:

Memory operationWhat it does on the vector APIThe level it needs
Search, get, listSearch, query, retrieve, scrollRead access
Add, updateUpsert pointsRead and write access
Delete by ids, by filter, and delete metadata keysDelete points, delete payload fieldsRead and write access, and refused on a protected collection
Create a namespaceCreate a collectionRead and write access
Delete a namespace, clear() on a namespaceDelete the collectionFull access, and refused on a protected collection
clear() on a thread, delete a threadDelete the thread’s points by filterRead and write access, and refused on a protected collection
The first thread in a workspaceCreates the shared threads collection and two payload indexes on itRead and write access: creating a collection or an index adds and removes nothing
Set or delete a schemaChange the collection’s schemaFull access

At each level, memory behaves like this:

LevelAn agent using the memory SDK can
Read accessSearch, get and list memories and threads
Read and write access (the default)Everything above, and create namespaces and threads, add, update and delete memories, and clear a thread
Full accessEverything above, and delete or clear a namespace and set a schema

At the default level, memory works out of the box. Deleting or clearing a namespace needs full access, and the refusal says so and how to raise it.

Why the default is read and write

An agent that reads, writes and creates can do its job, and cannot delete a collection until a person raises it to full access. That keeps a mistake that destroys gigabytes out of reach by default, without taking memory away: creating a namespace creates a collection and its indexes, which read and write access allows.

To raise or lower it, change the workspace’s default (every agent that follows it), or one agent’s own setting. Both are in Changing the levels.

Protected collections

A collection can be protected. Protected means no agent removes data from the collection. On a protected collection, at any level, no agent’s key may:

  • delete the collection;
  • delete points, delete vectors or delete payload fields, by id or by filter, including clearing a payload;
  • delete, rename or repoint an alias that points at it.

Each is refused 403 COLLECTION_PROTECTED, with collection_name.

Protection stops an agent from deleting the collection or deleting data from it. An agent with write access can still change or overwrite points. An agent that may write can still add points, upsert an existing point id, set or overwrite a payload and update vectors on a protected collection. To stop all changes, give the agent read access.

You, with your own API key, the dashboard or the CLI, can still do all of it, and only you can turn protection off. An agent’s key cannot.

How fast it applies. Protection applies within a minute: at once when the change reaches the region that answers the agent, and within 60 seconds at the latest everywhere. If the vector service cannot confirm the change at once, the dashboard and the CLI say it is saved and may take up to a minute to apply (the request answers 503 SERVICE_UNAVAILABLE with a Retry-After); sending the same request again applies it. If Aetherfy cannot read a collection’s protection, an agent’s request that removes data is refused 503 rather than assumed to be unprotected.

Two layers

The level and protection answer different questions. The level is what an agent may do in a workspace, for all of its collections. Protection is about one collection, whatever the agent’s level: it holds even for an agent at full access. A request meets the level first, then protection. Neither is a backup: they stop an agent from removing data, and do not bring it back once a person has.

Turning protection on and off

WhereHow
DashboardThe collection’s page, its settings: the protection switch. Turning it off asks you to type the collection’s name
CLIafy collections protect <name>, afy collections unprotect <name>; afy collections list shows which collections are protected
Aetherfy agents APIPATCH /api/v1/collections/{id} with {"protected": true}, sent on its own (400 COLLECTION_PROTECTED_COMBINED when it comes with regions, or with a workspace_id other than the collection’s own)

Turning protection off asks first, since it lets agents delete again: “Unprotecting a collection lets agents with read and write access delete its points, and agents with full access delete the collection.”

Where an agent’s secrets come from

An agent receives the secrets of the workspace it lives in, plus its own. A grant never brings a granted workspace’s secrets. A grant means “you may use this data”; it does not hand over the keys that workspace’s agents run with. If a task needs a credential, give it to the agent explicitly, on the agent or in the workspace it lives in.

The secrets switch

Each agent has a switch, off by default. While it is on, the agent’s own key may create, update, rotate and delete its own secrets, and nothing else. It never reaches the secrets of its workspace (shared by every agent living there: a switched-on agent could redirect its siblings or break them, so workspace secrets are written by people only), of a workspace it was granted, or of another agent. It cannot list secrets, so a secret’s value is never read back by the agent. Names beginning AETHERFY_ stay reserved, and a value is at most 32 KiB (32 768 UTF-8 bytes; one byte more is refused with 422 SECRET_VALIDATION_ERROR).

The use case is a scheduled task that rotates a credential, such as an OAuth refresh token, and saves it for its next run. A secret the agent writes is stored at once and read when the agent starts: a service sees the new value after its next deployment (a redeploy, afy deploy, a push to a linked repository, or a rollback); a task sees it on its next run, which is why the switch suits tasks. A running machine never changes its environment.

The switch is read on every request, so turning it off closes the routes on the agent’s next request, with no redeploy. Moving the agent turns it off. Turn it on in the dashboard (the agent’s ACCESS tab, which asks first), with afy access <agent> --secrets on, or PUT /api/v1/agents/{agent}/access/secrets with {"enabled": true}. With the switch off, the secret routes answer 403 AUTH_AGENT_KEY_OUT_OF_SCOPE, and the message says the account owner has not turned the switch on.

What a move resets

Moving an agent to another workspace (afy update <name> --workspace <workspace>, or MOVE on its ACCESS tab) changes where it lives, and so:

  • Its own level is cleared. It follows the new home’s default, because a level chosen for one workspace is not carried into another whose owner chose a different default.
  • A grant to the new home is dropped: the agent lives there now, and the grant would otherwise come back to life if it moved again. Its other grants stay.
  • Its secrets switch is turned off. The switch was your decision about the agent in the place it lived.
  • The old home is no longer reachable unless you grant it, and protection is not affected: a protected collection stays protected.

The confirmation lists what the move changes

Both surfaces ask before they move an agent (afy update --workspace asks you to answer y; MOVE on the ACCESS tab opens a dialog), and both list what the move does to this agent, in these sentences. A line appears only when it applies.

LineShown when
Its own level in '<old>' (<level>) is cleared; in '<new>' it holds that workspace's default.the agent has its own level set
Its secrets switch is turned off.the switch is on
Its grant to '<new>' is dropped: it is its home now.the agent holds a grant to the new home
It keeps its other grants: '<workspace>' (<level>), '<workspace>' (<level>).it has other grants; each is named with its level, separated by commas
It has no other grants.it has none
It no longer reaches '<old>' unless it is granted there.always

--yes skips the question, not the list: the CLI prints the same lines to stderr, and a script without --yes and without a terminal is refused (exit 2) before anything is sent. If the lines cannot be read, the CLI says so and still asks; the move itself is never refused for it. An agent already in the target workspace has nothing to confirm.

What happens when a collection is deleted

The collection’s record goes at once, and the name is free to use again. The physical removal of its data in each region runs in the background, with retries. Nothing refuses the delete for being in use. Before afy collections delete asks you to confirm, it tells you which agents used the collection in the last 35 days (“Used by agent invoice-bot in the last 35 days.”), and the delete is your call. The collection’s page in the dashboard shows the same agents in its USED BY list (the dashboard deletes points, not collections). The 35 days is how far back Aetherfy records which agent used which collection, so an agent whose only trigger is a monthly scheduled task is named too. It is not a retention promise, and the delete is never refused for it. What stops an agent deleting a collection is its level (the default cannot delete one) and protection (no agent can, at any level).

When the plan’s limit is hit

Creating more collections than the plan allows is refused 403 PLAN_LIMIT_EXCEEDED by the vector API, with the same body the agents API sends for its own plan limits: code, message, upgrade_url, limit (the limit that fired), allowed (what your plan allows) and current (what you hold now). allowed is a number, or false for a feature the plan lacks; a feature that is simply on or off has no current.

{ "error": { "code": "PLAN_LIMIT_EXCEEDED", "message": "Collection limit reached. Your free plan allows 3 collections.", "upgrade_url": "https://app.aetherfy.com/dashboard/settings/billing", "limit": "max_collections", "allowed": 3, "current": 3 } }
{ "detail": { "code": "PLAN_LIMIT_EXCEEDED", "message": "Your plan does not support always-on mode. Upgrade to enable it.", "upgrade_url": "https://app.aetherfy.com/dashboard/settings/billing", "limit": "allows_always_on", "allowed": false } }

The agents API carries the same fields inside detail, the vector API inside error. allowed is null for a limit your plan sets no cap on; a refusal is only sent when there is a cap to reach, so a client normally sees a number or false. A memory size the schedule does not price is not a plan limit: it is 422 MEMORY_SIZE_UNSUPPORTED, with the supported sizes in its body.

Spawning does not pass access on

Levels are not transitive through spawn. An agent at read access can spawn a worker listed in its allowed_workers, and that worker runs with its own level, which may be full access. Listing a worker is a decision you take, so give a worker the level you want it to hold and list it deliberately.

Changing the levels

WhereHow
DashboardThe agent’s page, ACCESS tab: the workspaces it can access, each with a level, set when granting and changeable after, and the level where it lives. The workspace’s page, SETTINGS tab: its default level. The workspace’s page, AGENTS & ACCESS tab: which agents live there or can access it, each with its level
CLIafy access <agent> --add <workspace> --level read_write; afy access <agent> --own-level read (or default); afy workspaces update <workspace> --agent-access-level read
Aetherfy agents APIPOST /api/v1/agents/{agent}/access/workspaces with level; PUT /api/v1/agents/{agent}/access/own-workspace with level (null follows the workspace’s default); PATCH /api/v1/workspaces/{workspace} with agent_access_level

A change that lets the agent’s code do more asks first, in the dashboard and in the CLI (--yes skips the question, and is required without a terminal; a “no” exits 1 and changes nothing). A change that changes nothing asks nothing, and a change that narrows asks nothing; it only says when it takes effect.

An agent can read its own access, never another’s: GET /api/v1/agents/{agent}/access with its injected key answers the levels it holds and whether its secrets switch is on.

Error codes

CodeStatusMeaning, and the way out
AGENT_ACCESS_LEVEL_INSUFFICIENT403The request needs more than the level the agent holds in that workspace. Raise its level in that workspace, or stop the request
AGENT_KEY_WORKSPACE_FORBIDDEN403The workspace is not the agent’s and was not granted to it, or does not exist. Grant it, or use a workspace it reaches
AUTH_AGENT_KEY_OUT_OF_SCOPE403A route the agent’s key may not call at all (an account route, renaming a collection), or a secret route while the switch is off. Use your own key, or turn the switch on
COLLECTION_PROTECTED403An agent’s key tried to delete a protected collection, remove data from it, or delete, rename or repoint an alias that points at it. Turn protection off first, or do it with your own key
COLLECTION_PROTECTED_COMBINED400protected was sent with regions, or with a workspace_id other than the collection’s own, in one request. Send it on its own
AGENT_ACCESS_UNAVAILABLE503Aetherfy could not read the agent’s levels; nothing was applied. Retry
COLLECTION_LOOKUP_UNAVAILABLE503Aetherfy could not look the collection up just now, which includes its protection when the request removes data. Retry
SERVICE_UNAVAILABLE503On a protection change: it is saved but the vector service did not confirm it yet, so it may take up to a minute to apply. Send the same request again to apply it now
PLAN_LIMIT_EXCEEDED403The plan’s collection limit is reached; the answer names limit, allowed and current. Delete a collection or upgrade

What an agent catches for each (the full mapping is on errors):

CodePython and JavaScript raiseWhat it carries (Python / JavaScript)
AGENT_KEY_WORKSPACE_FORBIDDENAgentWorkspaceForbiddenError.workspace
AGENT_ACCESS_LEVEL_INSUFFICIENTAccessLevelInsufficientError.workspace, .level, .required_level / .requiredLevel, each one of the machine values read, read_write, full
COLLECTION_PROTECTEDCollectionProtectedError.collection_name / .collectionName
AUTH_AGENT_KEY_OUT_OF_SCOPEAgentKeyOutOfScopeError.agent_id / .agentId, .required_scope / .requiredScope
PLAN_LIMIT_EXCEEDEDQuotaExceededError.limit, .allowed, .current, .upgrade_url / .upgradeUrl

The first four are kinds of PermissionDeniedError, so one handler for PermissionDeniedError catches every refusal of a valid key. A plan limit is not one of them: the agent may do the thing, the account is at its cap.

Frequently asked questions

Does this limit my own key or the dashboard?

No. Levels and protection apply to an agent’s key only. Your own API key and the dashboard can do everything an agent is refused.

Where does an agent live, and what is a grant?

An agent lives in exactly one workspace. A grant gives one agent access to another workspace’s collections, never its secrets. Grants belong to agents, not to workspaces: a workspace has a default level for the agents living in it, and each agent that can access it from elsewhere holds the level of its own grant.

How do the levels combine?

In the workspace where it lives, an agent holds its own setting, or the workspace’s default when it has none. In a workspace it can access, it holds the grant’s level. The home level never carries over: see the worked examples above.

What happens when an agent at read access tries to write?

It is refused with 403 AGENT_ACCESS_LEVEL_INSUFFICIENT, naming the workspace, the level held and the level needed, and a line is written into its log. The full answer is shown above.

Is it enough to protect a collection?

Protection and levels are two layers. Protection is about one collection and holds at any level; the level is about everything an agent may do in a workspace. Protection does not stop an agent with write access from changing or overwriting points. To stop all changes, give the agent read access.

How do schema changes relate to levels?

Reading needs read access; changing a schema, deleting an index or changing an alias needs full access. Creating an index needs read and write access.

Why is the default read and write? How do I raise or lower it?

See “Why the default is read and write” above: agents read, write and create, including memory namespaces, and cannot delete a collection until a person raises them to full access. Raise or lower the workspace’s default, or one agent’s own setting, as described under “Changing the levels”.

Where does an agent’s configuration come from?

Its secrets come only from where it lives: its own and its workspace’s. A grant never brings secrets. The secrets switch lets the agent write its own secrets only, and a new value takes effect at its next run or deploy, which is why it is for tasks.

Why doesn’t a grant bring the other workspace’s secrets?

A grant means “you may use this data”. It should not silently hand over the keys that workspace’s agents run with. If a task needs a credential, give it to the agent explicitly, on the agent or in the workspace it lives in.

Do memories follow the same rules as collections?

Yes: a namespace is a collection. See the table under “Memories and collections follow the same rules”.

What happens when a collection is deleted?

The record goes at once; the physical removal in each region runs in the background with retries. You are warned which agents used it in the last 35 days.

How fast does a change take effect?

Within a minute on the vector API: 60 seconds at most. Lowering a level or removing a grant takes effect within the same window: requests above the new level are refused.

Can an agent change its own access?

No. Its key cannot change a level, a grant, a default or a collection’s protection, and aetherfy.yaml has no field for them.

Does an agent pass its access on when it spawns another?

No. See “Spawning does not pass access on”.

Last updated on