Repository navigation
v0.3.0 — Company Brain: knowledge mounted, not prompted
v0.3.0 — Company Brain: knowledge mounted, not prompted
Date: 2026-09-03 · Base: main @ 20a4ad4 (v0.2.0 line) · Wave: v03/brain — k-041..k-045
v0.2 made the kernel governed — every surface pinned by a frozen,
hash-attested contract. v0.3 teaches the kernel the Company Brain:
five collections under /org/<id>/ (missions, decisions, capabilities,
evidence, notes) where knowledge is mounted, not prompted. An
agent that wants to cite a decision no longer pastes a chunk of context
into a prompt — it asks the kernel for a mount of that path, and the
kernel returns a read view, scoped to the caller, with the authority law
already applied (you can read an authoritative object; you can never
be one without a human stamp).
That is why the brain namespace was the last big unmaterialized frozen
contract. ADR-0023 was already a brain.ns/1.0 schema in
contracts/manifest.json (sha256 0f5ed6…35f4); what v0.3 does is wire
the store, the REST surface, and the release-ring law that lets the
brain surface roll out under the same one-step-only discipline as the
rest of the kernel. The contract is law; v0.3 makes it live.
What this wave added
Four sibling slices land in this release. All four are gate-checked
together — the brain surface goes live when store + API land
together, never half-on.
k-041 — brain kernel laws (k-impl, v03/brain-kernel)
The namespace regex, the append-only revision law, the central
authoritative ⇒ human_stamped promotion invariant, the
ephemeral-never-authoritative law, tombstone-as-append, and the mount
scope + org-boundary rules. This is where ADR-0023 becomes code, not
just a schema. Without k-041 the rest of the wave is unmounted; with
k-041 alone, nothing is exposed.
- Namespace regex (frozen in
brain.ns/1.0):
^/org/[a-f0-9-]+/(missions|decisions|capabilities|evidence|notes)/[A-Za-z0-9_/-]+$
— five collections only, lowercase hex org id, an object may live in
one collection. No cross-collection aliases; no implicit
normalisation. A path that does not match is a 400 at the API and a
schema-rejection at the store. - Append-only revisions: every write to a
(path, revision)pair
is a new row, never a mutation. The PK is(path, revision)so
revision collisions are detected at the constraint, not in
application logic. There is no UPDATE path onbrain_objects;
the only mutating verbs arepromoteandtombstone, and both
append a new revision. - The central law — authoritative ⇒
human_stamped: if and only
ifauthoritative == truethenpromotion == "human_stamped".
This is theallOf/if/thenclause in the schema. The store
enforces it again on insert; the API enforces it on the wire; the
test
tests/contracts/contracts_test.go::TestAdversarialAgentKnowledgeCannotBecomeAuthoritative
enforces it as regression law. Three layers, one rule. - Ephemeral can never become authoritative:
class == "ephemeral"
⇒authoritative == falseis not a soft warning, it is a
structural property. Promoting an ephemeral object is rejected
with the same error code as any other authoritative-without-human
attempt. - Tombstone-as-append: deleting an object is not a row removal,
it is a new revision withtombstone == trueand empty body.
Reads default to "latest non-tombstone revision", so a tombstone
hides the object without erasing its lineage. A consumer that
walks the full revision log still sees the whole history. - Mount scope + org-boundary: a mount is a READ view of a path
rooted at a single org. The mount'sorg_idmust equal the
object's org; a mount from org0a1bcannot reach into org
deadbeefregardless of token scopes. Cross-org reads are
rejected at the store, not the API.
k-042 — brain schema v11 persistence (k-impl, v03/brain-conformance)
Two new tables behind the existing schema_version ledger:
| table | PK | notes |
|---|---|---|
brain_objects |
(path, revision) |
append-only, every write is a new revision, tombstone revisions hide without erasing |
brain_mounts |
(subject, path) |
read views; subject is the token identity, path is the org-rooted brain path; revoked_at nullable |
Restart migrates v10 → v11 idempotently. Both tables are
CREATE TABLE IF NOT EXISTS; the existing bumpSchemaVersion(11)
guard (services/work/store/store.go) checks
SELECT COALESCE(MAX(version), 0) FROM schema_version and only
inserts 11 if current < 11. No backfill, no destructive ALTER.
How to check (operator-side, after the v0.3 binary is live and a
restart has happened):
sqlite3 /var/lib/works/works.db 'select max(version) from schema_version'
# expect: 11Honest note: measured baseline on this host (2026-09-03) — the live
store at /var/lib/works/works.db reports max(version) = 10 with
the v0.2 ledger rows 5, 6, 7, 9, 10. The 11 will only appear after
the v0.3 binary has been started at least once. If you read 10, the
binary on disk is still v0.2.
k-043 — /v1/brain REST surface (k-impl, v03/brain-cli)
The HTTP surface that the kernel exposes for brain objects and brain
mounts. Bearer auth, 64 KiB bodies (KB-class per ADR-0026 §9; the
link surface uses the same cap, kept consistent for v1), JSON
in/out. Every route is documented in contracts/, and the wire
table below is exactly the route table — do not invent flags.
| Endpoint | Method | Auth | Body | Purpose |
|---|---|---|---|---|
/v1/brain/objects |
POST | Bearer (worker) | {path, class, body, evidence_ref} |
append a new revision to a path (writes require a real wrk_<32hex> work id; see runbook) |
/v1/brain/objects |
GET | Bearer (worker, read scope) | — | ?path=<exact> returns the latest non-tombstone revision; ?prefix=<dir> lists latest-non-tombstone revisions under that org-rooted prefix |
/v1/brain/objects/promote |
POST | Bearer (worker + write scope) | {path, revision, human_id} |
append a new revision with authoritative: true, promotion: human_stamped; rejected if class == "ephemeral" |
/v1/brain/objects/tombstone |
POST | Bearer (worker + write scope) | {path, revision} |
append a new revision with tombstone: true; the object is hidden from default reads but its revision log is preserved |
/v1/brain/mounts |
POST | Bearer (worker) | {path, scope, reason} |
create a read view of a path for the caller's subject; org-boundary checked |
/v1/brain/mounts |
GET | Bearer (worker) | — | ?subject=<self> (or omit for self) lists the caller's active mounts |
/v1/brain/mounts/revoke |
POST | Bearer (worker) | {path, subject} |
revoke a mount the caller owns; idempotent |
Auth model (v1): bearer-auth with read scopes on the GET
surface, write scopes on the promote / tombstone / write verbs.
A policy.token carrying a narrower scope than the route requires
is rejected (401). The policy-token scope-subset enforcement on
mounts themselves (the ADR-0023 §6 double-enforcement rule) is not
in this wave — v1 mounts are bearer-auth with read scopes only.
See Known deferred limits below.
Fail-closed 503-unwired design. When the brain surface is not
fully wired — the running binary predates k-042, so the concrete
store does not yet satisfy the BrainBackend interface — every
/v1/brain/* route answers 503 brain_unavailable. There is no
env opt-in and no secret: the wiring is a type assertion in
cmd/works-api/main.go. This is loud by design: an operator
pulling on a brain route before the wave is fully landed sees a 503
with the exact reason, never a 200 with an empty list. The boot log
line is Brain surface enabled (/v1/brain/) when live (mirrors the
link-surface log line). This is what the runbook greps for.
The brain surface goes live when store + API land together.
k-041, k-042, and k-043 are three pieces of the same lock: the
routes mount whenever the API side (k-043) is in the binary, but
they only serve once the store side (k-042) is too — the type
assertion is the interlock. The integrator's deploy (rebuild +
restart after all three merges) flips the surface live as one
atomic action.
k-044 — release.rings law (k-impl, v03/release-rings)
The release-ring contract from the frozen release.rings/1.0 schema
(9677b52…01a9 in the manifest) is now operational law for every
kernel-surface rollout, not just the link surface. The brain wave
is the first surface shipped under it.
- Advance one-step-only.
ringsis anenum: [internal, alpha, beta, stable]array withuniqueItems: true; the advance law
is that a surface moves at most one ring per release promotion.
No skipping internal → beta, no skipping alpha → stable. The
schema'sno_ring_skips: trueis the regression test; the
release tool refuses to advance two rings. - 48h beta soak.
beta_soak_hours: const 48is in the
schema. A surface inbetacannot be promoted tostableuntil
it has been continuously live inbetafor at least 48 hours.
The release tool records thebeta_attimestamp and refuses
promotion otherwise. This is the same soak that the link
surface is currently running. - Kill-switch required off-internal. Every ring below
stable
MUST have at least one entry inkill_switch(a list of env-var
names or runtime flags that can revert the surface without a
redeploy). The schema accepts an empty list forstable. The
brain surface ships withWORKS_BRAIN_KILL_SWITCH(default: off
in prod) wired in from day one. - Revert-with-reason + RevertLog. Any revert to an earlier ring
must carry a written reason (operator note, ticket ref, or
auto: <detector>for the automated health-check reverts) and is
appended torelease_revert_log(durable, append-only). The
RevertLog is what makes the rings auditable after the fact; it
is the surface of evidence that the law was followed. - Stable needs freeze evidence. A
stablepromotion requires
the freeze-attested contract tests for that surface to be
green at the promotion SHA. For v0.3, the brain surface's
freeze evidence is thebrain.ns/1.0adversarial test plus
the schema hash incontracts/manifest.sha256; a stable
promotion that does not have both is rejected by the release
tool.
Known deferred limits (be honest)
The following are deliberately not in v0.3. They are documented
here so the next wave's slice-card can name them precisely, not so
the next wave can silently slip them in.
- Policy-token scope-subset enforcement on mounts (ADR-0023 §6
double-enforcement). v1 mounts are bearer-auth with read scopes
only. The full policy-token-derived scope-subset check on a mount
(the rule that a mount's effective scope is the intersection of
the caller's token scope and the mounted object's ownallowed_*
metadata) is a v0.4+ slice. The API does not yet accept
policy_tokenin the mount body; if you need it, file the slice
card against ADR-0023 §6 explicitly. - PULSE edge-mounts over
/link/v1. A PULSE device cannot yet
request a brain mount through the link surface. The route exists
on the link side (POST /link/v1/mounts) for context mounts
(ADR-0026); brain mounts over link are a later slice that needs
a brain-aware claims shape on the link device token. The two
surfaces are independent in v1. - No search / index. There is no
GET /v1/brain/searchand
there is no inverted index. This is per ADR-0023 §5: search is a
presentation concern, never a source of truth. An object that
only exists in an index is not a brain object. If you want to
find a decision, you know its path; if you do not, the right
answer is "make the path findable from where the decision is
referenced" — not "build a search index". - Content is not deduplicated across paths. If
/org/0a1b/notes/x
and/org/0a1b/notes/yhave the same body, both revisions are
stored in full. Content-addressed dedup is a storage optimisation,
not a correctness one, and is deferred. If you want to share a
body, mount the same path from two places — that is what mounts
are for. - CLI
works braincommand not shipped this wave. The
operator-side CLI verb for inspecting mounts / objects from the
shell is not in v0.3. The k-043 sibling worktree (CLI surface)
shipsworks brainas a separate slice; if that slice merges
after this release the verb will exist; if it does not, you
havecurland the runbook. Do not pretend the CLI is shipped
in v0.3.
Upgrade notes (v0.2 → v0.3)
- No breaking wire changes for existing routes.
/link/v1/*,
/v1/works/*,/v1/workers/*are unchanged. The only new wire
is the/v1/brain/*prefix above; it answers 503 until
the binary lacks the k-042 store methods. - Schema migration v10 → v11, automatic and idempotent on
restart. Verified baseline (2026-09-03, on this host): the
liveworks.dbreportsmax(version) = 10. After the v0.3
binary has restarted at least once, the same query returns
11. The migration isCREATE TABLE IF NOT EXISTSonly — no
backfill, no destructive ALTER, safe to run repeatedly. - No new env flag. The brain surface needs no opt-in and no
secret; k-041+k-042+k-043 in the running binary is the enable
condition (store type-assertion interlock). Until then routes
answer 503brain_unavailable. The runbook
(docs/runbooks/brain-mounts.md)
walks the smoke loop. WORKS_BRAIN_KILL_SWITCHships populated. The brain
surface lands with at least one kill-switch wired in. The
default state in prod is off; flipping it on reverts the
surface to a previous ring without a redeploy.- Contract tests are still regression law. The brain tests
intests/contracts/contracts_test.go(TestAdversarialAgentKnowledgeCannotBecomeAuthoritative
and the conformance / baseline tests forbrain.ns/1.0) fail
on drift; the manifest hash forbrain.ns/1.0is the freeze
attestation.
v0.3.0 wave — the four slices
| Slice | Title | Owner worktree | PR |
|---|---|---|---|
| k-041 | brain kernel laws (namespace, append-only, authoritative ⇒ human_stamped, tombstone-as-append, mount scope + org-boundary) | v03/brain-kernel |
PR (pending) |
| k-042 | brain schema v11 persistence (brain_objects PK(path,revision), brain_mounts, idempotent v10→v11 migration) |
v03/brain-conformance |
PR (pending) |
| k-043 | /v1/brain REST surface (POST objects, GET objects?path/?prefix, POST objects/promote, POST objects/tombstone, POST mounts, GET mounts?subject, POST mounts/revoke; bearer auth; 64 KiB; fail-closed 503-when-unwired) |
v03/brain-cli |
PR (pending) |
| k-044 | release.rings operational law (one-step-only, 48h beta soak, kill-switch required off-internal, RevertLog, stable-needs-freeze-evidence) | v03/release-rings |
PR (pending) |
| k-045 | v0.3.0 release notes + brain-mounts runbook + README v0.3 section (this slice) | v03/brain-docs |
PR (pending) |
Five workers, disjoint file-ownership. The integrator fills the
"PR (pending)" cells with the merge SHAs once the wave lands
together — that is the same pattern the v0.2 wave used (see
docs/RELEASE-v0.2.0.md, final table).
Governance invariants (unchanged by v0.3, now contract-pinned)
All v0.2 invariants carry over. The one new invariant v0.3 adds:
authoritative ⇒ human_stampedis three-enforced: schema
(brain.ns/1.0allOf/if/then), store (re-validated on insert),
and adversarial test
(TestAdversarialAgentKnowledgeCannotBecomeAuthoritative).
Drift in any one of the three fails the wave.
Verification at release
go build ./...— cleango test ./tests/contracts/ -count=1— 21/21 PASS
(the brain adversarial test is in this set; if it goes red the
central law has drifted)- Full suite
go test ./... -count=1— all packages ok - Live store schema version (after restart):
11 journalctl -u works-api -n 20 --no-pager | grep "Brain surface"
→Brain surface enabled (/v1/brain/)once the store asserts
ADR boundary (honest note)
ADRs 0005–0007 live in this repo (docs/adr/). ADR-0023
(Company Brain) and ADR-0013 (release rings) are the governing ADRs
for this wave; they are cited from the frozen schemas and the
package docs here, but their full text is not vendored in-repo.
Treat the frozen schemas (contracts/schemas/brain.ns.schema.json,
contracts/schemas/release.rings.schema.json) and the
contracts/manifest.sha256 as the authoritative restatement.