What Change Loop writes
Change Loop writes in two places, and the split is the whole point.
openspec/ is yours. Durable intent, reviewed by humans, committed to Git.
.foundation/ is the machine’s. Lifecycle state, receipts, logs, and proof
bundles, ignored by Git and safe to delete between changes.
Nothing durable is ever stored only in chat, and nothing machine-generated is ever committed as if a human wrote it.
The openspec/ tree
Section titled “The openspec/ tree”openspec/├── config.yaml project OpenSpec configuration and authoring rules├── repositories.yaml repository topology and per-repository CI issuers├── specs/ the requirements the landed system is held to├── changes/│ ├── <change-id>/ one active change packet│ └── archive/ landed packets, dated├── investigations/ durable findings from /investigate└── schemas/ the two assurance profiles and their templatesOwnership is not uniform across that tree, and it decides what an upgrade may overwrite:
| Path | Owner | On install |
|---|---|---|
schemas/ |
Change Loop | Overwritten every install. Edit a profile here and the next upgrade discards it |
config.yaml |
your project | Copied only when missing, yours afterwards |
repositories.yaml |
your project | Copied only when missing, yours afterwards |
specs/, changes/, investigations/ |
your project | Never touched by the installer |
foundation.json sits at the repository root rather than in openspec/,
because it holds project policy rather than intent: execution budgets, packet
size caps, model tiers, escalation triggers, the review diversity and
independence settings, and the sandbox setup command (sandbox.setupCommand)
that runs once inside every new Build workspace.
It is seeded when missing and yours afterwards.
The shipped policy permits at most three parallel agents, four evidence providers or services, and three repository setup commands. It uses 45-minute leases. Task and review packets are capped at 8 KiB, repository packets at 12 KiB, and the global packet at 16 KiB. Rapid runs receive ceilings of 800,000 tokens and 100 requests; standard runs receive 1,600,000 tokens and 200 requests. These values bound a run—they are not work quotas.
Model tiers are purpose-based: fast/Haiku handles inventory, logs, and
mechanical docs; standard/Sonnet handles implementation, tests, and focused
investigation; deep/Opus handles architecture, security, migration, and
review. The default reviewer is Claude Code Opus in a read-only ephemeral run,
with Codex GPT-5.6 Sol configured as an alternate. The shipped
independence: "self" and diversity: "single-model" policy works without a
second identity or provider and records both waivers in its receipts. Projects
that need separation of duties can strengthen independence, diversity, or both
to required. The risk-tiered review circuit allows one full review and at
most one required delta.
See Configure foundation.json for every field, valid ranges, and ready-to-use policy recipes.
Consumer quality adds another committed, project-owned tree:
quality/├── foundation-quality.json repository profiles, providers, thresholds, exceptions└── baselines/ ├── manifest.json decision references and baseline provenance └── <repository>/ versioned CRAP and mutation reportsquality init previews this configuration before writing it. Baselines are
never created implicitly: quality baseline --write requires both a decision
reference and a reason. See Consumer quality gates.
config.yaml is worth reading once. It carries the default schema plus the
authoring rules every change inherits — what a proposal must state, that specs
use stable names and WHEN/THEN, that design records only decisions constraining
implementation or rollback, and that tasks.md stays a single ledger. Changing
it changes what the harness asks of every future change.
The change packet
Section titled “The change packet”One directory per active change, at openspec/changes/<change-id>/. This is
what a reviewer reads.
| File | What it holds | Profile |
|---|---|---|
proposal.md |
Why the change exists, what observably changes, impact, and non-goals | both |
tasks.md |
The sole implementation ledger — the only place work is tracked | both |
evidence.yaml |
The stable behavioral contract: claim IDs, scenarios, capabilities | both |
grounding.yaml |
Semantic v3 non-derived material decisions; legacy read-set grounding remains readable | conditional when a decision must be locked |
execution.yaml |
Replaceable custom wiring: provider commands, services, readiness | conditional when derived wiring is insufficient |
repositories.yaml |
Explicit repository selection and write modes | conditional for multi-repository scope |
handoffs.yaml |
Permission-bound external operations and activation safety | conditional when such work exists |
.openspec.yaml |
Which assurance profile governs the packet | both |
design.md |
Durable decisions, diagrams, versioned integrations, prototype selection, compatibility, and risks | standard, conditional on design context |
specs/**/spec.md |
Requirement deltas — ADDED, MODIFIED, REMOVED |
standard |
A foundation-rapid packet omits spec deltas and normally omits design.md. The moment
impact rises above low, coupling stops being isolated, or review or acceptance
becomes required, the change upgrades itself to standard and its delta
artifacts are created for you. Optional extensions still appear only when their
concern exists.
The agent does not author cross-ledger IDs by hand. Semantic draft v3 compiles requirements, scenarios, tasks, claims, and provider bindings into this packet. That compiled OpenSpec packet remains the source of truth. A selected prototype or diagram may be referenced from design, but prototype output is still non-authoritative and is rejected as evidence.
Machine state
Section titled “Machine state”Everything under .foundation/ is generated. Its .gitignore is an allow-list
— it ignores * and re-admits only .gitignore and README.md — so machine
state cannot drift into a commit by accident.
| Path | Contents |
|---|---|
runtime/ |
Lifecycle state, one file per change |
receipts/ |
Live provider receipts and proof.json |
evidence/ |
Immutable proof bundles and the review-attempt ledger |
snapshots/ |
One workspace snapshot descriptor per proof |
logs/ |
Provider logs, telemetry, receipt-reuse and budget audits |
sandboxes/ |
The control sandbox — a Git worktree or a copy |
repository-sandboxes/ |
Per-repository sandboxes for multi-repository work |
plans/ |
Agent execution plans |
leases/ |
Task and resource leases |
transactions/ |
Land apply journals and staged backups |
tools/ |
Harness-owned project-local CLI dependencies keyed by the pinned runtime contract |
authority/ |
Review and acceptance requests and their completion records |
attestations/ |
Unattended-execution challenges and consumed nonces |
instruction-manifests/ |
Instruction provenance per command |
recovery/ |
Quarantined abandoned changes and orphaned state |
prototypes/ |
Disposable comparison prototypes |
policy.json |
Optional project rules mapping paths to required capabilities |
quality/results/ |
Latest consumer-quality lane reports, aggregate summary, and rendered debt |
install-manifest.txt |
Installer record of which files it owns |
Several of these appear only once something creates them —
repository-sandboxes/ needs multi-repository work, recovery/ needs an
abandoned change, and policy.json is yours to write or leave absent.
The evidence vault
Section titled “The evidence vault”receipts/ holds the live receipt for each provider, which is overwritten
every time that provider runs. evidence/ holds the immutable copy taken at
the moment proof was finalized:
.foundation/evidence/<change-id>/ <proof-run-id>/ manifest.json the proof, copied verbatim receipts/<provider>.json each receipt, with sha256 and byte size artifacts/<provider>/<digest>-<name> logs, reports, traces, screenshots review-attempts/ 0001-<digest>.json hash-chained review ledgerEvery copied receipt and artifact is bound by SHA-256 and byte size.
proof audit re-reads them and fails if either has moved. An artifact that
lives outside the vault is not admissible, which is why a durable report is
copied in rather than referenced where it was produced.
The review-attempt ledger is a hash chain. A broken link fails closed rather than being treated as an empty history.
The archive
Section titled “The archive”Landing moves the packet to openspec/changes/archive/<YYYY-MM-DD>-<change-id>/
with the same files intact, and merges the requirement deltas into the durable
specs at openspec/specs/<capability>/spec.md.
The merge is verified rather than trusted: Change Loop re-derives the before, after, and delta states and blocks the land if the archived specs do not match what the deltas said they would produce.
Artifacts that are deliberately not evidence
Section titled “Artifacts that are deliberately not evidence”Two kinds of output exist to help you think, and neither can be cited as proof.
Prototypes written to .foundation/prototypes/<id>/ during a comparison
investigation are explicitly rejected as evidence artifacts or references. A
prototype demonstrates that an approach is possible; it does not demonstrate
that the shipped code works.
Investigation notes at openspec/investigations/<name>.md are the durable
output of /investigate when findings need to outlive the session. They are
committed and reviewable, and they rank below specs and code when the three
disagree — a note records what was believed at the time, not what is true now.
Telemetry
Section titled “Telemetry”Each command appends a row to .foundation/logs/<change-id>/operations.jsonl,
alongside context events and phase-context records. telemetry reports totals,
estimated tokens, and duration percentiles by kind. Scheduler rows expose
queueing, reuse, executed nodes, and peak concurrency for harness-owned waves.
The accounting deliberately distinguishes unknown from zero. A run whose cost could not be measured is reported as unmeasured rather than free.