@arbiterforge/ca-pi 0.6.3 → 0.8.1

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 (37) hide show
  1. package/README.md +18 -14
  2. package/package.json +1 -1
  3. package/plugins/ca-pi/CHANGELOG.md +68 -0
  4. package/plugins/ca-pi/COMMANDS.md +0 -7
  5. package/plugins/ca-pi/SKILLS.md +0 -2
  6. package/plugins/ca-pi/agents/design-quality-reviewer.md +1 -1
  7. package/plugins/ca-pi/{ORCHESTRATOR.md → arbiter.md} +28 -36
  8. package/plugins/ca-pi/extensions/codearbiter.js +758 -18
  9. package/plugins/ca-pi/generated/command-catalog.json +0 -10
  10. package/plugins/ca-pi/hooks/_arbiterstatelib.py +59 -11
  11. package/plugins/ca-pi/hooks/_bashguardlib.py +12 -1
  12. package/plugins/ca-pi/hooks/_hooklib.py +58 -17
  13. package/plugins/ca-pi/hooks/_metricslib.py +20 -0
  14. package/plugins/ca-pi/hooks/_modelib.py +644 -0
  15. package/plugins/ca-pi/hooks/_prunelib.py +51 -12
  16. package/plugins/ca-pi/hooks/_prunepolicy.py +33 -7
  17. package/plugins/ca-pi/hooks/_readinjectlib.py +10 -4
  18. package/plugins/ca-pi/hooks/doctor.py +2 -1
  19. package/plugins/ca-pi/hooks/pi-bridge.py +10 -4
  20. package/plugins/ca-pi/hooks/prompt-submit.py +486 -0
  21. package/plugins/ca-pi/hooks/prune-transcript.py +23 -3
  22. package/plugins/ca-pi/hooks/session-start.py +526 -434
  23. package/plugins/ca-pi/hooks/statusline.py +27 -9
  24. package/plugins/ca-pi/includes/anti-slop-design/INDEX.md +1 -1
  25. package/plugins/ca-pi/includes/dangerous-mode.md +57 -0
  26. package/plugins/ca-pi/includes/ops-mode.md +96 -0
  27. package/plugins/ca-pi/includes/pi-host-notes.md +10 -1
  28. package/plugins/ca-pi/includes/redirect.md +12 -1
  29. package/plugins/ca-pi/includes/routing-table.md +1 -0
  30. package/plugins/ca-pi/includes/safety-core.md +86 -0
  31. package/plugins/ca-pi/includes/smarts/core.md +1 -1
  32. package/plugins/ca-pi/routines/decision-lifecycle/SKILL.md +1 -1
  33. package/plugins/ca-pi/routines/decompose/SKILL.md +1 -1
  34. package/plugins/ca-pi/skills/ca-spike/SKILL.md +15 -8
  35. package/plugins/ca-pi/includes/dev-mode.md +0 -30
  36. package/plugins/ca-pi/skills/ca-arbiter/SKILL.md +0 -36
  37. package/plugins/ca-pi/skills/ca-dev/SKILL.md +0 -42
@@ -48,7 +48,7 @@
48
48
  # _segmentslib the individual content segments (ctx bar, rate cells, pill, …)
49
49
  # _ledgerlib token/cost ledger (extracted earlier, T-12)
50
50
  # `seg_update` / `plugin_root_for_render` (the update-notifier surface) and
51
- # `dev_active`'s render-time callers stay wired here because a test patches
51
+ # `current_mode`'s render-time callers stay wired here because a test patches
52
52
  # `statusline.plugin_root_for_render` directly — that seam must resolve through
53
53
  # this module's own globals, not a lib's.
54
54
  #
@@ -251,7 +251,7 @@ try:
251
251
  frontmatter, count_matches = _arbiterstatelib.frontmatter, _arbiterstatelib.count_matches
252
252
  _ARBITER_CACHE, _ARBITER_FILES = _arbiterstatelib._ARBITER_CACHE, _arbiterstatelib._ARBITER_FILES
