Skip to content
Beta. This surface may change before GA; breaking changes are dated in the changelog.

Review

A Brain is either open or reviewed. In both modes an admission policy decides each write — not the caller. On a reviewed Brain most writes wait for a decision; your own edits and additive schema still land immediately; destructive changes always wait; unbacked agent claims wait until you admit them. On an open Brain the default is to land, with the same holds on destructive writes. mode is a property of the Brain, never of the caller.

One Brain · chain of custodyIllustrative lifecycle
01Sources
Records
Documents
Agent writes
02Review
ProposedHuman or policy decisionAccept · edit · reject
03Context
Accepted stateCited answer[1] source passage
04Receipt
Verifiedrcp_019fWhat the read consumed
Terminal window
curl -X PATCH "$API/v1/brains/tenant:acme" \
-H "authorization: Bearer $NICIA_KEY" \
-H "content-type: application/json" \
-d '{ "mode": "reviewed" }'

New Brains are open, because a Brain that waits on everything answers nothing on its first day. Turn review on when the knowledge starts mattering — typically when an agent you did not write starts producing it, or when a customer will see the answers.

Nothing about how you write. The same call returns a different status:

{
"data": {
"change": {
"id": "chg_44a1e0",
"status": "staged",
"createdAt": "2026-08-14T10:59:41Z"
}
}
}

Branch on change.status, always:

Status Meaning
applied It landed. Readable now.
staged Waiting for a decision. Not readable yet.
rejected The Brain declined it. The request was fine; the content was not.

A rejection is a 200. The request was well-formed and the Brain made a decision — that is not an HTTP error.

A write only ever returns one of those three. A change you read back — from GET /changes, or from the response to approve/reject — can also carry partially_accepted (what a partial approve, below, leaves behind) or superseded (a staged change whose target moved on before it was reviewed). The ?status= filter on /changes still only selects the three admission outcomes above.

Reads tell you the same thing from the other side: every /context response carries staged, so an empty answer distinguishes “nothing known” from “waiting on you.”

Terminal window
curl "$API/v1/brains/tenant:acme/changes?status=staged" \
-H "authorization: Bearer $NICIA_KEY"
{
"data": {
"changes": [
{
"id": "chg_44a1e0",
"status": "staged",
"author": {
"kind": "key",
"id": "key_7f3a1c",
"name": "support-agent"
},
"records": [
{
"id": "bob-smith",
"kind": "person",
"before": { "role": "Head of Platform" },
"after": { "role": "VP Platform" },
"evidence": [
{
"source": "zendesk:ticket:8821",
"quote": "Bob Smith, now VP Platform, confirmed…"
}
]
}
],
"createdAt": "2026-08-14T10:55:12Z"
}
],
"nextCursor": "eyJrIjoi…"
}
}

Every staged change carries the diff and the passage it came from, so a reviewer is deciding about evidence rather than about a model’s assertion.

Terminal window
curl -X POST "$API/v1/brains/tenant:acme/changes/chg_44a1e0/approve" \
-H "authorization: Bearer $NICIA_KEY" \
-H "content-type: application/json" \
-d '{}'
curl -X POST "$API/v1/brains/tenant:acme/changes/chg_44a1e0/reject" \
-H "authorization: Bearer $NICIA_KEY" \
-H "content-type: application/json" \
-d '{ "reason": "Title is from a signature block, not a statement." }'

Both take a JSON body, and {} is the one that approves the whole change. A POST carrying no body at all is a 400, not a whole approve.

Approve part of a change by naming what you want:

Terminal window
-d '{ "records": ["bob-smith"], "fields": { "bob-smith": ["role"] } }'

Naming part of a change is a decision about the rest of it, too: any record — or, within a named record, any field — you did not name is declined in this same call. A partial approve settles the whole change at once, so this is final: the producer has to write again for anything declined.

Edit before approving when the substance is right and the wording is not:

Terminal window
curl -X POST "$API/v1/brains/tenant:acme/changes/chg_44a1e0/approve" \
-H "authorization: Bearer $NICIA_KEY" \
-H "content-type: application/json" \
-d '{ "edits": { "bob-smith": { "role": "VP, Platform Engineering" } } }'

The edit is attributed to you, not to the agent that proposed it.

Undoing a change that has already landed is a console action today, not an operation on this API surface. When it runs, it either restores the content or refuses the whole revert up front — it never marks a change reverted while leaving the content in place.

Attribution is derived from the key that made the call — never from a field somebody filled in. “Who approved this” will be answered by the Brain, not by your logging.

Review is a checkpoint, not necessarily a human. A key with the review capability can settle changes, so you can put your own evaluator in front of the queue and only escalate what it is unsure about.

const changes = `${API}/v1/brains/tenant:acme/changes`;
const auth = { authorization: `Bearer ${NICIA_KEY}` };
// One page of the queue; walk the rest with `data.nextCursor`.
const { data } = await fetch(`${changes}?status=staged`, {
headers: auth,
}).then((response) => response.json());
for (const change of data.changes) {
const verdict = await myEvaluator(change);
if (verdict.confident) {
await fetch(`${changes}/${change.id}/approve`, {
method: "POST",
headers: { ...auth, "content-type": "application/json" },
body: "{}",
});
}
// leave the rest for a person
}

mode sets the policy’s default outcome — it is not a per-write switch. A key cannot ask for its writes to skip review, and no request body can either — the Brain’s admission policy decides every write, whoever sent it. That is deliberate: an outcome a caller can select is an outcome an agent can select.

So there is exactly one lever, and it is on the Brain. What each write does depends on its kind:

Write kind open reviewed
Destructive — schema, identity, delete wait wait
Human STAKE land land
Additive schema land land
Agent STAKE land wait
Everything else land wait

“Wait” means the change stages until a human or a trusted service settles it; “land” means it is admitted immediately and shows up in /changes. On reviewed, most agent output waits — not all of it.

If you want a trusted pipeline writing straight in while agents are reviewed, give them separate Brains rather than separate trust levels inside one. A Brain is cheap, its handle is yours to choose, and two Brains with different modes say plainly what one Brain with per-caller exceptions only implies.

Register a webhook so a staged change reaches your queue instead of waiting to be polled:

Terminal window
curl -X POST "$API/v1/brains/tenant:acme/webhooks" \
-H "authorization: Bearer $NICIA_KEY" \
-H "content-type: application/json" \
-d '{ "url": "https://ops.example/nicia", "events": ["change.staged"] }'

See Webhooks for signature verification and delivery semantics.