BrainDB write contract
Every write to BrainDB carries governance metadata. Here is the contract — and how to satisfy it.
Last updated · 2026-06-04
BrainDB is the organizational memory layer behind every Odin product. It stores decisions, audit events, and assumptions across the platform. What makes it useful — and what separates it from a key-value store — is the governance contract enforced at the write path.
The four required fields
Every POST /api/v1/memory body must include:
namespace— 3+ segment path with the decision id (e.g.brain/decisions/use-pgvector). The first segment determines the namespace type (decisions, audit, hubs, projects, sessions, assumptions, ai-sessions, coordination, people, knowledge, compass, feedback, trust).key— typically a version tag likev1. Append-only namespaces (audit, llm-calls, llm-redaction) reject duplicate (namespace, key) by 409 Conflict at the storage layer.value— the entry payload, any JSON shape.rationale— ≥10 chars, ≥2 words. The why behind this write.owner— singular string with prefixhub:,user:, orsystem:. NOT an array.dependencies— array of{namespace}:{key}strings. Colon between namespace and key.
Minimal example
POST /api/v1/memory
{
"namespace": "brain/decisions/use-pgvector",
"key": "v1",
"value": {
"choice": "pgvector",
"alternatives": ["weaviate"],
"rationale": "Lower op cost. Same recall."
},
"rationale": "Vector store choice — pgvector preferred",
"owner": "user:mitchell",
"dependencies": ["brain/decisions/postgres-version:v1"]
}Append-only audit namespaces
Three namespace types are immutable once written: audit, llm-calls, llm-redaction. They are enforced by three defense layers:
- Postgres trigger raises an exception on UPDATE/DELETE for rows in these namespaces.
AppendOnlyConflictErroris thrown by the storage layer before any SQL runs when (namespace, key) already exists. HTTP layer maps this to 409 Conflict.- Monotonic key scheme: helpers like
buildAuditKey(correlationId)from@odinlabs-ai/auditreturn${correlationId}-${Date.now()}, making (namespace, key) collisions unreachable by construction.
Read shape vs write shape
The write shape above is the canonical contract. The read shape returned by GET /api/v1/memory/:namespace/:key is slightly different — governance fields are flattened to the top level instead of nested under metadata:
GET /api/v1/memory/brain%2Fdecisions%2Fuse-pgvector/v1
{
"success": true,
"entry": {
"namespace": "brain/decisions/use-pgvector",
"key": "v1",
"value": {...},
"owner": "user:mitchell",
"rationale": "Vector store choice...",
"dependencies": ["brain/decisions/postgres-version:v1"],
"createdAt": "2026-...",
"updatedAt": "2026-...",
"version": 1
},
"correlationId": "..."
}Helpers reading governance fields should accept both shapes:
OWNER=$(jq -r '.entry.owner // .entry.metadata.owner // ""')
RATIONALE=$(jq -r '.entry.rationale // .entry.metadata.rationale // ""')
DEPS=$(jq -c '.entry.dependencies // .entry.metadata.dependencies // []')Why governance at the write path
The cheapest moment to enforce governance is at the boundary where data enters. By making rationale, owner, and dependencies required fields, BrainDB shifts compliance work from review-time to write-time. A six-month review can answer “who decided this and why” with a single query — because there was nowhere else to put the answer.