@arbiterforge/ca-pi 0.6.3 → 0.10.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 (67) hide show
  1. package/README.md +41 -98
  2. package/package.json +1 -1
  3. package/plugins/ca-pi/CHANGELOG.md +145 -0
  4. package/plugins/ca-pi/COMMANDS.md +138 -68
  5. package/plugins/ca-pi/SKILLS.md +137 -30
  6. package/plugins/ca-pi/agents/INDEX.md +3 -2
  7. package/plugins/ca-pi/agents/checkpoint-aggregator.md +8 -7
  8. package/plugins/ca-pi/agents/design-quality-reviewer.md +1 -1
  9. package/plugins/ca-pi/agents/finding-triage.md +31 -14
  10. package/plugins/ca-pi/agents/verdict-aggregator.md +64 -0
  11. package/plugins/ca-pi/{ORCHESTRATOR.md → arbiter.md} +37 -36
  12. package/plugins/ca-pi/extensions/codearbiter.js +844 -19
  13. package/plugins/ca-pi/generated/command-catalog.json +386 -196
  14. package/plugins/ca-pi/generated/roles.json +9 -0
  15. package/plugins/ca-pi/hooks/_arbiterstatelib.py +59 -11
  16. package/plugins/ca-pi/hooks/_bashguardlib.py +30 -12
  17. package/plugins/ca-pi/hooks/_gitexec.py +23 -0
  18. package/plugins/ca-pi/hooks/_githooks.py +50 -23
  19. package/plugins/ca-pi/hooks/_hooklib.py +148 -20
  20. package/plugins/ca-pi/hooks/_host.py +9 -1
  21. package/plugins/ca-pi/hooks/_metricslib.py +20 -0
  22. package/plugins/ca-pi/hooks/_modelib.py +762 -0
  23. package/plugins/ca-pi/hooks/_protectedlib.py +13 -4
  24. package/plugins/ca-pi/hooks/_prunelib.py +51 -12
  25. package/plugins/ca-pi/hooks/_prunepolicy.py +33 -7
  26. package/plugins/ca-pi/hooks/_readinjectlib.py +10 -4
  27. package/plugins/ca-pi/hooks/_releaselib.py +278 -48
  28. package/plugins/ca-pi/hooks/_updatelib.py +230 -50
  29. package/plugins/ca-pi/hooks/doctor.py +58 -9
  30. package/plugins/ca-pi/hooks/git-enforce.py +10 -3
  31. package/plugins/ca-pi/hooks/hostapi.py +220 -22
  32. package/plugins/ca-pi/hooks/pi-bridge.py +10 -4
  33. package/plugins/ca-pi/hooks/prompt-submit.py +486 -0
  34. package/plugins/ca-pi/hooks/prune-transcript.py +23 -3
  35. package/plugins/ca-pi/hooks/session-start.py +529 -435
  36. package/plugins/ca-pi/hooks/statusline.py +28 -10
  37. package/plugins/ca-pi/hooks/wire-statusline.py +13 -8
  38. package/plugins/ca-pi/includes/anti-slop-design/INDEX.md +1 -1
  39. package/plugins/ca-pi/includes/command-compatibility.md +16 -0
  40. package/plugins/ca-pi/includes/dangerous-mode.md +57 -0
  41. package/plugins/ca-pi/includes/ops-mode.md +96 -0
  42. package/plugins/ca-pi/includes/pi-host-notes.md +10 -1
  43. package/plugins/ca-pi/includes/redirect.md +12 -1
  44. package/plugins/ca-pi/includes/routing-table.md +14 -5
  45. package/plugins/ca-pi/includes/safety-core.md +86 -0
  46. package/plugins/ca-pi/includes/smarts/core.md +1 -1
  47. package/plugins/ca-pi/routines/INDEX.md +1 -1
  48. package/plugins/ca-pi/routines/decision-lifecycle/SKILL.md +55 -3
  49. package/plugins/ca-pi/routines/decision-lifecycle/references/adr-template.md +9 -1
  50. package/plugins/ca-pi/routines/decompose/SKILL.md +1 -1
  51. package/plugins/ca-pi/routines/dispatching-parallel-agents/SKILL.md +4 -4
  52. package/plugins/ca-pi/routines/release/SKILL.md +1 -1
  53. package/plugins/ca-pi/skills/ca-checkpoint/SKILL.md +5 -4
  54. package/plugins/ca-pi/skills/ca-cleanup/SKILL.md +6 -0
  55. package/plugins/ca-pi/skills/ca-context-check/SKILL.md +6 -0
  56. package/plugins/ca-pi/skills/ca-create-context/SKILL.md +6 -0
  57. package/plugins/ca-pi/skills/ca-decompose/SKILL.md +6 -0
  58. package/plugins/ca-pi/skills/ca-doctor/SKILL.md +4 -0
  59. package/plugins/ca-pi/skills/ca-init/SKILL.md +18 -1
  60. package/plugins/ca-pi/skills/ca-pr/SKILL.md +17 -1
  61. package/plugins/ca-pi/skills/ca-review/SKILL.md +3 -4
  62. package/plugins/ca-pi/skills/ca-spike/SKILL.md +15 -8
  63. package/plugins/ca-pi/skills/ca-status/SKILL.md +13 -1
  64. package/plugins/ca-pi/skills/ca-watch/SKILL.md +6 -0
  65. package/plugins/ca-pi/includes/dev-mode.md +0 -30
  66. package/plugins/ca-pi/skills/ca-arbiter/SKILL.md +0 -36
  67. package/plugins/ca-pi/skills/ca-dev/SKILL.md +0 -42
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: dispatching-parallel-agents
3
- description: "The parallel fan-out primitive. Routed to by any skill or command that splits work across independent units and dispatches an agent per unit — subagent-driven-development, /sprint, parallel /review. It owns the dispatch/collect/funnel discipline: bound concurrency, isolate units, collect every result, dedupe overlap, and funnel through finding-triage then checkpoint-aggregator. Raw agent output is never consumed before the funnel runs; an agent that errors drops its unit without corrupting the batch."
3
+ description: "The parallel fan-out primitive. Routed to by any skill or command that splits work across independent units and dispatches an agent per unit — subagent-driven-development, /sprint, parallel /review. It owns the dispatch/collect/funnel discipline: bound concurrency, isolate units, collect every result, dedupe overlap, and funnel through finding-triage then the read-only verdict-aggregator. Raw agent output is never consumed before the funnel runs; an agent that errors records its unit as incomplete without corrupting the batch."
4
4
  disable-model-invocation: true
