How it works · drawn from the reference build at 0.1.1

One unit, end to end.

The never touches the code. It writes a contract, hands a session a worktree, reads the report the session wrote, re-runs the checks itself against the commit, and merges or routes. Everything on this page is what packages/regulator/src/controller.ts and the Pi host's session extensions actually do, and none of it is aspirational.

This page runs deeper than the others on purpose. Where the product and course pages summarize, this one shows the actual sequence diagram, two state diagrams (one for a single unit's own lifecycle, one for how a whole software change moves through six different unit types), the real contract and report JSON, a table of every extension hook a session fires, and the exact files an instance writes to disk. If you came here to see the mechanism itself, this is the page.

Vocabulary — for this page specifically Full glossary ↗
unit
The smallest piece of dispatched work — one contract, one session, one verdict.
worktree
A git checkout on its own branch, dedicated to exactly one unit, so units never collide.
work contract
What the unit is authorized to decide: fixed, delegated, or left explicitly unresolved.
lease
A time-limited claim on that worktree — it expires if whoever holds it goes quiet.
closeout gate
The check that re-runs the unit's tests itself before trusting its report.
obligation
A signal — often "a person needs to answer this" — that stays open until resolved.
attempt
One immutable, claimed run of a unit against a specific revision. It doesn't finish or cancel the work by itself — routing decides what happens next.
workload
A declared set of unit types for one kind of job — six of them, below, for software.
capability profile
A bounded grant of tools and writable paths a unit runs under — a positive list, not a persona.
evidence
A check result tied to the exact commit it ran against — never just "the tests passed," always "the tests passed, at this revision."
technical verdict
Pass, fail, or inconclusive — decided mechanically from evidence, never from what the unit says about its own work.
reintegration
Bringing an isolated unit's work back into the main line — the moment two units' assumptions about the same file can collide.
The loop

Orchestrator, session, worktree, stores

Five participants. The orchestrator is the S3 loop in the base checkout. The session is Pi with the host's extensions loaded, running in a git worktree that belongs to exactly one unit. The domain, which is the repository, sits on the far right and is only ever read as a domain, never as state.

ORCHESTRATOR S3 loop · base checkout EXECUTION STORE .regulator/units/u1/ SESSION Pi + regulator-pi WORKTREE branch unit/u1 REGULATORY STATE audit log · signal sink CONTRACT DISPATCH THE UNIT WORKS VERIFY CLOSE · or ROUTE checkContract → createUnit contract.v1.json · unit.json (contracted) startUnit: acquire lease (TTL) · git worktree add unit/u1 .regulator/leases/u1.json · .regulator/worktrees/u1/ dispatch: createAgentSession(cwd = worktree, model = route.primary) only the definition's extensions load · flags: unit, profile, contract, policy · the router's hint, if any session_start: lease → unit → contract from the store; budget ledger opened coordination: lease gate · contract: contract section · budget: meter · recovery: reconcile effects · authority: protected paths read · write · edit · bash every tool_call passes the gates: profile grant, lease, protected paths, budget run_tests · run_checks (typed tools) results stamped with the revision they ran at git commit evidence binds to a commit; a dirty tree cannot close observations · signals, as they happen tool errors (recovery) · thrash signal (coordination) · protected file touched by bash → restored, finding (authority) report_result → report.v1.a1.json refused unless the cited runs happened here at HEAD (evidence), every delegated choice is reported, unresolved are preserved or surfaced, evidence classes present (contract) session ends (agent_end); dispatcher returns the session id the transcript is Pi's; the orchestrator never reads it getReport(u1, v1, attempt 1) no report → attempt "no-report" · invalid → "invalid-report" · ledger exhausted → "budget-exhausted" auditUnit: run_checks · run_tests, with the orchestrator's own runner, at the worktree's HEAD same commands the unit ran; different runner, different time — the report's claims satisfy nothing evidence records (revision, environment, criterion) + technical verdict → audit.ndjson pass · fail (failed / contradicted) · inconclusive (missing / stale / awaiting human acceptance) PASS → attempt "reported" · finishUnit: merge unit/u1 into main · remove worktree · release lease a merge conflict is not resolved: the unit stays blocked and S2 signals S3 · an unanswered question → attempt "paused", held until a person answers otherwise → attempt "check-failure" · unit blocked routeUnit: cause → policy → decision (decisions.ndjson) · audit finding S3* → S3 retry / repair → dispatch again with a hint (same worktree, new attempt) · escalate → algedonic signal to S5 · abort → lease and worktree gone retry / repair: back to dispatch, while attempts remain
One unit through the loop. Solid arrows are calls. The teal ones are the session acting inside its worktree; the orange ones are S3* verifying independently of what the session reported. The orchestrator writes to the execution store and reads the report from it; it never reads the transcript and never reads the diff to learn how the unit is doing. Every step is in controller.ts (runUnit, auditUnit, routeUnit, driveUnit) and the host's extensions.
  1. ContractThe orchestrator checks the contract (shape, consistency, a unit type the workload declares) and records the unit under it. The contract file is immutable; a new version is a replan, not a retry.
  2. DispatchA lease and a worktree are taken for the unit (a branch unit/u1 checked out under .regulator/worktrees/u1), and a Pi session starts there with the definition's checkpoints loaded and nothing the project supplies.
  3. SessionThe gates find the unit the way S3 recorded it: the lease whose resource is this worktree, then the contract from the store. The contract becomes a system-prompt section (advice) and a typed session entry (state).
  4. SessionThe model works inside the gates. Writes need the 's grant and a live lease, and must not touch identity or protected paths. The budget meter counts every turn, tool errors become observations, and run_tests results are stamped with the revision they ran at.
  5. SessionIt commits and calls report_result, the only way a unit ends well. The report is refused unless it honours the contract and cites runs that happened here, on the committed tree, and passed.
  6. VerifyThe orchestrator reads the report, never the diff, and re-runs the workload's checks itself against the commit. and the go to the audit log; a claim in the report that the host contradicts is named.
  7. CloseOn pass, the branch is merged into the base, the worktree removed, the lease released. On anything else the is recorded as it ended and the unit is blocked.
  8. RouteA blocked unit is routed under the versioned recovery policy: the cause is classified from the orchestrator's records first, then S2's signals (an , say), then the session's observations. The Nth occurrence takes the Nth action, and retry and repair spend attempts until they become escalate at the ceiling.

In the docs: Running units · Host checks · Coordination

The unit's own states

The same journey, drawn as a state machine

The sequence diagram above shows who calls whom, in what order. This is the complementary view: what the unit itself can be, at any moment, and exactly what moves it from one thing to the next. There are only six values a 's status field can ever hold: contracted, dispatched, reported, closed, blocked, aborted. They are defined once in packages/protocol/src/execution.ts and enforced everywhere that reads or writes a unit record. Any other value in that field is a bug.

CONTRACTED checked, recorded DISPATCHED lease + worktree + session REPORTED checks already passed; merging CLOSED terminal · merged, lease gone BLOCKED this attempt didn't close WAITING an obligation is open on this unit ABORTED terminal · lease + worktree gone startUnit report_result, host re-check: pass merge succeeds no-report · invalid-report budget-exhausted · paused check-failure reintegration conflict retry / repair: attempt N+1 remediate · replan clarify · pause · escalate abort disposition resolves it: resume, decision as the hint disposition: abort
Six states, and every real transition between them. Solid arrows are automatic; the loop takes them on its own. Dashed arrows wait on something outside the loop: a policy decision, a person's answer, or S3 or S5 dispositioning an obligation. Notice what's not here: there is no "in progress" percentage and no "70% done". A unit is exactly one of these six things, always, and the field that says which one is written by the orchestrator, never inferred from the worktree.
Reported is not "the model finished"By the time a unit's status becomes reported, the host has already re-run every check itself and they already passed, because closeVerifiedUnit only sets this status right before attempting the merge. A unit whose checks fail never becomes reported at all; it goes straight from dispatched to blocked.
Waiting isn't a sixth statusIt's blocked plus an open that vetoes the next dispatch. The schema stays at six values; the veto lives in the obligation ledger, checked fresh on every dispatch attempt.
Paused is a special case of blockedWhen a unit asks a person a blocking question and nobody answers before the session ends, the attempt's outcome is recorded as paused and the unit's status is blocked, with the reason spelled out in plain language. regulator answer turns the obligation from open to resolved and lets the next dispatch through.
The full decision logic is nextThis diagram shows where a blocked unit can go. The recovery section below shows how the choice between retry, repair, remediate, replan, clarify, pause, escalate and abort actually gets made.

In the docs: Running units · Obligations

The first workload

A software change, phase by phase

A single unit's lifecycle, drawn above, says nothing about what kind of work it is. That's the 's job: it declares the unit types available to a definition, each with its own and its own closeout checks. This is software-development.json, the first workload the course ships and the one behind every example on this page, including the fix-known-issue contract in the next section, which is an implement unit.

RESEARCH profile: intelligence · read-only answers one question; routed into an obligation — advice, never a decision PLAN profile: research writes contracts IMPLEMENT profile: implement changes source + tests VERIFY profile: research read-only re-examination INTEGRATE profile: implement reintegrates the branch CLOSE profile: research evidence fresh? before planning, or mid-implementation one contract per unit closes; a second unit re-examines it no problems found merged finds a problem → a new implement unit, contract citing the finding — not an automatic retry
Six unit types, one workload. Every box here still goes through the full six-state lifecycle drawn above, independently. A verify unit can be blocked and routed exactly like an implement unit. What this diagram adds is the layer above that: which unit type's work becomes which other unit type's contract. Nothing here is enforced as a literal state machine in code, because plan and research units decide the next contract, same as a person would. Still, this is the shape every closed feature in the fixture actually takes.
Unit typeProfileNeeds a contract?Checks at closeout
planresearchno—
researchintelligenceyes—
implementimplementyesrun_checks, run_tests, inherited-tests, identity-untouched, export-signature, glossary-lint (commit messages advisory)
verifyresearchyesrun_checks, run_tests, inherited-tests, identity-untouched, export-signature, glossary-lint (commit messages advisory)
integrateimplementyesrun_tests, inherited-tests, identity-untouched, export-signature, glossary-lint (commit messages advisory)
closeresearchyes—

Straight from packages/regulator/workload/software-development.json. Note that plan is the one unit type that runs with no contract at all: it's the thing that produces contracts, so there's nothing yet for one to check it against.

In the docs: Workload · Capability profiles · Session tools

A work contract

What a unit is authorized to decide

This is the real first contract from the lab, packages/regulator/contracts/fix-known-issue.json, unchanged. A contract is not a task description: it allocates decisions. Some are fixed before the unit runs, some are delegated within bounds, and some are explicitly nobody's yet, and the report is refused if it settles one of those.

{
  "kind": "task",
  "id": "tc-fix-known-issue",
  "version": 1,
  "unitId": "u1",
  "unitType": "implement",
  "workload": { "name": "software-development", "version": 1 },
  "objective": "Fix the known issue described in the README so that
                the project's own test suite passes.",
  "contribution": "First contracted unit against the fixture: proves
                   the loop before the loop is trusted with anything larger.",
  "constraintRefs": ["reg.authority.vendor-write-gate.v1"],
  "fixed": [
    { "id": "f-signature", "subject": "public signature of slugify",
      "decision": "slugify remains a single-argument function returning
                   a string; no options object, no second parameter.",
      "authorityRef": "S3 planning decision P1 (lesson 06)" },
    { "id": "f-vendor", "subject": "vendored helper",
      "decision": "vendor/left-pad.js is not modified, wrapped, or replaced.",
      "authorityRef": "reg.authority.vendor-write-gate.v1" }
  ],
  "delegated": [
    { "id": "d-helpers", "subject": "private helper decomposition",
      "bounds": "Private helpers inside src/slugify.js only;
                 no new modules, no new dependencies." },
    { "id": "d-tests", "subject": "additional test cases",
      "bounds": "May add cases to the existing test files under test/;
                 may not delete or weaken an existing assertion." }
  ],
  "unresolved": [
    { "id": "u-unicode", "subject": "non-ASCII input",
      "reason": "Nobody has decided whether accented characters are
                 transliterated, stripped, or preserved.",
      "handling": "defer" }
  ],
  "expectedEvidence": [
    { "id": "e-tests",  "description": "run_tests reports every test passing",
      "class": "test",    "required": true },
    { "id": "e-checks", "description": "run_checks reports every check passing",
      "class": "command", "required": true }
  ],
  "provenance": { "createdBy": "S3", "createdAt": "2026-09-22T00:00:00.000Z" }
}
version · unitTypeThe store keeps contract.v1.json immutably. The unit type selects the the session runs under and the checks the orchestrator re-runs at closeout, both from the workload definition; the contract itself names neither a model nor a tool.
fixedDecisions already made, with the authority that made them. The report may not silently deviate: a deviation from a fixed decision must be declared and becomes a blocking signal for S3. f-vendor is also a gate; the contract restates it so the unit knows why the gate refuses.
delegatedDecisions the unit makes, within bounds. The report must say what it chose for each one; a missing choice is refused at the tool and again at close.
unresolvedDecisions nobody has made. The unit may preserve them (leave the behaviour untouched) or surface them (report what it found); there is no settled. A report that omits u-unicode is refused: "settled silently or forgotten".
expectedEvidenceThe criteria the binds host-run evidence to, by class. The unit's own run_tests call satisfies the report's shape; only the orchestrator's re-run at the committed revision satisfies the criterion.

In the docs: Work contracts · Work contracts and reports

The result report

What the unit says back, and who checks which field

The report is the only thing the orchestrator reads about the work. It is written by a typed tool the session calls once, checked against the exact contract version at the tool and again at close, and then contradicted or not by evidence the orchestrator produced itself.

{
  "contractId": "tc-fix-known-issue", "contractVersion": 1,
  "unitId": "u1", "attempt": 1, "reportedAt": "…",
  "summary": "Collapsed repeated separators and trimmed dashes; all tests pass.",
  "evidence": [
    { "class": "test",    "ref": "run_tests",  "observation": "4 passed, 0 failed" },
    { "class": "command", "ref": "run_checks", "observation": "2 ok" }
  ],
  "delegatedResults": [
    { "decisionId": "d-helpers", "choice": "one private collapse() helper" },
    { "decisionId": "d-tests",   "choice": "added two edge cases" }
  ],
  "unresolvedOutcomes": [
    { "decisionId": "u-unicode", "outcome": "preserved",
      "note": "accented input still passes through untouched" }
  ],
  "emergentDecisions": [
    { "subject": "trailing whitespace", "choiceOrQuestion": "trimmed it",
      "consequenceIfWrong": "low" }
  ],
  "deviations": [],
  "residualUncertainty": []
}
attemptOne report per contract version and attempt: a repair attempt writes its own, and none is revised.
evidenceChecked for shape at the tool (every required class present) and for provenance before the tool runs (the run happened in this session, at HEAD, on a clean tree, and passed). Then the closeout gate re-runs the checks and, if they fail, lists this claim as contradicted.
delegatedResults · unresolvedOutcomesChecked at the tool and at close: every delegated decision has a choice; every unresolved decision has an outcome of preserved or surfaced.
emergentDecisions · deviationsThese are not gated, only recorded: a high-consequence emergent decision and every deviation become typed signals for S3 at close.
FieldWho checks itWhenWhat happens if it fails
evidence (classes)report_result tool, then runUnitat the call · at closerefused with reasons · attempt "invalid-report"
evidence (provenance)evidence preflightbefore the tool runsblocked: "run_tests has not run in this session / ran at another revision / did not pass"
evidence (truth)auditUnit (the orchestrator's own run)at close, against HEADverdict fail with the claim listed as contradicted; attempt "check-failure"; routed to repair
delegatedResultsreport_result tool, then runUnitat the call · at closerefused: "delegated decision d-helpers has no reported choice"
unresolvedOutcomesreport_result tool, then runUnitat the call · at closerefused: "u-unicode … settled silently or forgotten"
deviations (fixed)runUnit → emitReportSignalsat closethe unit still closes; a blocking operational signal goes to S3

In the docs: Work contracts · report_result · What the report raises

Three stores

Nothing reads its own progress off the domain

INV-005. Execution state, regulatory state and the domain are three different things with three different owners, and no arrow below is inferred from another. The orchestrator knows what it dispatched because it wrote it down, not because it looked at the diff. The direction matters too: the definition is the product (the registry, profiles, policies, workloads and the identity seed, shipped as a package); an instance is one repository that regulator init installed it into, and nothing flows back from an instance into the definition except by a person's decision, made with regulator identity promote under S5 authority.

ORCHESTRATOR (S3) SESSION (S1 + gates) AUDIT · ROUTER (S3*, S2) EXECUTION STORE .regulator/units · leases · trace unit.json — status, attempt count contract.v<N>.json · report.v<N>.a<M>.json — immutable attempts · observations · decisions — append-only budget.a<M>.json — a counter leases/<unit>.json — TTL, owner, resource owner: the orchestrator. Regulators never write here. THE DOMAIN the repository base checkout on main .regulator/worktrees/u1 — branch unit/u1 regulator/identity/ — write-protected, diffed at closeout vendor/ — protected by convention src/ test/ — the unit's writable grant the output: read as code, tested as code; never read as "how far along is the unit". REGULATORY STATE .regulator/*.ndjson, append-only audit.ndjson — evidence, verdicts, acceptances signals.ndjson — every typed message, and the obligation events that say what became of each effects.ndjson — intended / committed / confirmed memory.ndjson — facts with provenance + expiry; not identity outbox — what is owed to a person, delivered once; reminded owner: the regulators; the orchestrator only reads. writes units, attempts, decisions reads the report report_result · budget ledger merges unit/u1 into main; runs the checks at HEAD write · edit · bash · commit signals · effects · observations evidence, verdicts, findings, decisions reads the worktree at HEAD — as code no arrow leaves the domain for either store: state is written down, never inferred from the diff
Who writes where. The orchestrator owns the execution store and is the only thing that merges into the base. The session writes the domain through gated tools and writes its report and ledger into the store. S3* and S2 write regulatory state; the router and the read model consume it. The one thing missing on purpose is an arrow from the repository back into either store.

In the docs: Definition, instance, domain · Instance layout

Typed channels

A signal is not an audit; a proposal does not mutate policy

Everything the functions say to each other is a typed message, and the type carries the control semantics: who may send it, what it means, and who it is routed to. The routing policy then declares, per kind, the severity at which a message stops being trace and opens an obligation for someone, with floors that raise anything naming a protected invariant to blocking, whatever the sender said.

KindFromMeansEmitted byRouted to
operational-signalS1something about the work: a blocker, a deviationthe loop, from a report's emergent decisions and deviations; a session whose rendered identity was truncatedS3
uncertainty-signalS1residual uncertainty with a reported impact; the policy maps the claim to a severitythe loop, from a report's residualUncertaintyS3
coordination-signalS2a lease expired, a conflict, oscillationthe thrash detector in the session; reintegration on a conflict, textual or found by the pre-merge trialS3
audit-findingS3*evidence contradicts a claim or an invariantthe bash watch on a restored protected path; the closeoutS3
intelligence-signalS4the environment changed, or willreport_intelligence in a research unitS3
policy-proposalanya request to change identity or policy; never a mutationpropose_policy_changeS5
algedonic-signalanyexceptional escalation that bypasses the hierarchythe loop, when the recovery policy answers escalatea person
constraintS5, S3a boundary a unit runs under, stated ahead of the workdeclared, not yet emitted: a unit's constraints reach it as the contract's references and the rendered identitythe unit
One severity line for every kindinfo, advisory, blocking, critical. The protocol, not the sender, fixes what each one means: an advisory is noted as trace with the reason. A blocking message opens an obligation that holds the unit it names until someone dispositions it, and a blocking finding with no unit holds every dispatch.

In the docs: The control plane · Obligations · Routing policy

Recovery

What happens on attempt two, and on attempt six

A blocked unit is not retried; it is routed. The cause is a closed set, classified in a fixed order. The action comes from a versioned policy, by occurrence, and the attempt ceiling is the floor under the lattice.

BLOCKED unit.json · last attempt CLASSIFY → cause 1 · the orchestrator's record conflict · budget-exhausted · invalid-report check-failure · error → environment / timeout 2 · S2's signals oscillation (the thrash detector) 3 · the session's observations environment · timeout · tool-error else: no-report · dispatch-error · unknown POLICY · recovery v1 no-report: retry, retry, escalate invalid-report: repair, repair, escalate check-failure: repair, repair, replan environment: remediate, escalate oscillation: clarify fallback: pause the Nth occurrence of a cause takes the Nth action; the last one repeats cause decisions.ndjson — immutable cause · occurrence · action · policy version · hint retry · repair dispatch again with a hint, same worktree; spends an attempt remediate · replan clarify · pause recorded; the unit waits, lease kept, for a decision from outside the loop escalate algedonic signal S3 → S5; claim kept abort lease released, worktree removed; status "aborted" the floor under the lattice retry or repair with no attempts left becomes escalate, whatever the policy says runUnit again — attempt N+1, the hint appended to the prompt — then verify; back here if blocked
The recovery lattice. Classification is a fixed precedence over recorded facts: the orchestrator's own record wins, then what signalled, then what the session observed. Every decision is appended with the policy name and version that produced it, so attempt three can be explained after the policy changes. Only retry and repair re-enter the loop; everything else either waits (as an owed to or a person, which vetoes the unit's dispatch until it is dispositioned) or ends the unit. escalate is this loop's only path to an : it skips the queue entirely and puts the problem in front of directly. A unit that asked a person and got no answer never reaches this lattice: its attempt is recorded as paused, the obligation is delivered to the outbox, and regulator answer releases it with the answer as the next hint (drawn below).

In the docs: Recovery policy · Routing policy · Obligations · Recovery, budgets and model routes

The algedonic path

When a unit needs a person

A person's attention is the scarcest thing the system spends, so the way to it is narrow. A unit asks through one typed tool, under a contract that says what happens next; the loop reaches a person only when recovery has nothing left to try. Either way what is owed is an obligation, and silence is never an answer.

ask_human recap · choice clarification consent · uat OBLIGATION FIRST owed to a person, opened before anything is asked answered? timeout per kind ANSWER = DISPOSITION recorded on the spot; for consent, only an explicit yes is a yes UNIT CONTINUES told what was decided; a refused action is not taken PAUSE GATE every tool with an effect is refused; the attempt is recorded paused, not routed OUTBOX delivered once, reminded after an hour; regulator watch forwards regulator answer --by is checked against the interaction policy's people escalate recovery policy exhausted: an algedonic signal, owed to a person attention is a budget 2 questions that wait, per attempt; past that, ask_human refuses: record residual uncertainty instead, or offer a recap, which never waits the next attempt carries the answer as its hint a person answers no answer: headless, timed out, cancelled — silence is never consent
The algedonic path. Which kinds may continue without an answer is a constant in the protocol, not a policy setting: only a recap does, so no configuration can turn a timeout into a yes. A paused unit is not a failure, so the recovery lattice never sees it; it waits on its , and the attempt it spent counts against its ceiling. The same outbox carries what an exhausted recovery policy escalates, so a person has one place to look, and regulator watch can forward it to mail, chat or a webhook.

In the docs: Asking a person · Obligations · ask_human · Interaction policy

Inside a session

Where the gates sit in a session

A unit's session is plain Pi with eleven extensions loaded in order (tools, profiles, coordination, contract, budget, recovery, evidence, authority, intelligence, identity, algedonic), each hooking a handful of lifecycle events. Hover or tap a point on the line for what runs there. A solid red marker can refuse a tool call or halt the session; a hollow marker only records what happened.

gate — can refuse or halt hook — records only
The loop repeats once per model turn until the unit reports or a gate stops it; session_before_compact only fires when the context nears its limit.

In the docs: Session tools · Enforcement boundary · Protecting identity

On disk

An instance, after one routed unit

Everything the orchestrator and the regulators know lives under .regulator/ in the base checkout, ignored by git. The repository itself is the domain. This is what a fixture looks like after a unit was blocked at verification, repaired, and closed.

<repo>/
  src/ test/ vendor/            the domain
  regulator/identity/           IDENTITY, INVARIANTS, GLOSSARY, BOUNDARIES — write-protected
  .regulator/                   the instance (ignored by git)
    units/u1/
      unit.json                 closed · attempts 2
      contract.v1.json          immutable
      report.v1.a1.json         attempt 1's report (refused at close)
      report.v1.a2.json         attempt 2's report
      attempts.ndjson           check-failure · reported
      budget.a1.json            the ledger of attempt 1
      budget.a2.json
      observations.ndjson       what the session saw fail
      decisions.ndjson          check-failure → repair (recovery v1)
    leases/                     empty: released at close
    worktrees/                  empty: removed at close
    audit.ndjson                evidence ×5, verdicts ×2 (fail, pass)
    signals.ndjson              audit-finding S3*→S3 (closeout refused),
                                its obligation: opened → resolved (rework)
    effects.ndjson              notify_owner: intended, committed
    memory.ndjson               remember: "tests need FOO=1", review by +30d
    outbox                      deliver:<obligation>:0 — owed to a person; +1 after the reminder interval
    trace.ndjson                one record per turn (tools)
    events.db                   the generic vsm_* reporting tools' store (SQLite); a unit's session never loads them
    instance.json               the manifest: definition, harness revision, pi pin, who initialized it,
                                the writable and protected prefixes the profile grant and the closeout read
    every store above reads as OpenTelemetry GenAI spans: regulator spans --json, redacted
    canaries                    values that must never leak
Two immutable files per attempt, one mutableThe contract and each report are written once with wx and never overwritten; unit.json is the one thing that changes, and it holds only status and the attempt count.
Append-only logs, replayableAttempts, observations, decisions, audit entries, signals and are NDJSON lines validated on write and on read. regulator unit evidence u1 and the 's inspector are replays of these files; the inspector's replay view lists one unit's records in time order, from the span projection.
The read modelregulator status --definition packages/regulator --instance <repo> projects the definition (registry, workload, policies, profiles, identity, the eval suite and its committed reports, and each regulator's review date, ablation switch and retirement condition) and the instance (units with contract, report, budget, decisions, verdict and what is owed on them; leases; obligations with their deliveries; interactions, that is, what units asked a person and what came back; memory; unrouted signals; the manifest), all from files only, in the same shape as the the control room serves. regulator doctor is the go/no-go over the same files before the first unit and in CI.
What is not hereThe transcript: Pi's session file is authoritative for the conversation and the orchestrator never reads it. Also missing is any notion of progress derived from the diff.

In the docs: Instance layout · The control room