Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
108 commits
Select commit Hold shift + click to select a range
17d13c0
Implement context store root parity
TabishB Jun 9, 2026
0c2d3eb
Clarify simplified model roadmap
TabishB Jun 9, 2026
2662ff4
Add roadmap progress checklists
TabishB Jun 9, 2026
adc6ade
Number roadmap work items
TabishB Jun 9, 2026
245f6b8
Add --store root selection for normal commands
TabishB Jun 10, 2026
296e384
Fix stream-purity and message bugs found in review
TabishB Jun 10, 2026
d00c955
Validate all rebuilt specs before writing any
TabishB Jun 10, 2026
31a5cf4
Mark beta context-store and workspace docs as transition history
TabishB Jun 10, 2026
e3b053d
Record store-root-selection slice artifacts and roadmap progress
TabishB Jun 10, 2026
b8eec83
Record store-lifecycle-proof slice artifacts and roadmap progress
TabishB Jun 10, 2026
aff801c
Prove the standalone store lifecycle end to end
TabishB Jun 10, 2026
650f3fd
Fix review findings in the store lifecycle slice
TabishB Jun 10, 2026
827b507
Keep validate and show hints inside the selected store
TabishB Jun 10, 2026
5c87692
Derive setup's commit from the store shape and extract Git mechanics
TabishB Jun 10, 2026
51c2d5c
Point the roadmap's next-item marker at slice 1.4
TabishB Jun 10, 2026
080bf6e
Restructure the roadmap around root relationships
TabishB Jun 10, 2026
51fcb9b
Lock the naming, Phase 3, and Phase 5 decisions
TabishB Jun 10, 2026
1a499a4
Add the roadmap loop runbook
TabishB Jun 10, 2026
9b8555e
Make the roadmap loop fully autonomous with layered reviews
TabishB Jun 10, 2026
330fd72
Add the loop's parallelism policy
TabishB Jun 10, 2026
dcd986b
Switch the roadmap run driver from /loop to /goal
TabishB Jun 10, 2026
b9ab72e
Add the final acceptance capstone and standing quality bars
TabishB Jun 10, 2026
0e868ec
Bake the /goal invocation into the runbook header
TabishB Jun 10, 2026
d72f103
Write and review the store-rename-and-guidance slice spec
TabishB Jun 10, 2026
7d3adf3
Write and review the store-rename-and-guidance plan
TabishB Jun 10, 2026
59bca9f
Rename the context-store surface to store
TabishB Jun 10, 2026
7a3d8fd
Land the two store-rename riders
TabishB Jun 10, 2026
d05edf9
Regenerate guidance around stores
TabishB Jun 10, 2026
d2b62cc
Record the git-ignored .codex discovery in the slice artifacts
TabishB Jun 10, 2026
e6cce15
Guard the rename with sweeps, format pins, and the dogfood proof
TabishB Jun 10, 2026
68bd6e6
Fix the post-implementation review findings
TabishB Jun 10, 2026
434c2d2
Apply the simplify-pass cleanups
TabishB Jun 11, 2026
e643db9
Tick slice 1.4 in the roadmap and point at the deletion slice
TabishB Jun 11, 2026
21426cc
Write and review the delete-legacy-command-groups slice spec
TabishB Jun 11, 2026
ef45d5d
Write and review the delete-legacy-command-groups plan
TabishB Jun 11, 2026
f858c19
Delete the workspace and initiative command groups
TabishB Jun 11, 2026
f0848b1
Fix the deletion-slice review findings
TabishB Jun 11, 2026
a217281
Apply the deletion-slice simplify pass and tick the roadmap
TabishB Jun 11, 2026
82cee2a
Write and review the store-references slice spec (3.1)
TabishB Jun 11, 2026
26bad75
Write and review the store-references plan (3.1)
TabishB Jun 11, 2026
404eece
Add the references config field and the index assembler core
TabishB Jun 11, 2026
231063c
Wire the referenced-store index into both instruction surfaces
TabishB Jun 11, 2026
9c9a240
Fix the 3.1 review findings
TabishB Jun 11, 2026
2b81da5
Apply the 3.1 simplify pass and tick the roadmap
TabishB Jun 11, 2026
12ddaf4
Write and review the declared-store-fallback slice spec (3.2)
TabishB Jun 11, 2026
071865c
Write and review the declared-store-fallback plan (3.2)
TabishB Jun 11, 2026
8734289
Add the declared-store fallback to root resolution
TabishB Jun 11, 2026
d41184a
Add the init pointer guard, externalized-planning e2e, and docs
TabishB Jun 11, 2026
ac1e417
Fix the 3.2 review findings
TabishB Jun 11, 2026
0b295ad
Apply the 3.2 simplify pass and tick the roadmap
TabishB Jun 11, 2026
76e9e4a
Write and review the store-canonical-remote slice spec (3.3)
TabishB Jun 11, 2026
a9c7cce
Write and review the store-canonical-remote plan (3.3)
TabishB Jun 11, 2026
6d5f2fb
Record canonical and observed store remotes (3.3 checkpoint 1)
TabishB Jun 11, 2026
834fd4d
Carry clone sources in reference declarations (3.3 checkpoint 2)
TabishB Jun 11, 2026
c32f803
Fix the 3.3 review findings
TabishB Jun 11, 2026
61836b2
Apply the 3.3 simplify pass and tick the roadmap
TabishB Jun 11, 2026
6f90ed8
Write and review the store-targets slice spec (3.4)
TabishB Jun 11, 2026
df77729
Write and review the store-targets plan (3.4)
TabishB Jun 11, 2026
c2420dd
Add the targets declaration layer (3.4 checkpoint 1)
TabishB Jun 11, 2026
5a88faa
Surface effective targets in instructions (3.4 checkpoint 2)
TabishB Jun 11, 2026
35868f8
Fix the 3.4 review findings
TabishB Jun 11, 2026
fbf36eb
Apply the 3.4 simplify pass and tick the roadmap
TabishB Jun 11, 2026
cc8e97e
Write and review the repo-map slice spec (3.5)
TabishB Jun 11, 2026
2595a20
Write and review the repo-map plan (3.5)
TabishB Jun 11, 2026
30f9697
Add typed registry sections and the repo map core (3.5 checkpoint 1)
TabishB Jun 11, 2026
0eebec1
Add the repo command group, typed rejection, and path enrichment (3.5…
TabishB Jun 11, 2026
73de3b8
Fix the 3.5 review findings
TabishB Jun 11, 2026
e43573c
Apply the 3.5 simplify pass and tick the roadmap
TabishB Jun 11, 2026
215f0c6
Write and review the relationship-health slice spec (3.6)
TabishB Jun 11, 2026
661b530
Write and review the relationship-health plan (3.6)
TabishB Jun 11, 2026
6a80825
Add the health-mode assembler options and the relationship inspector …
TabishB Jun 11, 2026
3a0d3ce
Add openspec doctor (3.6 checkpoint 2)
TabishB Jun 11, 2026
2a6bfed
Fix the 3.6 review findings
TabishB Jun 11, 2026
7294c13
Apply the 3.6 simplify pass and tick the roadmap - Phase 3 complete
TabishB Jun 11, 2026
fd78f3c
Trim the review profile for Phase 5 deletion slices
TabishB Jun 11, 2026
f327248
Write and review the assemble-working-context slice spec (4.1)
TabishB Jun 11, 2026
ac55e82
Write and review the assemble-working-context plan (4.1)
TabishB Jun 11, 2026
1022577
Delete the workspace opening machinery (4.1 checkpoint 1)
TabishB Jun 11, 2026
4ff970b
Add openspec context, the assembled working set (4.1 checkpoint 2)
TabishB Jun 11, 2026
f7a77ad
Fix the 4.1 review findings
TabishB Jun 11, 2026
b278f39
Apply the 4.1 simplify pass and tick the roadmap - Phase 4 complete
TabishB Jun 11, 2026
9b0fcb6
Execute the Phase 5 remainder - 5.1 fully closed
TabishB Jun 11, 2026
4f110d1
Capstone: all four persona journeys pass (6.1)
TabishB Jun 11, 2026
466081a
Capstone: usability audits done (6.1)
TabishB Jun 11, 2026
f227b24
Fix the capstone usability-audit findings
TabishB Jun 11, 2026
bd100f4
Capstone: technical audits done (6.1)
TabishB Jun 11, 2026
db455c2
Capstone: whole-delta gauntlet run - findings ledger (6.1)
TabishB Jun 11, 2026
37ad867
Fix every gauntlet P1/P2 plus the cheap P3 set (6.1)
TabishB Jun 11, 2026
f37db1f
Capstone complete: gauntlet passed, release-readiness report committe…
TabishB Jun 11, 2026
d686fb9
Fix the phantom-root regression test's environment dependence
TabishB Jun 11, 2026
d7e14e8
Record the user-directed workset correction (post-capstone review)
TabishB Jun 11, 2026
9784d9c
Record 4.2 personal worksets with FR1; supersede the change-anchored …
TabishB Jun 11, 2026
cd382e0
Record 4.2 FR2: tool opening with the two-style extensible opener pat…
TabishB Jun 11, 2026
e313d90
Flesh out 4.2 personal worksets as a full roadmap item with its goal run
TabishB Jun 11, 2026
154086f
Renumber personal worksets to Phase 7 item 7.1
TabishB Jun 11, 2026
633f839
Add the 7.1 capstone dogfood and branch-push steps to the goal run
TabishB Jun 11, 2026
980b056
Add the 7.1 personal-worksets research checkpoint
TabishB Jun 11, 2026
b7bc1d1
Windows-compatibility pass per test/AGENTS.md
TabishB Jun 11, 2026
8f7a1fe
Make the clone-fix unit pin platform-aware
TabishB Jun 11, 2026
6f4ca4a
Write the 7.1 personal-worksets spec; fold the dual spec review
TabishB Jun 11, 2026
eedadf4
Write the 7.1 personal-worksets plan; fold the dual plan review
TabishB Jun 11, 2026
e8bf29b
7.1 CP1: worksets core, opener table, shared file-state mechanics
TabishB Jun 11, 2026
d6fb613
7.1 CP2: the workset command group, registration, docs, and tests
TabishB Jun 11, 2026
0c203f6
Tick 7.1 implementation and tests boxes; record the implementation round
TabishB Jun 11, 2026
52a1db2
7.1 review round: fix all converged P2s from the three review mechanisms
TabishB Jun 11, 2026
567bb03
7.1 simplify pass: collapse the parallel mechanisms the reviews queued
TabishB Jun 11, 2026
b976507
7.1 capstone dogfood passes; transcript committed, box ticked
TabishB Jun 11, 2026
ded268d
Close 7.1: pushed-branch box ticked, glance and pointer finalized
TabishB Jun 11, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ jobs:
name: Test (${{ matrix.label }})
runs-on: ${{ matrix.os }}
timeout-minutes: 15
if: github.event_name == 'push'
if: github.event_name == 'push' || github.event_name == 'workflow_dispatch'
strategy:
fail-fast: false
matrix:
Expand Down
149 changes: 149 additions & 0 deletions docs/agent-contract.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
# OpenSpec Agent Contract

Machine-readable surfaces of the `openspec` CLI, verified against `src/` (capstone audit, 2026-06-11). Every shape below is documented from the emitting code.

## 1. General conventions

- **One JSON document per invocation.** In `--json` mode, stdout carries exactly one JSON document (2-space pretty-printed). Human prose, spinners, and the store banner go to stderr.
- **Store banner.** In human mode, a store-selected root prints `Using OpenSpec root: <id> (<path>)` to stderr. Never printed in JSON mode.
- **Key casing is surface-dependent** (see Known inconsistencies): store/repo/doctor/context payloads use `snake_case`; workflow payloads (`status`, `instructions`, `new change`, `validate`, `list`) use `camelCase`, except the embedded `root` object, which always uses `store_id`.
- **Optional keys are omitted, not null**, in most payloads (e.g. `root.store_id`, `member.path`). Exceptions that use explicit `null` are called out per shape (store doctor `git.*`, failure payloads).

## 2. The diagnostic envelope

One envelope shape is shared by every machine-readable diagnostic (`StoreDiagnostic`):

```json
{
"severity": "error" | "warning" | "info",
"code": "snake_case_string",
"message": "human sentence",
"target": "dotted.surface (optional)",
"fix": "one actionable sentence/command (optional)"
}
```

Diagnostics appear in two positions: **status arrays** (`status: StoreDiagnostic[]` at top level or per entry) for health findings, and **thrown errors** converted to a single-element `status` array on command failure.

## 3. Root selection and `RootOutput`

All root-resolving commands (`list`, `show`, `validate`, `status`, `instructions`, `instructions apply`, `new change`, `archive`, `doctor`, `context`) resolve one OpenSpec root with one precedence:

1. `--store <id>` → the registered store's root (`source: "store"`).
2. Otherwise, nearest ancestor with `openspec/`: planning shape → `source: "nearest"` (a `store:` pointer is ignored with a stderr warning); config-only dir with a valid `store:` pointer → that store, `source: "declared"`.
3. No nearest root + registered stores exist → error `no_root_with_registered_stores`.
4. No root, no stores: scaffolding commands treat the cwd as `source: "implicit"`; diagnostic commands (`doctor`, `context`) fail with `no_openspec_root` instead — they inspect, never scaffold.

Successful JSON payloads embed the root:

```json
"root": { "path": "/abs/path", "source": "store" | "declared" | "nearest" | "implicit", "store_id": "id (only when store-selected)" }
```

**Root-failure contract**: in JSON mode a resolution failure prints `{ ...commandNullShape, "status": [diagnostic] }` on stdout and exits 1.

## 4. Command JSON shapes

### 4.1 `list --json`
`{ "changes": [ { "name", "completedTasks", "totalTasks", "lastModified", "status": "no-tasks"|"complete"|"in-progress" } ], "root": RootOutput }` — note the per-change `status` is a string enum here. `--specs`: `{ "specs": [ { "id", "requirementCount" } ], "root" }`.

### 4.2 `show <item> --json`
Change: `{ "id", "title", "deltaCount", "deltas": [...], "root" }`. Spec: `{ "id", "title", "overview", "requirementCount", "requirements": [...], "metadata": { "version", "format", "sourcePath"? }, "root" }`.

### 4.3 `validate --json`
`{ "items": [ { "id", "type": "change"|"spec", "valid", "issues": [ { "level", "path", "message", "line"?, "column"? } ], "durationMs" } ], "summary": { "totals": {items,passed,failed}, "byType": {...} }, "version": "1.0", "root" }`. Exit 1 when any item fails.

### 4.4 `status --json`
`{ "changeName", "schemaName", "planningHome"?: { "kind", "root", "changesDir", "defaultSchema" }, "changeRoot", "artifactPaths": { "<id>": {outputPath, resolvedOutputPath, existingOutputPaths} }, "nextSteps": ["..."], "actionContext": { "mode": "repo-local", "sourceOfTruth": "repo", "planningArtifacts", "linkedContext", "allowedEditRoots", "requiresAffectedAreaSelection", "constraints" }, "isComplete", "applyRequires", "artifacts": [ {id, outputPath, status: "done"|"ready"|"blocked", missingDeps?} ], "root" }`. No active changes: `{ "changes": [], "message", "root" }`, exit 0.

### 4.5 `instructions <artifact> --json`
`{ "changeName", "artifactId", "schemaName", "changeDir", "planningHome"?, "outputPath", "resolvedOutputPath", "existingOutputPaths", "description", "instruction"?, "context"?, "rules"?, "references"?: ReferenceIndexEntry[], "targets"?: EffectiveTargets, "template", "dependencies": [{id,done,path,description}], "unlocks", "root" }`.

`ReferenceIndexEntry`: `{ "store_id", "root"?, "specs"?: [{id,summary}], "fetch"?, "status": [] }` — resolved entries carry root/specs/fetch; unresolved carry store_id + warning status. Index capped at 50KB (`reference_index_truncated`).

`EffectiveTargets`: `{ "source": "store"|"change", "repos": [ { "id", "remote"?, "path"? } ], "status": [] }`.

### 4.6 `instructions apply --json`
`{ "changeName", "changeDir", "schemaName", "targets"?, "contextFiles": { "<artifactId>": ["/abs", ...] }, "progress": {total,complete,remaining}, "tasks": [{id,description,done}], "state": "blocked"|"all_done"|"ready", "missingArtifacts"?, "instruction", "references"?, "root" }`.

### 4.7 `new change <name> --json`
Success: `{ "change": { "id", "path", "metadataPath", "schema" }, "root" }`. Failure: `{ "change": null, "status": [d] }`, exit 1.

### 4.8 `archive <name> --json`
Success: `{ "archive": { "change", "archivedAs": "YYYY-MM-DD-name", "path", "specsUpdated", "totals"? }, "root" }`. Failure: `{ "archive": null, "root"?, "status": [d] }`, exit 1. JSON mode is strictly non-interactive: every prompt point becomes an `archive_*` code.

### 4.9 `doctor --json`
`{ "root": { "path", "source", "store_id"?, "healthy", "status": [] }, "store": { "id", "metadata": {present,valid,remote?}, "origin_url"?, "status": [] } | null, "references": [...], "targets": [ {id, remote?, path?, "status": []} ], "status": [] }`. Health findings of any severity exit 0. Failure payload: `{ "root": null, "store": null, "references": [], "targets": [], "status": [d] }`, exit 1.

### 4.10 `context --json`
`{ "root": { "path", "source", "store_id"?, "role": "openspec_root" }, "members": [ { "role": "referenced_store"|"target_repo", "id", "path"?, "remote"?, "fetch"?, "status": [] } ], "status": [] }`. AVAILABLE = path present AND status empty. `--code-workspace <path>` writes `{folders:[{name,path}]}` (available members only, `ref:`/`repo:` prefixes); in JSON mode the write runs before printing so stdout holds exactly one document even on write failure. Failure: `{ "root": null, "members": [], "status": [d] }`, exit 1.

### 4.11 `store ... --json`
setup/register: `{ "store": {id, root, metadata_path?}, "registry": {path, registered, already_registered}, "git": {is_repository, initialized, committed}, "created_files": [], "status": [] }`. unregister/remove: `{ "store", "registry": {path, removed}, "files": {deleted, deleted_path, left_on_disk}, "status": [] }`. list: `{ "stores": [{id, root}], "status": [] }`. doctor: `{ "stores": [ { id, root, metadata_path?, openspec_root: {...healthy, status}, metadata: {present, valid, id?, remote}, git: {is_repository, has_commits, has_uncommitted_changes, has_remote, origin_url}, status } ], "status": [] }` (`null` = unknown/not probed). Health findings exit 0; failures exit 1 with the matching null-shape. Prompt cancellation exits 130.

### 4.12 `repo ... --json`
register: `{ "repo": {id, path}, "registry": {path, registered, already_registered}, "status": [] }`. unregister: `{ "repo", "registry": {path, removed}, "status": [] }`. list: `{ "repos": [{id, path}], "status": [] }` (sorted). Failures: null-shapes with `status: [d]`, exit 1.

### 4.13 `schemas --json` / `templates --json`
`schemas`: bare array `[ {name, description, artifacts, source} ]`. `templates`: keyed object `{ "<artifactId>": {path, source} }`. Both cwd-based, no root/status keys.

## 5. Exit-code contract

| Situation | Exit | Stdout |
|---|---|---|
| Success, incl. health findings (doctor/context/store doctor) | 0 | the payload |
| Command failure in `--json` mode | 1 | one JSON document with `status: [d]` and the command's null-shape |
| `validate` with failing items | 1 | full report |
| Prompt cancellation (`store` group, human mode) | 130 | stderr only |

## 6. Diagnostic code catalog

### Resolution
`no_openspec_root`, `no_root_with_registered_stores`, `no_registered_stores`, `unknown_store`, `store_id_is_repo`, `store_identity_mismatch`, `unhealthy_store_root`, `store_path_not_supported`, `invalid_store_pointer`, `initiative_option_removed`, `areas_option_removed`; pass-through: `invalid_store_id`, `invalid_store_registry`, `invalid_store_metadata`.

### OpenSpec-root health (error, no fix)
`openspec_store_root_missing`, `openspec_root_missing`, `openspec_config_missing`, `openspec_specs_missing`, `openspec_changes_missing`, `openspec_archive_missing`, plus `_not_directory` variants of each.

### Store registry/identity/state
`invalid_store_id`, `invalid_store_registry`, `invalid_store_metadata`, `store_registry_busy`, `store_not_found`, `no_store_registry`, `store_registry_changed`, `store_metadata_missing`, `store_metadata_id_mismatch`, `store_metadata_invalid`, `store_id_conflict`, `store_path_conflict`, `store_id_claimed_by_repo`, `store_path_claimed_by_repo`, `store_already_registered` (info).

### Store setup/register/remove
`store_setup_id_required`, `store_setup_path_required`, `store_setup_path_not_directory`, `store_setup_inside_git_repo`, `store_setup_non_empty_directory`, `store_setup_cancelled`, `store_path_required`, `store_path_missing`, `store_path_not_directory`, `store_register_root_unhealthy`, `store_register_identity_confirmation_required`, `store_register_cancelled`, `store_remote_empty`, `store_remote_requires_hand_edit`, `store_remove_confirmation_required`, `store_remove_cancelled`, `store_remove_path_not_directory`, `store_remove_metadata_missing`, `store_root_missing` (warning in remove, error in doctor), `store_root_not_directory`.

### Store git
`store_git_init_failed`, `store_git_identity_missing`, `store_git_commit_failed`, `store_git_no_commits` (warning), `store_clone_fragile_directories` (warning), `store_remote_divergence` (info, doctor).

### Repo map
`invalid_repo_id`, `repo_path_missing`, `repo_path_not_directory`, `repo_id_claimed_by_store`, `repo_path_claimed_by_store`, `repo_id_conflict`, `repo_path_conflict`, `repo_not_found`.

### References (warning)
`reference_invalid_id`, `reference_registry_unreadable`, `reference_unresolved`, `reference_root_unhealthy`, `reference_index_truncated`.

### Targets (warning)
`target_invalid_id`, `target_not_declared`, `target_unmapped`, `target_path_missing`.

### Relationships (warning; doctor; context keeps only the registry one)
`relationship_registry_unreadable`, `root_pointer_ignored`, `root_pointer_invalid`, `pointer_declarations_inert`.

### Archive (JSON mode)
`archive_change_name_required`, `archive_change_not_found`, `archive_validation_failed`, `archive_confirmation_required`, `archive_tasks_incomplete`, `archive_spec_update_failed`, `archive_spec_validation_failed`, `archive_target_exists`, `archive_error`.

### Context writes
`context_file_exists`, `context_output_dir_missing`.

### Fallbacks
`doctor_failed`, `context_failed`, `store_error`, `repo_error`, `change_error`, `archive_error`.

## Known inconsistencies

Recorded by the capstone audit; published-key renames are product decisions deferred past this release:

1. ~~In `--json` mode, several failure paths printed stderr only with no JSON document.~~ Fixed in the capstone gauntlet round: `show`/`validate` unknown and ambiguous items emit `{status:[{code: unknown_item | ambiguous_item, ...}]}`; thrown errors in `status`/`instructions`/`list`/`show`/`validate` route through the JSON-aware failure helper (the command's null-shape + `status`); `store <unknown subcommand> --json` emits `{status:[{code: unknown_store_subcommand}]}`; `list` carries its `{changes|specs: [], root: null}` null-shape on resolution failures.
2. `store_root_missing` is emitted with two severities (warning in remove, error in store doctor) — context-dependent, documented above.
3. `target_invalid_id` carries `target: "targets"` from instructions surfaces and `target: "relationships"` from doctor/context.
4. snake_case (store family) vs camelCase (workflow family) key casing; `root.store_id` is snake_case everywhere.
5. Four parallel envelope type declarations exist in src; archive diagnostics never carry `target`.
6. `list --json` reuses the `status` key as a string enum per change.
7. Only `validate` output carries a `version` field.
8. `schemas`/`templates` ignore root selection (cwd-based, no `--store`).
9. Deprecated noun forms (`change`/`spec` subcommands) emit unenveloped payloads without `root`/`status`.
Loading
Loading