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.
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.
controller.ts (runUnit, auditUnit, routeUnit, driveUnit) and the host's extensions.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.run_tests results are stamped with the revision they ran at.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.In the docs: Running units · Host checks · Coordination
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.
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.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 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.In the docs: Running units · Obligations
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.
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 type | Profile | Needs a contract? | Checks at closeout |
|---|---|---|---|
| plan | research | no | — |
| research | intelligence | yes | — |
| implement | implement | yes | run_checks, run_tests, inherited-tests, identity-untouched, export-signature, glossary-lint (commit messages advisory) |
| verify | research | yes | run_checks, run_tests, inherited-tests, identity-untouched, export-signature, glossary-lint (commit messages advisory) |
| integrate | implement | yes | run_tests, inherited-tests, identity-untouched, export-signature, glossary-lint (commit messages advisory) |
| close | research | yes | — |
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
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" }
}
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.f-vendor is also a gate; the contract restates it so the unit knows why the gate refuses.u-unicode is refused: "settled silently or forgotten".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 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": []
}
preserved or surfaced.| Field | Who checks it | When | What happens if it fails |
|---|---|---|---|
| evidence (classes) | report_result tool, then runUnit | at the call · at close | refused with reasons · attempt "invalid-report" |
| evidence (provenance) | evidence preflight | before the tool runs | blocked: "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 HEAD | verdict fail with the claim listed as contradicted; attempt "check-failure"; routed to repair |
| delegatedResults | report_result tool, then runUnit | at the call · at close | refused: "delegated decision d-helpers has no reported choice" |
| unresolvedOutcomes | report_result tool, then runUnit | at the call · at close | refused: "u-unicode … settled silently or forgotten" |
| deviations (fixed) | runUnit → emitReportSignals | at close | the unit still closes; a blocking operational signal goes to S3 |
In the docs: Work contracts · report_result · What the report raises
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.
In the docs: Definition, instance, domain · Instance layout
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.
| Kind | From | Means | Emitted by | Routed to |
|---|---|---|---|---|
operational-signal | S1 | something about the work: a blocker, a deviation | the loop, from a report's emergent decisions and deviations; a session whose rendered identity was truncated | S3 |
uncertainty-signal | S1 | residual uncertainty with a reported impact; the policy maps the claim to a severity | the loop, from a report's residualUncertainty | S3 |
coordination-signal | S2 | a lease expired, a conflict, oscillation | the thrash detector in the session; reintegration on a conflict, textual or found by the pre-merge trial | S3 |
audit-finding | S3* | evidence contradicts a claim or an invariant | the bash watch on a restored protected path; the closeout | S3 |
intelligence-signal | S4 | the environment changed, or will | report_intelligence in a research unit | S3 |
policy-proposal | any | a request to change identity or policy; never a mutation | propose_policy_change | S5 |
algedonic-signal | any | exceptional escalation that bypasses the hierarchy | the loop, when the recovery policy answers escalate | a person |
constraint | S5, S3 | a boundary a unit runs under, stated ahead of the work | declared, not yet emitted: a unit's constraints reach it as the contract's references and the rendered identity | the unit |
info, 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
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.
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
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.
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
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.
session_before_compact only fires when the context nears its limit.In the docs: Session tools · Enforcement boundary · Protecting identity
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
wx and never overwritten; unit.json is the one thing that changes, and it holds only status and the attempt count.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.regulator 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.In the docs: Instance layout · The control room