Memory
Memory gives an account durable context that outlives a single request: an agent or a training task can read what it wrote before, without you shipping that context in every prompt.
It is account-scoped by construction. A namespace belongs to one account, and nothing reads across accounts. Access to a namespace is an explicit grant, and a revoked grant denies reads from that moment on — a restore that brings an old ACL back does not resurrect it, because the control plane checks the live authorization before admitting any read.
The model
| object | what it is |
|---|---|
| namespace | the unit of ownership and isolation. Belongs to one account. |
| record | a piece of content in a namespace, versioned. Writes are idempotent per key. |
| snapshot | an immutable, named point in a namespace, so a task reads a fixed view rather than a moving one. |
| grant | who may read a namespace, with a scope. Revocation is immediate and durable. |
| search | exact lookup inside a namespace, with an explicit budget. A query over its budget is rejected rather than served slowly. |
Content at rest is encrypted with keys held by an external key authority (Cloud KMS), and the platform keeps a ledger of key operations. Deleting a record erases its source content; the lineage that remains is content-free.
How a task uses it
Memory is on, enabled per account, and ColabHive attaches it. An account that has Memory gets one namespace, and the platform points it at the snapshot your tasks read. There is nothing for you to choose and nothing to send: not a namespace id, not a snapshot id, not a binding. A request that tried to name one would be choosing on behalf of an account, which is precisely what this design removes.
So the only surface you ever need is a read-only status, below. The catalogue — namespaces, records, snapshots, grants — stays internal on purpose: with the platform choosing, there is nothing in it for a caller to set.
The binding shape further down is what the platform resolves from your account and attaches to the task. It is shown so the guarantees that follow from it are checkable, not because you send it.
You do not fetch memory and paste it into a prompt, and you do not name it either. The platform reads your account's namespace and its current snapshot, binds them to the request, and resolves the read on the node that runs the task. What it binds looks like this:
{
"model": "<your-endpoint>",
"input": { "...": "..." },
"memory_binding": {
"namespace_id": "<uuid>",
"snapshot_id": "<uuid>"
}
}
Three properties follow from doing it this way:
- The content never travels through your client. The node reads it from the control plane over mutually authenticated TLS, so the memory payload is not in your request, your logs or ours.
- The binding is part of the request identity. Two requests that differ only in their binding are different requests, so a cached result from one is never served to the other.
- The delegated identity must match. The binding carries which principal and credential it acts for, and the task's own binding record has to agree, field by field, or the read is refused.
If the memory authority is unavailable, the request fails with
503 memory_authority_unavailable instead of silently running without the context you asked for.
Is my account's memory on, and is it working?
Those are two questions, and the answer separates them, because they fail apart: a namespace is prepared before it is usable, so an account can be enabled while its tasks are not yet reading memory. One combined flag would have to pick which of the two to get wrong.
GET /api/builder/v1/memory/status
{ "enabled": true, "ready": true, "detail": null }
enabled is whether the platform has given this account memory. ready is whether a task would
attach it right now. When ready is false, detail says why, and it is one of a closed set:
snapshot_pending and provisioning both mean the platform is still finishing, while
unavailable means it is enabled and not usable — ask ColabHive. When there is nothing to explain
—memory off, or memory ready— detail is null.
state = client.memory.status()
if state.enabled and state.ready:
...
The same status is an MCP tool, get_memory_status, with no arguments, and a badge in the console's
account settings. There are no namespace, snapshot or binding tools, in any surface, for the reason
in the note above.
What stays internal. The catalogue — namespaces, records, snapshots and grants — lives behind
/api/builder/v1/memory on the private control plane, is not a /api/v1 route, and answers 404
from the internet. memory_binding is not a field you can send: it is deliberately absent from the
published OpenAPI schema, and the platform fills it from your account.
Node-side routes under /internal/memory/ are internal traffic between an enrolled node and the
private control plane. They authenticate with the node's own signature and are not callable by
clients.
The same answer in every layer
Memory has one customer-facing question — is it on, and would a task carry it now? — and every
layer answers it with the same three fields (enabled, ready, detail) and the same closed
vocabulary for detail. Pick the layer you are already in; none of them can tell you more than the
others, because none of them is allowed to name a namespace.
| layer | how you ask | reference |
|---|---|---|
| REST | GET /api/builder/v1/memory/status | Memory API |
| Python SDK | client.memory.status() → MemoryStatus | SDK Reference |
| MCP | the get_memory_status tool | MCP tools |
What no layer exposes, deliberately: turning memory on, naming or listing namespaces, and reading or writing what memory contains. That is not a gap waiting to be filled in one of them — the platform owns the binding, and the caller names nothing.
Limits that are deliberate
- A memory payload over its byte limit is rejected (
413), not truncated. - An exact search over its declared budget is rejected (
413), not served partially. - A version conflict on a record is a
409: the platform never silently picks a winner. - A missing or insufficient grant is a
403, and an absent namespace a404— the error does not reveal whether a namespace exists in another account.