Turning it on
Working memory is the space’sagent_state feature, off by default and turned on in the features document by the security role. The agent’s key needs the agent_state scope. The schema is a type with ownership: agent in the object-types document (Object types): the type named like the agent or, when the registry declares exactly one type of that ownership, that one; without one, no field is declared, and every write is refused with not_declared_field.
The schema and the scope
The type declares its fields like any type,pii, sensitivity and retention included, and an agent_state section:
kind and id: the conversation’s or the task’s id, the object as type:namespace:id, or the canonical form of one of the customer’s handles) and by the agent that writes it. The scope travels in the body, never in a URL, because a conversation id can look like a phone number, and Niadra keeps it only as a keyed hash. The state is written by code, never by a model: Niadra does not offer it as a model’s tool in any protocol, it never enters a context or an extraction, and the Console shows its size, version and dates, never its content (the profile’s working memory tab, and GET /v1/profiles/{profile_id}/agent-state).
Writing
PUT /v1/agent-state takes the scope, the agent, the mode, if_version and body, and subject when the scope does not name the customer, so the erasure and the subject’s data package find the state.
- Compare-and-swap (
cas):bodyis the whole new state, and the write applies only when the stored version isif_version(0 when the state must not exist yet); otherwise the answer is 412agent_state_conflictand nothing changes. A field left out ofbodyis gone. - Merge by key (
merge_by_key): each top-level field ofbodyreplaces that field whole, with no deeper merge; a field written as exactly{"$delete": true}is removed; the fieldsbodydoes not name stay. Sub-agents writing different fields in parallel never lose each other’s writes, and a removed field never comes back unless someone writes it again. Withif_version, the merge applies only at that version.
{stored, version, reason}. A field the schema does not declare is refused (stored: false, reason: not_declared_field), and a pii field is masked at write by the space’s rules. A write that would take the state over the cap is not an error: the previous state stays, and the answer is 200 with stored: false and reason: over_cap, because the state usually arrives after the last byte of the agent’s answer, and failing there would cut the conversation. The check order is the version (412), the declared fields, the cap.
Reading
POST /v1/agent-state/read with the scope and the agent returns body, version and updated_at; a state never written reads as an empty body at version 0. A writer reads its own writes: after a stored: true at version N, every later read of the same scope and agent returns N or a newer version, even across Niadra’s two stores, and a read never waits for the database. The SDK keeps, per scope and agent, the last version it wrote or read, and serves the higher of that and what it reads. With Niadra out of reach, it keeps the version locally and sends the write again later with the same if_version; a compare-and-swap that then conflicts is reported to the code (the conflicts property of agent_state in Python and of agentState in TypeScript), never merged in silence. In a replay, the state starts empty and the writes stay with the runner.
Retention and erasure
A state is kept 30 days after its last write by default (from 1 to 180, in the type’sretention.state), and a field may be kept for less (retention.<field>), counted from its own last write: an expired field is never served, leaves the state with the next write and Niadra removes it from what it stores. Erasing a customer erases the states of their scope and the ones naming them in subject; erasing a conversation erases the states of that conversation’s scope. The subject’s data package carries their states, by declared field.
Next steps
Object types and state
the type with
ownership: agent that gives the schema.Agent memory
the notes about the trade, which enter the prompt and never speak of a customer.
Write working memory
the reference of
PUT /v1/agent-state.Privacy
the erasure and the subject’s data package.

