@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.
- package/README.md +18 -14
- package/package.json +1 -1
- package/plugins/ca-pi/CHANGELOG.md +68 -0
- package/plugins/ca-pi/COMMANDS.md +0 -7
- package/plugins/ca-pi/SKILLS.md +0 -2
- package/plugins/ca-pi/agents/design-quality-reviewer.md +1 -1
- package/plugins/ca-pi/{ORCHESTRATOR.md → arbiter.md} +28 -36
- package/plugins/ca-pi/extensions/codearbiter.js +758 -18
- package/plugins/ca-pi/generated/command-catalog.json +0 -10
- package/plugins/ca-pi/hooks/_arbiterstatelib.py +59 -11
- package/plugins/ca-pi/hooks/_bashguardlib.py +12 -1
- package/plugins/ca-pi/hooks/_hooklib.py +58 -17
- package/plugins/ca-pi/hooks/_metricslib.py +20 -0
- package/plugins/ca-pi/hooks/_modelib.py +644 -0
- package/plugins/ca-pi/hooks/_prunelib.py +51 -12
- package/plugins/ca-pi/hooks/_prunepolicy.py +33 -7
- package/plugins/ca-pi/hooks/_readinjectlib.py +10 -4
- package/plugins/ca-pi/hooks/doctor.py +2 -1
- package/plugins/ca-pi/hooks/pi-bridge.py +10 -4
- package/plugins/ca-pi/hooks/prompt-submit.py +486 -0
- package/plugins/ca-pi/hooks/prune-transcript.py +23 -3
- package/plugins/ca-pi/hooks/session-start.py +526 -434
- package/plugins/ca-pi/hooks/statusline.py +27 -9
- package/plugins/ca-pi/includes/anti-slop-design/INDEX.md +1 -1
- package/plugins/ca-pi/includes/dangerous-mode.md +57 -0
- package/plugins/ca-pi/includes/ops-mode.md +96 -0
- package/plugins/ca-pi/includes/pi-host-notes.md +10 -1
- package/plugins/ca-pi/includes/redirect.md +12 -1
- package/plugins/ca-pi/includes/routing-table.md +1 -0
- package/plugins/ca-pi/includes/safety-core.md +86 -0
- package/plugins/ca-pi/includes/smarts/core.md +1 -1
- package/plugins/ca-pi/routines/decision-lifecycle/SKILL.md +1 -1
- package/plugins/ca-pi/routines/decompose/SKILL.md +1 -1
- package/plugins/ca-pi/skills/ca-spike/SKILL.md +15 -8
- package/plugins/ca-pi/includes/dev-mode.md +0 -30
- package/plugins/ca-pi/skills/ca-arbiter/SKILL.md +0 -36
- 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
|
-
# `
|
|
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
|
-
|
|
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
|
|
289
|
-
return
|
|
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
|
-
#
|
|
555
|
-
#
|
|
556
|
-
|
|
557
|
-
|
|
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
|
-
|
|
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 (`
|
|
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
|
|
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
|
|
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
|
-
(
|
|
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`" (
|
|
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/`, `
|
|
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
|
|
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),
|
|
25
|
-
|
|
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
|
|
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.
|
|
32
|
-
|
|
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
|
|
35
|
-
|
|
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`.
|