5
5
  ---
6
6
 
@@ -59,8 +59,8 @@ Gate: the result set is deduped, contradictions surfaced, and completion claims
59
59
 
60
60
  The batch is consumed only here, through the fixed funnel — never directly by the caller.
61
61
 
62
- 1. Dispatch `finding-triage` (`<plugin-root>/agents/finding-triage.md`) over the deduped result set: it classifies severity, marks out-of-scope items with an inline `[NEEDS-TRIAGE]` marker, and discards noise.
63
- 2. Hand the triaged set to `checkpoint-aggregator` (`<plugin-root>/agents/checkpoint-aggregator.md`): it aggregates into the single batch verdict the caller consumes — pass, or a blocking finding list.
62
+ 1. Dispatch `finding-triage` (`<plugin-root>/agents/finding-triage.md`) over the deduped result set and batch completion contract: it classifies severity and marks out-of-scope items with an inline `[NEEDS-TRIAGE]` marker. Every reviewer finding reaches the verdict; only non-finding transport metadata may be omitted.
63
+ 2. Hand the triaged set to `verdict-aggregator` (`<plugin-root>/agents/verdict-aggregator.md`): it composes the single read-only batch verdict the caller consumes — `PASS`, `BLOCKING_FINDINGS`, or `INCOMPLETE`.
64
64
 
65
65
  The errored and deferred units from Phase 3 ride through the funnel as findings — an `ERRORED` unit is a finding the caller must see, not a silent gap.
66
66
 
@@ -71,6 +71,6 @@ Gate: the caller receives only the aggregated verdict. Bypassing the funnel —
71
71
  - MUST NOT dispatch two units that mutate the same path in one batch; isolate via `using-git-worktrees` or serialize.
72
72
  - MUST NOT fan out unbounded; dispatch within the concurrency bound.
73
73
  - MUST NOT let one `ERRORED` unit discard or corrupt the rest of the batch.
74
- - MUST NOT consume agent output before the `finding-triage` → `checkpoint-aggregator` funnel runs.
74
+ - MUST NOT consume agent output before the `finding-triage` → `verdict-aggregator` funnel runs.
75
75
  - MUST NOT trust a subagent's self-reported completion; verify with a fresh proving command.
76
76
  - MUST NOT silently drop a unit — every unit terminates with a recorded state that rides through the funnel.
@@ -269,7 +269,7 @@ The tag and the GitHub Release publish together, and only after the user explici
269
269
  On authorization:
270
270
 
271
271
  1. Push the tag: `git push origin ${TAG_PREFIX}${VERSION}`.
