session-orchestrator 3.22.0 → 3.24.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.
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/.cursor/commands/autopilot-multi.md +14 -0
- package/.cursor/commands/autopilot.md +14 -0
- package/.cursor/commands/bootstrap.md +14 -0
- package/.cursor/commands/brainstorm.md +14 -0
- package/.cursor/commands/close.md +13 -0
- package/.cursor/commands/contract-version-bump.md +14 -0
- package/.cursor/commands/debug.md +14 -0
- package/.cursor/commands/discovery.md +14 -0
- package/.cursor/commands/dispatcher.md +14 -0
- package/.cursor/commands/eli5.md +14 -0
- package/.cursor/commands/eval.md +14 -0
- package/.cursor/commands/evolve.md +14 -0
- package/.cursor/commands/go.md +14 -0
- package/.cursor/commands/grill.md +14 -0
- package/.cursor/commands/harness-audit.md +13 -0
- package/.cursor/commands/journey-audit.md +14 -0
- package/.cursor/commands/memory-cleanup.md +14 -0
- package/.cursor/commands/persona-panel.md +14 -0
- package/.cursor/commands/plan.md +14 -0
- package/.cursor/commands/portfolio.md +14 -0
- package/.cursor/commands/reconcile.md +14 -0
- package/.cursor/commands/release.md +14 -0
- package/.cursor/commands/repo-audit.md +13 -0
- package/.cursor/commands/session.md +14 -0
- package/.cursor/commands/spinout.md +14 -0
- package/.cursor/commands/sunset-review.md +14 -0
- package/.cursor/commands/templates-ack.md +14 -0
- package/.cursor/commands/test.md +14 -0
- package/.cursor/hooks.json +60 -0
- package/.cursor/rules/000-session-orchestrator.mdc +8 -0
- package/.cursor/rules/010-session-workflow.mdc +9 -1
- package/.cursor/rules/020-quality-gates.mdc +1 -1
- package/.cursor/rules/030-wave-execution.mdc +1 -1
- package/.cursor/rules/050-plan.mdc +2 -2
- package/.cursor/rules/070-gitlab-ops.mdc +73 -57
- package/.cursor/rules/080-ecosystem-health.mdc +7 -7
- package/.cursor/skills/architecture/SKILL.md +13 -0
- package/.cursor/skills/autopilot/SKILL.md +12 -0
- package/.cursor/skills/bootstrap/SKILL.md +12 -0
- package/.cursor/skills/brainstorm/SKILL.md +13 -0
- package/.cursor/skills/claude-md-drift-check/SKILL.md +13 -0
- package/.cursor/skills/contract-version-bump/SKILL.md +12 -0
- package/.cursor/skills/convergence-monitoring/SKILL.md +12 -0
- package/.cursor/skills/daily/SKILL.md +12 -0
- package/.cursor/skills/debug/SKILL.md +13 -0
- package/.cursor/skills/discovery/SKILL.md +13 -0
- package/.cursor/skills/dispatcher/SKILL.md +13 -0
- package/.cursor/skills/docs-orchestrator/SKILL.md +13 -0
- package/.cursor/skills/domain-model/SKILL.md +13 -0
- package/.cursor/skills/ecosystem-health/SKILL.md +13 -0
- package/.cursor/skills/eli5/SKILL.md +13 -0
- package/.cursor/skills/eval/SKILL.md +12 -0
- package/.cursor/skills/evolve/SKILL.md +13 -0
- package/.cursor/skills/frontmatter-guard/SKILL.md +13 -0
- package/.cursor/skills/gitlab-ops/SKILL.md +13 -0
- package/.cursor/skills/gitlab-portfolio/SKILL.md +13 -0
- package/.cursor/skills/grill/SKILL.md +13 -0
- package/.cursor/skills/hook-development/SKILL.md +13 -0
- package/.cursor/skills/journey-audit/SKILL.md +13 -0
- package/.cursor/skills/mcp-builder/SKILL.md +13 -0
- package/.cursor/skills/memory-cleanup/SKILL.md +12 -0
- package/.cursor/skills/mode-selector/SKILL.md +13 -0
- package/.cursor/skills/npm-publish/SKILL.md +12 -0
- package/.cursor/skills/peekaboo-driver/SKILL.md +13 -0
- package/.cursor/skills/persona-panel/SKILL.md +12 -0
- package/.cursor/skills/plan/SKILL.md +13 -0
- package/.cursor/skills/playwright-driver/SKILL.md +13 -0
- package/.cursor/skills/quality-gates/SKILL.md +13 -0
- package/.cursor/skills/reconcile/SKILL.md +12 -0
- package/.cursor/skills/remote-offload/SKILL.md +13 -0
- package/.cursor/skills/repo-audit/SKILL.md +13 -0
- package/.cursor/skills/session-end/SKILL.md +13 -0
- package/.cursor/skills/session-plan/SKILL.md +13 -0
- package/.cursor/skills/session-start/SKILL.md +13 -0
- package/.cursor/skills/skill-creator/SKILL.md +13 -0
- package/.cursor/skills/spinout/SKILL.md +12 -0
- package/.cursor/skills/sunset-review/SKILL.md +13 -0
- package/.cursor/skills/test-runner/SKILL.md +13 -0
- package/.cursor/skills/tmux-layout/SKILL.md +13 -0
- package/.cursor/skills/ubiquitous-language/SKILL.md +13 -0
- package/.cursor/skills/using-orchestrator/SKILL.md +13 -0
- package/.cursor/skills/vault-mirror/SKILL.md +13 -0
- package/.cursor/skills/vault-sync/SKILL.md +13 -0
- package/.cursor/skills/wave-executor/SKILL.md +13 -0
- package/.cursor/skills/write-executable-plan/SKILL.md +13 -0
- package/.mcp.json +4 -1
- package/CHANGELOG.md +446 -0
- package/README.md +22 -17
- package/agents/AGENTS.md +23 -4
- package/agents/code-implementer.md +2 -1
- package/agents/db-specialist.md +2 -2
- package/agents/docs-writer.md +3 -1
- package/agents/eval-judge.md +1 -1
- package/agents/session-reviewer.md +7 -1
- package/agents/test-writer.md +2 -1
- package/agents/ui-developer.md +2 -1
- package/commands/bootstrap.md +2 -2
- package/commands/close.md +3 -1
- package/commands/go.md +1 -1
- package/commands/journey-audit.md +43 -0
- package/docs/USER-GUIDE.md +2 -2
- package/docs/ci-setup.md +194 -25
- package/docs/codex-setup.md +64 -0
- package/docs/components.md +7 -7
- package/docs/cursor-setup.md +26 -47
- package/docs/events-schema.md +120 -10
- package/docs/github-mirror-protection.md +197 -0
- package/docs/pi-setup.md +2 -0
- package/docs/rule-authoring.md +3 -1
- package/docs/scope-collision-guard.md +49 -2
- package/docs/session-config-reference.md +89 -9
- package/docs/session-config-template.md +38 -7
- package/docs/telemetry/telemetry-claims.md +11 -10
- package/docs/telemetry.md +52 -1
- package/hooks/_lib/atomic-json.mjs +111 -0
- package/hooks/_lib/lock-bootstrap.mjs +8 -4
- package/hooks/_lib/subagent-paths.mjs +143 -0
- package/hooks/_lib/vcs-create-matcher.mjs +397 -38
- package/hooks/cwd-change-restore.mjs +9 -29
- package/hooks/enforce-scope.mjs +93 -0
- package/hooks/hooks-codex.json +1 -1
- package/hooks/hooks-cursor.json +201 -20
- package/hooks/hooks-pi.json +1 -1
- package/hooks/hooks.json +2 -2
- package/hooks/on-session-end.mjs +486 -19
- package/hooks/on-session-start.mjs +263 -12
- package/hooks/on-stop.mjs +392 -24
- package/hooks/post-bash-write-verify.mjs +104 -4
- package/hooks/post-subagent-discovery-validator.mjs +182 -21
- package/hooks/post-tool-batch-wave-signal.mjs +165 -42
- package/hooks/post-tool-failure-corrective-context.mjs +9 -32
- package/hooks/pre-bash-issue-budget.mjs +117 -4
- package/hooks/pre-bash-memory-propose-audit.mjs +13 -7
- package/hooks/pre-bash-sessions-ledger-guard.mjs +159 -0
- package/hooks/pre-bash-staging-fence.mjs +4 -0
- package/hooks/pre-task-scope-disjoint.mjs +368 -35
- package/hooks/skill-invocation-telemetry.mjs +21 -10
- package/hooks/subagent-telemetry.mjs +11 -26
- package/monitors/monitors.json +6 -0
- package/package.json +1 -1
- package/pi/prompts/journey-audit.md +12 -0
- package/rules/_index.md +9 -1
- package/rules/always-on/ask-via-tool.md +62 -0
- package/rules/always-on/bash-harness-pitfalls.md +168 -0
- package/rules/always-on/build-value.md +47 -0
- package/rules/always-on/cross-session-messaging.md +59 -0
- package/rules/always-on/loop-and-monitor.md +221 -0
- package/rules/always-on/parallel-sessions.md +142 -12
- package/rules/always-on/receiving-review.md +108 -0
- package/rules/always-on/test-value.md +40 -0
- package/rules/always-on/verification-before-completion.md +77 -0
- package/scripts/archive-closed-prds.mjs +258 -18
- package/scripts/autopilot.mjs +31 -12
- package/scripts/backfill-abandoned-sessions.mjs +80 -11
- package/scripts/backfill-evidence-digest.mjs +376 -0
- package/scripts/cursor-install.mjs +89 -48
- package/scripts/emit-event.mjs +10 -2
- package/scripts/export-hw-learnings.mjs +143 -2
- package/scripts/express-path.mjs +299 -0
- package/scripts/generate-cursor-adapter.mjs +253 -0
- package/scripts/github-protection-audit.mjs +358 -0
- package/scripts/lib/auq/parse.mjs +5 -29
- package/scripts/lib/auto-dialectic.mjs +68 -0
- package/scripts/lib/autopilot/worktree-pipeline.mjs +318 -18
- package/scripts/lib/build-live-signals.mjs +49 -27
- package/scripts/lib/ci-status-banner.mjs +158 -11
- package/scripts/lib/cold-start-detector.mjs +23 -14
- package/scripts/lib/command-blocker.mjs +70 -0
- package/scripts/lib/config/block-header.mjs +55 -0
- package/scripts/lib/config/discovery-validator.mjs +7 -2
- package/scripts/lib/config/health-endpoints.mjs +383 -0
- package/scripts/lib/config/reconcile.mjs +79 -4
- package/scripts/lib/config/remote-hosts.mjs +233 -0
- package/scripts/lib/config/section-extractor.mjs +235 -36
- package/scripts/lib/config-schema.mjs +9 -1
- package/scripts/lib/config.mjs +87 -8
- package/scripts/lib/convergence-monitor.mjs +13 -2
- package/scripts/lib/cursor-hook-bridge.mjs +443 -0
- package/scripts/lib/dispatcher/cli.mjs +2 -2
- package/scripts/lib/dispatcher/enumerate.mjs +2 -17
- package/scripts/lib/events-schema.mjs +48 -0
- package/scripts/lib/events.mjs +238 -5
- package/scripts/lib/evolve/autonomy-verdict.mjs +9 -4
- package/scripts/lib/evolve/autopilot-effectiveness.mjs +18 -1
- package/scripts/lib/express-path.mjs +327 -0
- package/scripts/lib/file-lock.mjs +22 -4
- package/scripts/lib/gates/gate-full.mjs +81 -8
- package/scripts/lib/gates/gate-helpers.mjs +76 -15
- package/scripts/lib/git-config-drift.mjs +134 -5
- package/scripts/lib/gitlab-portfolio/cli.mjs +3 -15
- package/scripts/lib/harness-audit/categories/category1.mjs +17 -6
- package/scripts/lib/host-identity.mjs +247 -2
- package/scripts/lib/instruction-budget-guard.mjs +31 -1
- package/scripts/lib/issue-budget.mjs +229 -30
- package/scripts/lib/learnings/io.mjs +55 -10
- package/scripts/lib/learnings/schema.mjs +95 -28
- package/scripts/lib/lock-reaper.mjs +7 -1
- package/scripts/lib/locks/staging-fence-lock.mjs +5 -1
- package/scripts/lib/locks/state-md-lock.mjs +8 -1
- package/scripts/lib/memory-banner.mjs +25 -10
- package/scripts/lib/memory-paths.mjs +15 -6
- package/scripts/lib/mode-selector/scoring.mjs +53 -6
- package/scripts/lib/peer-discovery.mjs +20 -2
- package/scripts/lib/platform.mjs +72 -9
- package/scripts/lib/plugin-root.mjs +143 -19
- package/scripts/lib/project-hygiene.mjs +43 -3
- package/scripts/lib/quality-gate.mjs +271 -13
- package/scripts/lib/reconcile/emitter.mjs +87 -19
- package/scripts/lib/reconcile/engine.mjs +517 -18
- package/scripts/lib/reconcile/idempotency.mjs +102 -1
- package/scripts/lib/reconcile/renderer.mjs +148 -3
- package/scripts/lib/reconcile/sanitize.mjs +40 -17
- package/scripts/lib/reconcile/writer.mjs +415 -84
- package/scripts/lib/rule-loader.mjs +37 -2
- package/scripts/lib/rules-sync.mjs +51 -8
- package/scripts/lib/scope-gate.mjs +126 -0
- package/scripts/lib/session-close-backfill.mjs +427 -37
- package/scripts/lib/session-discovery.mjs +69 -5
- package/scripts/lib/session-end/phase-skip.mjs +38 -5
- package/scripts/lib/session-end/worktree-cleanup.mjs +154 -7
- package/scripts/lib/session-id.mjs +30 -14
- package/scripts/lib/session-identity/own-session.mjs +220 -0
- package/scripts/lib/session-lock.mjs +85 -30
- package/scripts/lib/session-schema/normalizer.mjs +70 -3
- package/scripts/lib/session-schema/validator.mjs +40 -0
- package/scripts/lib/session-start-probes.mjs +608 -0
- package/scripts/lib/session-transition.mjs +277 -0
- package/scripts/lib/sessions-canonical.mjs +446 -0
- package/scripts/lib/sessions-staleness-banner.mjs +124 -57
- package/scripts/lib/spiral-carryover.mjs +90 -9
- package/scripts/lib/state-md/frontmatter-mutators.mjs +41 -8
- package/scripts/lib/state-md/mission-status.mjs +350 -52
- package/scripts/lib/state-md/yaml-parser.mjs +145 -16
- package/scripts/lib/state-md.mjs +12 -2
- package/scripts/lib/telemetry/schema.mjs +74 -8
- package/scripts/lib/telemetry/sync.mjs +91 -16
- package/scripts/lib/tmux-layout/telemetry.mjs +14 -2
- package/scripts/lib/validate/check-agents.mjs +66 -0
- package/scripts/lib/validate/check-cursor-adapter.mjs +102 -0
- package/scripts/lib/validate/check-dead-bridge.mjs +24 -2
- package/scripts/lib/validate/check-doc-cli-commands.mjs +25 -65
- package/scripts/lib/validate/check-hooks-emit-event-guard.mjs +370 -0
- package/scripts/lib/validate/check-hooks-symmetry.mjs +29 -63
- package/scripts/lib/validate/check-playwright-mcp-canary.mjs +13 -22
- package/scripts/lib/validate/check-plugin-monitors.mjs +10 -4
- package/scripts/lib/validate/check-skill-script-paths.mjs +436 -0
- package/scripts/lib/validate/check-test-value-bans.mjs +165 -17
- package/scripts/lib/validate/check-untracked-test-deps.mjs +10 -0
- package/scripts/lib/validate/check-unwired-features.mjs +333 -32
- package/scripts/lib/validate/check-validator-registration.mjs +248 -0
- package/scripts/lib/validate/check-vcs-repo-flag.mjs +6 -28
- package/scripts/lib/validate/markdown-fences.mjs +196 -0
- package/scripts/lib/validate/repo-files.mjs +275 -0
- package/scripts/lib/validate-vendored-rules.mjs +229 -7
- package/scripts/lib/vault-mirror/process.mjs +99 -43
- package/scripts/lib/vault-mirror/telemetry.mjs +210 -0
- package/scripts/lib/vault-staleness-banner.mjs +76 -6
- package/scripts/lib/vault-status/board-lock.mjs +185 -0
- package/scripts/lib/vault-status/board-writer.mjs +381 -141
- package/scripts/lib/vault-status/narrative-mirror.mjs +190 -27
- package/scripts/lib/wave-executor/foreign-dispatch.mjs +832 -0
- package/scripts/lib/wave-executor/remote-dispatch.mjs +504 -0
- package/scripts/lib/wave-resource-gate.mjs +127 -7
- package/scripts/lib/wave-transcript-tail.mjs +889 -0
- package/scripts/materialize-wave-scope.mjs +228 -15
- package/scripts/mcp-server.sh +11 -2
- package/scripts/memory-propose.mjs +132 -8
- package/scripts/parse-config.mjs +65 -0
- package/scripts/promote-vault-strict.mjs +4 -15
- package/scripts/site-numbers.mjs +36 -4
- package/scripts/token-audit.sh +9 -2
- package/scripts/validate-plugin.mjs +29 -0
- package/scripts/validate-wave-scope.mjs +67 -0
- package/scripts/vault-consolidate.mjs +3 -11
- package/scripts/vault-integration-watcher.mjs +2 -4
- package/scripts/vault-mirror.mjs +305 -51
- package/skills/_shared/monitor-patterns.md +31 -5
- package/skills/_shared/parallel-aware-auq.md +31 -2
- package/skills/_shared/parallel-aware-preamble.md +19 -4
- package/skills/_shared/platform-tools.md +11 -5
- package/skills/_shared/state-ownership.md +29 -2
- package/skills/autopilot/SKILL.md +5 -1
- package/skills/bootstrap/SKILL.md +3 -3
- package/skills/bootstrap/_shared-template.md +18 -10
- package/skills/bootstrap/deep-template.md +10 -6
- package/skills/bootstrap/fast-template.md +15 -8
- package/skills/bootstrap/standard-template.md +10 -6
- package/skills/claude-md-drift-check/checker.mjs +39 -11
- package/skills/contract-version-bump/SKILL.md +1 -1
- package/skills/dispatcher/SKILL.md +1 -1
- package/skills/ecosystem-health/SKILL.md +4 -1
- package/skills/ecosystem-health/wizard.md +5 -0
- package/skills/evolve/SKILL.md +38 -1
- package/skills/journey-audit/SKILL.md +270 -0
- package/skills/peekaboo-driver/SKILL.md +15 -3
- package/skills/persona-panel/SKILL.md +1 -1
- package/skills/reconcile/SKILL.md +46 -3
- package/skills/remote-offload/SKILL.md +89 -0
- package/skills/session-end/SKILL.md +17 -4
- package/skills/session-end/metrics-collection.md +7 -4
- package/skills/session-end/phase-3-6-tail.md +20 -9
- package/skills/session-end/phase-3-7a-recommendations.md +16 -2
- package/skills/session-plan/SKILL.md +6 -1
- package/skills/session-plan/wave-template.md +1 -0
- package/skills/session-start/SKILL.md +54 -17
- package/skills/session-start/phase-7-5-mode-selector.md +15 -3
- package/skills/session-start/phase-8-5-express-path.md +77 -12
- package/skills/vault-sync/validator.mjs +31 -0
- package/skills/wave-executor/SKILL.md +5 -3
- package/skills/wave-executor/circuit-breaker.md +34 -9
- package/skills/wave-executor/wave-loop.md +143 -22
- package/templates/_shared/journey-manifest.md +110 -0
- package/templates/_shared/rules/parallel-sessions.md +0 -77
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,452 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [3.24.0] - 2026-09-02
|
|
11
|
+
|
|
12
|
+
Five commits since v3.23.0 (4 `feat`, 1 `docs`; 152 files, +14,596/−942), no
|
|
13
|
+
`BREAKING CHANGE:` footer and no `!` subject.
|
|
14
|
+
|
|
15
|
+
One `docs` commit (`c3ab4801`) adds ADR-0013, naming the ownership-check-before-deregister
|
|
16
|
+
ordering that closed Wave 4 of the previous session. One `feat` commit (`a019d5a4`, deep
|
|
17
|
+
session, 5 waves, 37 agents + 3 reviewers + 3 panel) closes the GH#67 peer-filter class
|
|
18
|
+
across every affected site, plus #1170, #1176, #1177, #1166, #1167, #1174, #1180 and #1175.
|
|
19
|
+
One `feat` commit (`936dae8a`) closes a Fleet-Mining v2 instrument audit across 18 repos
|
|
20
|
+
(1,587 learnings, 144k events, 347 telemetry records) with five repairs to the fleet's own
|
|
21
|
+
measurement instruments (#1189, #1190, #1191, #1192, #1193).
|
|
22
|
+
|
|
23
|
+
Two further `feat` commits (`2ccea0f2`, `3b352d78`) are Waves 2 and 3 of a new session (11
|
|
24
|
+
agents each; Opus for guards/identity/protocol, Sonnet for consolidation/polish). The
|
|
25
|
+
through-line: identity and scope boundaries are now drawn at the PROCESS, not the working
|
|
26
|
+
copy — a peer session's manifest in the same checkout is `foreign`, a dispatched subagent's
|
|
27
|
+
raw session id belongs to its coordinator, and four duplicated helper implementations
|
|
28
|
+
collapse to one canonical each.
|
|
29
|
+
|
|
30
|
+
### Added
|
|
31
|
+
|
|
32
|
+
- **`orchestrator.reconcile.completed` (#1192).** Wrapper around `runReconcile` covering all
|
|
33
|
+
three return paths (empty corpus, normal, engine-error) with `trigger`
|
|
34
|
+
(`skill|session-end|phase-skip|unknown`), `targets` (allowlisted `repo-local|baseline`),
|
|
35
|
+
counters including measured zeros, `duration_ms`, and `aborted`+`reason` on the catch path.
|
|
36
|
+
Skipped with a stderr WARN when no `repoRoot` is passed, so test runs never write the fleet
|
|
37
|
+
ledger. First live record: `eligible 102 / proposals 10 / rejected 154 / capped 72 /
|
|
38
|
+
already_materialized 20`.
|
|
39
|
+
- **`docs/audits/2026-09-02-fleet-instruments.md`** — the public scrubbed extract of the
|
|
40
|
+
Fleet-Mining v2 instrument audit: 18 repos, 1,587 learnings, 143,967 events, 347 telemetry
|
|
41
|
+
records (6 `anon_id`), 13 instrument verdicts and 12 orchestrator candidates (K1–K12).
|
|
42
|
+
- **A new blocking validator catches dead script paths cited in skill/command/agent prose
|
|
43
|
+
(#1176).** `scripts/lib/validate/check-skill-script-paths.mjs` scans `skills/`, `commands/`
|
|
44
|
+
and `agents/` for `scripts/**.mjs` citations that neither exist nor carry a same-line/
|
|
45
|
+
line-above `<!-- path-check: planned #<iid> | historical | example -->` marker; fenced code
|
|
46
|
+
blocks are skipped as illustrative shape, not a claim. Measured 2026-09-02 @ `c3ab480`: 237
|
|
47
|
+
distinct citations, 7 dead, 4 of the 7 inside fences.
|
|
48
|
+
- **`events.jsonl` records are now schema-versioned and validated before they are written
|
|
49
|
+
(#1177).** `emitEvent()` stamps every record `schema_version: 1` (never overwriting a
|
|
50
|
+
caller-supplied value) and runs `validateEventRecord()` BEFORE the append and BEFORE any
|
|
51
|
+
webhook POST — an invalid record throws `EventValidationError` and produces neither.
|
|
52
|
+
`scripts/emit-event.mjs` maps that to exit `1` (I/O failures keep exit `2`);
|
|
53
|
+
`scripts/lib/tmux-layout/telemetry.mjs` stamps + validates synchronously and drops invalid
|
|
54
|
+
lines. The read path stays lenient — the 33k+ pre-#1177 records without the field remain
|
|
55
|
+
valid.
|
|
56
|
+
- **A canonical reader collapses `sessions.jsonl`'s append-only duplication (#1167).**
|
|
57
|
+
`scripts/lib/sessions-canonical.mjs` applies newest-wins per `session_id`, drops any record a
|
|
58
|
+
later `supersedes` pointer refutes, and narrowly collapses the systemic double-stub class
|
|
59
|
+
(two `abandoned` records sharing an exact `started_at`/`completed_at` pair, one synthetic).
|
|
60
|
+
The startup/CLI backfill path (`scripts/backfill-abandoned-sessions.mjs`) now also emits
|
|
61
|
+
`orchestrator.session.backfill_completed` per record — previously only the SessionEnd hook
|
|
62
|
+
did — and stamps `raw_session_id`; `hooks/on-session-end.mjs`'s backfill gained a second
|
|
63
|
+
UUID→semantic bridge via the `session.ended` event for sessions that lost the
|
|
64
|
+
lock-acquire race.
|
|
65
|
+
- **A vault-scoped lock protects the shared live-status board's read-modify-write (#1180).**
|
|
66
|
+
`scripts/lib/vault-status/board-lock.mjs` wraps `sweepBoard()`'s merge in a cross-repo mutex
|
|
67
|
+
(mtime-based staleness — the vault dir can be synced cross-host, so a recorded pid isn't
|
|
68
|
+
probeable); fail-open on acquire timeout or fs-error (one stderr WARN, then runs unlocked)
|
|
69
|
+
since a board update is best-effort telemetry. `.gitignore` gained `state.lock` and
|
|
70
|
+
`rules.lock`.
|
|
71
|
+
- **A GitLab Project Access Token recipe for the schema-drift CI job (#1175).**
|
|
72
|
+
`docs/ci-setup.md` documents Option A (Project Access Token, recommended) and Option B
|
|
73
|
+
(personal PAT) for `SCHEMA_DRIFT_TOKEN`. Activation is blocked on the documented
|
|
74
|
+
vendor-ahead drift tracked in #531: the token is provisioned but the CI/CD variable is not
|
|
75
|
+
yet set upstream.
|
|
76
|
+
- **A `remote-hosts:` config block routes wave work to another machine over SSH (#1160).**
|
|
77
|
+
`scripts/lib/config/remote-hosts.mjs` adds the block (opt-in template + reference doc) and
|
|
78
|
+
an `ssh:<alias>` channel in `agent-mapping`; the wave-resource gate adds an `offload`
|
|
79
|
+
decision AFTER the HR-004 heavy-repo cap, gated on an injected readiness witness
|
|
80
|
+
(`remoteReady` map or async `probeFn`) — the gate never probes the network itself, so with
|
|
81
|
+
no witness the decision stays local. `dispatchRemote()`/`remoteDoctor()`/
|
|
82
|
+
`remoteReadyProbe()` wrap the host-side `offload` CLI (prompt travels on stdin, never argv;
|
|
83
|
+
exit codes 1–8 mapped to typed refusal reasons; an empty returned patch counts as failure,
|
|
84
|
+
not success). Emits `orchestrator.remote_dispatch.completed` on every attempt AND every
|
|
85
|
+
refusal (`ok:false`, `exit_code: null`) — the payload carries the configured alias, never a
|
|
86
|
+
hostname or IP. `skills/remote-offload/SKILL.md` documents the channel generically for any
|
|
87
|
+
consuming repo (skill count measured 48 → 49); wave-3 added the fourth wave-executor
|
|
88
|
+
dispatch branch (`ssh:<alias>` via `dispatchRemote()`) to `wave-loop.md` alongside the
|
|
89
|
+
existing three.
|
|
90
|
+
- **A Peer-Scope-Union protocol lets two coordinator sessions in the same working copy share
|
|
91
|
+
scope without racing (#1195).** `skills/_shared/parallel-aware-auq.md` documents the
|
|
92
|
+
four-step handshake plus a message template; `skills/wave-executor/wave-loop.md` §
|
|
93
|
+
Scope Manifest 3.1a adds a `peer-session-<id>` record (rolled over each wave, cleared at
|
|
94
|
+
session-end) that is included in the disjoint check but excluded from the coordinator's own
|
|
95
|
+
file-scope union; a new branch in the `parallel-sessions.md` decision tree routes to it; and
|
|
96
|
+
`hooks/post-bash-write-verify.mjs` now partitions a peer's writes from genuine scope
|
|
97
|
+
violations instead of flagging both alike.
|
|
98
|
+
- **Session-start now writes its own identity before anything can read it wrong (#1199).**
|
|
99
|
+
Phase 1.05 adds a self-report block (`session_id: null` before Phase 1.2 resolves it) so
|
|
100
|
+
downstream consumers see an explicit unresolved state instead of inferring one.
|
|
101
|
+
- **`/evolve` and the auto-dialectic nudge now emit their own completion events (#1200).**
|
|
102
|
+
`orchestrator.evolve.completed` and `dialectic.completed` are emitted via `emit-event.mjs`
|
|
103
|
+
from inside the skill; `decideAndRecordAutoDialectic()` emits `dialectic.nudge_decided`
|
|
104
|
+
mechanically rather than leaving the decision only in skill prose, consumed by
|
|
105
|
+
`phase-3-6-tail.md`.
|
|
106
|
+
|
|
107
|
+
### Changed
|
|
108
|
+
|
|
109
|
+
- **BREAKING (behavior): `discovery-validator.enabled` defaults to `false` again (#1191).**
|
|
110
|
+
Reverts the #690 flip of 2026-06-25. Fleet measurement (2026-09-02, 18 repos): 6,946
|
|
111
|
+
`discovery_validator_violation` events had accumulated in repos that never declared the
|
|
112
|
+
block, and a scope-adjusted n=60 sample put real precision at 0/60 — the hook was scanning
|
|
113
|
+
the MAIN transcript on `SubagentStop`, not the subagent's own. It now reads the subagent
|
|
114
|
+
transcript (`agent_transcript_path` when the harness sends it, else
|
|
115
|
+
`<dir>/<base>/subagents/agent-<agent_id>.jsonl` — no fallback to the main transcript), and
|
|
116
|
+
the violation event now carries `agent_id`. Repos that relied on the silent default lose the
|
|
117
|
+
signal until they set `enabled: true` explicitly.
|
|
118
|
+
- **Scope enforcement now treats every identity as process-local, including your own
|
|
119
|
+
(#1194).** `enforce-scope.mjs` reads session ids via a new `readProcessLocalSessionIds()`
|
|
120
|
+
instead of `readOwnSessionIds()` — a peer's manifest sitting in the SAME working copy now
|
|
121
|
+
classifies as `foreign`, not `own`. Two existing tests had asserted the inverted behaviour
|
|
122
|
+
and were rewritten with a named ceiling (a harness with no session id, e.g. bare
|
|
123
|
+
Codex/Cursor, resolves to `unknown` → enforce, never skip); `scope-collision-guard.md` and
|
|
124
|
+
`state-ownership.md` were updated to match.
|
|
125
|
+
- **`memory.propose`'s lock check is now a raw→semantic lookup, not a trust boundary
|
|
126
|
+
(#1188).** The lock is consulted only to translate the caller's raw id into its semantic
|
|
127
|
+
session id, authorised by a process-local match against the RAW id — measured: a dispatched
|
|
128
|
+
subagent carries the COORDINATOR's raw UUID in `CLAUDE_CODE_SESSION_ID`, never its own.
|
|
129
|
+
`sessions-canonical.mjs` and the backfill path now distinguish silent `ENOENT` from loud
|
|
130
|
+
`EACCES`/`EISDIR` in two separate ledger readers instead of treating every read failure the
|
|
131
|
+
same.
|
|
132
|
+
- **Four duplicated helper implementations collapse to one each.**
|
|
133
|
+
`scripts/lib/validate/markdown-fences.mjs` (#1181) replaces 4 line-start-only fence
|
|
134
|
+
scanners with one line-start-AND-end-anchored automaton shared by all 4 callers
|
|
135
|
+
(`validate-plugin` output byte-identical before/after, 203/0). `expandTilde` (#1182)
|
|
136
|
+
replaces 8 copies of home-directory expansion with the existing `common.mjs`
|
|
137
|
+
implementation — one of the deleted copies (`gitlab-portfolio/cli.mjs`) mis-expanded
|
|
138
|
+
`~user` (a different user's home, not the caller's). `hooks/_lib/subagent-paths.mjs`
|
|
139
|
+
(#1196) replaces 4 divergent sidecar-path derivations with one carrying the strictest rules
|
|
140
|
+
from any of them (agent-id length `{1,64}`, `'unknown'` rejected,
|
|
141
|
+
`agent_transcript_path` confined inside the transcript directory).
|
|
142
|
+
`hooks/_lib/atomic-json.mjs` (#1197) replaces 4 byte-identical copies with one whose
|
|
143
|
+
read-modify-write default only replaces a genuinely MISSING file (`ENOENT`) — an
|
|
144
|
+
unparsable or unreadable file is no longer silently overwritten with the default.
|
|
145
|
+
- **A block-header matcher gained an indent+inline-value form, additively (#1185).**
|
|
146
|
+
`matchBlockHeaderDetailed` is now shared so `health-endpoints.mjs` no longer maintains its
|
|
147
|
+
own `HEADER_RE`.
|
|
148
|
+
- **Five readers now go through the canonical `sessions.jsonl` collapse instead of counting
|
|
149
|
+
raw lines (#1186).** `telemetry/sync.mjs` and `build-live-signals.mjs` (wave 2), plus
|
|
150
|
+
`site-numbers.mjs` and `vault-mirror.mjs --kind session` (wave 3), now read
|
|
151
|
+
newest-per-`session_id`; on this repo the session count measured 289 lines → 278 sessions
|
|
152
|
+
(11 duplicate lines collapsed). Two tests pinning the old raw-line count were removed as no
|
|
153
|
+
longer testing real behaviour.
|
|
154
|
+
- **Wave-completion refusals are now named events, not silent skips (#1201).**
|
|
155
|
+
`KNOWN_TRIGGERS` plus three explicit wrapper functions (`runReconcileFromSkill`/
|
|
156
|
+
`AtSessionEnd`/`FromPhaseSkip`) replace an implicit trigger string — an unrecognised
|
|
157
|
+
trigger now throws instead of silently defaulting. `emitFinalWaveCompleted` emits
|
|
158
|
+
`orchestrator.wave.final_refused` for all six refusal paths instead of leaving them
|
|
159
|
+
unrecorded — closing the same class of instrument gap named in
|
|
160
|
+
`.claude/rules/host-resources.md` § HR-105.
|
|
161
|
+
|
|
162
|
+
### Fixed
|
|
163
|
+
|
|
164
|
+
- **`orchestrator.agent.stopped` carried `agent: ""` in 86.7% of fleet records (#1190).**
|
|
165
|
+
89,991 of 103,763 historical records carried an empty `agent` because
|
|
166
|
+
`input?.agent_type ?? 'unknown'` never fires on an empty string — the harness's actual
|
|
167
|
+
shape. `agent` is now omitted when empty (never `'unknown'`, never a fabricated `0`/`false`).
|
|
168
|
+
Seven optional sidecar-derived fields were added — `agent_id`, `transcript_found`,
|
|
169
|
+
`tool_use_id`, `agent_type_meta`, `duration_ms` + `duration_source` (`meta-birthtime`), and
|
|
170
|
+
`status` (`done|partial|blocked|failed|no-tests-needed`, from the last line-anchored
|
|
171
|
+
`STATUS:` marker in the final 64 KiB of the agent transcript) — each independently omitted
|
|
172
|
+
when unmeasured, each wrapped in its own try/catch, with a charset guard on `agent_id`
|
|
173
|
+
before path interpolation. `CURRENT_SCHEMA_VERSION` is unchanged (additive). Measured
|
|
174
|
+
`status` coverage: 61.7% (71 done / 3 partial / 46 absent) over 120 completed sidecars.
|
|
175
|
+
- **`commands[]` was empty in every usage ping (#1189).** `classifyInvocationName` routes
|
|
176
|
+
plugin-prefixed command names (`session-orchestrator:session`) into `commands[]` under the
|
|
177
|
+
bare name — the prefix is required, so a bare foreign name never becomes one of our
|
|
178
|
+
commands — and `.command`-field names are prefixed before classification, since that field
|
|
179
|
+
is itself the "this is one of ours" provenance signal a bare `.skill` arrival lacks.
|
|
180
|
+
- **The final `orchestrator.wave.completed` of every session was never emitted (#1193).**
|
|
181
|
+
Fleet-wide: 1,018 `started` vs. 722 `completed`, a gap of exactly 296 — one per wave run.
|
|
182
|
+
`hooks/on-session-end.mjs` now emits it at SessionEnd, idempotent via a
|
|
183
|
+
`last_wave_completed` high-water mark written monotonically by both emitters, gated on
|
|
184
|
+
ownership of `current-session.json` via the RAW stdin session id (not the resolved one), and
|
|
185
|
+
skipped on `reason: clear`. `hooks/post-tool-batch-wave-signal.mjs` gained the same
|
|
186
|
+
raw-stdin-id ownership check, so it can no longer write wave keys into a peer session's
|
|
187
|
+
record either.
|
|
188
|
+
- **`orchestrator.session.stopped.duration_ms` was a literal `0` in 8,127 of 8,127 fleet
|
|
189
|
+
records.** The harness never sends `start_ms`, so the old expression fell back to a
|
|
190
|
+
fabricated zero — indistinguishable from a real instant turn. It is now derived from an
|
|
191
|
+
OWNED `.orchestrator/session.lock` (`duration_source: 'session-lock'`, session-elapsed
|
|
192
|
+
measured at turn end) or omitted entirely, never `0`.
|
|
193
|
+
- **`resolveSession()`'s ownership predicate was self-fulfilling** when the stdin `session_id`
|
|
194
|
+
was absent or non-UUID: it fell back to the recorded id and then compared the fallback
|
|
195
|
+
against itself. Fixed at the root (`rawStdinId !== null && rawStdinId === recordedId`) in
|
|
196
|
+
`hooks/on-session-end.mjs` for `duration_ms`, `semantic_session_id` and the new wave-completed
|
|
197
|
+
emit, plus the sibling site `resolveSessionId()` in `hooks/on-stop.mjs`.
|
|
198
|
+
- **A live local `session.lock` no longer hides a same-working-copy registry peer (GH#67).**
|
|
199
|
+
Registry-sourced entries in `scripts/lib/session-discovery.mjs` / `peer-discovery.mjs` now
|
|
200
|
+
carry additive `registryOnly` / `lockSuperseded` / `lockOwnerId` annotations instead of
|
|
201
|
+
being filtered out — `lockSuperseded: true` is a HINT (the lock is advisory, so the entry
|
|
202
|
+
may still be a live session that lost the acquire race), never a verdict. Only
|
|
203
|
+
PROMOTION_OFFER decisions downgrade such a peer to advisory; peer-count and display
|
|
204
|
+
consumers keep it. Lock-sourced sessions carry none of the three fields, so their shape
|
|
205
|
+
stays byte-identical to pre-GH#67.
|
|
206
|
+
- **Worktree-promotion teardown is now mechanical, not skill prose (#1170).**
|
|
207
|
+
`enterWorktree()` takes an optional `rawSessionId`; when given, it calls `leaveSourceRoot()`
|
|
208
|
+
on the OLD root after the destination provably exists and records the outcome on
|
|
209
|
+
`result.left`. Before #1170, four promotion call sites relied on coordinator prose to
|
|
210
|
+
release the source root — measured zero `deregisterSelf`/`release(` call sites across the
|
|
211
|
+
affected skill docs, so the abandoned registry entry advertised a phantom peer for up to an
|
|
212
|
+
hour.
|
|
213
|
+
- **`memory.propose` filed wave-N+1 proposals into the wave-N quota bucket (#1166).**
|
|
214
|
+
`scripts/memory-propose.mjs` now resolves the RUNNING wave from `<state-dir>/wave-scope.json`
|
|
215
|
+
first (when present and unbound or bound to this session), falling back to `STATE.md
|
|
216
|
+
current-wave + 1` only when no usable manifest exists — `current-wave` itself always
|
|
217
|
+
records the JUST-COMPLETED wave.
|
|
218
|
+
- **`health-endpoints` silently dropped the wizard's own nested-block output (#1174).** The
|
|
219
|
+
key was read off the flat KV map via `_coerceList`, which bails to `null` on any `{` and
|
|
220
|
+
cannot see a nested YAML block at all. `scripts/lib/config/health-endpoints.mjs` now parses
|
|
221
|
+
it content-scoped, accepting inline object arrays, the nested block form (top-level or
|
|
222
|
+
under `ecosystem-health:`), and a bare URL list; `ecosystem-health`'s own valueless
|
|
223
|
+
block-header form is now read as a fallback when the scalar key is absent.
|
|
224
|
+
- **`emitEvent()`'s automatic session/semantic-session fill now requires a process-local
|
|
225
|
+
witness (#1177).** `CLAUDE_CODE_SESSION_ID` (or the hook-input session id) must exactly
|
|
226
|
+
equal the lock's raw `session_id` before `session_id`/`semantic_session_id` are
|
|
227
|
+
auto-filled — STATE.md is never treated as a witness. `wave` is filled the same way, only
|
|
228
|
+
from a `wave-scope.json` manifest bound to this same session, and is coerced to an integer.
|
|
229
|
+
See `docs/events-schema.md` § Correlation keys.
|
|
230
|
+
- **The memory banner's "sessions ever" stat now counts distinct sessions, not JSONL lines
|
|
231
|
+
(#1167).** `sessions.jsonl` is append-only, so one physical session can occupy two lines;
|
|
232
|
+
on this repo the stat drops from 286 lines to 275 sessions. Five readers now go through
|
|
233
|
+
the canonical collapse: cold-start detection, the memory banner, harness-audit Category 1,
|
|
234
|
+
evolve's autopilot-effectiveness/verdict, and autopilot's id-set guard.
|
|
235
|
+
- **`check-skill-script-paths` no longer goes blind past an unbalanced code fence (#1176).**
|
|
236
|
+
An unclosed/unbalanced fence now reports as its own `unbalanced-fence` finding instead of
|
|
237
|
+
silently absorbing the rest of the file as "inside a fence"; a fence opened inside a
|
|
238
|
+
blockquote is now recognised as a fence too.
|
|
239
|
+
- **`sessions-canonical.mjs`'s `supersedes` collapse now requires an attestable join key
|
|
240
|
+
(#1167).** A `supersedes` pointer on an abandoned record is honoured only when it can be
|
|
241
|
+
matched to the record it claims to supersede; rule ordering was fixed so a superseded
|
|
242
|
+
record's synthetic double-stub twin is collapsed too. A new `keepUnidentified` option lets
|
|
243
|
+
callers retain records the canonicalizer could not confidently classify instead of
|
|
244
|
+
dropping them.
|
|
245
|
+
- **`memory.propose` no longer trusts an unbound `wave-scope.json` (#1177).** A manifest
|
|
246
|
+
without a `semantic_session` binding is a peer's or a stale artefact, not this session's
|
|
247
|
+
own — it is now ignored with a stderr note instead of adopted; an unreadable/malformed
|
|
248
|
+
manifest also WARNs on stderr before falling back to `current-wave + 1`, rather than
|
|
249
|
+
failing silently.
|
|
250
|
+
- **The vault-status board lock's stale-override is now surfaced, not silent (#1180).**
|
|
251
|
+
`onLockOutcome` reports a `staleOverride` reason when the lock was force-acquired past a
|
|
252
|
+
stale holder, and `sweepBoard()`'s board event now records it too — distinguishing "the
|
|
253
|
+
mutex worked as designed" from "a slow host looked like a crash".
|
|
254
|
+
- **`check-hooks-emit-event-guard` and `check-validator-registration` both went live in
|
|
255
|
+
`validate-plugin` (#1183, #1184).** `check-hooks-emit-event-guard.mjs` (#1183) parses hooks
|
|
256
|
+
via `@babel/parser` (AST, not regex) to catch a hook that mutates state without emitting a
|
|
257
|
+
corresponding event; 5 pre-existing sites are grandfathered into an explicit WARN baseline
|
|
258
|
+
with a reason and stale-detection instead of silently passing. `check-validator-registration.mjs`
|
|
259
|
+
(#1184) confirms every validator module is actually wired into `validate-plugin.mjs`
|
|
260
|
+
(measured 33 of 33 wired, using comment-stripped source so a commented-out registration
|
|
261
|
+
doesn't count as live).
|
|
262
|
+
- **`check-skill-script-paths`'s new `--strict-sh` mode found its own premise refuted
|
|
263
|
+
(#1187).** Extending the dead-path scan to shell-script citations, only 1 of 27 `.sh`
|
|
264
|
+
references sits inside the tool's own scan directories (`skills/`, `commands/`, `agents/`)
|
|
265
|
+
— the other 26 are in `docs/`, alongside 7 dead `.mjs` citations inside `docs/adr/` the same
|
|
266
|
+
run surfaced. Shipped as a WARN-only opt-in flag; the `docs/` sweep is a follow-up.
|
|
267
|
+
- **The discovery-validator's dedupe key, gate-summary skip, and masking order all landed
|
|
268
|
+
together (#1198).** A dedupe key (`session_id`, `agent_id`, `sha256(claim)`) collapses
|
|
269
|
+
repeated flags of the identical claim; gate-summary recap lines (the coordinator's own
|
|
270
|
+
restatement of a subagent's findings, not a fresh claim) are now skipped entirely; claim
|
|
271
|
+
masking now runs before every pattern is checked, not a subset. Measured against the
|
|
272
|
+
flagged corpus: 186 of 400 flagged claims were false positives. Two claims from this
|
|
273
|
+
session's own discovery briefing were checked against the fix and refuted.
|
|
274
|
+
- **A pre-push scratch-vs-publish check now reads the two arguments git already passes it.**
|
|
275
|
+
`.husky/pre-push` had never read `$1` (remote name/URL) or `$2` (remote URL) — confirmed by
|
|
276
|
+
`rg -n '\$1|\$2' .husky/pre-push` finding only a local function's own arguments — so every
|
|
277
|
+
push ran the full quality gate regardless of destination. It now skips the gate for a raw,
|
|
278
|
+
unconfigured scratch URL (e.g. the remote-offload sync target) while continuing to gate
|
|
279
|
+
real publish remotes; a named ceiling covers a real but unlisted third publish host, which
|
|
280
|
+
still reads as scratch.
|
|
281
|
+
- **`check-untracked-test-deps` misclassified `.git` as an untracked file inside a linked
|
|
282
|
+
worktree.** In a normal checkout `.git` is a directory and was already excluded; in a
|
|
283
|
+
`git worktree add` checkout `.git` is a FILE containing `gitdir: <path>`, which satisfied
|
|
284
|
+
the same `isFile()` check the untracked-candidate branch uses. `.git` is now explicitly
|
|
285
|
+
exempted regardless of which shape it takes — measured 62 of 62 tests passing across the 5
|
|
286
|
+
affected test files inside a linked worktree checkout.
|
|
287
|
+
|
|
288
|
+
## [3.23.0] - 2026-08-28
|
|
289
|
+
|
|
290
|
+
Two commits today (1 `feat`, 1 `fix`; 64 files, +4,971/−184) close Waves 3 and 4 of the
|
|
291
|
+
resumed session, plus eight items carried forward from Wave 2 (`36aa605`, 2026-08-26,
|
|
292
|
+
never previously changelogged). No `BREAKING CHANGE:` footer and no `!` subject. The
|
|
293
|
+
pattern repeats across both waves: a guard, sanitizer, or census that already existed but
|
|
294
|
+
checked the wrong population or stopped short of the surface it needed to reach — a parity
|
|
295
|
+
guard sampling five rule files by name instead of reading the directory, a sanitizer whose
|
|
296
|
+
findings never reached stderr, a byte-count drifting 338 lines from the line it cited, a
|
|
297
|
+
tracked directory hiding an untracked hook beside it.
|
|
298
|
+
|
|
299
|
+
One `feat` commit (session-2, `30940cb`, 2026-08-28; 39 files, +2,475/−405) closes Wave 2
|
|
300
|
+
with three GitHub-mirror fixes and a session-identity cluster at the process boundary. No
|
|
301
|
+
`BREAKING CHANGE:` footer and no `!` subject. The through-line: identifiers the platforms
|
|
302
|
+
mint (UUIDv7, semantic session ids) were rejected or dropped by readers built for UUIDv4
|
|
303
|
+
only — every resume looked foreign — and call sites that needed a repo root passed
|
|
304
|
+
`undefined` instead, so fail-open paths ran on every invocation.
|
|
305
|
+
|
|
306
|
+
### Added
|
|
307
|
+
|
|
308
|
+
- **Eight core rules ship as sanitized copies, with a report-only leak scanner (#1098).**
|
|
309
|
+
`rules/always-on/` holds sanitized copies of `ask-via-tool`, `build-value`,
|
|
310
|
+
`loop-and-monitor` and five more; `scanVendoringLeaks()` now reaches stderr as one line
|
|
311
|
+
per finding in both CLIs, folded into `validate-vendored-rules` with a rule-ID census.
|
|
312
|
+
- **Session Config fails loud on an unparsable line (#1097).** `collectUnparsableLines`
|
|
313
|
+
gates warn/strict via one `htmlCommentSkipper` shared by extractor and classifier — a
|
|
314
|
+
commented-out `enforcement: strict` had been reading as live config.
|
|
315
|
+
- **A read-only protection-audit CLI, with a runbook naming the order (#1079).** States
|
|
316
|
+
the required sequence; never flips a setting itself.
|
|
317
|
+
- **The scope guard now emits `orchestrator.wave_dispatch.scope_checked` (#1092).** Closes
|
|
318
|
+
the ledger half that never recorded a signal-free ALLOW.
|
|
319
|
+
- **`/journey-audit` — a user-facing product audit as a repeatable skill (#1161).** Skill,
|
|
320
|
+
command and manifest template; skill/command counts measured at 48/28.
|
|
321
|
+
- **A Cursor `.mdc` parity guard that reads the directory, not a fixed list (#1093).**
|
|
322
|
+
Catches bare `PID=`/`${VAR}` IDs a name-sampling guard had missed; `priority::` swept
|
|
323
|
+
across all 5 files.
|
|
324
|
+
- **The old root now formally leaves before the new one claims it, wired at all four
|
|
325
|
+
promotion sites (#1069).** `scripts/lib/session-transition.mjs` → `leaveSourceRoot()`:
|
|
326
|
+
`deregisterSelf()` → lock-release (reusing `on-session-end`'s ownership rules) →
|
|
327
|
+
`orchestrator.session.root_left` (carries `source_root_hash`/`source_root_basename`,
|
|
328
|
+
never an absolute path — the payload also travels over the optional webhook). Review
|
|
329
|
+
found the Phase-1.2.1 promotion site had been missing the call; it is now wired at
|
|
330
|
+
session-start Phase 0.5, Phase 1.2.1, and both `parallel-aware-*` docs. A real
|
|
331
|
+
`git worktree` two-root integration test goes phantom-peer red → green.
|
|
332
|
+
|
|
333
|
+
### Fixed
|
|
334
|
+
|
|
335
|
+
- **Six onboarding contradictions + a `cursor-install` TARGET guard (#1078).** First
|
|
336
|
+
production diff authored by a foreign model (composer-2.5) under mandatory Claude review.
|
|
337
|
+
- **Amber is now a documented normal state (#1062).** `docs/ci-setup.md` names it instead
|
|
338
|
+
of leaving it an unexplained CI color.
|
|
339
|
+
- **A tracked directory no longer hides an untracked hook beside it (#1158).**
|
|
340
|
+
`hooksPathIsTracked` now requires a GIT-tracked file directly under `core.hooksPath`.
|
|
341
|
+
- **`probe-stale` collapses to one vocabulary term (#1159).** A record older than 7 days
|
|
342
|
+
is `probe-stale`, severity `warn`, never a live finding; the registry remap is gone.
|
|
343
|
+
- **The scope-cap saw operators, not shell keywords (#1145).** `splitSegments` now splits
|
|
344
|
+
on keywords too, so `for t in a b c; do glab issue create; done` no longer slips a
|
|
345
|
+
compound-statement head past the cap.
|
|
346
|
+
- **A missing `.claude/rules/` was misdiagnosed as a loop (#1132).** `err.code` now
|
|
347
|
+
separates silent `ENOENT`/`ENOTDIR` from loud `EACCES`; the repeat was caller fan-out.
|
|
348
|
+
- **Two probes measured the wrong population (#1143/#1148).** One counted a whole file and
|
|
349
|
+
cited a line that had already drifted 338 lines from the finding; both scanners read the
|
|
350
|
+
filesystem instead of the git index, censoring 5 gitignored files as documentation.
|
|
351
|
+
- **Generated rules now self-verify offline (#1101).** Each carries a sha256 seal over its
|
|
352
|
+
own Evidence block instead of a learning-key into a gitignored file; 23 rules sealed,
|
|
353
|
+
fresh-clone warnings 23 → 0.
|
|
354
|
+
- **`reconcile.targets` had zero consumers (#1099).** Now wired through with a closed enum,
|
|
355
|
+
visible rejection of unknowns, and per-target path confinement.
|
|
356
|
+
- **Orphaned wave-scope files survived re-materialization (#1103).** Reconciled by
|
|
357
|
+
ownership proof now, never a blind directory wipe — two parallel sessions can share one
|
|
358
|
+
wave-N directory (PSA-003).
|
|
359
|
+
- **Two rival vendoring paths wrote the same rule file (#1060).** `rules/` is now sole SSOT
|
|
360
|
+
for PSA-001..007; `templates/_shared/rules/` is deleted.
|
|
361
|
+
- **`parseSessionId` accepted only UUIDv4; Codex mints v7 (#66/#1091).**
|
|
362
|
+
`scripts/lib/session-id.mjs` now accepts RFC-9562 v1–8 (`UUID_RE`, additive `version`
|
|
363
|
+
field — see `### Removed` below for the alias this superseded). Every SessionStart had
|
|
364
|
+
minted a fresh v4; a
|
|
365
|
+
resumed/compacted thread read its own lock as a foreign session. `hooks/on-stop.mjs` and
|
|
366
|
+
`hooks/on-session-end.mjs` now apply the writer's acceptance rule, closing a lock-leak via
|
|
367
|
+
non-UUID stdin ids.
|
|
368
|
+
- **phase-3-7a called `updateFrontmatterFieldsOnDisk(undefined, …)` (#65/#1036).**
|
|
369
|
+
`skills/session-end/phase-3-7a-recommendations.md` requires a repo root; every `/close`
|
|
370
|
+
took the fail-open path — 0 of 5 recommendation fields were ever written. The snippet now
|
|
371
|
+
binds `repoRoot` via `git rev-parse --show-toplevel`; the catch logs the cause.
|
|
372
|
+
- **Codex MCP launch resolved to `/scripts/mcp-server.sh` from non-git cwd (#64).** Codex
|
|
373
|
+
copies a marketplace plugin to
|
|
374
|
+
`~/.codex/plugins/cache/<marketplace>/session-orchestrator/<version>/` and starts the MCP
|
|
375
|
+
child with no plugin-root env var. `.mcp.json` and `scripts/lib/plugin-root.mjs` gained a
|
|
376
|
+
plugin-cache scan tier (name-matched `package.json`, newest by mtime). Codex snapshots
|
|
377
|
+
`.mcp.json` at install time — existing installs need a reinstall.
|
|
378
|
+
- **`scoring.mjs` read a flat `completion_rate` 0 of 281 records carry (#1071).** The value
|
|
379
|
+
lives under `effectiveness`, so the high-completion bonus was unreachable.
|
|
380
|
+
`resolveMemoryDir`/`buildLiveSignals` now take an explicit `repoRoot` instead of
|
|
381
|
+
`process.cwd()`.
|
|
382
|
+
- **mission-status recovery aborted on the first non-canonical body line (#1104).**
|
|
383
|
+
`scripts/lib/state-md/mission-status.mjs` now skips per line, reports skipped lines
|
|
384
|
+
(`recoverFrontmatterMissionStatusDetailed`). `setMissionStatus` refuses ids outside the
|
|
385
|
+
grammar with a stderr WARN from the on-disk wrapper.
|
|
386
|
+
- **`enterWorktree` failed with `already used by worktree` when the source branch was
|
|
387
|
+
checked out (#1067).** `scripts/lib/autopilot/worktree-pipeline.mjs` now creates
|
|
388
|
+
`so/<sessionId>` from that branch and returns `branch`/`promotedFrom`.
|
|
389
|
+
- **Phase 4a auto-promoted-worktree cleanup was dead under the #1069 process boundary.**
|
|
390
|
+
Since the promoted worktree runs as a brand-new session with its own id,
|
|
391
|
+
`detectAutoPromotedWorktree()`'s basename match against the CURRENT session id could
|
|
392
|
+
never fire post-#1069. `enterWorktree()` now writes `.orchestrator/promoted-from.json`
|
|
393
|
+
(source-root hash + basename, source session id, branch) at creation time;
|
|
394
|
+
`detectAutoPromotedWorktree()` tries this marker FIRST (`source: 'marker'`), falling back
|
|
395
|
+
to the legacy basename match (`source: 'basename'`) for pre-marker worktrees.
|
|
396
|
+
`isWorktreeClean()` discounts exactly the marker's own untracked line so the marker never
|
|
397
|
+
reads as dirty by itself. Re-promoting onto an existing `so/<sessionId>` branch now reuses
|
|
398
|
+
it (`reusedBranch: true`) or reports a typed refusal, instead of failing outright. See
|
|
399
|
+
ADR-0013.
|
|
400
|
+
- **`.mcp.json`'s bash bootstrap had silently drifted from `resolvePluginRoot()`'s tier
|
|
401
|
+
order.** The shell mirror now matches the same five env tiers in the same order, tests
|
|
402
|
+
`package.json`'s `name` field via `node -e JSON.parse(...)` instead of a substring `grep`
|
|
403
|
+
(which had matched `session-orchestrator-fork`), and ties the newest-by-mtime cache scan
|
|
404
|
+
to the same strict `-nt` comparison as the JS side. Two drift tests pin JS and shell
|
|
405
|
+
staying in sync.
|
|
406
|
+
- **`ci-status-banner.mjs` escaped control bytes in the JSON preview but not in the
|
|
407
|
+
parse-error message.** `JSON.stringify()` alone is not enough — V8 quotes the raw
|
|
408
|
+
offending input inside `SyntaxError.message`, carrying control bytes straight to the
|
|
409
|
+
terminal. `escapeControlBytes()` now covers both the preview AND `err.message`;
|
|
410
|
+
`parseCliJson()` also gained a shape-gate against `null`/`[]`/a bare `"ok"` string, all of
|
|
411
|
+
which parse as valid JSON but are not the object/array shape callers expect.
|
|
412
|
+
- **A refused mission-status write warned on only 1 of 5 call paths.**
|
|
413
|
+
`setMissionStatusDetailed()` now reports the refusal reason (e.g. `id-grammar`) to every
|
|
414
|
+
caller, and the on-disk wrapper emits the stderr WARN on all 5 paths instead of the one it
|
|
415
|
+
happened to cover before.
|
|
416
|
+
- **`check-unwired-features` exempted itself from its own edge census via its allowlist
|
|
417
|
+
string, hiding a real orphan behind it.** The `SELF_REL` self-reference correctly
|
|
418
|
+
contributes zero edges by design, but the same code path was masking that
|
|
419
|
+
`scripts/lib/webhook-url.mjs` has zero callers repo-wide — genuinely unreachable, not a
|
|
420
|
+
false positive. Follow-up issue pending to wire it in or remove it.
|
|
421
|
+
- **Three load-sensitive tests hardened with margin instead of being disabled.**
|
|
422
|
+
`tests/scripts/validate-plugin.test.mjs`'s child-process timeout moved from 30s to 120s (a
|
|
423
|
+
killed child returns `status: null`, which had read as a different failure than a real
|
|
424
|
+
one) plus a matching `hookTimeout` bump, and two further spawn-timeout assertions gained
|
|
425
|
+
the same discriminating margin between contention and a genuine failure.
|
|
426
|
+
|
|
427
|
+
### Changed
|
|
428
|
+
|
|
429
|
+
- **Host-registry census counts `semantic_session_id` (#1066).** `hooks/on-session-start.mjs`
|
|
430
|
+
falls back to `session_id` only when it is itself semantic. Before, only UUIDs were
|
|
431
|
+
projected — the n-increment discards them — so the registry contributed nothing to
|
|
432
|
+
numbering.
|
|
433
|
+
- **Session end events carry `semantic_session_id`; backfill event + supersede (#1068).**
|
|
434
|
+
`orchestrator.session.ended` / `.stopped` carry `semantic_session_id` (omitted when
|
|
435
|
+
unknown). A new `orchestrator.session.backfill_completed` event records each backfill outcome. A
|
|
436
|
+
completed record may now supersede an `abandoned` stub (append-only, `supersedes` marker).
|
|
437
|
+
Readers preferring the newest record are a follow-up.
|
|
438
|
+
- **`.semgrep.yml` regains two taint-mode rules (#1129).** `json-parse-untrusted-input` and
|
|
439
|
+
`prototype-pollution-object-assign` aimed at this repo's real trust boundary (hook stdin,
|
|
440
|
+
child-process stdout); 27 rules total. `unsafe-llm-output-rendering` stays excluded with a
|
|
441
|
+
measured reason (no DOM code).
|
|
442
|
+
|
|
443
|
+
### Removed
|
|
444
|
+
|
|
445
|
+
- **`UUID_V4_RE` removed** from `scripts/lib/session-id.mjs` — deprecated alias of
|
|
446
|
+
`UUID_RE` with zero importers repo-wide (measured @ 7daa3d2; hits in
|
|
447
|
+
`tests/telemetry/anon-id.test.mjs` and `server/ingest/validate.mjs` are unrelated local
|
|
448
|
+
constants of the same name). Use `UUID_RE`, any RFC 9562 version 1–8.
|
|
449
|
+
|
|
450
|
+
### Notes
|
|
451
|
+
|
|
452
|
+
Two of this session's diffs were authored by foreign models under the #1150 adapter —
|
|
453
|
+
#1078 by composer-2.5, #1093 by grok-4.6 — each passing mandatory Claude review before
|
|
454
|
+
landing. First production use of the foreign-dispatch path.
|
|
455
|
+
|
|
10
456
|
## [3.22.0] - 2026-08-22
|
|
11
457
|
|
|
12
458
|
Twenty commits (12 `fix`, 5 `docs`, 2 `feat`, 1 `chore`; 150 files, +17,312/−2,575), no
|
package/README.md
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# Session Orchestrator
|
|
2
2
|
|
|
3
3
|
[](LICENSE)
|
|
4
|
-
[](CHANGELOG.md)
|
|
5
5
|
[](https://www.npmjs.com/package/session-orchestrator)
|
|
6
|
-
[](docs/telemetry/telemetry-claims.md)
|
|
7
7
|
|
|
8
8
|
Loop engineering for AI coding agents — turn ad-hoc sessions into a repeatable research → plan → wave-execute → close loop with verification gates. Runs on **Claude Code, Codex CLI, Cursor, and [Pi](docs/pi-setup.md)**.
|
|
9
9
|
|
|
@@ -52,6 +52,8 @@ That is the whole loop. `/plan` and `/evolve` extend it (see [Lifecycle](#lifecy
|
|
|
52
52
|
|
|
53
53
|
## Quick Start
|
|
54
54
|
|
|
55
|
+
Run `/bootstrap` in your project repo first — it writes `.orchestrator/bootstrap.lock`, which session-start requires before `/session` will run.
|
|
56
|
+
|
|
55
57
|
Add a `## Session Config` section to your project's `CLAUDE.md` (Claude Code and Cursor IDE) or `AGENTS.md` (Codex CLI and Pi) — see [instruction-file-resolution](skills/_shared/instruction-file-resolution.md) for which file each platform reads. The smallest valid config is seven fields:
|
|
56
58
|
|
|
57
59
|
```yaml
|
|
@@ -70,11 +72,11 @@ Everything else is opt-in. See [`docs/session-config-template.md`](docs/session-
|
|
|
70
72
|
|
|
71
73
|
## What you get
|
|
72
74
|
|
|
73
|
-
- **
|
|
74
|
-
- **
|
|
75
|
+
- **49 skills** for the session lifecycle (start, plan, execute, close, evolve), discovery, vault sync, MCP authoring, debugging, brainstorming, plan grilling, persona panels, cross-repo dispatch, learning→rule reconciliation, session-process eval, audits, and more
|
|
76
|
+
- **28 slash commands** (`/session`, `/go`, `/close`, `/discovery`, `/plan`, `/grill`, `/evolve`, `/autopilot`, `/dispatcher`, `/reconcile`, `/eval`, `/test`, `/debug`, …)
|
|
75
77
|
- **15 typed subagents** (code-implementer, test-writer, security-reviewer, session-reviewer, qa-strategist, architect-reviewer, …)
|
|
76
78
|
- **10 hook event types** enforcing scope, blocking destructive commands, gating templates-first, capturing telemetry — full on Claude Code; experimental, post-hoc, or bridged on the other platforms ([Platform support](#platform-support))
|
|
77
|
-
- **
|
|
79
|
+
- **15,000+ vitest tests** run on every commit ([telemetry methodology](docs/telemetry/telemetry-claims.md))
|
|
78
80
|
|
|
79
81
|
Full component inventory: [`docs/components.md`](docs/components.md).
|
|
80
82
|
|
|
@@ -127,22 +129,25 @@ The system is markdown-driven config plus a thin Node runtime — skills, comman
|
|
|
127
129
|
- **Five typed waves, not one big batch.** Discovery first, so implementers start with shared context. Impl-Core before Impl-Polish, so architecture lands before integrations. Quality runs a *simplification pass* on AI-generated code **before** tests are written — otherwise tests pin the AI patterns into place.
|
|
128
130
|
- **Inter-wave reviews, not just end-of-session.** Catching regressions between waves — not only at the end — stops a bad pattern from propagating into later work; the confidence floor filters speculative criticism so only high-signal findings reach you.
|
|
129
131
|
- **State persists across crashes.** `STATE.md` records wave progress and deviations; the next `/session` offers to resume from the last completed wave.
|
|
130
|
-
- **Hooks enforce, not just warn.** A pre-Bash guard blocks destructive shell commands, and pre-Edit scope enforcement blocks writes outside an agent's allowed paths — in main sessions and subagent waves alike (specifics in [Safety](#safety)). This hard enforcement is full on Claude Code;
|
|
132
|
+
- **Hooks enforce, not just warn.** A pre-Bash guard blocks destructive shell commands, and pre-Edit scope enforcement blocks writes outside an agent's allowed paths — in main sessions and subagent waves alike (specifics in [Safety](#safety)). This hard enforcement is full on Claude Code; Cursor and Pi reach it through payload bridges; Codex is still pending a real `apply_patch` adapter (see [Platform support](#platform-support)).
|
|
131
133
|
- **Cross-session learning is opt-in and inspectable.** Every session writes a record; after 5+ sessions `/evolve analyze` extracts confidence-scored patterns you can read and prune. Nothing is hidden.
|
|
132
134
|
- **VCS dual support, no lock-in.** Auto-detects GitLab or GitHub from your remote and drives the full lifecycle for both.
|
|
133
135
|
|
|
134
|
-
## Recent highlights (v3.
|
|
136
|
+
## Recent highlights (v3.24.0)
|
|
135
137
|
|
|
136
|
-
Every release is additive and backward-compatible. Highlights of the v3.
|
|
138
|
+
Every release is additive and backward-compatible. Highlights of the v3.24.0 line: parallel-session identity moves from repo-scoped to process-local, remote work gets a declared host channel, and four duplicated-copy classes collapse to one module each:
|
|
137
139
|
|
|
138
|
-
- **
|
|
139
|
-
- **
|
|
140
|
-
- **
|
|
141
|
-
- **
|
|
142
|
-
- **
|
|
143
|
-
- **
|
|
140
|
+
- **Parallel-session identity moves from repo-scoped to process-local (#1194 / #1188)** — `enforce-scope` now reads only process-local session ids (`readProcessLocalSessionIds`), so a peer's manifest in the same working copy is treated as foreign, not as your own; `memory-propose` authorizes off a process-local match of the raw session id rather than trusting the lock file alone. A peer's declared scope also gets its own place in the wave manifest now, as a `peer-session-<id>` record instead of a silent gap (#1195).
|
|
141
|
+
- **Remote-offload: declare hosts, route heavy roles to a ready host instead of halving the wave (#1160)** — a `remote-hosts:` config block, an `ssh:<alias>` dispatch channel, and an offload decision wired into the resource gate right after the HR-004 cap (readiness is injected, never measured inside the gate itself). `skills/remote-offload/SKILL.md` is now the generic entry point, with adapters around the `offload` CLI.
|
|
142
|
+
- **Four copy-classes collapsed to one module each (#1181 / #1182 / #1196 / #1197)** — atomic-JSON handling, subagent sidecar-path derivation, `expandHome`, and markdown-fence parsing each had 4–8 divergent copies; consolidating `atomic-json.mjs` also closed a data-loss path where a read-modify-write default silently replaced an unparsable or unreadable file.
|
|
143
|
+
- **Refusals are now events, not silence (#1200 / #1201)** — `emitFinalWaveCompleted` writes `orchestrator.wave.final_refused` for six refusal paths, evolve and dialectic completions emit their own events, and reconcile's trigger set now lives in code (`KNOWN_TRIGGERS`) instead of being asserted in prose.
|
|
144
|
+
- **Canonical session counting, fleet-wide (#1186)** — `site-numbers` and `vault-mirror --kind session` now count the same way everywhere: 289 raw lines in this repo's own ledger collapsed to 278 real sessions once double-counts were removed.
|
|
145
|
+
- **Discovery-validator false positives cut — 186 of 400 measured hits were the harness's own gate-summary lines (#1198)** — a dedupe key and a gate-summary skip removed the noise; two brief claims about the masking order were also measured and refuted along the way.
|
|
146
|
+
- **Three new mechanical guards land in `validate-plugin` (#1183 / #1184 / #1187)** — `emitEvent` try/catch coverage, validator-registration parity (every check actually wired in), and dead `.sh` citations in docs.
|
|
147
|
+
- **The pre-push gate distinguishes a publish push from a scratch push; linked-worktree gates run green (15,829/0 on the remote host)** — a `.git` file (not a directory) in a linked worktree was previously misread as an untracked candidate, flagging 13 tracked files as missing.
|
|
148
|
+
- **The AUQ clarity guard's delivery is proven live, not asserted (#1122)** — `check-auq-clarity` is wired into `validate-plugin` and blocks on the two hard hurdles at a measured 0% false-positive rate; its own wiring closes with a fake-regression proof, not a claim.
|
|
144
149
|
|
|
145
|
-
Previous line (v3.
|
|
150
|
+
Previous line (v3.23.0): three external bug reports fixed end-to-end (Codex session-id versions, missing `/close` fields, plugin-root resolution), the worktree-promotion process boundary, and three measurement fixes (host-registry numbering, the mode-selector's mis-shaped read, two regained Semgrep rules).
|
|
146
151
|
|
|
147
152
|
Full version history: [CHANGELOG.md](CHANGELOG.md).
|
|
148
153
|
|
|
@@ -165,10 +170,10 @@ The design goal is engineering quality: every wave exits verified, every unfinis
|
|
|
165
170
|
|
|
166
171
|
| Feature | Claude Code | Codex CLI | Cursor IDE | Pi |
|
|
167
172
|
|---|---|---|---|---|
|
|
168
|
-
| All
|
|
173
|
+
| All 28 commands | Native slash commands | Native plugin commands | Native `.cursor/commands` slash commands | Prompt templates |
|
|
169
174
|
| Parallel agents | Agent tool | Multi-agent roles | Sequential only | Sequential (parallel planned) |
|
|
170
175
|
| Session persistence | `.claude/STATE.md` | `.codex/STATE.md` | `.cursor/STATE.md` | `.pi/STATE.md` |
|
|
171
|
-
| Scope enforcement | PreToolUse hooks | Unavailable — pending a real `apply_patch` adapter | `afterFileEdit`
|
|
176
|
+
| Scope enforcement | PreToolUse hooks | Unavailable — pending a real `apply_patch` adapter | `preToolUse` + `beforeShellExecution` via cursor-hook-bridge; `afterFileEdit` post-hoc | `tool_call` bridge |
|
|
172
177
|
| AskUserQuestion | Native tool | Numbered-list fallback | Numbered-list fallback | Numbered-list fallback |
|
|
173
178
|
| Quality gates | Full | Full | Full | Full |
|
|
174
179
|
|
package/agents/AGENTS.md
CHANGED
|
@@ -73,7 +73,7 @@ tools: Read, Grep, Glob, Bash # comma-separated string OR JSON array (bo
|
|
|
73
73
|
**Body conventions** (from Anthropic's `plugins/plugin-dev/agents/*` reference set):
|
|
74
74
|
- Sections: `**Your Core Responsibilities:**` → `**[X] Process:**` → `**Quality Standards:**` → `**Output Format:**` → `**Edge Cases:**`.
|
|
75
75
|
- Length: 500–3000 words is the recommended range. Below 500 reads as under-specified; above 3000 reads as bloated.
|
|
76
|
-
- Read-only reviewer agents: tools `Read, Grep, Glob, Bash` (no Edit/Write). Implementer agents: `Read, Edit, Write, Glob, Grep, Bash`.
|
|
76
|
+
- Read-only reviewer agents: tools `Read, Grep, Glob, Bash` (no Edit/Write). Implementer agents: `Read, Edit, Write, Glob, Grep, Bash`. Agents on the escalation allowlist append `SendMessage` to either baseline — see § Escalation Channel (#1051) for the six that do and why the rest do not.
|
|
77
77
|
|
|
78
78
|
## Model Selection & Cost Routing (#768)
|
|
79
79
|
|
|
@@ -95,6 +95,25 @@ Every agent definition with `repo-write` sandbox-tier (i.e. `Edit`/`Write` prese
|
|
|
95
95
|
|
|
96
96
|
This is deliberately more explicit than a bare "Do NOT commit" — the git index and stash are SHARED resources across concurrently-dispatched sibling agents in the same wave, and `git stash`/`git add`/`git mv`/`git rm` are index-mutating even when scoped to the agent's own files. `docs-writer.md` had NO git-write restriction at all until #724 closed the gap (its `repo-write` siblings at least carried a bare "Do NOT commit" line) — when adding a new repo-write agent, copy the ban line verbatim rather than re-deriving a weaker phrasing so this gap does not recur. See `.claude/rules/parallel-sessions.md` § PSA-007 for the full rationale and fleet evidence.
|
|
97
97
|
|
|
98
|
+
## Escalation Channel (#1051)
|
|
99
|
+
|
|
100
|
+
Six agents opt into `SendMessage` so a wave-blocking obstacle can reach the coordinator **while the wave is still running**, instead of surfacing only in the final report after the wave has ended. The allowlist is exactly:
|
|
101
|
+
|
|
102
|
+
`code-implementer` · `db-specialist` · `ui-developer` · `test-writer` · `docs-writer` · `session-reviewer`
|
|
103
|
+
|
|
104
|
+
**The Nicht-Liste is deliberate, not an oversight.** `analyst`, `qa-strategist`, `architect-reviewer`, `security-reviewer`, `ux-evaluator`, `eval-judge`, `skill-applied-judge` and `dialectic-deriver` do NOT get the tool. Their output is a judgment over a whole corpus — a finding at minute three is provisional, and the analysis is complete only at the end. An early message from one of them would carry an unfinished verdict the coordinator cannot act on without re-reading the final report anyway, so the channel would add interrupts without adding information. The six above are different: each one can hit a state where its *task* becomes unfulfillable (the file it must edit does not exist, the migration target is missing, the diff under review is absent) — an obstacle, not a verdict.
|
|
105
|
+
|
|
106
|
+
**The contract every escalation-enabled agent carries** (see `.claude/rules/cross-session-messaging.md` CSM-001/004/005):
|
|
107
|
+
|
|
108
|
+
- **One message, upward only.** Exactly ONE `SendMessage` to `main` per obstacle. Never to a sibling agent — agents send upward, they cannot discover sideways.
|
|
109
|
+
- **Never wait for a reply.** Silence is neither refusal nor consent (CSM-004); the agent keeps working in its scope or ends `blocked`.
|
|
110
|
+
- **Degrade silently.** Where `SendMessage` is unavailable (disabled telemetry, non-Anthropic provider, native Windows — CSM-005), the obstacle goes in the final report instead. No code path may assume delivery happened.
|
|
111
|
+
- **Payload:** agent role, declared file scope, the obstacle. The send is noted in the agent's own report so the operator can see the hand-off.
|
|
112
|
+
|
|
113
|
+
**Mandate for new agents** — same shape as the git-write ban convention above: when adding a repo-write agent that belongs on this allowlist, copy the escalation block verbatim from `code-implementer.md` (adjusting only the role name) rather than re-deriving a weaker phrasing. A paraphrase that drops "never wait for a reply" or "upward only" re-opens exactly the failure modes CSM-004 and CSM-001 exist to close.
|
|
114
|
+
|
|
115
|
+
`SendMessage` does NOT lift an agent out of `read-only`: it is in `READ_ONLY_TOOLS` (`scripts/lib/validate/tier-inference.mjs`, #1049), so `session-reviewer` keeps `sandbox-tier: read-only` and every `sandbox-tier` in this directory is unchanged by the opt-in.
|
|
116
|
+
|
|
98
117
|
## Color Allocation Strategy (#443)
|
|
99
118
|
|
|
100
119
|
`color` is an **operator side-channel**, not a cosmetic field. In a `/tmux-layout` or multi-pane session, the per-agent color lets the operator tell co-running agents apart at a glance. With only a 9-color palette (`blue | cyan | green | yellow | purple | orange | pink | red | magenta`) and more than 9 agents in this directory, some colors are **deliberately shared** — but never carelessly.
|
|
@@ -124,12 +143,12 @@ Agents MAY declare their sandbox permission tier. Valid values:
|
|
|
124
143
|
|
|
125
144
|
| Value | Meaning | Typical tools |
|
|
126
145
|
|---|---|---|
|
|
127
|
-
| `read-only` | observes only; no file writes, no network | `Read, Grep, Glob, Bash` |
|
|
128
|
-
| `repo-write` | may create or modify files | `Read, Edit, Write, Glob, Grep, Bash` |
|
|
146
|
+
| `read-only` | observes only; no file writes, no network | `Read, Grep, Glob, Bash` (+ `Skill`, `SendMessage`, `ListAgents`) |
|
|
147
|
+
| `repo-write` | may create or modify files | `Read, Edit, Write, Glob, Grep, Bash` (+ `Skill`, `SendMessage`, `ListAgents`) |
|
|
129
148
|
| `network-allowed` | may make outbound network calls (future) | — |
|
|
130
149
|
| `dangerous` | may run destructive shell commands (future) | — |
|
|
131
150
|
|
|
132
|
-
Inference rule (backward-compat): agents without `sandbox-tier:` infer their tier from tools — `Edit` or `Write` present → `repo-write`; only `Read/Grep/Glob/Bash/Skill` → `read-only`. The validator emits **WARN**, not FAIL, when the field is absent, so existing agents continue to work during migration. Bash appears in all tiers — fine-grained Bash control is handled by `hooks/pre-bash-destructive-guard.mjs`, not by tier.
|
|
151
|
+
Inference rule (backward-compat): agents without `sandbox-tier:` infer their tier from tools — `Edit` or `Write` present → `repo-write`; only `Read/Grep/Glob/Bash/Skill/SendMessage/ListAgents` → `read-only`. `SendMessage` and `ListAgents` are pure agent↔coordinator communication surfaces with no filesystem write path, so they do not lift an agent out of `read-only` (`scripts/lib/validate/tier-inference.mjs` `READ_ONLY_TOOLS`, #1049) — that is what lets `session-reviewer` opt into the escalation channel while staying `read-only`. The validator emits **WARN**, not FAIL, when the field is absent, so existing agents continue to work during migration. Bash appears in all tiers — fine-grained Bash control is handled by `hooks/pre-bash-destructive-guard.mjs`, not by tier.
|
|
133
152
|
|
|
134
153
|
Example:
|
|
135
154
|
|