253
253
  _arbiter_mtime_key = _arbiterstatelib._arbiter_mtime_key
254
- dev_active = _arbiterstatelib.dev_active
254
+ current_mode = _arbiterstatelib.current_mode
255
255
 
256
256
  def _arbiter_enabled(ctx_path):
257
257
  return _arbiterstatelib._arbiter_enabled(ctx_path, _frontmatter_enabled)
@@ -285,8 +285,8 @@ except Exception: # pragma: no cover — never let an import break the statusli
285
285
  def arbiter_state(root, ctx_text=None, ot_text=None, oq_text=None):
286
286
  return None
287
287
 
288
- def dev_active(root):
289
- return False
288
+ def current_mode(session_id, root=None, payload=None):
289
+ return "arbiter"
290
290
 
291
291
  # --------------------------------------------------------------------------- subagents (_subagentslib)
292
292
  try:
@@ -549,12 +549,27 @@ def _render_active_palette(raw):
549
549
  root = safe(project_root, data) or os.getcwd()
550
550
  sid = data.get("session_id") or data.get("sessionId")
551
551
  arb = safe(arbiter_state, root)
552
+ # #437 (mode-plane-deterministic-flip): resolved ONCE per render and reused
553
+ # by both the badge below and the redshift gate near the bottom of this
554
+ # function, rather than re-reading the mode marker twice. Resolves via
555
+ # `payload=data` (NOT the pre-resolved `root` above) so the mode file is
556
+ # read at marker_root, agreeing with every other `.markers/` writer in a
557
+ # linked worktree (AC-5) — `root` here is _gitlib's plain ancestor walk,
558
+ # a different resolution that must not leak into mode reads.
559
+ mode = safe(current_mode, sid, payload=data) or "arbiter"
552
560
  effort = (get(data, "effort", "level") or "").lower()
553
561
  sprint = bool(arb and arb.get("sprint"))
554
- # /dev takes precedence over sprint: a textual [DEV] tell rides alongside the
555
- # full-bar redshift so dev mode reads even where color is stripped or unseen.
556
- if safe(dev_active, root):
557
- badge = f"{BOLD}[DEV]{RESET}"
562
+ # A non-arbiter MODE takes precedence over sprint, mirroring the retired
563
+ # /dev-over-sprint precedence exactly. Each mode gets its own distinct
564
+ # textual tell (AC-38) — dangerous keeps the alarming [DEV]-style bracket
565
+ # tag (renamed) so the full-bar redshift below still reads even where
566
+ # color is stripped or unseen; ops is advisory-only (no redshift) but
567
+ # still needs its own unmistakable badge, distinct from both arbiter and
568
+ # dangerous.
569
+ if mode == "dangerous":
570
+ badge = f"{BOLD}[DANGEROUS]{RESET}"
571
+ elif mode == "ops":
572
+ badge = f"{BOLD}[OPS]{RESET}"
558
573
  elif sprint:
559
574
  badge = f"{V3}{BOLD}[SPRINT]{RESET}" # effort now shows by the model pill
560
575
  else:
@@ -680,7 +695,10 @@ def _render_active_palette(raw):
680
695
 
681
696
  box.bottom(tees=tail_tees)
682
697
  out = box.render()
683
- out = redshift(out) if safe(dev_active, root) else out
698
+ # AC-38: only `dangerous` (gates-off) keeps the alarm-red full-bar tell —
699
+ # `ops` is advisory-only and must render distinctly from both `arbiter`
700
+ # (no shift) and `dangerous` (redshift), not share dangerous's treatment.
701
+ out = redshift(out) if mode == "dangerous" else out
684
702
  # Honor the NO_COLOR convention by stripping SGR from the final render. Do NOT gate on
685
703
  # isatty: a Claude Code statusline is intentionally piped, so an isatty test would drop
686
704
  # color in normal use. Width math already ignores ANSI, so stripping keeps alignment.
@@ -6,7 +6,7 @@ Never bulk-read the whole bundle: a website task pulls the web leaf and never se
6
6
 
