repo-harness 0.13.2 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/AGENTS.md +2 -2
  2. package/CLAUDE.md +2 -2
  3. package/README.es.md +2 -2
  4. package/README.fr.md +2 -2
  5. package/README.ja.md +2 -2
  6. package/README.md +2 -2
  7. package/README.zh-CN.md +2 -2
  8. package/assets/AGENTS.md +1 -1
  9. package/assets/CLAUDE.md +1 -1
  10. package/assets/hooks/AGENTS.md +1 -1
  11. package/assets/hooks/CLAUDE.md +1 -1
  12. package/assets/reference-configs/external-tooling.md +151 -0
  13. package/assets/reference-configs/harness-overview.md +1 -0
  14. package/assets/skill-version.json +2 -2
  15. package/assets/skills/repo-harness-cross-review/references/claude-mode.md +13 -7
  16. package/assets/templates/helpers/capability-config.ts +16 -2
  17. package/assets/templates/helpers/capability-resolver.ts +510 -30
  18. package/assets/templates/helpers/check-agent-tooling.sh +103 -0
  19. package/assets/templates/helpers/check-architecture-sync.sh +68 -6
  20. package/assets/templates/helpers/check-task-workflow.sh +53 -0
  21. package/assets/templates/helpers/ensure-task-workflow.sh +72 -1
  22. package/assets/templates/helpers/select-agent-context-blocks.sh +10 -3
  23. package/assets/templates/helpers/workstream-sync.sh +2 -2
  24. package/assets/workflow-contract.v1.json +1 -0
  25. package/dist/hook-entry.js +2497 -982
  26. package/package.json +4 -2
  27. package/scripts/AGENTS.md +1 -1
  28. package/scripts/CLAUDE.md +1 -1
  29. package/scripts/axr5-archctx-clean-room.ts +257 -0
  30. package/scripts/axr6-stop-host-cycle.ts +332 -0
  31. package/scripts/axr7-build-flow-repair-proposal.ts +44 -0
  32. package/scripts/axr7-build-model-proposal.ts +150 -0
  33. package/scripts/axr7-build-selector-repair-proposal.ts +50 -0
  34. package/scripts/axr7-consumer-e2e.ts +324 -0
  35. package/scripts/capability-config.ts +16 -2
  36. package/scripts/capability-resolver.ts +201 -28
  37. package/scripts/check-agent-tooling.sh +103 -0
  38. package/scripts/check-architecture-sync.sh +68 -6
  39. package/scripts/check-state-boundaries.ts +8 -0
  40. package/scripts/check-task-workflow.sh +53 -0
  41. package/scripts/ensure-task-workflow.sh +72 -1
  42. package/scripts/lib/project-init-lib.sh +20 -0
  43. package/scripts/select-agent-context-blocks.sh +10 -3
  44. package/scripts/workstream-sync.sh +2 -2
  45. package/src/cli/chatgpt-browser/engine.ts +1 -9
  46. package/src/cli/commands/architecture-projection.ts +104 -0
  47. package/src/cli/commands/capability-context.ts +29 -6
  48. package/src/cli/commands/global-runtime.ts +4 -6
  49. package/src/cli/commands/init.ts +3 -3
  50. package/src/cli/commands/mcp.ts +11 -2
  51. package/src/cli/commands/status.ts +24 -0
  52. package/src/cli/hook/handler-registry.ts +26 -0
  53. package/src/cli/hook/mutation-observed.ts +110 -22
  54. package/src/cli/hook/session-context.ts +5 -5
  55. package/src/cli/hook/stop-handler.ts +60 -4
  56. package/src/cli/index.ts +10 -0
  57. package/src/cli/installer/managed-entries.ts +1 -1
  58. package/src/cli/mcp/auth.ts +66 -41
  59. package/src/cli/mcp/server.ts +7 -6
  60. package/src/cli/mcp/setup.ts +189 -112
  61. package/src/cli/mcp/tools.ts +5 -1
  62. package/src/cli/mcp/transports/http.ts +11 -11
  63. package/src/core/adoption/gitignore-plan.ts +1 -0
  64. package/src/core/adoption/standard-plan.ts +21 -1
  65. package/src/core/architecture/projection.ts +356 -0
  66. package/src/core/capabilities/registry.ts +313 -1
  67. package/src/core/review/cross-review.ts +15 -4
  68. package/src/effects/architecture/archctx-provider.ts +303 -0
  69. package/src/effects/architecture/projection-jobs.ts +367 -0
  70. package/src/effects/architecture/projection-orchestrator.ts +230 -0
  71. package/src/effects/architecture/refresh-consumer.ts +172 -0
  72. package/src/effects/review/cross-review-runner.ts +5 -3
  73. package/src/effects/review/diff-fingerprint.ts +1 -0
  74. package/src/effects/state/resolve-effective-state.ts +150 -8