272
- 2. **Resolve `<Phase-1 section file>` fresh in every Phase-3 invocation — never assume Phase 1's scratch file survived** (HIGH, blind exercise run 19). That file was created with `mktemp` outside the working tree and discarded once Phase 3 no longer needed it; on the `resume_publish` path (tag composed in a prior invocation, published now) it is normally already gone, and there was previously no stated way to get it back that did not read as the "re-derive or hand-write" the hard rules forbid. There is one sanctioned, mechanical way: `"$PY" "<plugin-root>/hooks/_releaselib.py" changelog-section $CHANGELOG ${VERSION}` prints the `## [${VERSION}] …` section back out of the COMMITTED `$CHANGELOG` verbatim — guaranteed present, because Phase 1 step 7 committed it before any tag existed. Redirect its stdout to a fresh local file and use that as `<Phase-1 section file>` for every step below; this is reading the exact text back from its one permanent home, not composing new notes. Exit 1 (no heading for `${VERSION}`) means `$CHANGELOG` and the tag have drifted STOP and investigate; never compose a substitute section by hand. On a same-session fresh publish the Phase 1 scratch file is still there and this reconstruction is redundant but harmless — run it anyway, so Phase 3 does not need to know which case it is in. **Guard the notes-file first:** assert its first heading matches the tag — `"$PY" "<plugin-root>/hooks/_releaselib.py" notes-match ${TAG_PREFIX}${VERSION} <Phase-1 section file>` (exit 0). A stale notes-file (`notes_heading_matches` False) would publish the wrong changelog section under the right tag — STOP on mismatch. Then create the GitHub Release from the **same changelog section composed in Phase 1** — reuse it as the notes, never re-derive or hand-write them. **`--latest` follows the declared row:** assert it only when `$TARGET`'s row declares `latest-eligible: true`, and only when this tag is also the newest release across every declared series (compare against `gh release list`; vacuously satisfied when only one series is declared); every other target passes `--latest=false`. GitHub has one repo-wide "Latest"; a declared file may name several series, so a target claiming it wrongly hides another's current release from every visitor. `gh release create ${TAG_PREFIX}${VERSION} --title "<title>" --notes-file <Phase-1 section file> --latest --verify-tag` when the row qualifies per the rule above, otherwise `gh release create ${TAG_PREFIX}${VERSION} --title "<title>" --notes-file <Phase-1 section file> --latest=false --verify-tag` — two distinct, individually runnable commands, never the bracket notation `--latest[=false]`, which is prose shorthand and not shell `gh` accepts. The title convention is `<$DISPLAY_NAME> ${VERSION}: <summary>` — `$DISPLAY_NAME` is the row's declared `display-name`, or `$TARGET` itself when the row declares none — with no em-dash separator. **`<summary>` is derived, not invented** (MEDIUM, adversarial review 2026-07-31, run 3: it appeared exactly once in this file and was never defined, so it was whatever the agent made up): take the single highest-precedence entry from the Phase 1 section — the first bullet under `### Added` if the window bumped minor, otherwise the first bullet under `### Fixed`, else the first bullet of the first non-empty group — and compress it to a noun phrase under ten words, in the entry's own words. If that yields nothing usable because the section has one group with one terse bullet, use that bullet verbatim. Never write a summary that names a change absent from the section.
272
+ 2. **Resolve `<Phase-1 section file>` fresh in every Phase-3 invocation — never assume Phase 1's scratch file survived** (HIGH, blind exercise run 19). That file was created with `mktemp` outside the working tree and discarded once Phase 3 no longer needed it; on the `resume_publish` path (tag composed in a prior invocation, published now) it is normally already gone, and there was previously no stated way to get it back that did not read as the "re-derive or hand-write" the hard rules forbid. There is one sanctioned, mechanical way: `"$PY" "<plugin-root>/hooks/_releaselib.py" changelog-section "<project-root>" "${TAG_PREFIX}${VERSION}" "$CHANGELOG" "$VERSION"` prints the `## [${VERSION}] …` section back out of the exact regular-file blob committed under the already-composed tag — guaranteed present, because Phase 1 step 7 committed it before the tag was created. The project root and every value are separate quoted arguments; the helper rejects a nested or unrelated root, an absolute or escaping changelog path, a non-regular Git tree entry, a malformed heading, `Unreleased` in a released position, and duplicate target sections. It resolves the tag to a commit hash before reading the blob, so a dirty/deleted working file, a changed current `HEAD`, or an unrelated current directory cannot substitute Release notes after the tag is composed. Redirect stdout to a fresh local file and use that as `<Phase-1 section file>` for every step below; this is reading the exact text back from its one permanent home, not composing new notes. Exit 1 (no heading for `${VERSION}`) means the committed changelog and tag version disagree; exit 3 means the root/revision/path/blob binding could not be proven; exit 4 means the changelog is malformed or ambiguous. Every one STOPs for investigation; never compose a substitute section by hand. On a same-session fresh publish the Phase 1 scratch file is still there and this reconstruction is redundant but harmless — run it anyway, so Phase 3 does not need to know which case it is in. **Guard the notes-file first:** assert its first heading matches the tag — `"$PY" "<plugin-root>/hooks/_releaselib.py" notes-match "${TAG_PREFIX}${VERSION}" <Phase-1 section file>` (exit 0). A stale notes-file (`notes_heading_matches` False) would publish the wrong changelog section under the right tag — STOP on mismatch. Then create the GitHub Release from the **same changelog section composed in Phase 1** — reuse it as the notes, never re-derive or hand-write them. **`--latest` follows the declared row:** assert it only when `$TARGET`'s row declares `latest-eligible: true`, and only when this tag is also the newest release across every declared series (compare against `gh release list`; vacuously satisfied when only one series is declared); every other target passes `--latest=false`. GitHub has one repo-wide "Latest"; a declared file may name several series, so a target claiming it wrongly hides another's current release from every visitor. `gh release create "${TAG_PREFIX}${VERSION}" --title "<title>" --notes-file <Phase-1 section file> --latest --verify-tag` when the row qualifies per the rule above, otherwise `gh release create "${TAG_PREFIX}${VERSION}" --title "<title>" --notes-file <Phase-1 section file> --latest=false --verify-tag` — two distinct, individually runnable commands, never the bracket notation `--latest[=false]`, which is prose shorthand and not shell `gh` accepts. The title convention is `<$DISPLAY_NAME> ${VERSION}: <summary>` — `$DISPLAY_NAME` is the row's declared `display-name`, or `$TARGET` itself when the row declares none — with no em-dash separator. **`<summary>` is derived, not invented** (MEDIUM, adversarial review 2026-07-31, run 3: it appeared exactly once in this file and was never defined, so it was whatever the agent made up): take the single highest-precedence entry from the Phase 1 section — the first bullet under `### Added` if the window bumped minor, otherwise the first bullet under `### Fixed`, else the first bullet of the first non-empty group — and compress it to a noun phrase under ten words, in the entry's own words. If that yields nothing usable because the section has one group with one terse bullet, use that bullet verbatim. Never write a summary that names a change absent from the section.
273
273
  3. Handle edge cases explicitly, never silently: if a Release for the tag already exists, report it and skip creation (the tag push may already have landed); if `gh` is missing, unauthenticated, or the call fails, STOP and print the exact `gh release create` command so publication can be finished by hand rather than left half-done.