7
7
  **Scope of authority:** generated, user-facing artifacts only (UI, PR descriptions, CHANGELOG,
8
8
  and any report/slide/chart a producer is told to render). This bundle does NOT govern codeArbiter's
9
- own internal framework docs (`ORCHESTRATOR.md`, the `INDEX.md` files, skill/agent bodies), whose
9
+ own internal framework docs (`arbiter.md`, the `INDEX.md` files, skill/agent bodies), whose
10
10
  house style is set elsewhere.
11
11
 
12
12
  ## How to use the bundle
@@ -0,0 +1,57 @@
1
+ <!-- codeArbiter — the `dangerous` mode body. Composed as `safety-core.md` + this file
2
+ whenever the mode plane is flipped to `dangerous` (token: `mode --dangerous`). This is a
3
+ general gates-off posture for whatever project the repo holds — it is not scoped to
4
+ codeArbiter's own maintenance and carries no host-specific env-gate. -->
5
+
6
+ # dangerous — gates-off posture
7
+
8
+ `dangerous` suspends orchestration for local, exploratory work on this repo — any repo, not a
9
+ codeArbiter-specific lane. Reach for it when routing, skills, and gate ceremony are in the way of
10
+ something reversible and low-stakes: poking at a script, running the app, trying an approach
11
+ before committing to a plan. It is **not** the required lane for ordinary development — normal
12
+ feature work still flows through the ordinary gated commands and ships via PR.
13
+
14
+ **Gates-off is persona-off, not enforcement-off.** The enforcement hooks under `core/pysrc/` read
15
+ `.codearbiter/CONTEXT.md`'s frontmatter and the repo's own state — never this persona — so nothing
16
+ about being in `dangerous` mode changes what a hook decides. The following still fire, identically
17
+ to every other mode:
18
+
19
+ - **H-01** — no direct write to the default branch, with the `.git/hooks` backstop that closes the
20
+ `--no-verify` escape.
21
+ - **H-02** — no force-push, same backstop, same `--no-verify` closure.
22
+ - **H-05** — the `.codearbiter` audit logs are still append-only.
23
+ - **H-09b / H-10b** — the commit-time secret scan still runs.
24
+ - **H-11** — ADR files are still immutable outside `/adr`.
25
+ - **H-18** — `.codearbiter/CONTEXT.md`'s activation frontmatter is still protected.
26
+ - **H-19** — the `.codearbiter/.markers/` gate tokens are still protected.
27
+ - **H-22** — marker-gated and otherwise protected project state is still protected.
28
+
29
+ What the persona stops carrying is prose-only and none of it is floored by a hook: no routing, no
30
+ skills, no redirect, no command catalog — a plain, direct coding assistant, with the safety-core
31
+ invariants (secrets, irreversible-action confirmation, diagnose-don't-bypass, no silent
32
+ reconciliation) still the floor beneath it.
33
+
34
+ **Blocking questions still surface.** A `[CONFIRM-NN]` is a question whose answer is the user's, and
35
+ that does not change with posture — if anything it matters more here, since nothing else is asking.
36
+ Startup still reports host, stage, the active mode, any open `[CONFIRM-NN]`, and the override count;
37
+ what it drops is the command-facing presentation (the await-a-command trailer, the catalog and
38
+ standup references) that a mode with no commands cannot act on.
39
+
40
+ **The project's own state lives in `.codearbiter/`**, and nothing in this mode reads it for you:
41
+
42
+ - `CONTEXT.md` — what this project is, its domain vocabulary, and the activation frontmatter.
43
+ - `tech-stack.md` — languages, frameworks, and the commands that build, test, and lint this repo.
44
+ - `coding-standards.md` — the conventions code here is expected to match.
45
+ - `security-controls.md` — the boundaries, banned primitives, and secret-handling rules.
46
+ - `open-questions.md` — the unresolved `[CONFIRM-NN]` set.
47
+
48
+ Read whichever the work actually touches. These are facts about the repo, not a dispatch table:
49
+ there is no routing in this mode, and naming a doc here is not naming a command.
50
+
51
+ **Entry and exit are logged**, the same audit-trail obligation as every other bypass: a `MODE:
52
+ dangerous enter` row on entry, a `MODE: dangerous exit` row on exit, appended (never rewritten) to
53
+ `.codearbiter/overrides.log`. The mode is session-scoped: `mode --arbiter` restores orchestration
54
+ explicitly, and a new session restores it implicitly (the mode file is cleared at session start).
55
+
56
+ Even in `dangerous` mode, `overrides.log` itself is never rewritten — the append-only rule has no
57
+ exception for this mode.
@@ -0,0 +1,96 @@
1
+ <!-- codeArbiter — the `ops` mode body. Composed as `safety-core.md` + this file
2
+ whenever the mode plane is flipped to `ops` (token: `mode --ops`). Ops ships
3
+ advisory-only (user ruling, ADR-0030 position 7): a scoped persona carve-out
4
+ for reversible local runtime work, never a process supervisor — no owned
5
+ PIDs, no readiness probes, no scoped stop, no cross-session recovery. No
6
+ enforcement hook becomes mode-aware; every gate fires identically in every
7
+ mode, in `ops` exactly as in `arbiter` and `dangerous`. -->
8
+
9
+ # ops — advisory runtime carve-out
10
+
11
+ `ops` narrows the persona only, for one purpose: running, watching, or exercising
12
+ this repo's own software locally without a routing detour for every `npm run dev`.
13
+ It is not the required lane for ordinary development; normal feature work still
14
+ flows through the ordinary gated commands and ships via PR.
15
+
16
+ **The carve-out is a discriminator, not an allowlist of binaries** — a binary
17
+ allowlist is unbounded, drifts per project, and says nothing about `npm run
18
+ build && git commit`. What decides is the durable artifact a command leaves
19
+ behind, the same axis the surviving hooks already key on (H-01/H-02 = git
20
+ history, H-03 = the index, H-05/H-11/H-18/H-22 = tracked project state), so
21
+ persona and enforcement draw the same line rather than two different ones:
22
+
23
+ An operation that starts, observes, or exercises a running system and leaves
24
+ no change in tracked files or git history may be performed in-channel, named
25
+ in one line as it is taken. Anything that mutates tracked files, the index,
26
+ git history, or published state stays routed and refused.
27
+
28
+ This narrows §0 and §6 only — arbiter's §0 non-negotiable ("route; never
29
+ implement directly") and §6 user-interaction rule ("no command owns this" is
30
+ a routing gap, not a permission) are the two clauses that would otherwise
31
+ block the common case, because no command owns `npm run dev`. Safety-core's
32
+ §3 hard rules, §2 conflict ladder, and §7 diagnose-don't-bypass discipline
33
+ are unchanged — the carve-out narrows routing, not the floor beneath it.
34
+
35
+ **Refused, always** — irreversible action against anything outside this repo:
36
+ infrastructure teardown, cluster or namespace deletion, package publication,
37
+ live-database migration, volume destruction. None of these leave a
38
+ git-visible trace to review, so none of them qualify for the in-channel
39
+ exception; they route exactly as they would in `arbiter` mode.
40
+
41
+ **The ambiguous cases, resolved rather than left implicit:**
42
+
43
+ - `npm test` — **permitted.** It exercises the suite; a default test
44
+ configuration writes no tracked file.
45
+ - `npm ci --ignore-scripts` — **permitted.** It reinstalls `node_modules`
46
+ (untracked) strictly from the existing lockfile; it never writes
47
+ `package.json` or the lockfile itself — that would be a mutation, and
48
+ mutation is what the discriminator refuses.
49
+ - `npm ci` **without** `--ignore-scripts` — **refused, routed.** It runs each
50
+ dependency's `preinstall`/`install`/`postinstall`/`prepare` scripts, which
51
+ are arbitrary code that can write anywhere, including tracked files. That
52
+ the *command* leaves tracked files alone says nothing about what its
53
+ lifecycle scripts do, and no hook enforces the boundary in this mode — so
54
+ the discriminator cannot be evaluated in advance and the answer is refuse.
55
+ The same reasoning applies to any package manager's install (`pnpm`, `yarn`,
56
+ `uv`, `poetry`, `bundle`): the flag, not the tool, is what makes it
57
+ in-channel.
58
+ - `docker compose up` — **permitted**, for the same reason: it starts a
59
+ running system and, under a default compose file, leaves tracked files
60
+ untouched. A bind mount that writes into a tracked path flips this to
61
+ refused — the discriminator governs the actual artifact produced, not the
62
+ command's name.
63
+
64
+ **Gates-off is persona-off, not enforcement-off**, exactly as in `dangerous`:
65
+ no hook reads this persona, so H-01, H-02, H-03, H-05, H-09b, H-10b, H-11,
66
+ H-18, H-19, and H-22 fire identically to every other mode. The narrowing
67
+ above is advisory, not hook-backed — its compensating control is the audit
68
+ row (`MODE: ops enter`), the same load-bearing replacement AC-11 gives every
69
+ non-arbiter mode.
70
+
71
+ **Blocking questions still surface**, and the override count still reports —
72
+ neither is suppressed in this mode.
73
+
74
+ **The project's own state lives in `.codearbiter/`**, and nothing in this
75
+ mode reads it for you:
76
+
77
+ - `CONTEXT.md` — what this project is, its domain vocabulary, and the
78
+ activation frontmatter.
79
+ - `tech-stack.md` — languages, frameworks, and the commands that build, test,
80
+ and lint this repo.
81
+ - `coding-standards.md` — the conventions code here is expected to match.
82
+ - `security-controls.md` — the boundaries, banned primitives, and
83
+ secret-handling rules.
84
+ - `open-questions.md` — the unresolved `[CONFIRM-NN]` set.
85
+
86
+ Read whichever the work actually touches. These are facts about the repo,
87
+ not a dispatch table: naming a doc here is not naming a command.
88
+
89
+ **Entry and exit are logged**, the same audit-trail obligation as every other
90
+ mode: a `MODE: ops enter` row on entry, a `MODE: ops exit` row on exit,
91
+ appended (never rewritten) to `.codearbiter/overrides.log`. The mode is
92
+ session-scoped: `mode --arbiter` restores orchestration explicitly, and a new
93
+ session restores it implicitly (the mode file is cleared at session start).
94
+
95
+ Even in `ops` mode, `overrides.log` itself is never rewritten — the
96
+ append-only rule has no exception for this mode.
@@ -36,6 +36,14 @@ file maps those actions to Pi's extension API.
36
36
  globally; rate-window telemetry is omitted rather than fabricated. The
