session-orchestrator 3.19.0 → 3.20.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/CHANGELOG.md +80 -0
- package/README.md +9 -9
- package/commands/session.md +6 -2
- package/docs/USER-GUIDE.md +1 -1
- package/docs/instruction-delivery.md +350 -0
- package/docs/session-config-reference.md +1 -41
- package/docs/session-config-template.md +0 -23
- package/hooks/_lib/guard-source-loader.mjs +304 -91
- package/hooks/enforce-commands.mjs +216 -17
- package/hooks/enforce-scope.mjs +133 -9
- package/hooks/hooks-codex.json +1 -1
- package/hooks/hooks.json +1 -1
- package/hooks/on-session-start.mjs +7 -4
- package/hooks/pre-bash-destructive-guard.mjs +146 -59
- package/hooks/pre-bash-sessions-ledger-guard.mjs +493 -66
- package/package.json +2 -2
- package/scripts/backfill-learnings-from-vault.mjs +967 -0
- package/scripts/emit-session.mjs +3 -40
- package/scripts/lib/command-blocker.mjs +322 -62
- package/scripts/lib/hardening.mjs +9 -9
- package/scripts/lib/learnings/affinity.mjs +434 -0
- package/scripts/lib/learnings/candidates.mjs +736 -0
- package/scripts/lib/learnings/expiry-sweep.mjs +408 -53
- package/scripts/lib/learnings/judgment.mjs +782 -0
- package/scripts/lib/learnings/kebab.mjs +128 -0
- package/scripts/lib/learnings/select.mjs +550 -0
- package/scripts/lib/reconcile/emitter.mjs +107 -22
- package/scripts/lib/reconcile/engine.mjs +9 -15
- package/scripts/lib/reconcile/renderer.mjs +141 -25
- package/scripts/lib/reconcile/sanitize.mjs +518 -0
- package/scripts/lib/reconcile/writer.mjs +95 -1
- package/scripts/lib/scope-gate.mjs +194 -72
- package/scripts/lib/session-close-backfill.mjs +2 -2
- package/scripts/lib/session-record-repair.mjs +551 -0
- package/scripts/lib/session-schema/serializer.mjs +54 -0
- package/scripts/lib/session-schema.mjs +1 -0
- package/scripts/lib/session-token-rollup.mjs +68 -6
- package/scripts/lib/soul-resolve.mjs +12 -0
- package/scripts/lib/tmux-layout/telemetry.mjs +43 -10
- package/scripts/lib/validate/check-banner-parity.mjs +376 -0
- package/scripts/lib/validate/check-guard-requires-parity.mjs +1148 -0
- package/scripts/lib/validate/check-learning-provenance.mjs +511 -0
- package/scripts/lib/validate/check-owner-leakage.mjs +3 -3
- package/scripts/lib/validate/check-rules.mjs +31 -5
- package/scripts/lib/validate/check-unwired-features.mjs +549 -0
- package/scripts/print-applicable-rules.mjs +170 -7
- package/scripts/print-learnings-index.mjs +474 -0
- package/scripts/repair-invalid-sessions.mjs +209 -0
- package/scripts/sweep-expired-learnings.mjs +192 -32
- package/scripts/validate-plugin.mjs +21 -0
- package/skills/brainstorm/soul.md +47 -1
- package/skills/evolve/SKILL.md +116 -18
- package/skills/gitlab-ops/SKILL.md +5 -0
- package/skills/grill/soul.md +44 -1
- package/skills/plan/soul.md +46 -3
- package/skills/session-end/SKILL.md +1 -24
- package/skills/session-end/phase-3-6-tail.md +30 -1
- package/skills/session-end/plan-verification.md +1 -5
- package/skills/session-end/session-metrics-write.md +2 -0
- package/skills/session-start/SKILL.md +2 -0
- package/skills/session-start/soul.md +41 -1
- package/skills/wave-executor/SKILL.md +1 -5
- package/skills/wave-executor/wave-loop.md +36 -71
|
@@ -263,6 +263,7 @@ For each agent in this wave:
|
|
|
263
263
|
- Which files to read/modify (exact paths)
|
|
264
264
|
- Acceptance criteria (how to verify done)
|
|
265
265
|
- Relevant patterns — injected automatically as the <APPLICABLE-RULES> block (see Pre-Dispatch: Glob-Scoped Rule Injection below)
|
|
266
|
+
- Relevant past learnings — injected automatically as the <LEARNINGS-INDEX> block, computed PER AGENT from its file scope (see Pre-Dispatch: Learnings-Index Injection below)
|
|
266
267
|
- Any repo-state fact carried from an earlier wave: in the ASSERTED/UNVERIFIED form, never as a bare value (see Pre-Dispatch: Fact-Staleness Annotation above)
|
|
267
268
|
- VCS issue reference if applicable
|
|
268
269
|
- What NOT to touch (other agents' files)
|
|
@@ -405,7 +406,7 @@ After `wave-scope.json` is written for this wave and before assembling the `Agen
|
|
|
405
406
|
RULES_BLOCK="$(node "$PLUGIN_ROOT/scripts/print-applicable-rules.mjs" --context wave 2>/dev/null)"
|
|
406
407
|
|
|
407
408
|
`--context wave` (issue #692) excludes `tier: coordinator-only` rules (owner-persona, lsp, mvp-scope, loop-and-monitor) from the wave-agent prompt — those are operator/coordinator-context rules a wave implementation agent does not need. `tier: always` and `tier: wave-only` rules are unaffected; omitting the flag (or passing `--context coordinator`) disables wave-tier exclusion. Use `--wave-scope <path>` only if `wave-scope.json` is not at the default `.claude/wave-scope.json`. The CLI returns:
|
|
408
|
-
- a Markdown block (header `## Applicable Rules (scoped to this wave)
|
|
409
|
+
- a Markdown block (header `## Applicable Rules (scoped to this wave)`, a preamble naming the block's fence token, then each matching rule's raw content wrapped in `<rule-<token> index="i/N" src="<repo-relative path>">` … `</rule-<token>>`) when one or more rules apply, OR
|
|
409
410
|
- empty output (exit 0) when no rules match — in which case prepend nothing.
|
|
410
411
|
|
|
411
412
|
**Prompt assembly:** when `$RULES_BLOCK` is non-empty, prepend it to EACH agent's prompt in this wave under a clear separator:
|
|
@@ -420,6 +421,40 @@ When `$RULES_BLOCK` is empty (no `.claude/rules/`, no matching rules, or any CLI
|
|
|
420
421
|
|
|
421
422
|
This replaces the older prose slot "Relevant patterns from `<state-dir>/rules/`" in the `Agent()` template above: the `<APPLICABLE-RULES>` block IS that injection, now mechanically scoped to the wave instead of left to the coordinator's judgement.
|
|
422
423
|
|
|
424
|
+
#### Pre-Dispatch: Learnings-Index Injection (#1014)
|
|
425
|
+
|
|
426
|
+
> **Read this first — it is computed PER AGENT, unlike the block directly above.** The rule injection you just read states "Per-wave scoping (not per-agent): the rule set is computed ONCE per wave". This step is the opposite: **run the CLI once for EACH agent**, because per-agent differentiation IS the acceptance criterion — an agent scoped to `scripts/lib/learnings/**` must receive different entries than its sibling scoped to `skills/**`. Model it on **Pre-Dispatch Grounding Injection (#85)** above, not on its immediate neighbour. Computing it once and reusing it across the wave silently reduces this feature to a worse version of the coordinator banner that already exists.
|
|
427
|
+
|
|
428
|
+
89 learnings have accumulated across 233 sessions, and a dispatched wave agent receives **zero** of them: the only read paths are a coordinator banner, an autopilot call, and a nudge banner — none reaches an agent prompt. This step closes that loop by prepending a compact, relevance-ranked INDEX of learnings to each agent's prompt.
|
|
429
|
+
|
|
430
|
+
**Why this does not repeat the #931b mistake.** `docs/instruction-delivery.md` measured that adding a SECOND delivery path alongside Claude Code's native project-instruction loading costs **+72%** (292,836 B vs 169,961 B) — which is why the rule block above carries a "measure before you inject" warning. That warning does **not** transfer here, and not as a matter of argument: learnings have no native delivery path to duplicate. `learnings.jsonl` lives under `.orchestrator/metrics/`, is not a project-instruction file, is not `@`-imported from CLAUDE.md, and reaches nothing agent-facing today. This is the FIRST path, and it rides the dispatch-prompt channel this repo already owns and writes itself — no new mechanism is introduced. It is also bounded by a code constant (`LEARNINGS_INDEX_MAX_CHARS = 2000`, ~1.1% of the measured 178,095 B per-agent prompt baseline) with no `0 = unlimited` sentinel, so it cannot grow into the corpus it indexes.
|
|
431
|
+
|
|
432
|
+
**An INDEX, not a corpus.** One line per learning plus a retrieval pointer; an agent that needs a full entry greps it by subject. Measured: 12 entries in this form = 1,469 B.
|
|
433
|
+
|
|
434
|
+
**Gate:** runs when `.orchestrator/metrics/learnings.jsonl` exists. When it does not — or when nothing clears the confidence floor, or the corpus is unreadable — the CLI prints nothing and exits 0. Same best-effort convention as every injector above (Grounding `:307`, Frontmatter-Guard `:386`, Path-Cousin-Guard `:208`): silent no-op on any failure, **never blocks dispatch**. Any non-zero exit means "inject nothing, continue".
|
|
435
|
+
|
|
436
|
+
**Zero new coordinator obligations.** The per-agent file scope this needs is the SAME `$AGENT_FILESCOPE_JSON` temp file the Pre-Dispatch Scope-Union Assertion (#796, see `## Scope Manifest` § 3) already requires you to write for every agent in every `Agent()` batch. Reuse that file — do not write a second one.
|
|
437
|
+
|
|
438
|
+
**Invocation:** once per agent, immediately after that agent's `$AGENT_FILESCOPE_JSON` is written, capture stdout as `$LEARNINGS_INDEX`:
|
|
439
|
+
|
|
440
|
+
LEARNINGS_INDEX="$(node "$PLUGIN_ROOT/scripts/print-learnings-index.mjs" \
|
|
441
|
+
--file-scope "$AGENT_FILESCOPE_JSON" \
|
|
442
|
+
--task-text "<the agent's task title / one-line description>" 2>/dev/null)"
|
|
443
|
+
|
|
444
|
+
`--task-text` is optional and feeds the token axis of the affinity primitive; omitting it yields path-only ranking. **Resolution ladder** (mirrors Grounding Injection `:309`): the agent's own `--file-scope` → the wave-level `allowedPaths` from `.claude/wave-scope.json` (automatic fallback when the agent has no declared "Files:" scope) → empty scope, in which case only the general tier is selected. Caps are `--max-scoped` (default 8) and `--max-global` (default 4) — **split, never shared**, so the general tier can never crowd out the per-agent signal.
|
|
445
|
+
|
|
446
|
+
**Prompt assembly:** when `$LEARNINGS_INDEX` is non-empty, prepend it to THAT agent's prompt:
|
|
447
|
+
|
|
448
|
+
<LEARNINGS-INDEX>
|
|
449
|
+
$LEARNINGS_INDEX
|
|
450
|
+
</LEARNINGS-INDEX>
|
|
451
|
+
|
|
452
|
+
<original prompt>
|
|
453
|
+
|
|
454
|
+
When it is empty (no corpus, no qualifying entries, or any CLI failure), dispatch that agent unchanged — the prompt is then byte-identical to the legacy one.
|
|
455
|
+
|
|
456
|
+
**Instrumentation (why this one is measurable and its neighbours are not).** The rule injection above is a SHOULD and emits no signal either way, so "did the coordinator actually inject?" has been unanswerable after the fact — a gap the #1014 discovery wave had to leave open. This CLI emits `orchestrator.learnings.index.injected` to `.orchestrator/metrics/events.jsonl` (via `scripts/emit-event.mjs`, the canonical `emitEvent()` path — the same route `scripts/compute-grounding-injection.sh` uses for `orchestrator.grounding.injected`), carrying `count`, `scope_matched`, `global_count`, `candidates`, `truncated`, `bytes`, and `scope_source`. The before/after measurement is therefore a fact in the event log, not a matter of prose compliance. Emission is best-effort and suppressible with `--no-event`; a failed emit never blocks dispatch.
|
|
457
|
+
|
|
423
458
|
#### Structured Reasoning (STATE:/PLAN:) — opt-in via `reasoning-output: true` (#79)
|
|
424
459
|
|
|
425
460
|
When `$CONFIG.reasoning-output` is `true`, append the following block to every agent prompt. The pattern is adapted from the BitGN PAC Agent's Soft-SGR: short structured transparency lines before tool invocations, without forcing structured output. Leave the block OUT when the flag is `false` (default) — this preserves exact legacy prompt behavior.
|
|
@@ -667,29 +702,6 @@ Per attempt:
|
|
|
667
702
|
See `SKILL.md` § "Inter-Wave Quality-Gate (with Auto-Fix Loop — #521)" for
|
|
668
703
|
the full invocation pattern.
|
|
669
704
|
|
|
670
|
-
##### /goal Continuation Anchor (opt-in — #636)
|
|
671
|
-
|
|
672
|
-
> Advisory-only continuation anchor at the inter-wave fix-loop seam. Never auto-invokes `/goal`, never blocks forward progress. `/goal` is a user slash-command; the operator decides whether to use it.
|
|
673
|
-
|
|
674
|
-
**Gate conditions** — ALL must be true for this nudge to surface:
|
|
675
|
-
|
|
676
|
-
1. `goal-integration.enabled: true` in Session Config (default: `false`).
|
|
677
|
-
2. `inter-wave-fixloop` is listed in `goal-integration.seams`.
|
|
678
|
-
|
|
679
|
-
When any gate condition is false, skip this step entirely — proceed to `##### STATE.md Deviation — Auto-Fix Result`.
|
|
680
|
-
|
|
681
|
-
**What it does** — when the gate fires and the inter-wave Quality-Gate is failing (auto-fix retries in flight or about to begin), surface ONE suggested `/goal` command as an advisory bullet in the wave progress update. Example:
|
|
682
|
-
|
|
683
|
-
```
|
|
684
|
-
/goal Keep fixing Wave <N> quality-gate failures until 'npm run lint', 'npm run typecheck' and 'npm test' each print 0 failures in this turn's output, or stop after <max-retries+1> attempts.
|
|
685
|
-
```
|
|
686
|
-
|
|
687
|
-
**Advisory-only contract:** the `/goal` is the continuation anchor that keeps the coordinator working across turns while it iterates on the fix. The exit-code result of `runQualityGateWithRetry()` stays the judgment — `/goal` continues the loop, it never decides correctness. The hard-abort + diagnostics-bundle path (`.orchestrator/metrics/verification-failures/<ts>.json` after `max-retries`) is UNCHANGED: an active `/goal` does not extend, replace, or bypass the bounded retry ceiling. This step is informational prose only — no AskUserQuestion, no STATE.md write, no sidecar.
|
|
688
|
-
|
|
689
|
-
The `/goal` evaluator reads the transcript only and runs NO tools — it anchors CONTINUATION, never JUDGMENT. The suggested condition therefore references freshly-run gate output "in this turn's output" and embeds a bound ("or stop after N attempts"). Cross-reference `.claude/rules/loop-and-monitor.md § LM-008` for the full `/goal` continuation-vs-judgment contract rather than restating it here.
|
|
690
|
-
|
|
691
|
-
**One goal per session:** only ONE `/goal` can be active at a time. This inter-wave fix-loop seam and the session-end backlog seam (`skills/session-end/SKILL.md` § 1.3a) cannot both hold an active goal simultaneously — the operator picks one.
|
|
692
|
-
|
|
693
705
|
##### STATE.md Deviation — Auto-Fix Result
|
|
694
706
|
|
|
695
707
|
After `runQualityGateWithRetry()` returns:
|
|
@@ -1037,53 +1049,6 @@ When the hook is skipped (gate condition false), omit the `persona_gate` field e
|
|
|
1037
1049
|
|
|
1038
1050
|
**Motivating example:** a flagship product's W5 Buyer-Panel pattern (six buyer personas at `hard-gate-threshold` `6-of-6`, `mode: 'strict'`, `after: 'quality'`) — UI work is gate-checked against every persona before commit, abort on any dissent. See `docs/session-config-reference.md § Persona-Gate Wave (#458)` and `commands/persona-panel.md` for the standalone CLI equivalent.
|
|
1039
1051
|
|
|
1040
|
-
### 3c. Strategic Compact-Nudge (#620)
|
|
1041
|
-
|
|
1042
|
-
> Advisory-only checkpoint. Never auto-compacts. `/compact` is a user slash-command; the coordinator/operator decides when to invoke it.
|
|
1043
|
-
|
|
1044
|
-
**Gate conditions** — ALL must be true for the nudge to emit:
|
|
1045
|
-
|
|
1046
|
-
1. `compact-nudge.enabled: true` in Session Config (default: `false`).
|
|
1047
|
-
2. The just-completed wave's role is listed in `compact-nudge.after` (default: `['discovery', 'impl']`). Compare the wave's canonical role string (lower-case) against the list.
|
|
1048
|
-
3. `compact-nudge.mode !== 'off'` (when `mode: 'off'` the nudge is a silent no-op even when `enabled: true`).
|
|
1049
|
-
|
|
1050
|
-
When any gate condition is false, skip this step entirely — proceed to `### 4. Progress Update`.
|
|
1051
|
-
|
|
1052
|
-
**Nudge format** — when the gate fires, append ONE advisory bullet to the wave progress update (step `### 4`):
|
|
1053
|
-
|
|
1054
|
-
```
|
|
1055
|
-
- 💡 Compact checkpoint: Wave N (<Role>) complete — consider /compact before Wave N+1 (<NextRole>) to free context (advisory only; see decision table). Never auto-compacts.
|
|
1056
|
-
```
|
|
1057
|
-
|
|
1058
|
-
**What survives `/compact` vs what is lost:**
|
|
1059
|
-
|
|
1060
|
-
| Survives | Lost |
|
|
1061
|
-
|---|---|
|
|
1062
|
-
| CLAUDE.md, STATE.md (on disk), wave-scope.json, JSONL metrics (.orchestrator/), git history, all files on disk | Intermediate reasoning/thinking traces, previously-read file contents cached in context, tool-call history for prior waves |
|
|
1063
|
-
|
|
1064
|
-
This frames the nudge: the persistent artefacts (plan, scope, STATE.md, git diff) are the distilled output of completed work; losing in-context file reads is the cost. Compact is worth it when the completed wave produced bulky research/audit output that is unlikely to be re-referenced verbatim.
|
|
1065
|
-
|
|
1066
|
-
**Decision table:**
|
|
1067
|
-
|
|
1068
|
-
| Wave boundary (completed → next) | Compact? | Why |
|
|
1069
|
-
|---|---|---|
|
|
1070
|
-
| Discovery → Impl-Core | Yes — **but only after** Discovery's repo-state facts are written into the plan in annotated form (value + measurement command + `measured_at`) | Research/audit context is bulky and the plan + wave-scope.json is the distilled output. But compacting discards the raw evidence and leaves the briefing text as the only source of truth — the structural amplifier of the #908 damage. Un-annotated facts: re-measure or record them first, else **No**. See Pre-Dispatch: Fact-Staleness Annotation. |
|
|
1071
|
-
| Impl-Core → Impl-Polish (long Core) | Maybe | Compact only if Polish targets different files; keep if Polish builds on Core's changes. |
|
|
1072
|
-
| Impl-Polish → Quality | No | Quality references the just-written code; losing it is costly. |
|
|
1073
|
-
| Quality → Finalization | No | Finalization needs the full session diff. |
|
|
1074
|
-
| Mid-implementation (within a wave) | No | Losing file paths + partial state is expensive. |
|
|
1075
|
-
| After a FAILED/aborted wave | Yes | Clear the dead-end reasoning before the adapted retry. |
|
|
1076
|
-
| Switching to an unrelated task block (deep session) | Yes | Debug/exploration traces pollute unrelated downstream work. |
|
|
1077
|
-
|
|
1078
|
-
**Behaviour by mode:**
|
|
1079
|
-
|
|
1080
|
-
| `mode` | Action |
|
|
1081
|
-
|--------|--------|
|
|
1082
|
-
| `off` | No nudge (gate condition above). |
|
|
1083
|
-
| `warn` | Emit the advisory bullet in the wave progress update. Coordinator/operator acts at their discretion. |
|
|
1084
|
-
|
|
1085
|
-
The nudge is informational only — no AskUserQuestion, no state-md write, no sidecar. This step never blocks forward progress.
|
|
1086
|
-
|
|
1087
1052
|
### 4. Progress Update
|
|
1088
1053
|
|
|
1089
1054
|
After each wave, provide a brief status:
|