274
274
  4. **Verify publication — never assume it.** Read the Release back: `gh release view ${TAG_PREFIX}${VERSION} --json url,isDraft,tagName`. STOP unless it returns a **non-draft** Release on the correct tag; `gh release create` can partially succeed (tag pushed, Release rejected for an empty notes-file or a permissions/`--verify-tag` race), and an unverified publish is not a published release. Report the Release URL only once the read-back confirms it.
275
275
  5. **Record the tag's provenance, when the row declares one.** A git tag is a mutable ref, and the commit a tag was *originally* published at is not recoverable from the API once it moves — a moved tag looks exactly like a tag that was always there. So, when `$TARGET`'s row declares `$PROVENANCE_MANIFEST`, write it down: add the new tag to that file under `tags`, as `{"object_sha": <the ref's sha>, "object_type": "tag", "commit_sha": <the commit it dereferences to>}`. Read both mechanically from the remote you just pushed to, never from local state: `git ls-remote --tags origin ${TAG_PREFIX}${VERSION}` for the ref sha and `git rev-parse ${TAG_PREFIX}${VERSION}^{commit}` for the commit. If this project runs an automated tag-drift check in CI against that file, an unrecorded tag is an unguarded tag there. **A row declaring no `$PROVENANCE_MANIFEST` skips this step — say so explicitly in the report** rather than silently doing nothing (a skipped step and a forgotten one must never look the same to the person reading the report). The entry rides in a normal commit through `commit-gate` on the release branch.
@@ -23,8 +23,8 @@ Periodic sweep of the entire codebase with the reviewer fleet, funneled to a sin
23
23
  | `architecture-drift-reviewer` | `decisions/`; drift between code and accepted ADRs |
24
24
 
25
25
  2. Route to `dispatching-parallel-agents` (`<plugin-root>/routines/dispatching-parallel-agents/SKILL.md`) with that unit list (read-only batch). It dedupes, then
26
- funnels through `finding-triage` → `checkpoint-aggregator`.
27
- 3. `checkpoint-aggregator` writes the dated report to
26
+ funnels through `finding-triage` → `verdict-aggregator` and returns the single read-only verdict.
27
+ 3. After the verdict returns, separately dispatch `checkpoint-aggregator` with that verdict. It writes the dated report to
28
28
  `<project-root>/.codearbiter/checkpoints/YYYY-MM-DD.md`: findings by severity with
29
29
  file:line, and out-of-scope items marked inline `[NEEDS-TRIAGE]`.
30
30
  4. Write the current override **count** to `<project-root>/.codearbiter/last-checkpoint` — the
@@ -38,8 +38,9 @@ Periodic sweep of the entire codebase with the reviewer fleet, funneled to a sin
38
38
  ## Hard gate
39
39
 
40
40
  Read-only except writing the checkpoint doc and `last-checkpoint` — MUST NOT modify code. MUST NOT
41
- consume raw reviewer output — only the `finding-triage` → `checkpoint-aggregator` verdict. MUST NOT
42
- resolve a `[CONFIRM-NN]` surfaced during the sweep by guessing. The report surfaces findings; it does
41
+ consume raw reviewer output — only the `finding-triage` → `verdict-aggregator` verdict. Checkpoint
42
+ persistence MUST remain the separate `checkpoint-aggregator` step and MUST NOT run for `/ca-review`
43
+ or another generic parallel batch. MUST NOT resolve a `[CONFIRM-NN]` surfaced during the sweep by guessing. The report surfaces findings; it does
43
44
  not block or sign off anything.
44
45
 
45
46
  ## When NOT to use
@@ -6,6 +6,12 @@ argument-hint: (none)
6
6
 
7
7
  # /ca-cleanup — post-merge branch transition
8
8
 
9
+ <!-- catalog-compatibility-notice:start -->
10
+ > Compatibility route. Prefer `/ca-pr --cleanup` for new usage. This installed route remains
11
+ > functional under the command-route compatibility policy at <plugin-root>/includes/command-compatibility.md;
12
+ > continue with the unchanged cleanup workflow below.
13
+ <!-- catalog-compatibility-notice:end -->
14
+
9
15
  Your PR merged. You are still standing on the branch, with build output, worktree
10
16
  residue, and scratch files around you. This command owns the ordinary walk back:
11
17
  prove the branch actually landed, decide what the leftovers are, get to a clean
@@ -6,6 +6,12 @@ argument-hint: (none)
6
6
 
7
7
  # /ca-context-check — manual drift audit
8
8
 
9
+ <!-- catalog-compatibility-notice:start -->
10
+ > Compatibility route. Prefer `/ca-status drift` for new usage. This installed route remains
11
+ > functional under the command-route compatibility policy at <plugin-root>/includes/command-compatibility.md;
12
+ > continue with the unchanged drift workflow below.
13
+ <!-- catalog-compatibility-notice:end -->
14
+
9
15
  An optional, on-demand audit for bypass cases: a merge or external edit
10
16
  changed a tracked source file you are not about to commit, so commit-gate's
11
17
  auto-heal did not fire. Routes to the `context-check` skill.
@@ -6,6 +6,12 @@ argument-hint: (none)
6
6
 
7
7
  # /ca-create-context — brownfield populate