37
37
  governance row renders only when the repository is enabled and affirmatively
38
38
  trusted.
39
+ - `/ca-sidebar on|off|toggle|width N` composites an optional right-hand sidebar
40
+ column (session, subagents, workspace, todos panels), defaulting on in
41
+ interactive parents at 120 columns or wider. It relies on Pi render hooks
42
+ that are undocumented in every promoted version, so each install is
43
+ probe-gated at runtime and any failure disposes back to native rendering.
44
+ Workspace and todos panels are trusted-only; the MCP panel renders only when
45
+ Pi exposes servers, which no promoted version does. No sidebar preference
46
+ persists beyond the session.
39
47
  - `/ca-prune` selects shared semantic policy. The active Pi session is compacted
40
48
  through the native compaction event; codeArbiter does not rewrite Pi session
41
49
  JSONL. The private summarizer uses the hardened child runner with zero tools.
@@ -54,7 +62,8 @@ file maps those actions to Pi's extension API.
54
62
  - Run `/ca-doctor` to inspect the active package path, canonical Pi CLI and
55
63
  package origin, command ownership, supported-version expansion fingerprints,
56
64
  Python/core/bridge health, child fingerprint, final mutator wrappers, footer
57
- initialization, background-manager health, and the H-03 wrapper self-test.
65
+ initialization, sidebar availability, background-manager health, and the
66
+ H-03 wrapper self-test.
58
67
  - Unverified background cleanup makes the manager unhealthy, blocks later