package/AGENTS.md CHANGED
@@ -7,7 +7,7 @@ This repository self-hosts the `repo-harness` contract; the former `repo-harness
7
7
  - `tasks/current.md` for the tracked current-status snapshot derived from workflow artifacts
8
8
  - `tasks/todos.md` for deferred medium/long-term goals, not active execution checklists
9
9
  - `plans/prds/` for upper-layer PRDs; `plans/sprints/` for ordered sprint backlogs operated through `repo-harness run sprint-backlog`; task contracts stay the execution slices
10
- - `.ai/context/capabilities.json` for the capability registry and longest-prefix context boundaries
10
+ - `.archcontext/model/nodes/*.yaml` for the capability nodes and longest-prefix context boundaries, selected by `.ai/harness/policy.json#context.capability_source`
11
11
  - `tasks/workstreams/` for capability long-running workstreams that project durable progress into local contracts
12
12
  - `tasks/lessons.md` for correction-derived rules
13
13
  - `docs/researches/` for deep repo knowledge
@@ -25,7 +25,7 @@ This repository self-hosts the `repo-harness` contract; the former `repo-harness
25
25
  - Use `tasks/notes/<plan-stem>.notes.md` only for non-obvious slice decisions, deviations, tradeoffs, and open questions; `<plan-stem>` is the active plan filename without `plan-` and `.md` (for example `20260531-0045-governance-workflow`). Do not use notes as durable memory or a task log, and archive/promote them deliberately when the slice closes.
26
26
  - Treat hook execution as typed and user-level: `~/.claude/settings.json` and `~/.codex/hooks.json` invoke `repo-harness-hook`, whose route registry selects exactly one in-process handler. `.ai/hooks/lib/workflow-state.sh` is an operator-helper library, never a host-event dispatcher.
27
27
  - Keep the umbrella hierarchy explicit: architecture owns stable truth, capability contracts own local agent context, `tasks/workstreams/<domain>/<capability>/` owns durable progress, and `tasks/todos.md` owns only deferred medium/long-term goals with tradeoff and revisit trigger.
28
- - Treat `.ai/context/capabilities.json` as the source of truth for capability prefixes; `agent-context-blocks.txt` and nested agent files are initialization inputs only, never runtime resolver authority.
28
+ - Treat `.archcontext/model/nodes/*.yaml` as the source of truth for capability prefixes under `capability_source: "archcontext"`; `agent-context-blocks.txt` and nested agent files are initialization inputs only, never runtime resolver authority.
29
29
  - Keep architecture drift handling split: `architecture-queue.sh` writes architecture requests/events, `workstream-sync.sh` maintains durable capability workstreams, and `context-contract-sync.sh` only updates controlled local `CLAUDE.md`/`AGENTS.md` architecture blocks.
30
30
  - Keep `assets/workflow-contract.v1.json` and `.ai/harness/workflow-contract.json` in sync.
31
31
  - Keep `CLAUDE.md` and `AGENTS.md` short; put detailed guidance in `docs/reference-configs/`.
package/CLAUDE.md CHANGED
@@ -7,7 +7,7 @@ This repository self-hosts the `repo-harness` contract; the former `repo-harness
7
7
  - `tasks/current.md` for the tracked current-status snapshot derived from workflow artifacts
8
8
  - `tasks/todos.md` for deferred medium/long-term goals, not active execution checklists
9
9
  - `plans/prds/` for upper-layer PRDs; `plans/sprints/` for ordered sprint backlogs operated through `repo-harness run sprint-backlog`; task contracts stay the execution slices
10
- - `.ai/context/capabilities.json` for the capability registry and longest-prefix context boundaries
10
+ - `.archcontext/model/nodes/*.yaml` for the capability nodes and longest-prefix context boundaries, selected by `.ai/harness/policy.json#context.capability_source`
11
11
  - `tasks/workstreams/` for capability long-running workstreams that project durable progress into local contracts
12
12
  - `tasks/lessons.md` for correction-derived rules
13
13
  - `docs/researches/` for deep repo knowledge
@@ -25,7 +25,7 @@ This repository self-hosts the `repo-harness` contract; the former `repo-harness
25
25
  - Use `tasks/notes/<plan-stem>.notes.md` only for non-obvious slice decisions, deviations, tradeoffs, and open questions; `<plan-stem>` is the active plan filename without `plan-` and `.md` (for example `20260531-0045-governance-workflow`). Do not use notes as durable memory or a task log, and archive/promote them deliberately when the slice closes.
26
26
  - Treat hook execution as typed and user-level: `~/.claude/settings.json` and `~/.codex/hooks.json` invoke `repo-harness-hook`, whose route registry selects exactly one in-process handler. `.ai/hooks/lib/workflow-state.sh` is an operator-helper library, never a host-event dispatcher.
27
27
  - Keep the umbrella hierarchy explicit: architecture owns stable truth, capability contracts own local agent context, `tasks/workstreams/<domain>/<capability>/` owns durable progress, and `tasks/todos.md` owns only deferred medium/long-term goals with tradeoff and revisit trigger.
28
- - Treat `.ai/context/capabilities.json` as the source of truth for capability prefixes; `agent-context-blocks.txt` and nested agent files are initialization inputs only, never runtime resolver authority.
28
+ - Treat `.archcontext/model/nodes/*.yaml` as the source of truth for capability prefixes under `capability_source: "archcontext"`; `agent-context-blocks.txt` and nested agent files are initialization inputs only, never runtime resolver authority.
29
29
  - Keep architecture drift handling split: `architecture-queue.sh` writes architecture requests/events, `workstream-sync.sh` maintains durable capability workstreams, and `context-contract-sync.sh` only updates controlled local `CLAUDE.md`/`AGENTS.md` architecture blocks.
30
30
  - Keep `assets/workflow-contract.v1.json` and `.ai/harness/workflow-contract.json` in sync.
31
31
  - Keep `CLAUDE.md` and `AGENTS.md` short; put detailed guidance in `docs/reference-configs/`.
package/README.es.md CHANGED
@@ -466,8 +466,8 @@ repositorio adopte la misma política.
466
466
 
467
467
  ## Versión actual
468
468
 
469
- - Paquete npm: `repo-harness@0.13.2`
470
- - Sello de workflow generado: `repo-harness@0.13.2+template@0.13.2`
469
+ - Paquete npm: `repo-harness@0.14.0`
470
+ - Sello de workflow generado: `repo-harness@0.14.0+template@0.14.0`
471
471
  - Repositorio de GitHub: `Ancienttwo/repo-harness`
472
472
  - Notas de versión e historial: [`docs/CHANGELOG.md`](docs/CHANGELOG.md)
473
473
 
package/README.fr.md CHANGED
@@ -461,8 +461,8 @@ adopte la même policy.
461
461
 
462
462
  ## Release actuelle
463
463
 
464
- - Package npm : `repo-harness@0.13.2`
465
- - Generated workflow stamp : `repo-harness@0.13.2+template@0.13.2`
464
+ - Package npm : `repo-harness@0.14.0`
465
+ - Generated workflow stamp : `repo-harness@0.14.0+template@0.14.0`
466
466
  - Dépôt GitHub : `Ancienttwo/repo-harness`
467
467
  - Notes et historique de release : [`docs/CHANGELOG.md`](docs/CHANGELOG.md)
468
468
 
package/README.ja.md CHANGED
@@ -469,8 +469,8 @@ commit script や hooks に組み込まないでください。
469
469
 
470
470
  ## 現在の Release
471
471
 
472
- - npm package:`repo-harness@0.13.2`
473
- - Generated workflow stamp:`repo-harness@0.13.2+template@0.13.2`
472
+ - npm package:`repo-harness@0.14.0`
473
+ - Generated workflow stamp:`repo-harness@0.14.0+template@0.14.0`
474
474
  - GitHub repository:`Ancienttwo/repo-harness`
475
475
  - Release notes and history:[`docs/CHANGELOG.md`](docs/CHANGELOG.md)
476
476
 
package/README.md CHANGED
@@ -441,8 +441,8 @@ repo-harness commit scripts or hooks unless that repo adopts the same policy.
441
441
 
442
442
  ## Current Release
443
443
 
444
- - npm package: `repo-harness@0.13.2`
445
- - Generated workflow stamp: `repo-harness@0.13.2+template@0.13.2`
444
+ - npm package: `repo-harness@0.14.0`
445
+ - Generated workflow stamp: `repo-harness@0.14.0+template@0.14.0`
446
446
  - GitHub repository: `Ancienttwo/repo-harness`
447
447
  - Release notes and history: [`docs/CHANGELOG.md`](docs/CHANGELOG.md)
448
448
 
package/README.zh-CN.md CHANGED
@@ -448,8 +448,8 @@ policy。
448
448
 
449
449
  ## 当前 Release
450
450
 
451
- - npm package:`repo-harness@0.13.2`
452
- - Generated workflow stamp:`repo-harness@0.13.2+template@0.13.2`
451
+ - npm package:`repo-harness@0.14.0`
452
+ - Generated workflow stamp:`repo-harness@0.14.0+template@0.14.0`
453
453
  - GitHub repository:`Ancienttwo/repo-harness`
454
454
  - Release notes 和 history:[`docs/CHANGELOG.md`](docs/CHANGELOG.md)
455
455
 
package/assets/AGENTS.md CHANGED
@@ -14,7 +14,7 @@ Keep this file focused on the local contract for this primary functional block.
14
14
 
15
15
  ## Positioning
16
16
 
17
- Owns the workflow-engine-contract-assets capability boundary declared in .ai/context/capabilities.json.
17
+ Owns the workflow-engine-contract-assets capability boundary declared in .archcontext/model/nodes.
18
18
 
19
19
  ## Source Map
20
20
 
package/assets/CLAUDE.md CHANGED
@@ -14,7 +14,7 @@ Keep this file focused on the local contract for this primary functional block.
14
14
 
15
15
  ## Positioning
16
16
 
17
- Owns the workflow-engine-contract-assets capability boundary declared in .ai/context/capabilities.json.
17
+ Owns the workflow-engine-contract-assets capability boundary declared in .archcontext/model/nodes.
18
18
 
19
19
  ## Source Map
20
20
 
@@ -26,7 +26,7 @@ Keep this file focused on the local contract for this primary functional block.
26
26
 
27
27
  ## Positioning
28
28
 
29
- Owns the runtime-harness-hook-adapters capability boundary declared in .ai/context/capabilities.json.
29
+ Owns the runtime-harness-hook-adapters capability boundary declared in .archcontext/model/nodes.
30
30
 
31
31
  ## Source Map
32
32
 
@@ -26,7 +26,7 @@ Keep this file focused on the local contract for this primary functional block.
26
26
 
27
27
  ## Positioning
28
28
 
29
- Owns the runtime-harness-hook-adapters capability boundary declared in .ai/context/capabilities.json.
29
+ Owns the runtime-harness-hook-adapters capability boundary declared in .archcontext/model/nodes.
30
30
 
31
31
  ## Source Map
32
32
 
@@ -687,6 +687,157 @@ managed files by hand:
687
687
  ~/.codex/agents/harness-evaluator.toml
688
688
  ```
689
689
 
690
+ ## ArchContext Capability Source
691
+
692
+ `.ai/harness/policy.json#context.capability_source` selects the single capability
693
+ authority for a repo:
694
+
695
+ | Value | Authority | Read path |
696
+ |---|---|---|
697
+ | `registry` (default) | `.ai/context/capabilities.json` | JSON capability registry |
698
+ | `archcontext` | `.archcontext/model/nodes/*.yaml` | `archcontext.node/v2` capability nodes |
699
+
700
+ Exactly one source is read. There is no dual-read, no merge, and no fallback in
701
+ either direction: under `archcontext` a missing model directory fails instead of
702
+ falling back to the JSON registry, and under `registry` a present model
703
+ directory is never consulted. Under `archcontext` the JSON registry is not
704
+ writable, so `repo-harness run capability-config add` refuses and points at the
705
+ node files.
706
+
707
+ Capability authority does not require the `archctx` CLI: node files are read
708
+ directly with Bun's native YAML parser, so selecting `capability_source` never
709
+ spawns a daemon or external process. Bun older than 1.3 has no `Bun.YAML`; that
710
+ fails closed with upgrade guidance and only when `capability_source` is
711
+ `archcontext`.
712
+
713
+ Architecture projection is a separate authority. When
714
+ `architecture.projection_provider=archctx`, repo-harness resolves the exact
715
+ version from the consumer dependency tree, executes only that package's declared
716
+ `bin.archctx`, performs a JSON capability handshake, and rejects PATH-only,
717
+ escaping, or mismatched installations. The advisory
718
+ global-tool detector below does not satisfy projection readiness; use
719
+ `repo-harness architecture-projection status --json`. The provider remains
720
+ disabled by default until the release pin is cut over.
721
+
722
+ When enabled, PostEdit writes only `change_observed` v2 journal records. Stop
723
+ coalesces all eligible records into one durable projection job, excludes
724
+ ArchContext-owned `docs/architecture/**` and declared agent-context targets,
725
+ and acknowledges the source records only after a typed projection receipt is
726
+ durable. Process, timeout, stale-snapshot, invalid-result, and refresh failures
727
+ remain pending for three attempts before an explicit dead-letter transition.
728
+ Preflight failures are jobs too. Each pending journal slot has a stable source
729
+ key while its delivery event id rotates on every coalesced edit; a dead letter
730
+ blocks aggregate jobs containing that source key, so later edits cannot reset
731
+ its attempt budget. Store transitions and queue/dead-letter read models share
732
+ one repository lock. One repository has at most one claimed provider process.
733
+ If the Stop owner disappears, its running claim remains quarantined for 150
734
+ seconds—longer than the 120-second provider bound—before recovery can start a
735
+ new attempt; an abandoned third attempt then transitions directly to dead-letter.
736
+ Before a retry is claimed, the job refreshes delivery ids for its existing
737
+ stable source keys, so edits incorporated before the new snapshot can be
738
+ acknowledged while edits arriving during projection remain pending.
739
+ `ArchitectureRefreshSignalV1` is the only major-change refresh authority; the
740
+ consumer does not infer impact from path names, diff size, or queue-helper
741
+ stdout. A typed refresh-required signal runs the canonical architecture,
742
+ context-contract, and capability-context writers even when the legacy queue
743
+ helper creates no drift card. SessionStart and
744
+ `repo-harness architecture-projection drain --json` expose queue state.
745
+ Each successful canonical refresh action is checkpointed by action key before
746
+ the next action runs, so a partial failure resumes without replaying completed
747
+ writers. Missing or stale CLI authority remains a typed refresh failure; it is
748
+ not silently skipped.
749
+
750
+ Projection delivery failures use the independent
751
+ `architecture.projection_failure_gate` (`advisory` by default); the existing
752
+ `architecture.freshness_gate` retains its merge/drift meaning. A strict
753
+ projection failure can be recovered without deleting runtime evidence via
754
+ `repo-harness architecture-projection retry-dead-letter --job-id <job> --json`.
755
+ An unreadable policy with no active projection queue remains an advisory
756
+ configuration error; it cannot silently promote the default gate to strict.
757
+ The runtime snapshot excludes `.ai/harness/**`, so concurrent harness receipts
758
+ and traces cannot invalidate a provider snapshot.
759
+
760
+ Managed host adapters give only `Stop.default` 150 seconds so the configured
761
+ 120-second provider bound has control-plane margin. Every other managed route
762
+ remains at 30 seconds, and installer refresh replaces only repo-harness-owned
763
+ entries while preserving sibling user hooks.
764
+
765
+ Before rolling back to a runtime that only understands journal v1, disable the
766
+ projection provider with the current runtime, run
767
+ `repo-harness architecture-projection drain --json`, and verify the pending
768
+ journal count reported as `sourceJournalPending` is zero. The manual drain owns
769
+ the same selective source acknowledgement as Stop. Downgrading with v2
770
+ observations still pending is not a supported rollback state.
771
+
772
+ ### `source.include` grammar
773
+
774
+ Upstream matches an include glob against the whole repo-relative path, so a
775
+ wildcard-free literal addresses one file, not a directory subtree. To keep the
776
+ two authorities from disagreeing about what a boundary covers, only two shapes
777
+ are accepted:
778
+
779
+ | Include | Capability prefix |
780
+ |---|---|
781
+ | `src/core/adoption/**` | `src/core/adoption` |
782
+ | `AGENTS.md` (wildcard-free, not an existing directory) | `AGENTS.md` |
783
+
784
+ Everything else fails closed. A wildcard-free literal that names an existing
785
+ directory is rejected as ambiguous with guidance to write `<dir>/**`.
786
+ `source.exclude` is not supported, because capability prefixes have no exclusion
787
+ form. Include order is preserved as prefix order.
788
+
789
+ ### Required node fields
790
+
791
+ | Capability field | Node source | Rule |
792
+ |---|---|---|
793
+ | `domain` / `name` | `id` segments 2 and 3 | `id` must be exactly `capability.<domain>.<name>`, with no `namespace::` prefix |
794
+ | display `name` | `name` | required non-empty node/v2 field; validated but not translated into registry identity |
795
+ | `summary` | `summary` | required non-empty node/v2 field; validated but not translated into registry semantics |
796
+ | `responsibilities` | `responsibilities` | required non-empty string array; validated but not translated into registry semantics |
797
+ | `id` | derived | `<domain>-<name>` |
798
+ | `architecture_module` | derived | `docs/architecture/modules/<domain>/<name>.md` |
799
+ | `workstream_dir` | derived | `tasks/workstreams/<domain>/<name>` |
800
+ | `prefixes` | `source.include` | include grammar above |
801
+ | `contract_files` | `extensions.contractFiles.agents` / `.claude` | declared, never derived: root-facing capabilities deliberately do not follow their prefix |
802
+ | `lsp_profile` | `extensions.lspProfile` | required |
803
+ | `verification_hints` | `extensions.verification` | required array; explicit `[]` is allowed |
804
+
805
+ Nodes whose `kind` is not `capability`, or whose `status` is not `active`, are
806
+ skipped and claim no prefixes. Required node/v2 descriptive fields are validated
807
+ even when they are not translated. Optional fields this bridge does not consume —
808
+ `source.entrypoints`, `ownership`, `interfaces`,
809
+ `criticality`, `riskDomains`, `notes`, `parent` — are ignored rather than
810
+ translated into local semantics.
811
+
812
+ ### Fail-closed conditions
813
+
814
+ Source-selection failures exit `2`:
815
+
816
+ | Condition | Behavior |
817
+ |---|---|
818
+ | unknown `capability_source` value | error naming the policy key and legal values |
819
+ | unreadable `.ai/harness/policy.json` | error naming the policy file |
820
+ | missing `.archcontext/model/nodes` under `archcontext` | error; never falls back to the JSON registry |
821
+ | subdirectory or non-`.yaml`/`.yml` entry in the model directory | error naming the entry |
822
+ | unparseable node YAML | error naming the node file |
823
+ | `Bun.YAML` unavailable | error with the Bun upgrade path |
824
+
825
+ Node-shape failures surface as `ARCHCONTEXT_*` registry diagnostics and make
826
+ `capability-resolver validate` exit `1` with no stdout; missing/empty node/v2
827
+ `name`, `summary`, or `responsibilities` is a structural error and never yields a
828
+ partial registry. Derived registries then go through the same
829
+ validation as the JSON registry, so duplicate ids, duplicate prefixes, and
830
+ invalid paths keep their existing diagnostic codes.
831
+
832
+ ### Node/v2 export round-trip
833
+
834
+ `repo-harness run capability-resolver export --format archcontext-nodes-v2`
835
+ emits complete `archcontext.node/v2` capability nodes. Existing directory
836
+ prefixes become explicit `<dir>/**` selectors, while file prefixes remain exact.
837
+ The exported `extensions.contractFiles`, `lspProfile`, and `verification` fields
838
+ round-trip through the canonical node/v2 reader without deriving missing
839
+ semantics. The retired `archcontext-boundaries-v1` format is rejected.
840
+
690
841
  ## Manual Brain Vault Export
691
842
 
692
843
  Long-lived external knowledge may be exported to a brain file vault only through
@@ -201,6 +201,7 @@ rather than inferring those values from turns, tool names, or timestamps.
201
201
  - Use `repo-harness capability-context status|request|sync` to keep paired local context files aligned with the registry. The command writes only the controlled `CAPABILITY CONTEXT` block and preserves hand-authored content plus the separate architecture contract block.
202
202
  - `.ai/context/capability-source-map.json` is the optional human-edited source-map manifest for capability positioning and source pointers. Missing entries fall back to registry/architecture/workstream metadata; `--auto-fill-positioning` writes deterministic draft entries explicitly, not from hooks.
203
203
  - `.ai/harness/capability-context/` is ignored runtime queue state. Post-edit hooks may enqueue requests, and `SessionStart` only reminds the current agent to run `repo-harness capability-context sync --pending --apply`.
204
+ - `.ai/harness/architecture-projection/` is ignored durable projection runtime state. It owns one running provider job per repository, pending jobs, typed receipts, refresh receipts, and dead letters; source observations are acknowledged only after a terminal receipt. SessionStart exposes the exact oldest dead-letter id for the explicit `architecture-projection retry-dead-letter` recovery command.
204
205
  - `SessionStart` also summarizes pending architecture request cards so a resumed agent can see drift debt before claiming finish.
205
206
 
206
207
  ## Initializer and Runtime Model
@@ -1,6 +1,6 @@
1
1
  {
2
- "version": "0.13.2",
3
- "templateVersion": "0.13.2",
2
+ "version": "0.14.0",
3
+ "templateVersion": "0.14.0",
4
4
  "skillName": "repo-harness",
5
5
  "contractId": "tasks-first-harness-v1",
6
6
  "compatibility": {
@@ -1,18 +1,24 @@
1
1
  # Claude provider mode
2
2
 
3
3
  Runs the Claude Code CLI (`claude -p`) as a read-only reviewer. Claude is
4
- given only `Read,Grep,Glob` (no `Bash`/`Edit`/`Write`), so it cannot edit
5
- your code; the review scope's diff text is embedded directly in the prompt
6
- since Claude has no Bash access to inspect the repo itself.
4
+ started with `--safe-mode` so host hooks, plugins, MCP servers, and repository
5
+ instructions cannot mutate or block the review process while the normal OAuth
6
+ credential remains available. It is given only `Read,Grep,Glob` (no `Bash`/`Edit`/`Write`),
7
+ so it cannot edit your code; the review scope's diff text is embedded directly
8
+ in the prompt since Claude has no Bash access to inspect the repo itself.
7
9
 
8
10
  ## Model and timeout
9
11
 
10
12
  - Pinned to the `fable` alias so the external opinion does not silently
11
13
  follow the host's default model.
12
- - If the fable route fails (nonzero exit, no output, and it was not a
13
- timeout), retries exactly once on `opus` -- one fallback step, never a
14
- loop, and never a fallback to a different provider.
15
- - Default budget: 330 seconds.
14
+ - If the fable route emits its explicit capacity-limit signal, retries exactly once on `opus`
15
+ -- one fallback step, never a loop, and never a fallback to a
16
+ different provider. Other nonzero exits remain failures even if they wrote
17
+ stdout.
18
+ - Per-attempt default budget: 330 seconds; the bounded two-attempt capacity
19
+ route therefore has a 660-second worst-case budget.
20
+ - Claude Code must support `--safe-mode`; an older CLI fails closed instead of
21
+ loading host hooks or silently dropping isolation.
16
22
 
17
23
  ## Transcript recovery
18
24
 
@@ -3,7 +3,13 @@ import { existsSync, mkdirSync, writeFileSync } from "fs";
3
3
  import { basename, dirname, resolve } from "path";
4
4
  import { spawnSync } from "child_process";
5
5
  import { fileURLToPath } from "url";
6
- import { readRegistry as readCapabilityRegistry, type Capability, type CapabilityRegistry } from "./capability-resolver";
6
+ import {
7
+ CapabilitySourceError,
8
+ capabilitySourceMode,
9
+ readRegistry as readCapabilityRegistry,
10
+ type Capability,
11
+ type CapabilityRegistry,
12
+ } from "./capability-resolver";
7
13
 
8
14
  type Registry = CapabilityRegistry;
9
15
 
@@ -339,6 +345,14 @@ function createWorkstream(repo: string, capability: Capability): void {
339
345
  function main(): void {
340
346
  const args = parseArgs(process.argv.slice(2));
341
347
  const repo = repoRoot(args.repo);
348
+ // The JSON registry is a projection target, not an authority, once archcontext
349
+ // owns capabilities; writing here would create a second authority.
350
+ if (capabilitySourceMode(repo) === "archcontext") {
351
+ throw new CapabilitySourceError(
352
+ `capability source is "archcontext"; ${REGISTRY_PATH} is not writable. ` +
353
+ "Declare the capability as an archcontext node under .archcontext/model/nodes instead"
354
+ );
355
+ }
342
356
  const requestedCapability = buildCapability(args, repo);
343
357
  const prefixPath = resolve(repo, requestedCapability.prefixes[0]);
344
358
  const registry = readRegistry(repo);
@@ -381,5 +395,5 @@ try {
381
395
  main();
382
396
  } catch (error) {
383
397
  console.error(`capability-config: ${(error as Error).message}`);
384
- process.exit(1);
398
+ process.exit((error as { exitCode?: number }).exitCode ?? 1);
385
399
  }