8
8
 
9
+ <!-- catalog-compatibility-notice:start -->
10
+ > Compatibility route. Prefer `/ca-init --brownfield` for new usage. This installed route remains
11
+ > functional under the command-route compatibility policy at <plugin-root>/includes/command-compatibility.md;
12
+ > continue with the unchanged brownfield workflow below.
13
+ <!-- catalog-compatibility-notice:end -->
14
+
9
15
  Wraps an existing codebase in project state without guessing. Dispatches parallel scouts to read the repository, synthesizes their findings into the surviving `.codearbiter/` doc set, resolves gaps via a targeted interview, and locks the project initialized. No arguments — the skill reads the repo and asks only what it cannot determine.
10
16
 
11
17
  The only permitted path to populate `.codearbiter/` when meaningful source code already exists. For a greenfield project with no source, use `/ca-decompose`.
@@ -6,6 +6,12 @@ argument-hint: (none)
6
6
 
7
7
  # /ca-decompose — greenfield populate
8
8
 
9
+ <!-- catalog-compatibility-notice:start -->
10
+ > Compatibility route. Prefer `/ca-init --greenfield` for new usage. This installed route remains
11
+ > functional under the command-route compatibility policy at <plugin-root>/includes/command-compatibility.md;
12
+ > continue with the unchanged greenfield workflow below.
13
+ <!-- catalog-compatibility-notice:end -->
14
+
9
15
  Stands up project state for a greenfield project — one with no meaningful source code yet. A senior-architect persona drives a six-layer interview eliciting purpose, scope, primary users, domain vocabulary, and architectural constraints, persisting each layer to disk so a context reset loses nothing, then writes the surviving `.codearbiter/` doc set and locks the project initialized. No arguments — the skill interviews the user (a handoff summary may be supplied freely during the interview).
10
16
 
11
17
  The only permitted path to populate `.codearbiter/` when no meaningful source exists. For an existing codebase, use `/ca-create-context`.
@@ -42,3 +42,7 @@ remediation.
42
42
  Read-only. MUST NOT create markers, stage files, grant trust, weaken a block, or retry the
43
43
  wrapper self-test with different spelling. MUST preserve the degraded active-dispatch diagnosis until
44
44
  supported-version real-host promotion/CI evidence closes PI-AC-28.
45
+
46
+ For an arbiter-enabled repository, the mechanical report treats the Git backstop as healthy only
47
+ after exact managed-shim and live-enforcer validation, plus a harmless selected-Git
48
+ `git hook run pre-push` probe with empty input. It never executes a foreign hook.
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: ca-init
3
3
  description: Opt this repo into codeArbiter — scaffold the root-level .codearbiter/ state store.
4
- argument-hint: "(none) | --stage N | --check"
4
+ argument-hint: "[--stage N] [--greenfield|--brownfield] | --check"
5
5
  ---
6
6
 
7
7
  # /ca-init — first-run scaffold
@@ -15,6 +15,23 @@ the SessionStart persona injection. The scaffolded
15
15
  `CONTEXT.md` is a **stub** (no initialization sentinel), so after scaffolding the project still needs
16
16
  populating before normal operation.
17
17
 
18
+ <!-- catalog-command-modes:start -->
19
+ ## Explicit population strategies
20
+
21
+ <!-- command-mode:--greenfield legacy-route:decompose -->
22
+ `--greenfield` selects the exact `<plugin-root>/skills/ca-decompose/SKILL.md` workflow.
23
+
24
+ <!-- command-mode:--brownfield legacy-route:create-context -->
25
+ `--brownfield` selects the exact `<plugin-root>/skills/ca-create-context/SKILL.md` workflow.
26
+
27
+ The two flags are mutually exclusive and neither may combine with `--check`. `--stage N` may
28
+ accompany one only while `.codearbiter/CONTEXT.md` is absent: scaffold at that stage, then enter the
29
+ selected workflow. When an uninitialized stub already exists, skip the refusing scaffolder and enter
30
+ the selected workflow directly. An initialized marker or source-shape mismatch retains the selected
31
+ legacy workflow's BLOCK. Without an explicit strategy, continue with the unchanged auto-detection
32
+ procedure below.
33
+ <!-- catalog-command-modes:end -->
34
+
18
35
  ## Procedure
19
36
 
20
37
  1. Run the scaffolder against the repo's git toplevel (resolved by the script):
@@ -1,13 +1,29 @@
1
1
  ---
2
2
  name: ca-pr
3
3
  description: Open a pull request the only sanctioned way — clear every BLOCK-level review finding, then stage the PR. Never a direct write to the default branch.
4
- argument-hint: (none)
4
+ argument-hint: "[\"title\"] | --watch [PR] | --cleanup"
5
5
  ---
6
6
 
7
7
  # /ca-pr — open a pull request
8
8
 
9
9
  The only permitted path to a pull request. Every change lands through a PR — never a direct write or force-push to the default branch. No PR is drafted while any BLOCK-level review finding stands.
10
10
 
