session-orchestrator 3.22.0 → 3.23.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/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 +168 -0
- package/README.md +18 -15
- package/agents/AGENTS.md +23 -4
- package/agents/code-implementer.md +2 -1
- package/agents/db-specialist.md +2 -1
- 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 +14 -0
- package/docs/codex-setup.md +64 -0
- package/docs/components.md +6 -6
- package/docs/cursor-setup.md +26 -47
- package/docs/events-schema.md +76 -4
- 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 +26 -4
- package/docs/session-config-template.md +4 -3
- package/docs/telemetry.md +22 -0
- package/hooks/_lib/lock-bootstrap.mjs +8 -4
- package/hooks/_lib/vcs-create-matcher.mjs +397 -38
- package/hooks/enforce-scope.mjs +64 -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 +211 -10
- package/hooks/on-session-start.mjs +214 -11
- package/hooks/on-stop.mjs +48 -9
- package/hooks/post-subagent-discovery-validator.mjs +34 -3
- package/hooks/post-tool-batch-wave-signal.mjs +11 -2
- package/hooks/pre-bash-issue-budget.mjs +117 -4
- 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/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 +5 -0
- package/scripts/backfill-evidence-digest.mjs +376 -0
- package/scripts/cursor-install.mjs +89 -48
- 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/autopilot/worktree-pipeline.mjs +240 -16
- package/scripts/lib/build-live-signals.mjs +24 -5
- package/scripts/lib/ci-status-banner.mjs +158 -11
- package/scripts/lib/command-blocker.mjs +70 -0
- package/scripts/lib/config/reconcile.mjs +79 -4
- package/scripts/lib/config/section-extractor.mjs +235 -36
- package/scripts/lib/config-schema.mjs +9 -1
- package/scripts/lib/config.mjs +57 -6
- 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/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/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 +5 -2
- package/scripts/lib/memory-paths.mjs +15 -6
- package/scripts/lib/mode-selector/scoring.mjs +53 -6
- 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 +281 -13
- 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 +90 -0
- package/scripts/lib/session-close-backfill.mjs +369 -28
- package/scripts/lib/session-discovery.mjs +13 -3
- package/scripts/lib/session-end/phase-skip.mjs +37 -4
- 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 +159 -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-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/sync.mjs +46 -8
- 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 +16 -32
- 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-test-value-bans.mjs +165 -17
- package/scripts/lib/validate/check-unwired-features.mjs +340 -32
- 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-writer.mjs +211 -10
- package/scripts/lib/vault-status/narrative-mirror.mjs +188 -8
- package/scripts/lib/wave-executor/foreign-dispatch.mjs +832 -0
- package/scripts/lib/wave-transcript-tail.mjs +869 -0
- package/scripts/materialize-wave-scope.mjs +209 -12
- package/scripts/mcp-server.sh +11 -2
- package/scripts/parse-config.mjs +65 -0
- package/scripts/token-audit.sh +9 -2
- package/scripts/validate-plugin.mjs +3 -0
- package/scripts/validate-wave-scope.mjs +67 -0
- package/scripts/vault-mirror.mjs +203 -34
- package/skills/_shared/monitor-patterns.md +31 -5
- package/skills/_shared/parallel-aware-auq.md +1 -1
- package/skills/_shared/parallel-aware-preamble.md +4 -2
- 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/dispatcher/SKILL.md +1 -1
- package/skills/journey-audit/SKILL.md +269 -0
- package/skills/peekaboo-driver/SKILL.md +15 -3
- package/skills/persona-panel/SKILL.md +1 -1
- package/skills/reconcile/SKILL.md +41 -1
- 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 +11 -3
- 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 +30 -16
- 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 +4 -2
- package/skills/wave-executor/circuit-breaker.md +34 -9
- package/skills/wave-executor/wave-loop.md +102 -19
- package/templates/_shared/journey-manifest.md +110 -0
- package/templates/_shared/rules/parallel-sessions.md +0 -77
|
@@ -75,11 +75,32 @@ Some sub-configs live in dedicated policy files under `.orchestrator/policy/`:
|
|
|
75
75
|
| Field | Type | Default | Description |
|
|
76
76
|
|-------|------|---------|-------------|
|
|
77
77
|
| `agents-per-wave` | integer or integer with overrides | `6` | Maximum parallel subagents per wave. Supports session-type overrides: `6 (deep: 18)` outputs `{"default": 6, "deep": 18}`. Plain integers remain plain. The override key names a session type but does **not** create one: there is no `session-type:` Session Config key — `parseSessionConfig()` emits none, so writing one into a repo's `## Session Config` block is inert prose. The session type comes from the `/session` argument (default `deep`, see `commands/session.md`) and is persisted to STATE.md frontmatter as `session-type:`, which is the only live read (`scripts/print-applicable-rules.mjs` rule mode-gating). |
|
|
78
|
-
| `agent-mapping` | object | null | Optional mapping of role keys to agent names for explicit agent binding. Keys: `impl`, `test`, `db`, `ui`, `security`, `compliance`, `docs`, `perf`. Example: `{ impl: code-editor, test: test-specialist }`. Overrides auto-discovery when present. |
|
|
78
|
+
| `agent-mapping` | object | null | Optional mapping of role keys to agent names for explicit agent binding. Keys: `impl`, `test`, `db`, `ui`, `security`, `compliance`, `docs`, `perf`. Example: `{ impl: code-editor, test: test-specialist }`. Overrides auto-discovery when present. Values may carry a channel prefix — see § `agent-mapping` values below. |
|
|
79
79
|
| `waves` | integer | `5` | Number of execution waves for feature and deep sessions. |
|
|
80
80
|
| `recent-commits` | integer | `20` | Number of recent commits to display during session start git analysis. |
|
|
81
81
|
| `special` | string | none | Repo-specific instructions. Freeform text that the orchestrator reads and follows during sessions. |
|
|
82
82
|
|
|
83
|
+
### `agent-mapping` values — channel prefixes (#1150)
|
|
84
|
+
|
|
85
|
+
A mapping value has three forms, distinguished by the colon:
|
|
86
|
+
|
|
87
|
+
| Value form | Meaning | Dispatch |
|
|
88
|
+
|---|---|---|
|
|
89
|
+
| `<project-agent>` (no colon) | An agent file under `<state-dir>/agents/<name>.md` | Agent tool, unchanged |
|
|
90
|
+
| `session-orchestrator:<plugin-agent>` | A plugin agent shipped by this repo | Agent tool, unchanged |
|
|
91
|
+
| `cursor:<model>` | A **foreign model** over the Cursor channel (`cursor-agent`) | Coordinator-direct via `dispatchForeign()` — **not** the Agent tool |
|
|
92
|
+
|
|
93
|
+
```
|
|
94
|
+
agent-mapping: { impl: cursor:composer-2.5, test: cursor:cursor-grok-4.6-high, security: security-reviewer }
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
**Unknown channels fail loud.** `scripts/lib/config.mjs` parses this key and throws on any prefix outside `cursor` / `session-orchestrator` (`agent-mapping role '<k>' names unknown channel '<c>' …`), and on a prefix with an empty target. Silently accepting a typo would dispatch to an agent that does not exist and surface only as an empty wave, much later. A value without a colon is a plain agent name and is never channel-parsed.
|
|
98
|
+
|
|
99
|
+
**Where the rest of the contract lives** — deliberately not here, so one place owns it:
|
|
100
|
+
|
|
101
|
+
- **Model selection** (which model for which role, and why): the account-switch routing SSOT, ADR-002 / `tools/routing/routing.yaml`. Working defaults are `composer-2.5` for foreign impl and `cursor-grok-4.6-high` for review / test-writing / judgment roles.
|
|
102
|
+
- **Dispatch contract** (detached worktree, the `never_foreign` role lock, the filesystem-measured verdict, the MANDATORY Claude semantic diff-review before merge-back, wall-clock timeout instead of `maxTurns`, and the `orchestrator.foreign_dispatch.completed` event that replaces the hook-chain telemetry a foreign run cannot emit): `skills/wave-executor/wave-loop.md` § Third branch: foreign-model dispatch.
|
|
103
|
+
|
|
83
104
|
## VCS & Infrastructure
|
|
84
105
|
|
|
85
106
|
| Field | Type | Default | Description |
|
|
@@ -193,7 +214,7 @@ issue-budget:
|
|
|
193
214
|
|
|
194
215
|
**Exemptions (load-bearing).** `priority::critical`, the carryover class (`[Carryover]`, `[SPIRAL]`/`[FAILED]`, `type::carryover`, a bare `carryover` label) and `broken-window` closure issues bypass the cap unconditionally. Without those exemptions the cap would break the standing session-end promises in `skills/session-end/SKILL.md` (Phase 1.8 "non-deselectable" SPIRAL/FAILED carryover, and the Critical Rule "ALWAYS create issues for unfinished PLANNED work"). Exempt creations are counted in the state file's `exempt` field for observability but never blocked.
|
|
195
216
|
|
|
196
|
-
**Counter file:** `.orchestrator/runtime/issue-budget
|
|
217
|
+
**Counter file:** `.orchestrator/runtime/issue-budget/<sha256(sessionId)[0..16]>.json` — `{ sessionId, count, exempt, overflow: [...] }`, ONE file per session (#1141: the former single `issue-budget.json` slot was reset by whichever session wrote last, so two sessions in one working copy silently disabled each other's cap). Identity-less callers still use the legacy flat path; `budgetStatePath(repoRoot, sessionId)` in `scripts/lib/issue-budget.mjs` is the resolver.
|
|
197
218
|
|
|
198
219
|
**Used by:** `hooks/pre-bash-issue-budget.mjs` (shell path, PreToolUse/Bash), `scripts/lib/spiral-carryover.mjs` `runCli()` (programmatic path), `scripts/lib/issue-budget.mjs` (shared decision core), `skills/session-end/SKILL.md` Phase 5 Step 3b (overflow drain). Parser: `scripts/lib/config/issue-budget.mjs`.
|
|
199
220
|
|
|
@@ -1215,7 +1236,7 @@ reconcile:
|
|
|
1215
1236
|
|-------|------|---------|-------------|
|
|
1216
1237
|
| `reconcile.enabled` | boolean | `false` | Master toggle. When `false`, session-end Phase 3.6.8 is a silent no-op — the reconciliation engine never runs. When `true`, the engine evaluates learnings that meet `confidence-floor` and presents rule proposals to the operator via `AskUserQuestion`. Rules are never written without explicit operator approval. Epic #693 FA3 (#696). |
|
|
1217
1238
|
| `reconcile.mode` | string (`warn` \| `off`) | `warn` | Advisory posture. `warn`: proposals surface in the session-end AUQ and the operator may accept or reject each one; accepted proposals are written to `targets`. `off`: advisory surface is suppressed entirely (equivalent to `enabled: false` for the AUQ step, but Phase 3.6.8 may still emit metrics). In both modes, rules are **never** auto-applied — every write is operator-AUQ-gated. |
|
|
1218
|
-
| `reconcile.targets` | string[] | `["repo-local"]` | Where approved rules are written
|
|
1239
|
+
| `reconcile.targets` | string[] | `["repo-local"]` | Where approved rules are written — a **CLOSED enum**: `repo-local` → `<repoRoot>/.claude/rules/<slug>.md`; `baseline` (#1099) → `<baselineRoot>/proposals/<slug>.md`, where `<baselineRoot>` is `plan-baseline-path` resolved host-locally (`SO_BASELINE_PATH` env > `owner.yaml` `paths.baseline-path` > committed value). Both targets are equally AUQ-gated and advisory — the `baseline` write drops files into `proposals/` in that checkout and commits nothing. This is the rule-write location — it is NOT issue-state or label sync. An **unknown member is DROPPED with a stderr WARN** naming it and the valid set (`scripts/lib/config/reconcile.mjs` `VALID_TARGETS`), never a throw: the parser is tolerant by contract and runs at session-start, where a throw would fail the session on a config typo. `global` (cross-repo) is documented-but-unimplemented and is deliberately NOT a member — admitting a value nothing implements is the same defect class as the unvalidated pass-through this enum replaced. When `baseline` is declared but its root is unresolvable on all three tiers, is still the committed `OVERRIDE-IN-…` placeholder, or is not absolute, `resolveEffectiveTargets()` (`scripts/lib/reconcile/engine.mjs`) drops it with ONE WARN **before** the approval AUQ, so the operator is never asked to approve a write to a destination that cannot exist; a root that does not exist on disk is refused at the writer and is never created. |
|
|
1219
1240
|
| `reconcile.rule-expiry-days` | integer \| null | `null` | Optional override for the TTL stamped into each generated rule's `expires-at` frontmatter. **Default is `null`** — when null or absent, the engine uses per-type TTL (`deriveExpiresAt`, default 60 days). Setting this to a positive integer N forces a flat N-day expiry for all proposals in this repo, overriding per-type TTL. CRITICAL: the default must remain `null` to preserve per-type TTL behaviour; a non-null committed default would silently force flat expiry. |
|
|
1220
1241
|
| `reconcile.confidence-floor` | float | `0.5` | Minimum learning confidence (0.0..1.0) required before a learning is eligible for a rule proposal. Learnings with `confidence < confidence-floor` are skipped by the engine. Bounds: `0.0 ≤ value ≤ 1.0`; out-of-range values silently fall back to `0.5`. Set to `0.0` to surface proposals for all learnings regardless of confidence. |
|
|
1221
1242
|
| `reconcile.min-rule-days` | integer | `7` | Floor (in days) applied to the emitted rule's `expires-at` — issue #741.1. A learning close to its natural per-type TTL expiry could otherwise generate a rule that expires almost immediately ("born-dead"); `computeExpiresAt()` (`scripts/lib/reconcile/emitter.mjs`) floors the result at `now + min-rule-days` so an approved rule always has at least this many days of active life. Mirrors the hardcoded `MIN_RULE_DAYS_DEFAULT` constant in the emitter. Bounds: positive integer; non-finite or ≤0 values fall back to the default. |
|
|
@@ -1539,7 +1560,7 @@ When any condition is false, the full 5-wave flow runs as before — the check i
|
|
|
1539
1560
|
|
|
1540
1561
|
### What changes when express path is active
|
|
1541
1562
|
|
|
1542
|
-
- **session-start:** After Phase 8 Q&A, emits `"Express path activated — N tasks, coordinator-direct, no inter-wave checks."` banner
|
|
1563
|
+
- **session-start:** After Phase 8 Q&A, Phase 8.5 runs `node scripts/express-path.mjs` (the canonical caller — it makes the decision and records `orchestrator.express_path.evaluated` on refusal as well as activation, #1146), which emits the `"Express path activated — N tasks, coordinator-direct, no inter-wave checks."` banner. Tasks are then executed directly as the coordinator. session-plan is called but receives the express-path signal.
|
|
1543
1564
|
- **session-plan:** Detects the banner in conversation context and emits a minimal 1-wave `coordinator-direct` plan (0 agents dispatched). Skips all role decomposition, complexity scoring, and wave splitting.
|
|
1544
1565
|
- **STATE.md:** Activation is logged in the `## Deviations` section for traceability.
|
|
1545
1566
|
- **Inter-wave checkpoints:** Skipped entirely — no Discovery → Impl-Core → Quality pipeline.
|
|
@@ -1563,6 +1584,7 @@ Set `express-path.enabled: false` when:
|
|
|
1563
1584
|
| `housekeeping` | 1–3 | `true` | Yes | No — parallel agents required |
|
|
1564
1585
|
|
|
1565
1586
|
**Related skills and files:**
|
|
1587
|
+
- `scripts/express-path.mjs` — the CLI Phase 8.5 runs; `scripts/lib/express-path.mjs` holds the decision + its `orchestrator.express_path.evaluated` record
|
|
1566
1588
|
- `skills/session-start/SKILL.md` — Phase 8.5: Express Path Evaluation (activation logic + banner)
|
|
1567
1589
|
- `skills/session-plan/SKILL.md` — Express Path Short-Circuit section (1-wave plan emission)
|
|
1568
1590
|
- GitLab issue `#214` (foundation and codification)
|
|
@@ -410,7 +410,7 @@ Opt-in config foundation for the FA3 (#696) advisory rule-proposal delivery at s
|
|
|
410
410
|
reconcile:
|
|
411
411
|
enabled: false # opt-in; FA3 reads this to gate session-end Phase 3.6.8
|
|
412
412
|
mode: warn # off | warn — advisory only; rules NEVER auto-applied (#696)
|
|
413
|
-
targets: [repo-local] #
|
|
413
|
+
targets: [repo-local] # closed enum: repo-local = .claude/rules/ · baseline = <plan-baseline-path>/proposals/ (#1099)
|
|
414
414
|
rule-expiry-days: null # null = per-type TTL (default 60d); set positive integer for flat override (#697)
|
|
415
415
|
confidence-floor: 0.5 # float 0.0..1.0 — min learning confidence for rule proposal eligibility
|
|
416
416
|
min-rule-days: 7 # #741.1 — floor for emitted rule expires-at: max(derived, now + N days); prevents born-dead rules
|
|
@@ -425,6 +425,7 @@ Field semantics:
|
|
|
425
425
|
- **`confidence-floor`** — learnings below this confidence level are not eligible for rule proposals. Default 0.5 matches `memory.proposals.confidence-floor`.
|
|
426
426
|
- **`min-rule-days`** — floor window (days) applied to a proposed rule's `expires-at` so a near-dead or already-elapsed natural expiry never produces a born-dead rule. Positive integer; malformed or ≤0 falls back to 7 (issue #741.1).
|
|
427
427
|
- **`min-insight-chars`** — opt-in minimum insight length gating the eligibility placeholder-insight check; rejects a learning whose trimmed insight is shorter than N characters before rule conversion. Integer ≥ 0; `0` disables the check (issue #741.2).
|
|
428
|
+
- **`targets`** — CLOSED enum, `repo-local` | `baseline` (issue #1099). `repo-local` writes `<repoRoot>/.claude/rules/<slug>.md`; `baseline` writes `<baselineRoot>/proposals/<slug>.md`, where `<baselineRoot>` is `plan-baseline-path` resolved host-locally (`SO_BASELINE_PATH` env > `owner.yaml` `paths.baseline-path` > committed value). Both are AUQ-gated and advisory — the baseline write commits nothing in that repo. An unknown member is dropped with a stderr WARN naming it and the valid set; `global` is documented-but-unimplemented and is NOT a member. A `baseline` target whose root is unresolvable, is still an `OVERRIDE-IN-…` placeholder, is not absolute, or does not exist on disk degrades to a no-op with a WARN — the root is never created.
|
|
428
429
|
|
|
429
430
|
Read by: `scripts/lib/config/reconcile.mjs` (parser), `skills/session-end/SKILL.md` Phase 3.6.8 (FA3 delivery). FA2 engine: `scripts/lib/reconcile/`.
|
|
430
431
|
|
|
@@ -604,9 +605,9 @@ webhooks:
|
|
|
604
605
|
url: https://gitlab.example.com/hooks/pipeline
|
|
605
606
|
```
|
|
606
607
|
|
|
607
|
-
|
|
608
|
+
Measured: `scripts/lib/webhook-url.mjs` (`resolveWebhookUrl`) is the only reader of this `webhooks:` block, and it currently has **zero callers repo-wide** (`grep -rn "webhook-url" scripts/ hooks/` outside itself and one exemption comment in `check-unwired-features.mjs`) — the block is unreachable at HEAD; follow-up issue pending.
|
|
608
609
|
|
|
609
|
-
|
|
610
|
+
What actually fires a webhook today is a **separate** mechanism: `scripts/lib/events.mjs`'s `emitEvent()` reads `CLANK_EVENT_SECRET` + `CLANK_EVENT_URL` directly from the environment (never from this Session Config block) and, when both are set, fire-and-forget POSTs every emitted event to the internal Clank Event Bus. Every hook that calls `emitEvent()` — which is most of `hooks/` — participates in that path; none of them reads `webhooks:` here.
|
|
610
611
|
|
|
611
612
|
## Hook Runtime Profile (env-only, not config)
|
|
612
613
|
|
package/docs/telemetry.md
CHANGED
|
@@ -84,6 +84,16 @@ Precedence, highest wins:
|
|
|
84
84
|
headless or CI invocation never shows this prompt and never sends
|
|
85
85
|
telemetry, regardless of any saved state.
|
|
86
86
|
|
|
87
|
+
The prompt is triggered **mechanically**: `hooks/on-session-start.mjs` calls
|
|
88
|
+
`resolveConsent()` on every session start and, only when no decision is on
|
|
89
|
+
record and the run is not CI, injects a one-line instruction into the session
|
|
90
|
+
via `hookSpecificOutput.additionalContext` — riding the same single stdout
|
|
91
|
+
envelope as the host banner. The skill phase that describes the question
|
|
92
|
+
(`skills/session-start/SKILL.md` § Phase 6.8) is the wording, not the trigger.
|
|
93
|
+
The CI check is `isCiEnv()`, deliberately **not** `isHeadless()`: a hook's
|
|
94
|
+
stdout is always a pipe, so `isHeadless()` would answer "headless" every time
|
|
95
|
+
and the prompt could never appear (#1138).
|
|
96
|
+
|
|
87
97
|
If the consent file is corrupt or unreadable, the client fails **closed**:
|
|
88
98
|
telemetry state degrades to "no consent" (nothing sent) rather than
|
|
89
99
|
guessing, with a one-line stderr hint pointing at the CLI below.
|
|
@@ -129,6 +139,18 @@ unreachable, the batch queues locally (bounded size, oldest entries dropped
|
|
|
129
139
|
first) and retries later. Telemetry never blocks or slows down a session
|
|
130
140
|
beyond that short timeout budget.
|
|
131
141
|
|
|
142
|
+
**When a send is attempted.** `hooks/on-session-end.mjs` calls `flush()` at the
|
|
143
|
+
end of every session teardown — including sessions that never run `/close`. The
|
|
144
|
+
`skills/session-end/SKILL.md` § Phase 3.45 description documents the behaviour;
|
|
145
|
+
the hook is what fires it. Each attempt writes one
|
|
146
|
+
`orchestrator.telemetry.flush` breadcrumb (`{outcome, reason}` only — no
|
|
147
|
+
payload, no `anon_id`) to the repo's local `events.jsonl`, so the send rate is
|
|
148
|
+
measurable rather than assumed. A second, `Skill`-triggered daily fallback
|
|
149
|
+
sends when more than 24h have passed since the last successful flush AND either
|
|
150
|
+
the offline queue is non-empty or a session has completed since — the latter
|
|
151
|
+
clause is what lets the fallback originate a ping instead of only retrying a
|
|
152
|
+
failed one (#1138).
|
|
153
|
+
|
|
132
154
|
## Retention
|
|
133
155
|
|
|
134
156
|
- **Raw records:** kept 24 months, then pruned. The retention window exists
|
|
@@ -89,8 +89,9 @@ export async function bootstrapLock({
|
|
|
89
89
|
}
|
|
90
90
|
|
|
91
91
|
// Step 1: try to acquire. If a fresh acquire succeeds, we are done.
|
|
92
|
-
// If a stale-
|
|
93
|
-
//
|
|
92
|
+
// If a stale-heartbeat lock exists, force-overwrite it (the prior session
|
|
93
|
+
// stopped heartbeating past its ttl; the current raw owner can take the
|
|
94
|
+
// worktree).
|
|
94
95
|
// Only an exact match of the existing physical raw sessionId permits the
|
|
95
96
|
// same-session force-refresh. semantic_session_id, STATE.md `session`, and
|
|
96
97
|
// an owner proof never make a different raw id the same owner.
|
|
@@ -107,8 +108,11 @@ export async function bootstrapLock({
|
|
|
107
108
|
|
|
108
109
|
const shouldForce =
|
|
109
110
|
acquireResult.ok !== true && (
|
|
110
|
-
|
|
111
|
-
|
|
111
|
+
// #1137: 'stale-heartbeat' replaced the former 'stale-pid-dead' /
|
|
112
|
+
// 'stale-pid-alive' pair. Both legacy spellings are gone from
|
|
113
|
+
// session-lock.mjs; matching only the new one keeps this force-branch
|
|
114
|
+
// reachable.
|
|
115
|
+
acquireResult.reason === 'stale-heartbeat' ||
|
|
112
116
|
(acquireResult.reason === 'active' &&
|
|
113
117
|
acquireResult.existingLock &&
|
|
114
118
|
acquireResult.existingLock.session_id === sessionId)
|