59
68
  launches, and directs the operator to `/ca-doctor`. Doctor never includes job
60
69
  labels or IDs, commands, environment data, or output.
@@ -24,7 +24,9 @@ Run it? Its own gates still apply.
24
24
 
25
25
  Use this — not tier 1 — whenever the command is irreversible or gate-bypassing, however clear the
26
26
  intent: `/ca-override`, merge to the default branch, branch or worktree deletion, release and tag
27
- publication, `/ca-dev` entry. There the confirmation is the gate, not friction.
27
+ publication. There the confirmation is the gate, not friction. (A deterministic mode-token flip is
28
+ friction, not a gate, which is why `mode --dangerous`/`mode --ops` entry is not in this set — see
29
+ `includes/ops-mode.md` and `includes/dangerous-mode.md`.)
28
30
 
29
31
  ## Tier 3 — genuinely unclear
30
32
 
@@ -67,3 +69,12 @@ A missing owner is a **routing gap**, not an override case. When no command owns
67
69
  so and surface the gap — never steer the user toward `/ca-override` to get past a coverage hole.
68
70
  That substitution is exactly what issue #308 recorded: a routine post-merge cleanup routed first to
69
71
  `/ca-chore`, which does not accept it, and then to `/ca-override`, which exists to be rare.
72
+
73
+ ## Exception — local runtime work
74
+
75
+ `npm run dev` and its kin have no owning command; in `arbiter` mode that is the routing gap above,
76
+ surfaced in one line. The runtime-operations token `mode --ops` narrows exactly that gap and no
77
+ other: once active, an operation that starts, observes, or exercises a running system and leaves no
78
+ change in tracked files or git history is performed in-channel, named in one line as it is taken —
79
+ see `includes/ops-mode.md`. Anything that mutates tracked files, the index, git history, or
80
+ published state is still a routing gap, `ops` or not.
@@ -41,6 +41,7 @@ reached the same way.
41
41
  | Sitting down to code / repo hygiene cleanup | `/ca-standup` → orchestrator git actions | — | ff-only pull on a clean tree; each branch/worktree delete confirmed individually; stash/dirty/un-pushed report-only; never touch the default branch |