11
+ <!-- catalog-command-modes:start -->
12
+ ## Compatibility modes
13
+
14
+ <!-- command-mode:--watch legacy-route:watch -->
15
+ `--watch [PR number | URL | branch]` loads and follows
16
+ `<plugin-root>/skills/ca-watch/SKILL.md` with the remaining arguments. This is an internal resource
17
+ handoff to the exact watcher contract, not a second host-command invocation.
18
+
19
+ <!-- command-mode:--cleanup legacy-route:cleanup -->
20
+ `--cleanup` loads and follows `<plugin-root>/skills/ca-cleanup/SKILL.md` with no remaining argument. It
21
+ retains the cleanup route's containment proof and per-item confirmations.
22
+
23
+ The flags are mutually exclusive. A bare or quoted title named `watch` or `cleanup` is not a mode;
24
+ without either flag, continue with the unchanged PR flow below.
25
+ <!-- catalog-command-modes:end -->
26
+
11
27
  ## Flow
12
28
 
13
29
  Routes to the `finishing-a-development-branch` skill, open-PR path. The orchestrator reads the current
@@ -6,7 +6,7 @@ argument-hint: "[path | #<pr> | <pr-url>] (defaults to the current diff)"
6
6
 
7
7
  # /ca-review — diff review
8
8
 
9
- Read-only review of a change. Routes to `dispatching-parallel-agents` (`<plugin-root>/routines/dispatching-parallel-agents/SKILL.md`): dispatches the reviewer fleet by path matrix, dedupes, then funnels through `finding-triage` → `checkpoint-aggregator` to a single verdict. No code is modified.
9
+ Read-only review of a change. Routes to `dispatching-parallel-agents` (`<plugin-root>/routines/dispatching-parallel-agents/SKILL.md`): dispatches the reviewer fleet by path matrix, dedupes, then funnels through `finding-triage` → `verdict-aggregator` to a single in-memory verdict. No code is modified.
10
10
 
11
11
  **The change under review does not have to be yours.** `/ca-review #123` reviews an inbound pull request through the same fleet, the same matrix, and the same triage. That is the point of issue #80: a tool that only reviews the diff you just wrote is a linter for authors, not a gate for a team, and reviewing code you did NOT write is where a governance gate earns its keep.
12
12
 
@@ -38,7 +38,7 @@ It is an ARGUMENT, not a second command. The scope resolver already took one, th
38
38
 
39
39
  3. Route to `dispatching-parallel-agents` with that unit list (read-only batch — no collision check).
40
40
  It dedupes overlapping findings, then funnels through `finding-triage` (severity + inline
41
- `[NEEDS-TRIAGE]` on out-of-scope items) → `checkpoint-aggregator` (single verdict).
41
+ `[NEEDS-TRIAGE]` on out-of-scope items) → `verdict-aggregator` (single read-only verdict).
42
42
  4. Surface the aggregated verdict: findings by severity, file:line, remediation, and the applicable
43
43
  control from `<project-root>/.codearbiter/security-controls.md` for security findings.
44
44
  5. **For a PR target, posting the verdict is a separate, confirmed step.** Report locally first; post only on explicit instruction, with `gh pr review <number> --comment --body-file <file>`. A review comment on someone else's PR is outward-facing and effectively public the moment it lands — it notifies subscribers and cannot be un-sent. Never `--request-changes` or `--approve` from here: those carry merge authority, and this command produces a finding list, not a maintainer's decision.
@@ -52,8 +52,7 @@ It is an ARGUMENT, not a second command. The scope resolver already took one, th
52
52
 
53
53
  ## Hard gate
54
54
 
55
- Read-only — MUST NOT modify a file, and MUST NOT check out, merge, or otherwise move the repository to the PR's branch: reviewing an inbound PR means reading its DIFF, not adopting its code, and a checkout would run its content through hooks that trust the working tree. BLOCK on any CRITICAL or HIGH finding on your OWN change: it must be resolved before `/ca-pr`. On an inbound PR there is nothing local to block — the verdict is the deliverable. MUST NOT consume raw reviewer output — only the `finding-triage` → `checkpoint-aggregator`
56
- verdict. MUST NOT resolve a `[CONFIRM-NN]` surfaced during review by guessing.
55
+ Read-only — MUST NOT modify a file, and MUST NOT check out, merge, or otherwise move the repository to the PR's branch: reviewing an inbound PR means reading its DIFF, not adopting its code, and a checkout would run its content through hooks that trust the working tree. BLOCK on any CRITICAL or HIGH finding on your OWN change: it must be resolved before `/ca-pr`. On an inbound PR there is nothing local to block — the verdict is the deliverable. MUST NOT consume raw reviewer output — only the `finding-triage` → `verdict-aggregator` verdict. MUST NOT resolve a `[CONFIRM-NN]` surfaced during review by guessing.
57
56
 
58
57
  ## When NOT to use
59
58
 
@@ -15,24 +15,31 @@ it never merges, never PRs, and never becomes the implementation. What survives
15
15
  1. **Name the question** — a spike without a falsifiable question is just freelancing. Restate
16
16
  `$ARGUMENTS` as the question the spike answers and the timebox (default: one session). STOP for
17
17
  the user's confirmation.
18
- 2. **Branch** — create `spike/<slug>` from the current branch. All spike work stays on it.
18
+ 2. **Branch** — create `spike/<slug>` from the current branch. All exploratory code and experiments
19
+ stay on it; only the completed findings file may later cross back to the parent.
19
20
  3. **Explore** — no `tdd`, no plan, no review fleet. Two rules survive even here: no secret leaves
20
21
  the approved store, and no irreversible operation (prod data, destructive migration) runs from a
21
22
  spike.
22
23
  4. **Exit — exactly one of:**
23
24
  - **Answered** → write the findings to `<project-root>/.codearbiter/spikes/<slug>.md`
