machine .toml source → generated view → drift gate

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 adopt subcommand 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 FILE freezes 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 status reports 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 declares standard = "opf" (the exact discovery token) in its [opf] table, along with the base spec_version you conform to ("2.0.0"), the homes generation homes = 2, the storage layout, the enforcement posture, and import_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, and contribution, each as <type>.index.toml (empty to start).
  • The imported leaves: one <type>.imported.index.toml beside each of those eleven indexes, plus worklog.imported.toml for 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):

.working/toml/manifest.toml
[opf] standard = "opf" # discovery token; exact value required spec_version = "2.0.0" # the base spec version this store conforms to homes = 2 # the homes generation; required, and 2 is the only value layout = "inline" # "inline" or "per-record" posture = "required" # "off", "warn", or "required" (section 11) import_status = "none" # "none", "partial", or "complete"

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.