Adopt it
Adopt OPFiles
There are two ways in. The recommended path is to let your AI development assistant do
the adoption; adopting by hand is the fallback for when you cannot. Both paths target the same store format:
machine-written TOML sources, generated human-readable views, and a drift gate that re-renders the
views and compares them. This page walks the paths and the opf adopt flow, then
documents each opf command one by one, then lays out the manual steps.
Two paths
Two ways in, one store format
Assistant-driven (recommended)
Your AI development assistant follows the adoption procedure in the prompt pack: it investigates your project, proposes one plan, and asks for one approval of that plan. The reference CLI runs investigation and planning today; approval, apply and completion are not executable yet, so the assistant stops there and reports. The standard requires no particular assistant or tool.
By hand (fallback)
Create the plain-TOML store, configure your own checks, and work records-first. The standard requires no particular tool. The reference tooling requires Python 3.14 or newer. It validates spec 1.2.0 stores in either layout, with limits: it does not render or drift-check per-record views, and the baseline validator reports module-tier and importer record content schemas as cannot-evaluate. For a store with module-tier or importer records, or a per-record store that declares views, doctor's overall verdict is cannot-evaluate (exit 2).
On the assistant-driven path, give your assistant the prompt pack's adoption procedure,
adopt/SKILL.md, and its clean-start guidance, adopt/clean-start.md.
Both are under opf/prompt-pack/ in the reference repository, listed with their
digests in the pack's pack.toml. Provide the machine-readable
/llms.txt index and
/adopt.md guide as well. If adopting AIQT, include
OPFiles and any existing operational files in the plan. You can also adopt OPFiles alone.
The adoption flow
Investigate, plan, one approval, apply, verify
The standard's adoption flow (specification section 14) runs in this order: investigate, propose one plan, take one approval, apply, then a completion check before any old file is recorded as retired. The adopter approves one concrete plan, once; any change to a bound item takes a fresh plan and a fresh approval. Clean start is first-class: preserve and retire the old operational files, establish the new store and its enforcement, and import nothing.
What the reference CLI runs today
- Investigation, through the planner's read-only library entry; no
opf adoptsubcommand prints the inventory yet. It records a digest-stamped inventory, tells first adoption from re-adoption, and lists each file in its scope that needs a disposition: keep, migrate, move, or retire. opf adopt plan --inputs FILEfreezes and prints the plan from a planning worksheet and writes nothing. Its output is an inert, digest-bound proposal, never permission to apply. The planner checks the shape of the release, prompt-pack, enforcement and postimage digests the worksheet supplies, not the bytes they name, with one exception: when a kept file registers into a store the plan creates, the digest planned for its manifest must be the default manifest's real digest.opf adopt statusreports adoption runs and the adoption journal and writes nothing.
What it does not run yet
opf adopt approve, apply, complete and
reconcile refuse with exit 2, so no approval is recorded, nothing is applied,
and nothing is retired. Installing the enforcement pack through adoption, and
post-adoption import, are not available either. An assistant following the pack stops at
the approval step and reports, rather than doing the missing stages by hand.
Recovery after a refused or reversed run: when an adoption transaction is refused after
its intent opens, or is reversed, the engine retains .working/ holding only
the adoption journal (.working/journals/adoption/). That journal is recovery
state: the transaction record and its preimages, and the durable record that the refused
run id can never rerun. In that posture the store does not resolve, and plain
opf init refuses over the retained .working/ exactly as over any
other existing one. Recovery needs no cleanup: investigation reads a
.working/ holding only the journal as a first adoption, so a fresh
opf adopt plan with its own run id re-admits the tree. Do not delete
.working/ to unblock opf init; that discards the journal, and
with it the record that the refused run id is burnt.
For a project with no prior records, the clean-start guidance describes one interim route:
opf init, review and commit, opf render --write, commit, then
opf doctor --require-store and opf render --check. That route
initializes a store; it is not an adoption. It records no plan, approval, receipt or
completion check, and installs no enforcement. The reference tooling's opf init
does not scaffold a 2.0.0 store yet: its scaffold still writes a 1.2.0 store, a format the
standard's validation refuses (specification section 9.2).
Command reference
The opf commands, one by one
OPFiles names a standard command vocabulary; the opf reference CLI is
one implementation of it. A base adopter can use their own tooling instead, or adopt by hand. The
standard and the reference suite are both a draft, so this reference documents each command by
what it does at source today, except where marked Planned.
doctor distinguishes 0 clean,
1 a finding, and 2 cannot-evaluate.
render --check uses exit 1 for drift; render --write can also exit 1
on a finding. The retired import modes exit 2. Mutating commands can also
exit 2 on a refusal
or an unsuccessful operation: render --write requires passing source-integrity
checks, with no internal or unattributed faults; otherwise it exits 2 and writes nothing.
upgrade exits 2 for every command line, since the reference tooling defines no
store upgrade. record uses
only exit 0 and exit 2.
These statuses assume an interpreter that meets the reference tooling's Python floor. An older
interpreter stops before any command runs: one that can start the CLI refuses with exit 2, and
one too old to compile it fails with Python's own error and status. Each status here holds while
the CLI's output (its diagnostics on standard error, and what it prints on standard output) can
be written and flushed. A failing output stream can change the exit status and can lose output;
a separate fix in progress addresses this.
Where a command is aimed at a directory that has not adopted OPFiles, the
applicability probes (render, doctor,
absorb) report NOT APPLICABLE and exit 0. The commands documented one by one below
are adopt, init, render, doctor,
import, upgrade, migrate, sync,
absorb, and record.
opf adopt
Status. Partly implemented. The read-only plan and
status subcommands run; approve, apply,
complete, and reconcile refuse with exit 2 before reading anything.
Purpose. Guide setup and wiring of an existing project: investigate, plan, one approval, apply, and completion (specification section 14).
How it works. plan --inputs FILE reads a
planning worksheet: the observation digest from investigation, a disposition for each
candidate file, the operations to run, and the plan bindings (the observed revision, the tool
release, the prompt pack, one enforcement row per platform, and the skip policy). It
re-investigates the tree, refuses if the inventory changed, and freezes the
opf.adoption.plan/v2 proposal with its plan and inventory digests.
status lists the adoption evidence bundles, checking each one, and reports any
open transaction or held lock in the adoption journal. Neither needs an existing store.
Result. plan prints the frozen plan on stdout and
exits 0, exits 1 when an operation or the plan breaks the plan schema, and exits 2 when it
cannot evaluate (an unreadable worksheet, a malformed decision, a changed inventory, an
unresolved disposition).
status exits 0 clean, 1 on a finding, and 2 when it cannot evaluate. Both write
nothing.
opf adopt plan --inputs worksheet.toml opf adopt status opf adopt apply refused, exit 2
opf init
Purpose. Create validated source documents and a committed-store pointer for a project with no store, without rendering and with no git write beyond its operation lock.
How it works. A read-only preflight runs first: it inspects the
target for an existing store, an existing pointer, foreign content already under
.working/, or an existing root CHANGELOG.md or VERSION, and
refuses rather than absorbing what it finds. It then builds the machine
sources in memory (the manifest, the ID counters, the version ledger, the worklog, and the eleven
typed indexes), takes the shared operation lock and repeats its checks under it, holds the lease
while it writes them under .working/toml/, writes the .opf.toml
pointer at the product root, and creates a starter CHANGELOG.md. Publication is
create-only: it writes new paths and does not overwrite an existing one.
Result. A scaffolded store, a committed-store pointer, and a
starter changelog, all left untracked for your review; init does not
stage or commit them. See core store files for what the scaffold writes
into the manifest. Publication is create-only but not transactional: a later failure can leave
partial output for review. The lock and the lease exclude other OPF runs on the same
store, not other writers, and not runs on another store in the same repository; a run that stopped partway can leave its lock record, which
opf init --recover clears once its holder is confirmed dead. A successful
scaffold is not a whole-store validity verdict.
opf init opf init --root . opf init --recover
opf render
Purpose. Regenerate the store's declared views and check them against their sources, in one of two modes.
How it works. Exactly one of --check or
--write is required, so a preview never turns itself into a write; a bare
opf render is a usage error. --check is read-only: it re-renders every
declared view from its sources and compares the bytes, reporting whether the store is clean, has
drifted, or cannot be evaluated, and writing nothing. --write gates on source integrity, not
on the whole-store verdict: it gathers the git-derived observations, and a drifted or missing view is
its output to regenerate rather than a reason to refuse, so it rewrites the declared views from their
sources. A source-integrity check that fails or reports cannot-evaluate refuses with exit 2
before writing. Planning errors can also refuse before writing; a later I/O failure can leave
partial output and is reported.
Result. Under --check, a verdict and no change.
Under --write, post-write validation checks source integrity and the regenerated
outputs. A disagreement triggers a rollback attempt and exit 2; an incomplete rollback is
reported. Other deliverable failures remain visible and can produce a nonzero exit after
successful regeneration.
opf render --check opf render --write
opf doctor
Purpose. Run the whole-store integrity layer read-only and return a single verdict.
How it works. It resolves the store at the product root (or at
--root DIR), gathers the git-derived observations, and runs the integrity engine over
them. It makes no store change, and its report is a structured per-check verdict map, the findings
and cannot-evaluates, and a residual count, never a wall of diff lines. Its coverage spans schema
validity, ID uniqueness and counter monotonicity, bidirectional index reconciliation, transition
legality where observations suffice, the all-or-none resolution bundle, byte drift for declared
baseline views in an inline-layout store, the root VERSION deliverable (required
whenever releases exist, absent before the first release), worklog span tiling and frozen digests,
changelog coverage and freeze, archive
integrity, the tracked-store
requirement, pointer and sync-target agreement, and path containment.
Doctor reports per-record view drift and the content schemas of module-tier and importer
records, including legacy_fragment, as cannot-evaluate. Baseline view coverage includes
composed views and projections. A declared view outside the baseline set, such as a module-type
index mirror, makes the whole drift check cannot-evaluate. Transition checks also report
cannot-evaluate when legality depends on an unidentified last-transition actor or a rejection
requires unavailable pre-proposal state. Doctor does not check behind, ahead, or divergence
against a sync target.
Result. A valid, invalid, or cannot-evaluate verdict with the per-check breakdown, exiting 0, 1, or 2 to match.
opf doctor opf doctor --root .
opf import
Status. The ordinary import modes are retired. The reference CLI's
former --scan, --plan, --review, and --apply
modes now refuse with exit 2 and write nothing, as does every other opf import
command line.
Purpose. In the standard, opf import is only the
post-adoption import activity. Clean-start adoption is the intake for an existing project: it
preserves and retires the old operational files, establishes the new store and enforcement, and
imports nothing (spec section 14). Post-adoption import will use the approved, versioned prompt
pack (spec section 14.1); the reference CLI does not implement it yet.
How it works. The command refuses with a pointer, in words, to
clean-start adoption and the prompt pack. It reads none of its arguments, so every command line
gets the same refusal: no arguments, --help, any former mode or companion flag
however it is spelled, and an unknown flag alike. It resolves no root and reads no named file, so
the refusal is the same on an adopted store and on a directory that has not adopted OPFiles.
Result. Exit 2 and no change, whatever the mode: nothing is
staged under .working/imports/, and nothing is promoted into the store.
opf import --apply R refused, exit 2
opf upgrade
Status. The reference tooling has no store upgrade to apply.
Every opf upgrade command line refuses with exit 2.
Purpose. In the standard, opf upgrade is the
in-place store-schema upgrade that a later base-schema version bump ships (spec section 9.2).
Base 2.0.0 is the only base version the standard defines, so there is no upgrade to ship.
How it works. The command reads none of its arguments, so every
command line gets the same refusal: no arguments, --help, --root with
any directory, and an unknown flag alike. It resolves no root and reads no file, so the refusal
is the same on a store and on a directory that has not adopted OPFiles.
Result. Exit 2 and no change: the refusal on standard error and nothing on standard output.
opf upgrade refused, exit 2
opf absorb
Purpose. Draft a candidate changelog entry for human curation, or compute the freeze digest of an already-curated entry, without writing files.
How it works. --covers selects
unreleased (the default), a released version, or a contiguous version range.
A per-release draft draws on its worklog span; a range rollup draws on the existing per-release
changelog entries. --freeze-digest computes the selected curated entry's digest.
Both modes validate the ledger inputs and coverage token before producing output.
Result. Draft text or a digest on stdout, diagnostics on stderr, and no store changes. Exit 0 means success or not applicable; exit 2 means cannot-evaluate. Drafts still require human curation and the reviewed publication flow.
opf absorb opf absorb --covers 1.2.3 opf absorb --covers 1.2.3 --freeze-digest
opf record
Purpose. Author one change to the store's records at a time, without editing TOML by hand.
How it works. Four subcommands share one operation.
create adds a record of an enabled baseline type in its initial state.
transition changes a record's status under its type's rules: an assistant or
automation that lands a terminal or gated state gets /proposed, and only a
maintainer ratifies or rejects. When it lands a proposed status, transition writes
the state the record held at that moment into the record's own proposed_from
field. A rejection needs --reason, restores exactly that recorded state, and
removes the field; a record proposed outside transition, including one that
create lands directly in a proposed initial state, carries no such field, and the
verb refuses to reject it rather than infer or invent a predecessor. The worklog entry of the
proposing change is informational, never evidence. The verb never acts on a record whose
current row is not schema-valid, this field included; a canonical hand edit that keeps the
record schema-valid is not detected, the same as any other
field. done-with-receipt is
maintainer-only: it moves a backlog item to done and creates its one
done receipt in the same act. worklog-append adds one worklog entry.
The first three also add their own worklog entry. Every run refuses to rewrite a file that
carries comments or is not in canonical form, requires clean planned paths and the
single-writer lease, publishes every changed file in one journaled transaction, renders the
declared views, and runs a full doctor. The canonical-form check does not detect a hand edit
that leaves the file in canonical form.
Result. The change, left uncommitted in your working tree for
review; record never stages or commits. Exit 0 means the change is recorded and
doctor reports no finding; exit 2 means a refusal or cannot-evaluate. Until you commit a status
change, doctor can report it as cannot-evaluate, because the committed snapshot does not show
who made it; record says so when it happens. A failure after publication leaves the
change for review, with recovery commands scoped to the planned paths.
opf record create --type backlog_item --title "Add export" --actor maintainer opf record transition BI-1 active --actor assistant opf record done-with-receipt BI-1 --actor maintainer opf record worklog-append --kind docs --summary "Updated the guide" --actor assistant
opf migrate
Status. Planned; the reference CLI currently exits 2 (not yet implemented). The following describes the standard's intended operation.
Purpose. Relocate the whole tracked store to a target location, its git history and worklog preserved, as one recorded, verified operation.
How it works. It runs under the store consistency contract and the
single-writer lease, refusing to start from a stale, ahead, or divergent store. It validates the
target before any push: the destination is confirmed to be the recorded, intended target rather than
inherited from ambient state, so a store is not pushed to an unexpected place. It preserves the
store's git history into the destination and the worklog and its archive byte for byte, and keeps the
generated public deliverables (CHANGELOG.md and VERSION) in the product
repository, rewiring the render targets so future renders keep writing them there. It re-points the
committed pointer and the manifest's recorded sync target in the same change, then verifies the
destination before retiring the source: the relocated store is cloned back and reconciled (ledgers,
indexes, counters, and worklog digests) before the old location is removed or archived, and the
removal is recorded.
Result. The store at its new location with the pointer, the manifest's sync target, and the actual remote in agreement; the public deliverables still in the product repository; and a worklog entry naming both the old and the new location. Migration is symmetric: in-repo to a companion repository, companion to in-repo, or anywhere to anywhere, repeatably, each move one recorded, verified, history-preserving operation.
opf migrate --store dir:../product-ops-store opf migrate --store github:acme/product-ops
opf sync
Status. Planned; the reference CLI currently exits 2 (not yet implemented). The following describes the standard's intended operation.
Purpose. Reconcile the store with its sync target, the surfaced pull-and-push step of the store consistency contract.
How it works. The consistency contract holds the store
nothing-stale, nothing-ahead against its target. Where the local store is behind the target,
opf sync fast-forwards it to current; where it is ahead (local commits not yet pushed,
the lease still held by the resuming holder, and no divergent remote side), it pushes the pending
commits as an authorized reconciliation. It runs as its own surfaced step and is not folded silently
into another operation, so a pull or a push is a deliberate act you can see. A divergence (unsynced
commits on two systems) is not auto-merged: opf sync surfaces it and halts for you,
because a textual merge of the store's TOML records could mangle the very records the standard
protects.
Result. The store reconciled to a known-consistent state with its target, fast-forwarded to current or with its pending local commits pushed, or a surfaced halt on a divergence for you to resolve by hand.
opf sync opf sync --root .
Adopt by hand
The manual path, step by step
OPFiles specifies formats, layout, naming, lifecycle, and enforcement posture, and requires no particular tool: the specification states that a project can conform with hand-maintained files and its own checks. The reference tooling requires Python 3.14 or newer. It validates spec 1.2.0 stores in either layout, with limits: it does not render or drift-check per-record views, and the baseline validator reports module-tier and importer record content schemas as cannot-evaluate. For a store with module-tier or importer records, or a per-record store that declares views, doctor's overall verdict is cannot-evaluate (exit 2).
The shape of the manual path is short: create the store (write the files from the
specification and schemas), commit it, generate the views
with opf render --write for a supported store or your own renderer, and then work
records-first. The reference tooling's opf init does not scaffold this store yet:
its scaffold still writes a 1.2.0 store, a format the standard's validation refuses
(specification section 9.2). Conformance you
assert by hand is self-asserted, and you should say so wherever you claim it, because no validator
has checked it for you yet. The steps below fill that in.
Step 1
The minimal store
Create the machine store at .working/toml/ in your repository, with these files:
manifest.toml: the control document and discovery marker. It declaresstandard = "opf"(the exact discovery token) in its[opf]table, along with the basespec_versionyou conform to ("2.0.0"), the homes generationhomes = 2, the storagelayout, the enforcementposture, andimport_status. Register each enabled type in[types.<name>], declare[views], and supply the other tables the standard defines.counters.toml: the per-namespace ID high-water marks, so an ID is never reused. It holds the clean row and the imported counter row (the quoted key"imported:<NS>", at zero to start) of every enabled type.version.toml: the version and release ledger (numbers, dates, spans, and digests, never release prose).worklog.toml: the durable operational record: one entry per change, correctable in place until a release freezes its span, never deleted. It is the exempt ledger, not a typed index.- Eleven typed indexes, one per baseline record type:
backlog_item,done,finding,pending_decision,autonomous_decision,maintainer_decision,preference_pattern,block,handoff,reference, andcontribution, each as<type>.index.toml(empty to start). - The imported leaves: one
<type>.imported.index.tomlbeside each of those eleven indexes, plusworklog.imported.tomlfor the worklog, each empty to start. The standard requires them in every store (OPF-SPEC.md sections 4.2 and 8.2).
Then write the committed pointer .opf.toml at your product repository root, so
the store resolves from a stable location. A [profiles.aiqt] table is optional and
is ignored by base-only tooling; a base adopter need not add it.
The reference tooling does not yet implement spec 2.0.0, the only base version the standard
defines; it validates spec 1.2.0 stores, as described above. Its opf doctor
grades a manifest declaring spec_version = "2.0.0" with homes = 2
under its 1.2.0 rules, so its VALID verdict on such a store says nothing about conformance to
the standard; opf upgrade and opf record refuse such a store. The
reference tooling defines no store upgrade: opf upgrade refuses every invocation
with exit 2, reading and writing nothing.
The illustrative base [opf] table of a manifest, not a complete manifest:
also register enabled types in [types] and declare views and other settings (see
the standard for the normative shape, and
core store files for every table it can carry):
Step 2
The layout, and the one rule of adoption
Machine source lives under .working/toml/; generated human-readable views live at
.working/ top level; the curated CHANGELOG.md lives at the product
repository root. A generated root VERSION is required whenever releases exist.
The initial scaffold omits its view declaration; add that declaration when recording the first
release so the reference renderer can produce the file. Doctor checks VERSION
whenever releases exist, even if its view is undeclared.
<product repository root>/ .opf.toml committed store pointer CHANGELOG.md curated public changelog VERSION rendered from version.toml when declared as a view; required once releases exist .working/ BACKLOG.md FINDINGS.md DECISIONS.md WORKLOG.md ... generated views (UPPERCASE) toml/ manifest.toml counters.toml version.toml worklog.toml backlog_item.index.toml and its ten sibling indexes
One rule of adoption carries the whole convention: lowercase files are machine source you change
through tooling or review; UPPERCASE files are generated or published deliverables you read and
never hand-edit. The curated CHANGELOG.md is the one you edit, and only through its
publish flow. Once the files exist, commit them, then run opf render --write for an
inline-layout store (or your own generator) to produce the views from their sources.
Step 3
Working records-first
Treat the store as the source of truth: a decision, finding, or completion that is not recorded did not happen. Append a worklog entry per change; keep the backlog, findings, and decisions in their typed files; and regenerate the views rather than editing them. Typed index records carry an ID, type, status, title, timestamps, and an actor; links and captured references are optional envelope fields. An importer may omit an unknown creation timestamp with provenance. Capture references for claims that depend on external sources. IDs are never reused and records are never deleted. Worklog entries may be corrected before their span is released and are frozen afterward; post-release corrections are new linking entries. Other types follow their own lifecycles: completion receipts and autonomous decisions are immutable from creation.
Step 4
The release triad by hand
At a release, record the release and the worklog span it covers as a [[release]]
row in version.toml; draft the summary from that span; curate it by hand; publish
it into CHANGELOG.md; and record the freeze digest for the published entry. Old
summaries can be replaced by range summaries through the reviewed rollup flow; preserve the
underlying worklog entries and publication digests.
Step 5
Bring your own checks
Even before you run the reference validator, you can assert the standard's key invariants
yourself. A hand adopter can check that the store is a tracked git repository (an untracked
store is a hard failure, not a warning); that generated views match a fresh render; that release
worklog spans tile the released worklog entries in ID order without gaps or overlaps; and that
changelog summary ranges, among non-superseded summaries and excluding unreleased,
tile the released versions without gaps or overlaps, with published entries unchanged since their
recorded digest. These
are integrity checks specified by OPFiles. Record the scope and results of your manual checks.
The honest limits
What by-hand adoption does not give you
Without the validation tooling, your conformance is self-asserted and should say so. Digest freezing and span tiling are your own discipline until a validator checks them. Some residuals are part of the standard itself and no adopter escapes them: the freeze gate cannot judge whether prose is accurate, range coverage cannot judge summary quality, and the unreleased worklog tail rests on review rather than machine freezing. The disclosure page states these limits plainly.
Where next
Keep going
Read the standard
Store layout, the record model, the gates, and what they do and do not establish.
Reference tooling
The command vocabulary, its status, and how an assistant finds the standard.
Core store files
What the manifest, counters, version, worklog, and lease hold, and what each protects.
Disclosure
The residual limits the standard names plainly, so you know what it does not establish.