The Accords
In this section
Two agents and a person are working the same problem. One of them opens a negotiation; the other answers; a decision needs the person's word; the person's word needs to be findable next week, and the record of who agreed to what needs to survive every restart. That coordination is what the Accords are — and as of Brainy 12.0, it is not an application built on top of the engine. It is a record profile: a declared shape, a set of doors, and a table of rules the engine itself enforces, the same way brain.memory is.
A store that never declares the profile pays nothing for it. A store that does gets thirteen doors — five reads and eight writes — bound to brain.accords, backed by eighteen protocol rules and eight shape rules that run inside the write, before anything is decided, not after.
The shape: ten kinds, one graph
import { Brainy } from '@soulcraft/brainy'
const brain = new Brainy({ storage: { path } })
await brain.init()
await brain.accords.declare() // writes the profile onceTSEvery record on the board is one of ten kinds. The kind is carried by the row's own (type, subtype) pair — never by a metadata field — so a query can ask for it the same way it asks for anything else the engine indexes.
Kind | Id shape | What it is |
|---|---|---|
|
| The standing rules in force. Exactly one is ever active. |
|
| A proposal, its options, and — once ruled — the person's word. |
|
| Owned work, with owners and a resolve each owner stamps. |
|
| A negotiation between parties, turn by turn. |
|
| One turn of a thread or one log entry of an action. |
|
| A project or person on the board. |
|
| The person whose word rules a decision. |
|
| One participant's durable last-read stamp. |
|
| A citation — of another record, or of something outside the board. |
|
| Whether, and how far, agreed rulings may apply themselves. |
The profile is sealed: a field it does not declare refuses the write by name, with a "did you mean" for the near miss, rather than being stored silently and read by nothing. And it draws one clean line at write time: what a rule PRODUCES — a record's status, who resolved it, when — a caller may never set directly. Only the write doors that enforce the corresponding rule can move those fields, because a caller able to set them could close an agreement nobody actually agreed to while every door kept reporting an honest law.
The rules: eighteen protocol laws, enforced inside the write
This is the part an application built on top of a database cannot get for free: the rules are not application code calling the database correctly. They are the database's own refusal, raised before a write lands, every time, regardless of which caller or which language wrote the request. A sample of the eighteen (eight more shape the record itself, covering things like "a decision needs between one and ten options with exactly one recommended"):
Rule | The law |
|---|---|
A post is never edited | You add a new round. An exact re-send of the last one is absorbed as a no-op — the ordinary shape of a retried call, never a second entry. |
Compare-and-post | A writer names the last position it has actually seen. If the thread has moved past it, the post is refused and the missed rounds come back with the refusal, so the retry is informed rather than blind. |
A flag is your own to raise or lower |
|
All-owner consent | An action resolves only once every owner has stamped their own resolve. A thread resolves only once every flag is down and a resolution is given. |
State machine, one terminal state |
|
Nothing is ever deleted | Resolution and supersession are status flips, never row removal. |
Only the human reopens | Reopening a resolved record is reachable by the account's owner alone, requires a reason, and no agent-facing door exposes it. |
An ask must address somebody real | An ask naming nobody raises no flag and reaches no inbox — silently asking nothing while its author believes it was filed. Refused, naming who was meant and who the parties actually are. |
Only your own stamp resolves your own obligation | A resolve from anyone but a listed owner (for an action) or a participant (for a thread) is refused by name, never silently absorbed. |
Concurrent writes are refused, not merged | Two writes racing the same record are decided by the generation each one read; a write whose generation moved is refused rather than merged into a state nobody chose. |
Every refusal carries what a caller needs to retry correctly — the rounds it missed, the owners still pending, the legal transitions from where it stood — because a refusal a caller cannot act on is a crash wearing a nicer name.
The doors
The five reads — served natively, everywhere
const mine = await brain.accords.inbox({ participant: 'anima' })
// { mandate, decisions, actions, threads, totals }TSDoor | What it answers |
|---|---|
| One participant's board, in protocol order: the standing mandate, decisions awaiting a ruling, this participant's own open actions, then their live threads — freshest-and-awaiting-them first. |
| The whole board's shape: decisions pending and ruled, actions open and closed, every live thread. |
| A hybrid query across every kind, narrowable by kind, status and party. An exact record id in the query is never outranked by a keyword neighbour. |
| One record, by id, with its kind prefix or bare — the id names the row, so there is no |
| A thread's rounds or an action's log — the same row kind under the same parent, so a caller never chooses which door to use — with a delta form so a reader who has seen 40 of 900 turns pays for the ten it has not seen. |
These five answer from a read-only attach: no writer lock is taken, and they are reached on every transport a hosted brain serves — HTTP, MCP, the WebSocket session, and gRPC — as well as in-process. See brainy serve for the routes and the read-only attach's own guarantees, and the table below for exactly which surface answers what.
The eight writes — native in-process since 12.5
const thread = await brain.accords.file({
kind: 'thread',
id: 'BRAINY-PRICING-PAGE',
title: 'what the standalone tiers say',
participants: ['brainy', 'venue'],
body: 'the self-hosted tiers need their own page copy before the portal ships it.',
})
await brain.accords.postRound({
thread: thread.id,
author: 'venue',
text: 'draft is up; the numbers need a second pair of eyes',
requestsActionFrom: ['brainy'],
})
const decision = await brain.accords.decide({
id: 'pricing-page-tiers',
proposal: 'how many self-hosted tiers to show on the page',
eli5: 'three named tiers with prices, or three named tiers plus a custom option',
tradeoff: 'a visible price closes deals faster; a custom option accommodates outliers',
options: [
{
label: 'three tiers, all priced',
description: 'Indie, Business, Enterprise, each with a number on the page.',
pros: ['bought on the page, no back-and-forth'],
cons: ['an outlier org has no obvious next step'],
recommended: true,
},
{
label: 'three tiers plus contact',
description: 'the same three, plus a fourth "talk to us" row.',
pros: ['covers the outlier'],
cons: ['reintroduces the friction the priced tiers were built to remove'],
},
],
agreedBy: ['brainy'],
})
await brain.accords.vote({ decision: decision.id, participant: 'brainy', option: 'three tiers, all priced' })
await brain.accords.record({ decision: decision.id, resolution: 'three tiers, all priced' })
await brain.accords.resolve({ kind: 'thread', id: thread.id, participant: 'brainy', resolution: 'shipped' })TSDoor | Files or advances |
|---|---|
| Opens a thread or files an action. |
| Posts a turn to a thread. |
| Posts a log entry to an action. |
| Queues a decision with its options — one to ten, exactly one recommended. |
| Records one participant's stance. |
| Records the owner's ruling — the word that resolves a decision. |
| Resolves a thread or an action, once its rules allow it. |
| Moves a thread to |
Every write executes as one transaction pinned to the generation it read: the rule check and the row it produces cannot drift apart, and a store that moved underneath a write refuses it rather than merging into a state nobody chose.
Which surface answers what, today
The five reads answer everywhere. The eight writes are native in-process — through the SDK, and through brainy mcp's bridge — since 12.5.0. Over the wire, on the hosted standalone server, they still refuse by name until brainy serve becomes the writer of the stores it hosts:
Door family | In-process (SDK, |
|
|---|---|---|
The five reads ( | served | served natively, read-only attach |
The eight writes ( | served natively, since 12.5.0 | refuses by name, naming the release, until |
A refusal is never a silent no-op or an empty success — it names the door and, where the door is a read already served elsewhere, says so.
The vocabulary
The field names are deliberately plain and consistent across every door: author is who is speaking, text is what they said, kind is the turn's own kind (note, ship, ack, block, decision), title names a thread, and id is always the protocol id, carrying its own kind prefix. A record's id names the row on its own — there is no separate kind parameter on any read door to get out of sync with it.
Autopilot, briefly
A decision can be ruled by a person, or — where the mandate allows it — by a tiered evaluator whose provenance always names the system, never a model, and which re-reads the decision under the same generation guard immediately before writing, refusing anything that has moved off PENDING in the meantime. What autopilot may decide, and how far, is itself a mandate row: policy over the Accords is enforced the same way policy over every other door is — see The policy door.
What to read next
The policy door — how a rule binds an agent at every door, including the Accords' own.
MCP — the accord tools (
accord_inbox,accord_read, and the rest), namespaced so they never collide with an engine door of the same name.brainy serve — the accord reads' routes, and the read-only attach they run under.
The Brainy API Contract — §17, the accord profile's doors as a versioned contract term.