24
- (the question, what was tried, the answer, what it implies), then delete the branch. If the
25
- answer warrants building, hand the findings to `/ca-feature` — the spike file seeds
25
+ (the question, what was tried, the answer, what it implies), and commit only that findings file
26
+ on `spike/<slug>`. Return to the parent branch and run
27
+ `git restore --source spike/<slug> -- .codearbiter/spikes/<slug>.md` to transfer only the
28
+ committed findings file, review it, and commit that one file through `/ca-commit`; do not
29
+ merge the spike branch. Then delete the spike branch. If the answer warrants building, hand the
30
+ findings to `/ca-feature` — the spike file seeds
26
31
  `brainstorming` (`<plugin-root>/routines/brainstorming/SKILL.md`); the spike code is reference material, never the implementation.
27
- - **Timebox expired, no answer** → record that too (a dead end is a finding), delete the branch.
32
+ - **Timebox expired, no answer** → record that in the findings file and use the same findings-only
33
+ transfer before deleting the spike branch.
28
34
 
29
35
  ## Hard gate
30
36
 
31
- MUST NOT merge or PR a `spike/*` branch — its only exits are a findings file and deletion. MUST NOT
32
- copy spike code into an implementation branch wholesale; implementation re-enters through
37
+ MUST NOT merge or PR a `spike/*` branch — its only exits are a findings file and deletion. Do not
38
+ transfer spike code: the parent may receive only the committed findings file. MUST NOT copy spike
39
+ code into an implementation branch wholesale; implementation re-enters through
33
40
  `/ca-feature` and `tdd`. Secret-handling and irreversibility rules hold even in a spike. Commits on
34
- a `spike/*` branch are exempt from `commit-gate` — the exemption is safe precisely because nothing
35
- on the branch can ever land.
41
+ a `spike/*` branch are exempt from `commit-gate` — the exemption is safe because no spike commit is
42
+ merged and the parent may copy only the committed findings file's contents, never spike code.
36
43
 
37
44
  ## When NOT to use
38
45
 
@@ -1,13 +1,25 @@
1
1
  ---
2
2
  name: ca-status
3
3
  description: Show the project's current state at a glance — stage, open tasks, open questions, overrides since the last checkpoint, current branch. Read-only.
4
- argument-hint: (none)
4
+ argument-hint: "(none) | drift"
5
5
  ---
6
6
 
7
7
  # /ca-status — state snapshot
8
8
 
9
9
  A read-only summary of `.codearbiter/` state. No skill is routed to; no file is modified.
10
10
 
11
+ <!-- catalog-command-modes:start -->
12
+ ## Drift mode
13
+
14
+ <!-- command-mode:drift legacy-route:context-check -->
15
+ With the exact argument `drift`, load and follow
16
+ `<plugin-root>/skills/ca-context-check/SKILL.md`. The audit begins read-only; re-scout or re-baseline may
17
+ write only after the user's explicit selection. In drift mode the `context-check` contract governs;
18
+ the opening summary and Hard gate below apply only to the no-argument snapshot. With no argument,
19
+ continue with the unchanged read-only snapshot below. Reject other arguments rather than treating
20
+ them as drift mode.
21
+ <!-- catalog-command-modes:end -->
22
+
11
23
  ## Flow
12
24
 
13
25
  The orchestrator reads and presents:
@@ -6,6 +6,12 @@ argument-hint: "<PR number | url | branch>"
6
6
 
7
7
  # /ca-watch — PR CI babysitter
8
8
 
9
+ <!-- catalog-compatibility-notice:start -->
10
+ > Compatibility route. Prefer `/ca-pr --watch` for new usage. This installed route remains
11
+ > functional under the command-route compatibility policy at <plugin-root>/includes/command-compatibility.md;
12
+ > continue with the unchanged watcher workflow below.
13
+ <!-- catalog-compatibility-notice:end -->
14
+
9
15
  Watch a pull request's checks to completion without babysitting them by hand. The
10
16
  wait happens server-side, so it costs nothing while CI runs; arbiter wakes once, on
11
17
  the verdict — diagnoses a red, or offers you the merge on a green. Arbiter never
