The things it must never forget
Retrieval is probabilistic. Some context should not be. Memory slots are typed, always-on facts that go into every prompt regardless of what the query happened to match — pinned, scoped, evidenced, and lockable against deletion.
- 4 conventional slot types
- Global or per project
- Lock refuses deletion
- 6 named retrieval recipes
Pinned context, not retrieved context
“Never write to production without asking” is not something you want to hope a similarity search surfaces. Neither is “this client's fiscal year ends in March” or “the user prefers British spelling.” These are standing facts, and the right behaviour is to inject them every time.
A slot has a name, a value of any JSON shape, and a scope. The name
is yours to choose; the four the agent tool advertises cover most of
it — user_preferences, project_context,
active_constraints and do_not_do. Leave
project_id off and the slot is global; set it and the
slot only applies inside that project.
Writes upsert on the composite key
project:scope:slot_name, so a client that writes the
same slot on every boot updates one record instead of growing a pile
of them. That makes slot writes safe to make idempotent in an agent
loop.
memory_slot
A locked constraint slot as stored
- slot_name
- active_constraints
- slot_value
- { "deploy": "never on a Friday" }
- scope
- user
- project_id
- atlas-migration
- locked
- true
- confidence
- 0.95
- status
- approved
- authority
- human_reviewed
- evidence_refs
- sp_71c4
- verification_state
- supported
POST /v1/memory-controls/slots
A slot is governed like everything else
Pinned context is high-leverage, which is exactly why it should not be a free-text field an agent can overwrite on a whim.
The lock
Set locked: true and
DELETE /slots/{record_id} refuses with HTTP 409
and the message “slot is locked”. An agent cannot clear a safety
constraint by deciding it is no longer relevant. Unlocked deletion
is an archive rather than a purge — the record stays, with status
archived, and drops out of ordinary listings.
Review status and authority
Slots land as needs_review by default, which means a
slot an agent invented does not immediately carry the weight of one
a person wrote. Mark it approved or
promoted and the record's authority is upgraded to
human_reviewed; anything else stays
generated.
Evidence
Attach evidence_refs — source span ids, record ids — and
the slot is written as verification_state: supported.
Attach none and it stays unverified. “The client wants
weekly reports” either traces back to something or it does not, and
the slot records which.
Confidence and visibility
confidence defaults to 0.75 and is bounded to the 0–1
range. visibility defaults to private and
can widen to shared, organization or published. Both travel into the
assembled context block, so a consumer can weigh a slot rather than
treat every one as equally certain.
One call, ready to inject
GET /v1/memory-controls/slots/context collects the slots
that apply and returns them as a flat block: name, value, confidence,
review status and evidence references for each, plus a count. Pass
project_id to scope it, or repeat
slot_names to fetch only the ones this particular call
needs.
The block is deliberately data, not prose. Every value arrives with the metadata that says how much to trust it, so the caller decides how to frame it rather than receiving a paragraph that has already made that decision.
?project_id=atlas-migration
count 3
do_not_do
"never run a migration unreviewed"
confidence 0.95 · approved
project_context
{ "db": "postgres 16", "rls": true }
confidence 0.80 · approved
user_preferences
{ "spelling": "en-GB" }
confidence 0.75 · needs_review
Six named retrieval recipes
“Search harder” is not a setting. A recipe is a named, stored parameter set, so deep means the same thing in every service that asks for it, and changing what it means is one API call rather than a deploy.
| Recipe | vector_top_k | lexical_top_k | graph_depth | reranker | token_budget | Also sets |
|---|---|---|---|---|---|---|
cheap | 12 | 12 | 0 | off | 2,000 | prefer_verified |
balanced | 32 | 32 | 1 | on | 6,000 | prefer_verified |
deep | 80 | 80 | 2 | on | 16,000 | prefer_verified |
forensic | 120 | 120 | 3 | on | 30,000 | include_evidence |
verified_only | 48 | 48 | 1 | on | 8,000 | verified_only |
low_latency | 8 | 8 | 0 | off | 1,200 | prefer_verified |
Every recipe sets prefer_verified.
verified_only raises that from a preference to a rule and
drops anything unverified on the floor — the profile to reach for when
an answer is going in front of a client. forensic goes the
other way: three hops of graph depth, 120 candidates from each of the
lexical and vector arms, and include_evidence so the
supporting records travel with the result.
Saving a recipe merges your values over the built-in of the same name,
so raising deep's token budget does not mean restating its
other five fields. Listing returns your saved profiles plus any
built-in you have not overridden, each flagged
builtin: true with an id of
builtin:{name}, so a client can show which are
yours.
One thing to be clear about: a recipe is a declaration your client
reads and applies. It is not automatically bound to the retrieval
engine's own mode switch — POST /v1/context takes
mode of cheap, balanced, deep or forensic with its own
token budgets of 1,800, 3,500, 8,000 and 14,000. The recipe is where
your organisation's answer to “what does deep mean here?” lives, in
one place, versioned and readable by every service that needs it.
Six operations
Four paths under /v1/memory-controls.
| Endpoint | What it does |
|---|---|
POST /v1/memory-controls/slots | Create or replace a slot. Upserts on project, scope and slot name, so writing the same slot twice updates it rather than duplicating it. |
GET /v1/memory-controls/slots | List slots, optionally filtered by project or a substring query. Up to 1,000 per call. |
GET /v1/memory-controls/slots/context | Assemble the slots into an injection-ready block: name, value, confidence, review status and evidence references, plus a count. |
DELETE /v1/memory-controls/slots/{record_id} | Archive a slot. Returns HTTP 409 if the slot is locked; the lock has to come off first. |
POST /v1/memory-controls/retrieval-recipes | Save a named retrieval profile. Overrides are merged over the built-in of the same name, so you can change one number and keep the rest. |
GET /v1/memory-controls/retrieval-recipes | Your saved profiles, plus any built-in you have not overridden, flagged builtin so a client can tell them apart. |
Give your agents a memory you can audit
Run the whole system on your own hardware under the MIT licence, or ask us about hosted access. Both start from the same place.