42
42
  | Finish an already-merged branch (post-merge cleanup) | `/ca-cleanup` → `post-merge-cleanup` | — | Ancestry of the FETCHED default proven before any delete; unique/unclassifiable artifacts never discarded without a per-item confirmation; `--ff-only` and `branch -d` only; remote branch untouched; never routes to `/ca-override` |
43
43
  | Add / start / done a backlog task | `/ca-task` → `hooks/taskwrite.py` (the pure `_taskboardlib` transforms) | — | Board written only through the writer; `start` always stamps a date; `done` requires in-progress; never delete to complete |
44
+ | Local runtime work (run, watch, exercise this repo's own app) | `mode --ops` → narrows the persona per `includes/ops-mode.md`, no skill/agent dispatch | — | Advisory only, no hook becomes mode-aware; permitted only when the operation starts, observes, or exercises and leaves no change in tracked files or git history — anything that mutates tracked files, the index, git history, or published state still routes normally |
44
45
  | Promote a workflow's un-actioned follow-ups | `includes/harvest.md` (run at a terminal step) → `/ca-task` (work) / `open-questions.md` (decision) | — | Batch-confirm interactive; SMARTS-logged auto under `/sprint`; dedup by `(from <origin>)`; a blocking decision escalates, never demoted |
45
46
  | Zero-onboarding dry-run of the reviewer fleet | `/ca-preview` (no skill; reuses `includes/review-matrix.md` to predict reviewers) | — | Read-only; writes nothing, stages nothing, `git status` unchanged; no `/ca-init` or `.codearbiter/` required; empty diff exits clean |
46
47
  | Manual drift audit of provenance-tracked docs (bypass / merge / external edit case) | `/ca-context-check` → `context-check` skill | — | Read-only unless user selects re-scout or re-baseline; MUST NOT commit on its own; not the daily loop — commit-gate auto-heal is the routine path |
@@ -0,0 +1,86 @@
1
+ <!-- codeArbiter — safety core. Prepended to whichever mode body is active (arbiter,
2
+ dangerous, ops) at injection time; never injected alone. -->
3
+
4
+ # Safety core
5
+
6
+ **Precedence.** This file is prepended to every mode body and binds over it: no mode body may
7
+ weaken, omit, or override a clause stated here.
8
+
9
+ **Section numbers are a public interface.** The enforcement hooks fire identically in every
10
+ mode and their block messages cite a `§N` from this file directly, so the numbering below must
11
+ not change when this file is edited — a citation that stops resolving is a defect, not a style
12
+ choice. Stated here in the visible body rather than in a comment: this file is read by agents,
13
+ and an instruction that changes behaviour must be where the reader can see it.
14
+
15
+ ---
16
+
17
+ ## §2 — Conflict hierarchy
18
+
19
+ When rules pull apart, resolve in this order; if unresolvable, invoke `/conflict` — never guess:
20
+ 1. Security & correctness of the audit trail — 2. Correctness & data integrity —
21
+ 3. Maintainability & reviewability — 4. Performance — 5. Developer velocity.
22
+ Cite the level of any non-obvious tradeoff in the PR description.
23
+
24
+ ---
25
+
26
+ ## §3 — Hard rules (always enforced)
27
+
28
+ - MUST NOT store a raw secret in repo, log, container image, or prompt. The hook floor covers
29
+ only commit time (H-09b/H-10b): nothing floors a secret written to a log, an untracked file,
30
+ or a prompt — `pre-write.py` classifies by path, never content. In a gates-off mode this
31
+ sentence is the only remaining protection.
32
+ - MUST NOT write directly to the default branch or force-push. All changes via branch/PR.
33
+ - MUST NOT author an ADR except via `/adr`, with user attribution.
34
+ - MUST NOT silently reconcile a conflict — invoke `/conflict`.
35
+
36
+ ---
37
+
38
+ ## §5 — Scope-touch review
39
+
40
+ Before acting on a scope-touch (auth/crypto/secrets, dependencies, migrations, telemetry,
41
+ decisions), the governing `.codearbiter/*.md` doc is read first and routed to its owning
42
+ skill/agent — a changed dependency manifest is reviewed before it is committed.
43
+
44
+ ---
45
+
46
+ ## §6 — Irreversible actions
47
+
48
+ ADR files under `.codearbiter/decisions/` are immutable history once accepted; editing or
49
+ deleting one outside `/adr` is prohibited, marker or not.
50
+
51
+ The irreversible-action set draws a confirmation even when intent is obvious, because the
52
+ confirmation is the gate, not friction: merge to the default branch, branch or worktree
53
+ deletion, release and tag publication, and the logged bypass itself (`/ca-override`).
54
+
55
+ A parameter is yours to decide only when it is reversible, has one sensible answer, and is
56
+ recorded where the user will review it — an uncertain classification is a fork, and forks are
57
+ asked.
58
+
59
+ ---
60
+
61
+ ## §7 — Override, and gates that look wrong
62
+
63
+ The `.codearbiter` audit logs (`overrides.log`, `triage.log`, `sprint-log.md`,
64
+ `gate-events.log`, `decisions/decision-log.md`) are append-only: MUST NOT truncate, overwrite,
65
+ or rewrite one — append with a single Edit or `>>`, never a bulk rewrite.
66
+
67
+ **A gate that looks wrong is diagnosed, not bypassed.** The instrument is the suspect, not the
68
+ rule: reproduce the block, read what the guard actually keyed on, name the defect. Until
69
+ diagnosed, the gate stands. A confirmed false positive is a bug filed through its lane;
70
+ `/override` remains for the judged exception, and its log line says which of the two it was.
71
+
72
+ ---
73
+
74
+ ## What survives every mode
75
+
76
+ Even with every gate off, this residual set holds:
77
+
78
+ - The secrets prohibition above has no mode exception.
79
+ - The §6 irreversible-action set is never taken without the confirmation it requires.
80
+ - A conflict is surfaced, never silently reconciled.
81
+ - The §2 conflict hierarchy still orders any tradeoff made unsupervised.
82
+ - The §7 diagnose-don't-bypass discipline still governs any guard actually encountered.
83
+ - State is read, not remembered — a claim about now uses an instrument run now.
84
+
85
+ The rules bind by what they protect, not by their spelling: a path that satisfies a rule's
86
+ letter while defeating its protection is a violation with extra steps.
@@ -20,7 +20,7 @@ the three `plans/` artifacts; `CONTEXT.md` and `open-questions.md` (including it
20
20
  Deferred-decisions sections) constrain at their recorded level. Load index-first: consult the ADR
21
21
  index (`decision-log.md` or the `decisions/` filename listing) and plan section headings only;
22
22
  load a body only after the index names it relevant; never bulk-read `plans/` or `decisions/`
23
- (ORCHESTRATOR §3's no-bulk-reads rule).
23
+ (arbiter.md §3's no-bulk-reads rule).
24
24
 
25
25
  Three outcomes:
26
26
 
@@ -30,7 +30,7 @@ Gate: the existing ADRs are indexed by stem and, for `/adr`, the next number is
30
30
 
31
31
  Confirm the decision content with the user — context, the decision itself, alternatives, consequences. MUST NOT fill these from inference. Surface any unknown as an inline `[CONFIRM-NN]` placeholder; do not resolve it by guessing.
32
32
 
33
- **Drop the authoring marker first.** The `pre-write`/`pre-edit` hooks block any write to `.codearbiter/decisions/NNNN-*.md` unless a fresh authoring marker is present — that block is the mechanism enforcing "ADRs only via `/adr`" (ORCHESTRATOR §3), so the sanctioned path must arm it itself. Immediately before writing, create the marker at the path the hooks check (project root = git top level):
33
+ **Drop the authoring marker first.** The `pre-write`/`pre-edit` hooks block any write to `.codearbiter/decisions/NNNN-*.md` unless a fresh authoring marker is present — that block is the mechanism enforcing "ADRs only via `/adr`" (arbiter.md §3), so the sanctioned path must arm it itself. Immediately before writing, create the marker at the path the hooks check (project root = git top level):
34
34
 
35
35
  ```bash
36
36
  mkdir -p "$(git rev-parse --show-toplevel)/.codearbiter/.markers"
@@ -12,7 +12,7 @@ Spec the project before a line of code exists. Routed to at greenfield startup,
12
12
  Run these ordered checks. Each passes silently or hard-stops with a routing action — never guess:
13
13
 
14
14
  1. Read `<project-root>/.codearbiter/CONTEXT.md`. If it already carries the `<!--INITIALIZED-->` body marker on its own line, STOP — context exists. Route to normal operation.
15
- 2. Scan for meaningful source code: any file outside `.git/`, `.codearbiter/`, `.claude/`, `ORCHESTRATOR.md`, `AGENTS.md`, `CLAUDE.md`, `README.md`, `LICENSE`, `.gitignore`, `.gitmodules`, and standard tooling dotfiles. If any exist, STOP and route to `/create-context`.
15
+ 2. Scan for meaningful source code: any file outside `.git/`, `.codearbiter/`, `.claude/`, `arbiter.md`, `AGENTS.md`, `CLAUDE.md`, `README.md`, `LICENSE`, `.gitignore`, `.gitmodules`, and standard tooling dotfiles. If any exist, STOP and route to `/create-context`.
16
16
  3. Confirm `<project-root>/.codearbiter/` exists and is writable. If not, surface the gap and STOP.
17
17
 
18
18
  All three pass → proceed to Phase 1. Later phases consume this pass-status; they do not re-run it.
@@ -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,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`.