code-pact v1.0.0 freezes the public CLI contract. There are no breaking changes to the surfaces classified Stable (v1.0) in docs/cli-contract.md. Projects that worked on any prior alpha (v0.6, v0.7, v0.8, v0.9) continue to work without code changes.
This document explains what each prior release shipped, what — if anything — you need to do, and what diagnostic codes you may see during the first run on v1.0.
# 1. Upgrade the CLI.
npm install -g code-pact # or @latest, see README "Status"
# 2. Refresh the adapter manifest you committed at v0.9.
code-pact adapter upgrade claude-code --check --json
# Expected: ADAPTER_GENERATOR_STALE warning (manifest's generator_version
# is "0.9.0-alpha.0", current is "1.0.0").
# 3. Apply the refresh. Safe for managed-clean files; refuses
# managed-modified ones unless you also pass --accept-modified.
code-pact adapter upgrade claude-code --write
# 4. Confirm clean.
code-pact adapter doctor --json
code-pact doctor --json
code-pact validateNo CLI flags or JSON envelope shapes changed between v0.9 and v1.0. The only on-disk delta is the bumped generator_version field inside .code-pact/adapters/<agent>.manifest.yaml.
- Every Stable (v1.0) command in
docs/cli-contract.mdkeeps the same flags, exit codes, JSON envelope shape, and human-mode output. Field additions are additive only. - Every existing error code keeps its name and
error.codevalue. The full surface is locked bytests/unit/error-code-surface.test.ts. .code-pact/state/progress.yamlis forward-compatible. Logs written by v0.6–v0.9 parse and resolve correctly under v1.0'stask status/task completestate machine.- Bare-form
code-pact adapter [--agent X]still works (with a one-line stderr deprecation notice). Removal is targeted for v1.1, not v1.0. - Atomic write strategy (temp file + rename, no fsync, single-process owner) is documented in
docs/cli-contract.md§ State file write guarantees.
- Stability taxonomy in
docs/cli-contract.md(Stable (v1.0),Stable (human-output),Experimental,Deprecated). - Four-category public error-code tables in
docs/cli-contract.md, anchored bytests/unit/error-code-surface.test.ts. - End-to-end workflow smoke test (
tests/integration/e2e-workflow.test.ts). - JSON-stdout regression net (
tests/integration/json-stdout.test.ts). - Migration safety test for v0.6 / v0.8 / v0.9 shapes (
tests/integration/migration.test.ts). - This document.
No new commands. No new flags on existing commands. The init.ts write path was unified onto the shared atomicWriteText helper (internal refactor, behaviour unchanged).
This has been the behaviour since v0.6 and is locked for v1.0:
code-pact task complete <task-id>runs the phase'sverify.commands, and on pass appends adoneevent to.code-pact/state/progress.yaml.- It does NOT change the task's
statusfield indesign/phases/<phase>.yaml.
design/ is the source of truth for plan intent; progress.yaml is the operational log of what actually happened. These are intentionally separate.
When they diverge — task has a done event but design still says status: planned — code-pact plan analyze surfaces a STATUS_DRIFT warning with details.kind: "done-but-design-not-done". The agent or release-prep flow should intentionally update the design YAML when a task is truly complete (see the existing P7-T1 → P7-done patterns in design/phases/P7-adapter-platform.yaml for examples).
v0.6 introduced the task state machine (task start / block / resume / complete). Projects from this era may have:
- Tasks with
status: donein design YAML but no progress events (set by hand-editing before v0.6). - No adapter manifest under
.code-pact/adapters/.
Action: none required for the core workflow. After upgrade:
code-pact doctor --json # Expect: ADAPTER_MISSING (warning), no errors.
code-pact validate # Expect: exit 0.
code-pact plan analyze --json # Expect: no visible issues. Historical done
# tasks are hidden_by_default via the
# done-historical kind.
code-pact plan analyze --include-historical --json
# Surfaces the historical tasks so you can see
# what's being suppressed.When you're ready to take adapters out of legacy mode:
code-pact adapter install claude-code --json
# After this, doctor switches to manifest-aware checks. ADAPTER_MISSING
# stops firing.v0.7 added plan lint / plan normalize / plan analyze. There is no on-disk state owned by v0.7 — it was checks only. Migration is identical to the v0.6 path above.
If your CI ran plan analyze with --strict, that still works. If you want to suppress historical done-tasks from blocking CI under --strict, the v0.7 --include-historical flag is intentionally orthogonal — it shows the issues but does not affect exit code (hidden issues have affects_exit: false).
v0.8 extended recommend with the planning posture / preflight / budget profile output. The contract is strictly additive — every v0.7 caller still parses v1.0 output unchanged. The new fields (contextProfile, planningRequired, ambiguityAction, allowedEscalation, preflight, budgetProfile, structuredReasons) are documented in docs/cli-contract.md § recommend.
Action: none required. If you were ignoring the new fields, keep ignoring them — they're zod-strict on the schema side but additive on the consumption side.
v0.9 introduced the adapter platform: per-agent manifest, adapter list / install / doctor / upgrade --check / upgrade --write, the 8-value action enum, and the --force narrowing (force is now unmanaged-adoption only).
After upgrade:
code-pact adapter doctor --json
# Expect: ADAPTER_GENERATOR_STALE (warning) because every existing
# manifest's generator_version is "0.9.0-alpha.0" while current is
# "1.0.0". Not an error.
code-pact adapter upgrade <agent> --check --json
# Expect: plan[] mostly action:skip, possibly some action:update or
# action:update_manifest if the v1.0 templates diverge from v0.9.
code-pact adapter upgrade <agent> --write
# Safe for managed-clean files. Refuses managed-modified files unless
# you also pass --accept-modified. After this, generator_version is
# refreshed to "1.0.0".If you scripted around the v0.5–v0.8 bare-form code-pact adapter [--agent X] interface, that surface still works in v1.0 (with a one-line stderr deprecation notice). The shim is scheduled for removal in v1.1 — migrate scripts to:
- code-pact adapter --agent claude-code --force
+ code-pact adapter install claude-code--force semantics differ between the bare form (v0.8: overwrite everything) and adapter install --force (v0.9: unmanaged-adoption only). Destructive overwrite of managed-modified files now requires adapter upgrade --write --accept-modified.
v1.1.0 ships the Task Readiness Schema — five optional fields on the task type that let a task declare its own context-pack targets, read / write surface, dependencies, and acceptance references. The change is strictly additive: every v1.0.x phase YAML continues to parse and behave identically, and every Stable (v1.0) command keeps the same flags, exit codes, JSON envelope shape, and error code surface.
# 1. Upgrade the CLI.
npm install -g code-pact # or @latest
# 2. Refresh the local adapter manifest. The first run after upgrade
# reports ADAPTER_GENERATOR_STALE (warning) because the manifest's
# generator_version is "1.0.x" while the installed CLI is "1.1.0".
code-pact adapter upgrade claude-code --write
# 3. Confirm clean.
code-pact adapter doctor --json
code-pact doctor --json
code-pact validateNo other action is required. Projects that do not declare any of the new fields see no change in behaviour or output.
Five optional fields are added to the task schema (src/core/schemas/task.ts). Each one is .optional(), defaults to undefined, and is reported through additive plan lint codes only when declared.
| Field | Element type | Purpose |
|---|---|---|
depends_on |
task id string | Same-phase task ordering. P10 ships same-phase only; cross-phase references are deferred to a future extension. |
decision_refs |
repo-root-relative path | Force-surface specific decision files into task context regardless of context_size. |
reads |
repo-root-relative glob | Declared read surface. P10 renders the path list only — file contents are not inlined. |
writes |
repo-root-relative glob | Declared write surface. Future P11 task finalize will use this to detect writes outside the declaration; future P14 governance will enforce protected paths against it. |
acceptance_refs |
repo-root-relative path | Path references to acceptance criteria. P10 renders the path list only; richer rendering is deferred to P11 reconcile. |
The full RFC lives in design/decisions/task-readiness-schema-rfc.md. For a quick walkthrough of a phase YAML that uses every field end to end, see docs/concepts/task-readiness-fields.md.
- Declare new fields on new tasks first. Leave existing tasks alone unless you have a concrete reason to retro-declare. Full backfill is not necessary and is explicitly discouraged.
- Start with
depends_onanddecision_refs. These produce the most immediately visible effect ontask contextoutput (a "Depends on" section with derived state fromprogress.yaml, and a "Declared decisions" section that pulls referenced decisions into the pack). - Use
reads/writessparingly until you find them load-bearing. P10 surfaces them as declarations in the pack but does not enforce them; P11 / P14 are where they start to gate behaviour. - Skip
acceptance_refsuntil you have a real acceptance criteria layout. P10 ships path references only; P11 reconcile is the consumer.
Twelve new codes ship in plan lint to validate the new fields when declared. A task that declares none of the new fields produces none of these codes. The full list (severity + trigger condition) is in docs/cli-contract.md § Plan diagnostic codes — Task Readiness Schema diagnostics (P10, v1.1+).
Highlights:
TASK_DEPENDS_ON_UNRESOLVED(error),TASK_DEPENDS_ON_SELF_REFERENCE(error)TASK_DECISION_REF_NOT_FOUND(error),TASK_DECISION_REF_UNSAFE_PATH(error)TASK_READS_UNSAFE_PATH(error),TASK_READS_GLOB_INVALID(error),TASK_READS_NO_MATCH(warning)TASK_WRITES_UNSAFE_PATH(error),TASK_WRITES_GLOB_INVALID(error),TASK_WRITES_PROTECTED_PATH(warning in P10; configurable / error in P14)TASK_ACCEPTANCE_REF_NOT_FOUND(error),TASK_ACCEPTANCE_REF_UNSAFE_PATH(error)
The error-code surface is locked by tests/unit/error-code-surface.test.ts. Projects running plan lint --strict on existing v1.0.x corpora see no new errors unless they start declaring the new fields with invalid values.
Because v1.1.0 keeps the runtime dependency policy from CONTRIBUTING.md (only yaml and zod), the in-repo glob matcher supports only:
- literal path segments (e.g.
src/commands/init.ts) *within a single segment (e.g.src/commands/task-*.ts)**as a full path segment only (e.g.tests/**/integration.ts)
Brace expansion, extglob, negation, character classes, and backslash escapes are not supported. TASK_READS_GLOB_INVALID / TASK_WRITES_GLOB_INVALID fire when a declared glob steps outside the subset. If real usage shows the subset is too narrow, adopting an external glob library is a separate runtime-dependency RFC.
The pack rendered by task context gains five new sections when the corresponding fields are declared, in this order:
- Depends on — each dependency id with its current derived state.
- Declared read surface — each glob plus the set of currently-matched files. A
_(no current matches on disk)_note appears when the glob matches nothing. - Declared write surface — declared globs only, no fs lookup.
- Declared decisions — full body of each referenced decision file, surfaced regardless of
context_size. - Acceptance references — path list only.
When a task declares none of the new fields, the pack body is byte-identical to v1.0.2 (locked by tests/integration/pack-byte-identical.test.ts against a checked-in golden fixture).
# 1. Upgrade the CLI.
npm install -g code-pact@1.2.0
# 2. No mandatory action. Existing v1.1.x projects continue to work
# unchanged — `task finalize` and `phase reconcile` are opt-in.
code-pact validate --json # expect: ok
code-pact plan analyze --json
# Existing STATUS_DRIFT done-but-design-not-done warnings now carry an
# additive `details.remediation` hint. Existing JSON consumers see no
# shape change (details is a Record<string, unknown> payload).Two new commands ship as Stable (v1.2+). Both default to dry-run; --write is the explicit opt-in to mutate design/phases/*.yaml. Neither command mutates progress.yaml (append-only contract preserved), design/roadmap.yaml (still manual until P14), or the phase's own status field (advisory only via phase_status_candidate). Neither command takes --agent — they never call an adapter.
task finalize <task-id>— flips one task'sstatus: planned/in_progress→donein its phase YAML, but only whenprogress.yamlalready shows adoneevent for that task. Ineligible tasks raiseTASK_FINALIZE_NOT_ELIGIBLE(exit 2) in both dry-run and--write— dry-run means "won't write", not "won't validate". JSON envelope kinds:would_finalize/finalized/already_finalized.phase reconcile <phase-id>— bulk version. Walks every task in the phase, classifies each asflip/skip/manual_review, and (with--write) applies the flips in one shot. Partial successes (some flips applied, some refused for safety reasons) return exit 0 withapplied_writes[]+skipped_writes[]both populated.PHASE_RECONCILE_WRITE_REFUSED(exit 2) fires only when every eligible write was refused. JSON envelope kinds:would_reconcile/reconciled/no_eligible_tasks. Theno_eligible_taskscase is intentionally not an error — nothing to flip is a normal outcome.
The plan analyze STATUS_DRIFT done-but-design-not-done warning now also carries an additive details.remediation field of the form "code-pact task finalize <task-id>". Only this kind carries the hint — the other four kinds need human judgement, not a mechanizable fix.
For the full design rationale, read design/decisions/finalization-reconciliation-rfc.md. For the agent- and reviewer-facing walkthrough, read docs/concepts/finalization-reconciliation.md.
Stop hand-editing design status in release-prep PRs. Through v1.1.x, every release-prep PR included a step that hand-edited design/phases/*.yaml to flip completed tasks from status: planned to status: done. v1.2.0 replaces that step with a single command:
# 1. Bump version + write CHANGELOG.
# 2. Flip completed tasks for the phase being released.
code-pact phase reconcile <phase-id> --write --json
# 3. Hand-edit the phase's own status field if every task is now done
# (advisory only via `phase_status_candidate`; phase status auto-flip
# is P14 work).
# 4. Hand-edit design/roadmap.yaml if a phase weight or status moved
# (still manual until P14).
# 5. Commit + PR.Step 2 is the high-leverage change. The other steps remain manual on purpose: phase status and roadmap entries often depend on non-task work (release prep, docs, manual cleanup) that no deterministic command can verify, and P14 governance is the right home for opt-in policies that would let them be auto-managed.
For single-task finalization (e.g. closing one task mid-phase without affecting siblings), task finalize <task-id> --write is the per-task counterpart.
Projects running plan lint --strict or plan analyze --strict see no new errors in v1.2.0. The new fields are additive on existing diagnostic payloads, not new kinds. The STATUS_DRIFT done-but-design-not-done warning continues to fire pre-reconcile; once phase reconcile --write (or task finalize --write) has flipped a task, the warning clears on the next plan analyze run.
Three new public error codes ship in v1.2.0. The error-code surface lock at tests/unit/error-code-surface.test.ts is updated accordingly. Existing codes are unchanged.
| Code | Severity | Trigger |
|---|---|---|
TASK_FINALIZE_NOT_ELIGIBLE |
error | task finalize against a task whose derived state is not done (raised in both dry-run and --write) |
TASK_FINALIZE_WRITE_REFUSED |
error | task finalize --write failed the path-safety / phase-parse classification |
PHASE_RECONCILE_WRITE_REFUSED |
error | phase reconcile --write was unable to apply any of the eligible writes |
task completeis unchanged. Same flags, same JSON envelope, same exit codes, same error codes. The v1.0 contract —task completerecords progress only and never mutates design YAML — is preserved unchanged.progress.yamlremains append-only and is read-only for the new commands.task contextpack output is unchanged. The byte-identical pack regression test against the golden fixture passes without modification.tests/integration/json-stdout.test.tscontinues to pass for every Stable (v1.0) and Stable (v1.1) command; the two new commands are added to the test list and pass from day one.- No existing error code is removed, renamed, or recategorized.
In semver terms, v1.2.0 is a minor release.
The following remain on the backlog after v1.2.0:
- Removal of bare-form
code-pact adapter. - Multi-agent orchestration / MCP / GitHub-Linear-Jira sync.
- Advisory write locks for concurrent process safety.
- Enforcement of declared
writesagainst actual file-system writes. v1.1+ surfacesTASK_WRITES_PROTECTED_PATHas a warning against a narrow built-in seed set (.git/**,node_modules/**,.code-pact/**,design/roadmap.yaml,design/phases/*.yaml). Configurable governance and warning → error promotion are P14 work. v1.2.0 displays declaredwritesin thetask finalize/phase reconcileJSON payload but does not verify them against actual file-system writes. - Cross-phase
depends_on. v1.1+ ships same-phase only; cross-phase task ordering is a future extension. v1.2.0 surfacesdepends_on_check[]intask finalizeoutput as warning advisory only — it does not block on unsatisfied dependencies. - File-content inclusion for
readsandacceptance_refs. v1.1+ renders both as path lists only; v1.2.0 keeps that surface unchanged. - Phase status auto-flip. v1.2.0
phase reconcilereportsphase_status_candidateas advisory but never writes the phase's ownstatusfield. An--include-phase-statusopt-in is a candidate once the per-task flip path has been used through one release cycle. - Multi-phase reconcile (
--all). v1.2.0 ships per-phase only. design/roadmap.yamlmutation. Whether release prep should be able to delegate the per-phase weight / status flip to aroadmap reconcilecommand is P14 governance scope.- Semantic validation of
acceptance_refscontent. v1.2.0 only checks the path exists; richer validation would couple finalize to acceptance-criteria format choices the project has not yet made. - Runbook integration (
task run/phase close). P12 will consumetask finalize/phase reconcilefrom the runbook layer; v1.2.0 keeps the commands user-callable only. - Semver-aware
ADAPTER_GENERATOR_STALE(current implementation is simple equality). - Conformance test inclusion for
cursor/gemini-cliadapters — they remain Experimental.
A previously deferred item, promoting assertSafeRelativePath / resolveWithinProject to a neutral module, was partially closed in v1.1.0 (P10-T3): the helpers now live at src/core/path-safety.ts and are imported by plan lint for the new decision_refs / reads / writes / acceptance_refs validation. The adapter file re-exports them so existing call sites are unchanged. Extension of these helpers to the broader project state tree (design / progress file writes) remains P14 governance scope.
See docs/cli-contract.md § Stability taxonomy for the full list of stability bands per command and the criteria a v1.x command must meet to move between them.