@@ -1,30 +0,0 @@
1
- <!-- codeArbiter — maintainer dev-mode detail. Loaded on demand by the orchestrator
2
- when the user invokes /ca-dev or /ca-arbiter. The always-on kernel (ORCHESTRATOR.md)
3
- keeps only the env-gate + logged + load-before-gates-off invariant as a stub; the full
4
- mode description lives here. -->
5
-
6
- # /dev — Maintainer Override (evaluated FIRST, every turn, before anything else)
7
-
8
- `/ca-dev` (optionally `/ca-dev "note"`) **suspends the gates entirely** to edit codeArbiter itself
9
- with no orchestration mediating — skill, agent, command, and hook bodies, `ORCHESTRATOR.md`, settings.
10
- It is the gates-off escape hatch, **not** the required lane for touching those files: normal
11
- development of codeArbiter — fixing a hook bug, adding a command, editing this persona — flows through
12
- the ordinary gated lanes (`/ca-feature`, `/ca-fix`, `/ca-chore`) and ships via PR + release, the same
13
- dogfooding path as any other change. Reach for `/ca-dev` only when orchestration itself is broken or
14
- genuinely in the way of editing it. It is **env-gated and logged**:
15
-
16
- - **Gate:** activates only when the `CODEARBITER_DEV` environment variable is set to `1`. Absent or
17
- empty → refuse in one line ("dev mode requires CODEARBITER_DEV=1") and remain in orchestration.
18
- - **Log:** on entry, append `[ISO-8601] | BY: <git user.email> | DEV: enter | NOTE: <note or —>` to
19
- `.codearbiter/overrides.log` (append with `>>`, per ORCHESTRATOR §7's append-only rule). On exit,
20
- append the matching `DEV: exit` line. Dev mode is on the audit trail like any other bypass.
21
- - **Mode:** while active — no routing, no skills, no gates, no `[CONFIRM-NN]` surfacing, no redirect,
22
- no startup presentation; a plain, direct coding assistant. Drop the transient marker
23
- `<project-root>/.codearbiter/.markers/dev-active` (gitignored local UI flag). The marker is NOT the log — the overrides.log
24
- lines are.
25
- - **Exit:** `/ca-arbiter` restores orchestration (removes the marker, writes the exit line). A new
26
- session also restores it (SessionStart clears the marker); write the exit line at the next
27
- opportunity if the session ended mid-dev.
28
-
29
- Even in dev mode, `overrides.log` itself is never rewritten — the append-only rule has no dev
30
- exception.
@@ -1,36 +0,0 @@
1
- ---
2
- name: ca-arbiter
3
- description: Exit maintainer dev mode — restore orchestration, remove the dev marker, log the exit.
4
- argument-hint: (none)
5
- ---
6
-
7
- # /ca-arbiter — restore orchestration
8
-
9
- The exit door for `/ca-dev`. No-op if dev mode is not active.
10
-
11
- ## Flow
12
-
13
- 1. **Log exit** — append to `<project-root>/.codearbiter/overrides.log` (append-only, `>>`):
14
-
15
- ```
16
- [ISO-8601 timestamp] | BY: <email> | DEV: exit
17
- ```
18
-
19
- 2. **Marker** — remove `<project-root>/.codearbiter/.markers/dev-active`.
20
- 3. **Resume** — re-present the startup state (stage, blocking `CONFIRM-NN`, in-flight tasks) and
21
- await a slash command. Orchestration, routing, and all gates are back in force.
22
-
23
- ## Hard gate
24
-
25
- MUST write the `DEV: exit` line to `overrides.log` and remove the `dev-active` marker before resuming
26
- orchestration — the exit is on the audit trail like the entry. MUST NOT rewrite or truncate
27
- `overrides.log` — the append-only rule has no dev exception, on entry or exit. If a prior session
28
- ended mid-dev, SessionStart has already appended the synthetic `BY: session-cleanup | DEV: exit` close
29
- line and cleared the marker (`session-start.py`, observability-001). In that case MUST NOT write a
30
- second `DEV: exit` for that orphaned entry — the close is already on the trail.
31
-
32
- Session-scoped clearing (#271): SessionStart's synthetic close is now conditional on the marker
33
- plausibly being abandoned rather than owned by a different, still-live session — it will NOT clobber
34
- another concurrently-running session's live `/dev` marker or write a false `DEV: exit` for it.
35
- `/ca-arbiter` remains the ONLY way to cleanly close your OWN `/dev` session's audit pair; do not
36
- rely on a future SessionStart to do it for you.
@@ -1,42 +0,0 @@
1
- ---
2
- name: ca-dev
3
- description: Maintainer override — suspend orchestration to edit codeArbiter itself. Env-gated (CODEARBITER_DEV=1), entry/exit logged to overrides.log.
4
- argument-hint: "[note]"
5
- ---
6
-
7
- # /ca-dev — maintainer override
8
-
9
- Suspends orchestration for working ON codeArbiter — skill, agent, command, and hook bodies,
10
- `ORCHESTRATOR.md`, settings. Not for project work; for that, use the normal commands or
11
- `/ca-override`.
12
-
13
- ## Flow
14
-
15
- 1. **Env gate** — check the `CODEARBITER_DEV` environment variable. Not set to `1` → refuse in one
16
- line ("dev mode requires CODEARBITER_DEV=1") and remain in orchestration. This keeps the mode a
17
- deliberate maintainer posture, not a casual bypass.
18
- 2. **Log entry** — detect identity from `git config user.email`; append to
19
- `<project-root>/.codearbiter/overrides.log` (append-only, `>>`):
20
-
21
- ```
22
- [ISO-8601 timestamp] | BY: <email> | DEV: enter | NOTE: <note or —>
23
- ```
24
-
25
- 3. **Marker** — drop `<project-root>/.codearbiter/.markers/dev-active` (gitignored UI flag).
26
- 4. **Mode** — plain, direct coding assistant: no routing, no skills, no gates, no `[CONFIRM-NN]`
27
- surfacing, no redirect. Persists until `/ca-arbiter` or a new session.
28
-
29
- Note (#271): if another session starts in this repo while this marker is live, SessionStart no longer
30
- unconditionally clears it out from under you — it is session-scoped now, so a concurrently-running dev
31
- session's marker survives a different session's startup. See `/ca-arbiter` for the exit-path detail.
32
-
33
- ## Hard gate
34
-
35
- MUST refuse without `CODEARBITER_DEV=1`. MUST write the `DEV: enter` log line before suspending
36
- orchestration. Even in dev mode, `overrides.log` is never rewritten — the append-only rule has no
37
- dev exception.
38
-
39
- ## When NOT to use
40
-
41
- - Bypassing a single gate on project work → `/ca-override "reason"`.
42
- - Asking a question → `/ca-btw`.