Skip to content

Definition, instance, domain ​

The control plane keeps three things apart, and each has its own owner: the definition, the instance and the domain. Keeping them separate is what lets one control plane run against many repositories, and it is also what stops a run's traces from becoming a second source of truth beside the definition.

ORCHESTRATOR (S3)SESSION (S1 + gates)AUDIT · ROUTER (S3*, S2)EXECUTION STORE.regulator/units · leases · traceunit.json — status, attempt countcontract.v<N>.json · report.v<N>.a<M>.json — immutableattempts · observations · decisions — append-onlybudget.a<M>.json — a counterleases/<unit>.json — TTL, owner, resourceowner: the orchestrator. Regulators never write here.THE DOMAINthe repositorybase checkout on main.regulator/worktrees/u1 — branch unit/u1regulator/identity/ — write-protected, diffed at closeoutvendor/ — protected by conventionsrc/ test/ — the unit's writable grantthe output: read as code, tested as code;never read as "how far along is the unit".REGULATORY STATE.regulator/*.ndjson, append-onlyaudit.ndjson — evidence, verdicts, acceptancessignals.ndjson — every typed message, and the obligation events that say what became of eacheffects.ndjson — intended / committed / confirmedmemory.ndjson — facts with provenance + expiry; not identityoutbox — what is owed to a person, delivered once; remindedowner: the regulators; the orchestrator only reads.writes units, attempts, decisionsreads the reportreport_result · budget ledgermerges unit/u1 into main; runs the checks at HEADwrite · edit · bash · commitsignals · effects · observationsevidence, verdicts,findings, decisionsreads the worktree at HEAD — as codeno arrow leaves the domain for either store: state is written down, never inferred from the diff
Nothing reads its own progress off the domain. 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.

The definition ​

The definition is what the control plane is. It is versioned, checked, and shipped with the package, and every part of it is a declared file:

PartWhereWhat it declares
Registryregistry/regulators/*.jsonone record per regulator
Identity seedidentity/*.mdthe four S5 files every instance starts from
Profilesprofiles/*.jsonwhat a unit type may use and where it may write
Policiespolicies/*.jsonbudgets and model routes, recovery, routing, and interaction
Workloadsworkload/*.jsonthe unit types, with their profiles and their checks
Evalsevals/*.jsonsuites with declared arms and ablations
Contracts and fixturescontracts/, fixture*/the examples the package runs against itself
Settingssettings.jsonthe Pi settings a unit's session runs under

regulator check validates all of it together. It confirms that every profile a workload names exists, that every tool a profile grants is declared with its effect, that a contract-less unit type runs under a read-only profile, that every registry record cites tests that exist and states a limitation, and that no review date has passed. The check runs under pnpm check, so the definition cannot drift from the code that enforces it without the check failing. The definition reference documents each file.

A change to the definition is a pull request. The identity seed has one more way to change. An identity decision accepted in an instance can be promoted into the seed with regulator identity promote, and every later init then starts from the promoted version.

The instance ​

An instance is one repository running under one definition at one revision. regulator init creates it, and the instance layout lists what it holds. Two kinds of state live there. They sit in different stores, and neither is inferred from the other.

Execution state is the units, the attempts, the leases, the budgets consumed and the worktrees. It lives in the orchestrator's store, and only the loop writes it.

Regulatory state is the trace, the signals, the obligations, the evidence, the verdicts, the memory and the effect journal. It lives in append-only logs and the event store. The regulators write it, and the loop reads it to decide what a unit may do next.

Nothing in .regulator/ is configuration, and a person edits none of it by hand. What a person declares about an instance (the writable and protected prefixes, and who initialized it) lives in the manifest, which init writes and which the profile grant and the closeout read. The manifest also pins the definition's revision. An instance initialized under an older revision shows definition-drift in doctor until a person reads the upgrade note and runs the next unit.

The repository's own files say nothing to the harness. Its .pi/ directory, its AGENTS.md, its extensions and its skills never configure a unit's session. That is the trust rule: the project is the domain, and the domain does not configure its regulator.

The domain ​

The domain is the repository: the code, the tests, the ledger, whatever the workload is about. Units change it in worktrees, on branches, and the loop reintegrates what verified. The harness reads the domain as evidence at a revision, through the host checks, and never as state. Two files are the exception, and they are the domain's only harness-owned content. The first is regulator/identity/, the instance's copy of the S5 files, which is committed and protected by the write gate, the bash snapshot-and-restore and the identity-untouched check. The second is the .regulator/ line in .gitignore. Protecting identity explains those layers and the one path that changes an identity file.

Why the split matters ​

  • A run's trace under .regulator/ can be deleted, and the definition still says exactly what the control plane does.
  • Two repositories under the same definition behave the same way. They differ only in what their manifests declare.
  • The eval harness can run the same suite against a fixture under different arms, because an arm is a definition-level choice (which extensions load, which checks run, whether identity is seeded) and never a property of an instance.
  • Promotion has a direction, from instance to definition. A person does it, with a rationale, and commits it in the definition's repository. Nothing flows the other way by itself.

Released under the Apache-2.0 License.