@event4u/agent-config 8.7.0 → 8.9.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.
Files changed (171) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/CHANGELOG.md +109 -222
  3. package/CONTRIBUTING.md +25 -0
  4. package/README.md +7 -4
  5. package/dist/agent-src/commands/agent-handoff.md +39 -2
  6. package/dist/agent-src/commands/research/deep.md +8 -0
  7. package/dist/agent-src/commands/research/report.md +7 -0
  8. package/dist/agent-src/commands/roadmap/create.md +12 -0
  9. package/dist/agent-src/commands/roadmap/process-full.md +31 -5
  10. package/dist/agent-src/contexts/communication/rules-auto/think-before-action-mechanics.md +30 -1
  11. package/dist/agent-src/contexts/execution/auto-orchestration-activation.md +1 -1
  12. package/dist/agent-src/contexts/execution/orchestration-benchmark-gate.md +28 -16
  13. package/dist/agent-src/contexts/execution/orchestration-telemetry.md +36 -5
  14. package/dist/agent-src/contexts/execution/roadmap-process-loop.md +37 -0
  15. package/dist/agent-src/contexts/execution/subagent-topologies.md +34 -0
  16. package/dist/agent-src/contexts/execution/verification-mechanics.md +9 -9
  17. package/dist/agent-src/rules/active-remediation.md +92 -0
  18. package/dist/agent-src/rules/agent-authority.md +1 -1
  19. package/dist/agent-src/rules/broken-access-control.md +106 -0
  20. package/dist/agent-src/rules/communication-through-line.md +42 -0
  21. package/dist/agent-src/rules/decision-revisit-gate.md +8 -0
  22. package/dist/agent-src/rules/delegation-policy.md +5 -0
  23. package/dist/agent-src/rules/direct-answers.md +1 -1
  24. package/dist/agent-src/rules/downstream-changes.md +1 -0
  25. package/dist/agent-src/rules/external-code-graph-interop.md +65 -0
  26. package/dist/agent-src/rules/git-history-discipline.md +18 -0
  27. package/dist/agent-src/rules/lethal-trifecta-guard.md +6 -1
  28. package/dist/agent-src/rules/minimal-safe-diff.md +66 -1
  29. package/dist/agent-src/rules/non-destructive-by-default.md +3 -0
  30. package/dist/agent-src/rules/prefer-enums-over-literals.md +65 -0
  31. package/dist/agent-src/rules/question-not-instruction.md +76 -0
  32. package/dist/agent-src/rules/senior-engineering-discipline.md +82 -0
  33. package/dist/agent-src/rules/think-before-action.md +1 -0
  34. package/dist/agent-src/rules/tool-safety.md +8 -0
  35. package/dist/agent-src/rules/untrusted-input-defense.md +87 -22
  36. package/dist/agent-src/scripts/update_roadmap_progress.ts +2 -1
  37. package/dist/agent-src/skills/accessibility-auditor/SKILL.md +19 -0
  38. package/dist/agent-src/skills/ai-code-blindspots/SKILL.md +112 -0
  39. package/dist/agent-src/skills/ai-code-blindspots/evals/triggers.json +52 -0
  40. package/dist/agent-src/skills/authz-review/SKILL.md +21 -4
  41. package/dist/agent-src/skills/code-review/SKILL.md +2 -0
  42. package/dist/agent-src/skills/command-writing/SKILL.md +53 -40
  43. package/dist/agent-src/skills/dcf-modeling/evals/domain-truth.json +29 -0
  44. package/dist/agent-src/skills/deep-reading-analyst/SKILL.md +1 -0
  45. package/dist/agent-src/skills/dependency-upgrade/SKILL.md +20 -0
  46. package/dist/agent-src/skills/design-intelligence/SKILL.md +49 -12
  47. package/dist/agent-src/skills/design-review/SKILL.md +29 -15
  48. package/dist/agent-src/skills/design-system-capture/SKILL.md +63 -24
  49. package/dist/agent-src/skills/forecasting/evals/domain-truth.json +29 -0
  50. package/dist/agent-src/skills/frontend-render-security/SKILL.md +104 -0
  51. package/dist/agent-src/skills/frontend-render-security/evals/triggers.json +52 -0
  52. package/dist/agent-src/skills/markitdown/SKILL.md +1 -0
  53. package/dist/agent-src/skills/mcp/SKILL.md +24 -0
  54. package/dist/agent-src/skills/mcp-builder/SKILL.md +9 -1
  55. package/dist/agent-src/skills/memory-consolidation/SKILL.md +55 -4
  56. package/dist/agent-src/skills/roadmap-writing/SKILL.md +46 -5
  57. package/dist/agent-src/skills/runway-cognition/evals/domain-truth.json +29 -0
  58. package/dist/agent-src/skills/scenario-modeling/evals/domain-truth.json +29 -0
  59. package/dist/agent-src/skills/secrets-management/SKILL.md +7 -0
  60. package/dist/agent-src/skills/skill-writing/SKILL.md +12 -3
  61. package/dist/agent-src/skills/subagent-orchestration/SKILL.md +27 -33
  62. package/dist/agent-src/skills/supply-chain-intake/SKILL.md +112 -0
  63. package/dist/agent-src/skills/supply-chain-intake/evals/triggers.json +52 -0
  64. package/dist/agent-src/skills/testing-anti-patterns/SKILL.md +72 -2
  65. package/dist/agent-src/skills/ui-component-architect/SKILL.md +9 -0
  66. package/dist/agent-src/skills/unit-economics-modeling/evals/domain-truth.json +40 -0
  67. package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
  68. package/dist/agent-src/templates/roadmaps.md +60 -0
  69. package/dist/cli/registry.js +3 -0
  70. package/dist/cli/registry.js.map +1 -1
  71. package/dist/discovery/deprecation-report.md +1 -1
  72. package/dist/discovery/discovery-manifest.json +268 -46
  73. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  74. package/dist/discovery/discovery-manifest.summary.md +4 -4
  75. package/dist/discovery/orphan-report.md +1 -1
  76. package/dist/discovery/packs.json +18 -8
  77. package/dist/discovery/trust-report.md +11 -11
  78. package/dist/discovery/workspaces.json +16 -6
  79. package/dist/install/install.mjs +141 -3
  80. package/dist/mcp/awesome-mcp-servers.row.md +1 -1
  81. package/dist/mcp/mcp-cloudflare-catalogue.json +1 -1
  82. package/dist/mcp/registry-manifest.json +4 -4
  83. package/dist/router.json +1 -1
  84. package/dist/scripts/_lib/claude_builtin_names.js +145 -0
  85. package/dist/scripts/_lib/claude_builtin_names.js.map +1 -0
  86. package/dist/scripts/condense.js +14 -0
  87. package/dist/scripts/condense.js.map +1 -1
  88. package/dist/server/schemas/settings.js +2 -1
  89. package/dist/server/schemas/settings.js.map +1 -1
  90. package/docs/CLAIMS.md +58 -2
  91. package/docs/architecture.md +3 -3
  92. package/docs/archive/CHANGELOG-pre-8.9.0.md +306 -0
  93. package/docs/benchmark.md +113 -0
  94. package/docs/catalog.md +32 -5
  95. package/docs/contracts/command-clusters.md +18 -0
  96. package/docs/contracts/design-artifact-verification.md +124 -0
  97. package/docs/contracts/injected-block-authenticity-model.md +66 -0
  98. package/docs/contracts/mcp-tool-inventory.md +31 -30
  99. package/docs/decisions/ADR-061-corpus-grounding-layer.md +13 -0
  100. package/docs/decisions/ADR-105-automatic-subagent-orchestration.md +6 -0
  101. package/docs/decisions/ADR-116-memory-tripwire-activation-path.md +11 -2
  102. package/docs/decisions/ADR-117-subagents-auto-default-on.md +88 -0
  103. package/docs/decisions/INDEX.md +1 -0
  104. package/docs/experiences/content_creator.md +2 -0
  105. package/docs/experiences/finance.md +2 -0
  106. package/docs/experiences/founder.md +2 -0
  107. package/docs/experiences/ops.md +2 -0
  108. package/docs/featured-skills.md +2 -2
  109. package/docs/getting-started-by-role.md +1 -1
  110. package/docs/getting-started.md +1 -1
  111. package/docs/governance-advantage.md +1 -1
  112. package/docs/guidelines/agent-infra/asking-and-brevity-examples.md +27 -0
  113. package/docs/guidelines/agent-infra/emphasis-budget.md +45 -0
  114. package/docs/guidelines/agent-infra/memory-access.md +12 -0
  115. package/docs/guidelines/agent-infra/simplicity-and-goal-demos.md +151 -0
  116. package/docs/guidelines/agent-infra/tool-description-as-policy.md +35 -0
  117. package/docs/guidelines/design-canon.md +1 -0
  118. package/docs/proof.md +60 -3
  119. package/docs/release-runbook.md +138 -0
  120. package/docs/second-brain-scope.md +116 -0
  121. package/docs/succession.md +80 -0
  122. package/package.json +2 -2
  123. package/src/agent-src/scripts/update_roadmap_progress.ts +2 -1
  124. package/src/config/agent-settings.template.yml +25 -6
  125. package/src/scripts/_dispatch.bash +27 -0
  126. package/src/scripts/_lib/claude_builtin_names.ts +148 -0
  127. package/src/scripts/_lib/file_slicer.ts +117 -0
  128. package/src/scripts/_lib/lexical_index.ts +155 -0
  129. package/src/scripts/_lib/orchestration_gate.ts +12 -8
  130. package/src/scripts/_lib/orchestration_record.ts +170 -0
  131. package/src/scripts/_lib/orchestration_savings.ts +180 -0
  132. package/src/scripts/_lib/retrieval_sanitize.ts +71 -0
  133. package/src/scripts/_lib/security_lint.ts +1 -0
  134. package/src/scripts/_lib/stat_index.ts +98 -0
  135. package/src/scripts/benchmark.ts +122 -0
  136. package/src/scripts/build_proof.ts +51 -0
  137. package/src/scripts/chat_history.ts +79 -7
  138. package/src/scripts/check_memory.ts +2 -0
  139. package/src/scripts/check_quality_regression.ts +51 -0
  140. package/src/scripts/check_roadmap_trackable.ts +3 -2
  141. package/src/scripts/condense.ts +14 -0
  142. package/src/scripts/discovery_graph.ts +0 -0
  143. package/src/scripts/domain_soundness_status.ts +236 -0
  144. package/src/scripts/external_sources_denylist.json +4 -1
  145. package/src/scripts/generate_index.ts +17 -0
  146. package/src/scripts/hot_context_hook.ts +47 -2
  147. package/src/scripts/install-hooks.sh +25 -0
  148. package/src/scripts/install.ts +35 -2
  149. package/src/scripts/learning_sidecar.ts +0 -0
  150. package/src/scripts/lint_agent_skill_names.ts +29 -0
  151. package/src/scripts/lint_behavioural_eval_freshness.ts +140 -0
  152. package/src/scripts/lint_knowledge_scale.ts +4 -3
  153. package/src/scripts/lint_roadmap_complexity.ts +124 -0
  154. package/src/scripts/lint_versioned_cache.ts +195 -0
  155. package/src/scripts/mcp_server/consumer_tool_catalog.json +23 -3
  156. package/src/scripts/mcp_server/tools.ts +182 -1
  157. package/src/scripts/measure_lexical_ranking.ts +173 -0
  158. package/src/scripts/memory_lookup.ts +0 -0
  159. package/src/scripts/memory_replay.ts +285 -0
  160. package/src/scripts/orchestration_record.ts +140 -0
  161. package/src/scripts/orchestration_savings_report.ts +124 -0
  162. package/src/scripts/schemas/domain-truth.schema.json +94 -0
  163. package/src/scripts/schemas/evals.schema.json +113 -0
  164. package/src/scripts/schemas/skill.schema.json +4 -0
  165. package/src/scripts/score_domain_truth.ts +192 -0
  166. package/src/scripts/second_brain_retrieval.ts +278 -0
  167. package/src/scripts/second_brain_run.ts +341 -0
  168. package/src/scripts/second_brain_score.ts +186 -0
  169. package/src/scripts/session_memory_index.ts +94 -0
  170. package/src/scripts/skill_eval_coverage.ts +318 -0
  171. package/src/server/schemas/settings.ts +5 -2
@@ -0,0 +1,80 @@
1
+ # Succession — the minimal knowledge to take over
2
+
3
+ > **Bus-factor doc (road-to-maintainer-bus-factor Phase 3).** If the maintainer
4
+ > is unavailable, this is what a successor needs to keep `main` healthy and cut
5
+ > releases. **No secret values live here — pointers only.** Companion:
6
+ > [`release-runbook.md`](release-runbook.md) (the how-to-release steps).
7
+
8
+ ## Honest bus-factor (tracked, not inflated)
9
+
10
+ - **Distinct humans who have reviewed/merged in the trailing 90 days: 1** (the
11
+ maintainer, `@matze4u`). The project is a single-maintainer repo; an AI
12
+ self-review gate (deferred — see the roadmap Phase 1) raises the floor but is
13
+ **not** independent human review.
14
+ - Recompute this number honestly at any time:
15
+
16
+ ```bash
17
+ # merged PRs in the last 90 days + who reviewed them
18
+ gh pr list --state merged --search "merged:>=$(date -v-90d +%Y-%m-%d 2>/dev/null || date -d '90 days ago' +%Y-%m-%d)" \
19
+ --json number,author,reviews \
20
+ --jq '[.[] | .reviews[]?.author.login] | unique'
21
+ ```
22
+
23
+ Report the count as-is. A bus-factor of 1 stated plainly beats a bus-factor of
24
+ 1 implied to be more.
25
+
26
+ ## Secrets / tokens — where they live, what they gate
27
+
28
+ Configured in **GitHub → Settings → Secrets and variables → Actions** (repo
29
+ secrets), never in the tree. None is required for the *core* release (version
30
+ bump + tag + GitHub Release); they gate the **downstream** publish/deploy legs.
31
+
32
+ | Secret | Gates | Missing → |
33
+ |---|---|---|
34
+ | `RELEASE_PR_TOKEN` (optional PAT / App token, `contents:write` + `pull-requests:write`) | Unattended release PR checks in [`release.yml`](../.github/workflows/release.yml) | One manual **"Approve workflows to run"** click per release (deliberate checkpoint, not a failure). |
35
+ | — (none: **npm OIDC Trusted Publishing**) | `publish-npm.yml` — uses `id-token: write`, no stored npm token | If OIDC trust is misconfigured on npmjs, npm publish fails; fix the trusted-publisher config on the npm package, not a secret. |
36
+ | `CLOUDFLARE_ACCOUNT_ID`, `CLOUDFLARE_API_TOKEN`, `CLOUDFLARE_WORKER_SUBDOMAIN`, `MCP_SMOKE_TOKEN` | `deploy-mcp-worker.yml` (MCP worker deploy + smoke) | MCP worker deploy skips/fails; core release unaffected. |
37
+ | `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, `GEMINI_API_KEY` | `cross-model-canary.yml` + any AI-council / self-review automation | Canary + council automation skip; core release unaffected. |
38
+ | `GITHUB_TOKEN` (auto-provided) | all workflows' default auth | n/a — GitHub injects it. |
39
+
40
+ The live source of truth for which workflow needs which secret is the
41
+ `secrets.*` references in [`.github/workflows/`](../.github/workflows/) — grep
42
+ there if this table drifts:
43
+
44
+ ```bash
45
+ grep -rhoE "secrets\.[A-Z_]+" .github/workflows/ | sort -u
46
+ ```
47
+
48
+ ## Operator-gated steps (need a human with credentials)
49
+
50
+ - **Release-PR workflow approval** — the "Approve workflows to run" click when
51
+ `RELEASE_PR_TOKEN` is absent (see the runbook § 3.A).
52
+ - **Branch-protection ruleset** — applied in GitHub → Settings → Rules UI;
53
+ source of truth mirrored in [`branch-protection-policy.md`](contracts/branch-protection-policy.md).
54
+ Not in code; a successor edits it in the UI.
55
+ - **Repo administration** (visibility / rename / delete) — the
56
+ `production-visibility` environment gates manual approval; see
57
+ [`CONTRIBUTING.md`](../CONTRIBUTING.md).
58
+ - **npm trusted-publisher config** — set on npmjs.org for the package, not in
59
+ this repo.
60
+
61
+ ## "Healthy main" — what good looks like
62
+
63
+ - Latest `main` commit is green on all required checks for its PR shape
64
+ (see [`branch-protection-policy.md`](contracts/branch-protection-policy.md),
65
+ [`ci-green-floor.md`](contracts/ci-green-floor.md)).
66
+ - No drift gate red: `release-drift.yml`, `release-guard.yml`,
67
+ `check-visibility-drift.yml`, the consistency + claims + proof gates.
68
+ - `docs/CLAIMS.md` resolves (`task check-claims`); `docs/proof.md` is in sync
69
+ (`task build-proof-check`).
70
+ - No completed roadmap left unarchived in `agents/roadmaps/` (the
71
+ `roadmap:progress-check` backstop).
72
+
73
+ ## Minimal takeover checklist
74
+
75
+ 1. Get `gh` authenticated as a repo admin; confirm `gh auth status`.
76
+ 2. Read [`release-runbook.md`](release-runbook.md) end-to-end.
77
+ 3. Confirm the secrets above are present for whichever downstream legs matter.
78
+ 4. Cut a `--dry-run` release (`task release -- --dry-run`) to see the pipeline
79
+ with zero mutations.
80
+ 5. When ready, follow the runbook for a real release.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@event4u/agent-config",
3
- "version": "8.7.0",
3
+ "version": "8.9.0",
4
4
  "description": "Universal AI Agent OS — audited skills, governance rules, commands, and templates for AI coding tools (Claude Code, Cursor, Windsurf, Copilot).",
5
5
  "license": "MIT",
6
6
  "private": false,
@@ -12,7 +12,7 @@
12
12
  "bugs": {
13
13
  "url": "https://github.com/event4u-app/agent-config/issues"
14
14
  },
15
- "homepage": "https://github.com/event4u-app/agent-config#readme",
15
+ "homepage": "https://event4u-app.github.io/agent-config",
16
16
  "keywords": [
17
17
  "ai-agent",
18
18
  "mcp",
@@ -67,8 +67,9 @@ const _require = createRequire(import.meta.url);
67
67
  // CHECKBOX_RE = re.compile(r"^\s*[-*]\s+\[([ xX~\-])\]\s", re.MULTILINE)
68
68
  const CHECKBOX_RE = /^[ \t\n\r\f\v]*[-*][ \t\n\r\f\v]+\[([ xX~\-])\][ \t\n\r\f\v]/gm;
69
69
  // PHASE_RE (MULTILINE) — H2/H3 "Phase <id>" with optional separator + name.
70
+ // Numeric ids accept dotted sub-phases ("1.0", "4.1", "2.3.1").
70
71
  const PHASE_RE =
71
- /^(#{2,3})[ \t\n\r\f\v]+Phase[ \t\n\r\f\v]+(\d+[a-z]?|[IVX]+|[A-Z](?:\d+)?)(?:[\s:—\-]+([\s\S]*?))?[ \t\f\v\r]*$/gm;
72
+ /^(#{2,3})[ \t\n\r\f\v]+Phase[ \t\n\r\f\v]+(\d+(?:\.\d+)*[a-z]?|[IVX]+|[A-Z](?:\d+)?)(?:[\s:—\-]+([\s\S]*?))?[ \t\f\v\r]*$/gm;
72
73
  // TITLE_RE = re.compile(r"^#\s+(?:Roadmap:\s*)?(.+?)\s*$", re.MULTILINE)
73
74
  const TITLE_RE = /^#[ \t\n\r\f\v]+(?:Roadmap:[ \t\n\r\f\v]*)?(.+?)[ \t\f\v\r]*$/m;
74
75
  const EXCLUDE_NAMES: ReadonlySet<string> = new Set([
@@ -524,13 +524,21 @@ subagents:
524
524
  # on = auto-dispatch delegable tasks without asking (surface the choice
525
525
  # in one line).
526
526
  #
527
- # Initial SHIPPED default is `ask` on hosts whose capability manifest reports
527
+ # SHIPPED default is `on` on hosts whose capability manifest reports
528
528
  # `subagent_spawn: true`, and `off` on hosts without a subagent primitive.
529
- # The shipped default flips toward `on` (host-gated) only behind the Phase-6
530
- # benchmark gate of road-to-auto-subagent-orchestration.md — never on an
531
- # unmeasured claim. Auto-dispatch is also a no-op wherever the host manifest
532
- # reports `subagent_spawn: false`, regardless of this value.
533
- auto: ask
529
+ # Auto-dispatch stays a no-op wherever the manifest reports
530
+ # `subagent_spawn: false`, regardless of this value.
531
+ #
532
+ # The default was `ask` until 2026-07-09, when it was flipped to `on` after a
533
+ # re-evaluation (agents/settings/contexts/orchestration-default-flip-verdict.md
534
+ # § 2026-07-09; ADR-117). The flip rests on a bounded-downside argument, NOT a
535
+ # passed benchmark: delegable slices are already cost-routed to the cheapest
536
+ # capable tier, classification fires only on real structural signals (never
537
+ # unstructured or tiny work), and every return is verified — so `on` cannot
538
+ # delegate frontier-priced or speculative work. `resolveShippedDefault()`
539
+ # remains the telemetry-driven DEMOTION gate: a measured regression demotes
540
+ # back to `ask`.
541
+ auto: on
534
542
 
535
543
  # Route delegable sub-tasks to the lowest-capable model tier (cost + speed
536
544
  # via model downshift). true (default) = downshift per declared model_tier;
@@ -695,6 +703,17 @@ memory:
695
703
  # Example: ["api[_-]?key", "/Users/[a-z]+/Library"]
696
704
  redact_patterns: []
697
705
 
706
+ # Opt-in compact memory index at session start
707
+ # (road-to-memory-retrieval-economy Phase 5). When `on`, session_start
708
+ # injects a compact index of curated entries — id + title + ~tokens,
709
+ # hard cap 30 rows — through the hot-context hook surface. Bodies are
710
+ # never injected; the model fetches full entries via memory_get on
711
+ # demand. Default OFF: the ship-criterion (measured hit-rate gain at
712
+ # bounded fixed cost) is unproven — off unless proven.
713
+ # off = (default) no session-start index.
714
+ # on = inject the compact index (spotlighted as DATA).
715
+ session_index: "off"
716
+
698
717
  # --- Knowledge cards: global cross-project sharing (ADR-100) ---
699
718
  #
700
719
  # Structure-grounding v2. Promote *expensive* (remote) knowledge cards from
@@ -167,6 +167,12 @@ Tier 2 — maintenance / internal (hooks, MCP, memory, telemetry):
167
167
  mcp:run Run the built-in MCP server over stdio
168
168
  (requires `mcp:setup` first; see docs/mcp-server.md)
169
169
  (experimental — beta gates: docs/contracts/mcp-beta-criteria.md)
170
+ affected Show artefacts related to <artefact> via the discovery
171
+ relation-graph (relation-filtered BFS). Flags: --depth N
172
+ graph-explain Seed on a <concept>, expand 2 hops over the discovery
173
+ relation-graph with a node budget. Flags: --budget N
174
+ benchmark Report context-token reduction vs the full always-loaded
175
+ projection (from the pinned token baseline). Flags: --format
170
176
  roadmap:progress Regenerate agents/roadmaps-progress.md from open roadmaps
171
177
  roadmap:progress-check Fail if agents/roadmaps-progress.md is stale (for CI)
172
178
  roadmap:archive Archive completed roadmaps (branch-touched by default;
@@ -431,6 +437,24 @@ cmd_mcp_render() {
431
437
  exec_ts "$script" "$@"
432
438
  }
433
439
 
440
+ cmd_affected() {
441
+ local script
442
+ script="$(resolve_script "src/scripts/discovery_graph.ts")"
443
+ exec_ts "$script" affected "$@"
444
+ }
445
+
446
+ cmd_graph_explain() {
447
+ local script
448
+ script="$(resolve_script "src/scripts/discovery_graph.ts")"
449
+ exec_ts "$script" explain "$@"
450
+ }
451
+
452
+ cmd_benchmark() {
453
+ local script
454
+ script="$(resolve_script "src/scripts/benchmark.ts")"
455
+ exec_ts "$script" "$@"
456
+ }
457
+
434
458
  cmd_mcp_check() {
435
459
  local script
436
460
  script="$(resolve_script "src/scripts/mcp_render.ts")"
@@ -1031,6 +1055,9 @@ main() {
1031
1055
  mcp:setup) cmd_mcp_setup "$@" ;;
1032
1056
  mcp:run) cmd_mcp_run "$@" ;;
1033
1057
  use) cmd_use "$@" ;;
1058
+ affected) cmd_affected "$@" ;;
1059
+ graph-explain) cmd_graph_explain "$@" ;;
1060
+ benchmark) cmd_benchmark "$@" ;;
1034
1061
  roadmap:progress) cmd_roadmap_progress "$@" ;;
1035
1062
  roadmap:progress-check) cmd_roadmap_progress_check "$@" ;;
1036
1063
  roadmap:archive) cmd_roadmap_archive "$@" ;;
@@ -0,0 +1,148 @@
1
+ // Claude Code built-in command / bundled-skill names — the reserved namespace.
2
+ //
3
+ // A user- or project-scope skill (or flat command) whose name equals a
4
+ // built-in Claude Code slash command SHADOWS the built-in: typing `/mcp`
5
+ // then opens the package's skill instead of Claude Code's MCP auth dialog
6
+ // (observed 2026-07-10). The suite's contract is to complement the host,
7
+ // never to overlay or degrade it — so no Claude-facing projection may claim
8
+ // one of these names.
9
+ //
10
+ // Enforced at three layers:
11
+ // 1. `condense.ts::generate_claude_commands` — project-scope `.claude/skills/`
12
+ // command entries skip reserved slugs.
13
+ // 2. `install.ts::_apply_claude_flat_command_wrappers` — user-scope
14
+ // `~/.claude/` deploys neither a skill wrapper nor a flat command file
15
+ // for a reserved slug (nested `/cluster:sub` commands are unaffected —
16
+ // built-ins carry no `:`).
17
+ // 3. `lint_agent_skill_names.ts` — a skill in `src/skills/` (or a domain
18
+ // pack) with a reserved name fails CI unless it opts out of slash
19
+ // registration with `user-invocable: false` (Claude may still load it
20
+ // automatically; the built-in keeps the `/name`).
21
+ //
22
+ // Source: https://code.claude.com/docs/en/commands (fetched 2026-07-10),
23
+ // plus a small legacy set still present in older Claude Code versions.
24
+ // Refresh trigger: a package artefact stops appearing in Claude Code, or a
25
+ // release-notes entry adds a new built-in command.
26
+
27
+ const _CURRENT = [
28
+ 'add-dir',
29
+ 'advisor',
30
+ 'agents',
31
+ 'autofix-pr',
32
+ 'background',
33
+ 'batch',
34
+ 'branch',
35
+ 'btw',
36
+ 'cd',
37
+ 'chrome',
38
+ 'claude-api',
39
+ 'clear',
40
+ 'code-review',
41
+ 'color',
42
+ 'compact',
43
+ 'config',
44
+ 'context',
45
+ 'copy',
46
+ 'cost',
47
+ 'dataviz',
48
+ 'debug',
49
+ 'deep-research',
50
+ 'design-login',
51
+ 'design-sync',
52
+ 'desktop',
53
+ 'diff',
54
+ 'doctor',
55
+ 'effort',
56
+ 'exit',
57
+ 'export',
58
+ 'fast',
59
+ 'feedback',
60
+ 'fewer-permission-prompts',
61
+ 'focus',
62
+ 'fork',
63
+ 'goal',
64
+ 'heapdump',
65
+ 'help',
66
+ 'hooks',
67
+ 'ide',
68
+ 'init',
69
+ 'insights',
70
+ 'install-github-app',
71
+ 'install-slack-app',
72
+ 'keybindings',
73
+ 'login',
74
+ 'logout',
75
+ 'loop',
76
+ 'mcp',
77
+ 'memory',
78
+ 'mobile',
79
+ 'model',
80
+ 'passes',
81
+ 'permissions',
82
+ 'plan',
83
+ 'plugin',
84
+ 'powerup',
85
+ 'pr-comments',
86
+ 'privacy-settings',
87
+ 'radio',
88
+ 'recap',
89
+ 'release-notes',
90
+ 'reload-plugins',
91
+ 'reload-skills',
92
+ 'remote-control',
93
+ 'remote-env',
94
+ 'rename',
95
+ 'resume',
96
+ 'review',
97
+ 'rewind',
98
+ 'run',
99
+ 'run-skill-generator',
100
+ 'sandbox',
101
+ 'schedule',
102
+ 'scroll-speed',
103
+ 'security-review',
104
+ 'setup-bedrock',
105
+ 'setup-vertex',
106
+ 'simplify',
107
+ 'skills',
108
+ 'stats',
109
+ 'status',
110
+ 'statusline',
111
+ 'stickers',
112
+ 'teleport',
113
+ 'thinking',
114
+ 'trust',
115
+ 'upgrade',
116
+ 'usage',
117
+ 'verify',
118
+ 'vim',
119
+ 'web',
120
+ 'whats-new',
121
+ 'workflow',
122
+ 'workflows',
123
+ 'worktree',
124
+ ] as const;
125
+
126
+ // Retired from the current docs but still registered by older Claude Code
127
+ // versions users may run — reserving them costs nothing (no package artefact
128
+ // uses these names) and avoids version-dependent shadowing.
129
+ const _LEGACY = [
130
+ 'bashes',
131
+ 'bug',
132
+ 'migrate-installer',
133
+ 'output-style',
134
+ 'terminal-setup',
135
+ 'theme',
136
+ 'todos',
137
+ ] as const;
138
+
139
+ /** Lowercase names a Claude-facing `/name` projection must never claim. */
140
+ export const CLAUDE_CODE_BUILTIN_NAMES: ReadonlySet<string> = new Set<string>([
141
+ ..._CURRENT,
142
+ ..._LEGACY,
143
+ ]);
144
+
145
+ /** True when `slug` would shadow a Claude Code built-in command or bundled skill. */
146
+ export function is_claude_builtin_name(slug: string): boolean {
147
+ return CLAUDE_CODE_BUILTIN_NAMES.has(slug.toLowerCase());
148
+ }
@@ -0,0 +1,117 @@
1
+ /**
2
+ * Deterministic document slicer for oversized knowledge ingest
3
+ * (road-to-retrieval-substrate-hardening B8).
4
+ *
5
+ * Splits a large markdown document into bounded slices at the cleanest
6
+ * available boundary — heading > paragraph (blank line) > line — while
7
+ * guaranteeing three invariants a downstream re-assembler can rely on:
8
+ *
9
+ * 1. GAP-FREE + NON-OVERLAPPING — slices cover contiguous line ranges over
10
+ * the whole document, in order.
11
+ * 2. CONCAT == ORIGINAL — joining every slice's `text` in order reproduces
12
+ * the input byte-for-byte (slices are exact offset ranges).
13
+ * 3. PARENTED — every slice carries its source `parentPath` (when given) and
14
+ * its `[startLine, endLine)` range, so a chunk can point home.
15
+ *
16
+ * Deterministic: identical input + budget → identical slices.
17
+ */
18
+
19
+ export interface Slice {
20
+ parentPath: string | null;
21
+ index: number;
22
+ startLine: number; // 0-based, inclusive
23
+ endLine: number; // 0-based, exclusive
24
+ text: string;
25
+ }
26
+
27
+ /** Default per-slice character budget. */
28
+ export const DEFAULT_MAX_CHARS = 2000;
29
+
30
+ function _lineStartOffsets(text: string): number[] {
31
+ const starts = [0];
32
+ for (let i = 0; i < text.length; i++) {
33
+ if (text[i] === '\n') starts.push(i + 1);
34
+ }
35
+ return starts; // one entry per line; starts[k] = offset where line k begins
36
+ }
37
+
38
+ function _isHeading(line: string): boolean {
39
+ return /^#{1,6}\s/.test(line);
40
+ }
41
+ function _isBlank(line: string): boolean {
42
+ return line.trim() === '';
43
+ }
44
+
45
+ /**
46
+ * Slice `text` into ≤ `maxChars` pieces (best-effort — a single over-long line
47
+ * is emitted whole rather than split mid-line, preserving invariant 2).
48
+ * `parentPath` is stamped on every slice.
49
+ */
50
+ export function sliceDocument(
51
+ text: string,
52
+ opts: { maxChars?: number; parentPath?: string } = {},
53
+ ): Slice[] {
54
+ const maxChars = opts.maxChars ?? DEFAULT_MAX_CHARS;
55
+ const parentPath = opts.parentPath ?? null;
56
+ if (text === '') return [];
57
+
58
+ const starts = _lineStartOffsets(text);
59
+ const nLines = starts.length;
60
+ // lineAt(k) = the raw text of line k INCLUDING its trailing newline (if any).
61
+ const lineEnd = (k: number): number => (k + 1 < nLines ? starts[k + 1]! : text.length);
62
+ const lines: string[] = [];
63
+ for (let k = 0; k < nLines; k++) lines.push(text.slice(starts[k]!, lineEnd(k)));
64
+
65
+ const slices: Slice[] = [];
66
+ let sliceStartLine = 0;
67
+ let idx = 0;
68
+ const flush = (endLine: number): void => {
69
+ if (endLine <= sliceStartLine) return;
70
+ const from = starts[sliceStartLine]!;
71
+ const to = endLine < nLines ? starts[endLine]! : text.length;
72
+ slices.push({ parentPath, index: idx++, startLine: sliceStartLine, endLine, text: text.slice(from, to) });
73
+ sliceStartLine = endLine;
74
+ };
75
+
76
+ let curChars = 0;
77
+ for (let k = 0; k < nLines; k++) {
78
+ const lineLen = lines[k]!.length;
79
+ const wouldExceed = curChars + lineLen > maxChars && k > sliceStartLine;
80
+ // Cut BEFORE a heading that opens a new section (clean boundary), or
81
+ // when the budget would overflow — preferring a preceding blank line.
82
+ const headingBoundary = _isHeading(lines[k]!) && k > sliceStartLine;
83
+ if (headingBoundary || wouldExceed) {
84
+ // Prefer to end the previous slice at the last blank line in-range,
85
+ // so a slice ends on a paragraph boundary when one is available.
86
+ let cut = k;
87
+ if (wouldExceed && !headingBoundary) {
88
+ for (let b = k - 1; b > sliceStartLine; b--) {
89
+ if (_isBlank(lines[b]!)) {
90
+ cut = b + 1;
91
+ break;
92
+ }
93
+ }
94
+ }
95
+ flush(cut);
96
+ curChars = 0;
97
+ for (let j = sliceStartLine; j <= k; j++) curChars += lines[j]!.length;
98
+ } else {
99
+ curChars += lineLen;
100
+ }
101
+ }
102
+ flush(nLines);
103
+ return slices;
104
+ }
105
+
106
+ /** True iff the slices reproduce `text` exactly, gap-free and non-overlapping. */
107
+ export function verifySlices(text: string, slices: readonly Slice[]): boolean {
108
+ if (slices.length === 0) return text === '';
109
+ let expectedLine = 0;
110
+ const parts: string[] = [];
111
+ for (const s of slices) {
112
+ if (s.startLine !== expectedLine) return false; // gap or overlap
113
+ expectedLine = s.endLine;
114
+ parts.push(s.text);
115
+ }
116
+ return parts.join('') === text;
117
+ }
@@ -0,0 +1,155 @@
1
+ /**
2
+ * Hand-rolled, dependency-free lexical index for memory/knowledge retrieval
3
+ * (road-to-retrieval-substrate-hardening B2).
4
+ *
5
+ * The current `memory_lookup._score` gives every keyword match the SAME coarse
6
+ * bucket (0.8 glob / 0.6 substring), so several entries tie at the top and
7
+ * retrieval "recalls but does not rank" (the mean-tie-set 3.3 finding from
8
+ * road-to-second-brain-retrieval-precision). This module replaces that bucket
9
+ * with a continuous BM25 score over an IDF-weighted term index, plus a
10
+ * character-trigram candidate prefilter so it stays cheap at corpus scale.
11
+ *
12
+ * It is the BM25 core ADR-061 already sanctions — pure Node stdlib, NO engine
13
+ * fork, NO minisearch-class dependency. `_score` stays as the below-tripwire
14
+ * mini-corpus fallback; this index activates at the `lint_knowledge_scale`
15
+ * tripwire. Deterministic: identical docs + query → identical scores + order.
16
+ */
17
+
18
+ /** BM25 term-frequency saturation. */
19
+ export const BM25_K1 = 1.5;
20
+ /** BM25 length-normalisation strength. */
21
+ export const BM25_B = 0.75;
22
+ /** Minimum token length kept (drops single chars / punctuation noise). */
23
+ export const MIN_TOKEN_LEN = 2;
24
+
25
+ export interface IndexDoc {
26
+ id: string;
27
+ /** All searchable text of the entry, already concatenated. */
28
+ text: string;
29
+ }
30
+
31
+ interface DocStats {
32
+ id: string;
33
+ len: number; // token count
34
+ tf: Map<string, number>; // term → frequency in this doc
35
+ trigrams: Set<string>;
36
+ }
37
+
38
+ /** Lowercase, split on non-alphanumeric, keep tokens ≥ MIN_TOKEN_LEN. */
39
+ export function tokenize(s: string): string[] {
40
+ const out: string[] = [];
41
+ for (const raw of s.toLowerCase().split(/[^a-z0-9]+/)) {
42
+ if (raw.length >= MIN_TOKEN_LEN) out.push(raw);
43
+ }
44
+ return out;
45
+ }
46
+
47
+ /** Character trigrams of a normalised string (alphanumerics + single spaces). */
48
+ export function trigrams(s: string): Set<string> {
49
+ const norm = s.toLowerCase().replace(/[^a-z0-9]+/g, ' ').trim();
50
+ const out = new Set<string>();
51
+ if (norm.length < 3) {
52
+ if (norm.length > 0) out.add(norm);
53
+ return out;
54
+ }
55
+ for (let i = 0; i + 3 <= norm.length; i++) {
56
+ out.add(norm.slice(i, i + 3));
57
+ }
58
+ return out;
59
+ }
60
+
61
+ /**
62
+ * An in-memory BM25 index over a fixed document set. Built once, queried many
63
+ * times. Stateless after construction — `rank()` / `score()` never mutate it,
64
+ * so a cached instance is safe to reuse until the underlying corpus changes.
65
+ */
66
+ export class LexicalIndex {
67
+ private readonly docs: Map<string, DocStats> = new Map();
68
+ private readonly df: Map<string, number> = new Map();
69
+ private readonly n: number;
70
+ private readonly avgdl: number;
71
+
72
+ constructor(documents: readonly IndexDoc[]) {
73
+ let totalLen = 0;
74
+ for (const d of documents) {
75
+ const tokens = tokenize(d.text);
76
+ const tf = new Map<string, number>();
77
+ for (const t of tokens) tf.set(t, (tf.get(t) ?? 0) + 1);
78
+ for (const t of tf.keys()) this.df.set(t, (this.df.get(t) ?? 0) + 1);
79
+ this.docs.set(d.id, { id: d.id, len: tokens.length, tf, trigrams: trigrams(d.text) });
80
+ totalLen += tokens.length;
81
+ }
82
+ this.n = documents.length;
83
+ this.avgdl = this.n > 0 ? totalLen / this.n : 0;
84
+ }
85
+
86
+ /** Robertson–Spärck-Jones IDF, floored at 0 so common terms never subtract. */
87
+ private idf(term: string): number {
88
+ const df = this.df.get(term) ?? 0;
89
+ if (df === 0) return 0;
90
+ return Math.max(0, Math.log(1 + (this.n - df + 0.5) / (df + 0.5)));
91
+ }
92
+
93
+ /** BM25 score of one document against the tokenised query terms. */
94
+ score(queryTerms: readonly string[], docId: string): number {
95
+ const doc = this.docs.get(docId);
96
+ if (doc === undefined || doc.len === 0) return 0;
97
+ let s = 0;
98
+ for (const term of queryTerms) {
99
+ const tf = doc.tf.get(term);
100
+ if (tf === undefined) continue;
101
+ const idf = this.idf(term);
102
+ if (idf === 0) continue;
103
+ const denom = tf + BM25_K1 * (1 - BM25_B + (BM25_B * doc.len) / (this.avgdl || 1));
104
+ s += (idf * (tf * (BM25_K1 + 1))) / denom;
105
+ }
106
+ return s;
107
+ }
108
+
109
+ /**
110
+ * Rank documents for a set of query keys (phrases are tokenised). A
111
+ * character-trigram prefilter selects candidates cheaply; the guard keeps
112
+ * any doc sharing a query TOKEN even when no trigram overlaps, so the
113
+ * prefilter never drops a genuine lexical match. Ties break by id for a
114
+ * stable, deterministic order.
115
+ */
116
+ rank(queryKeys: readonly string[]): Array<{ id: string; score: number }> {
117
+ const queryText = queryKeys.join(' ');
118
+ const qTerms = tokenize(queryText);
119
+ const qTermSet = new Set(qTerms);
120
+ const qTrigrams = trigrams(queryText);
121
+
122
+ const candidates: string[] = [];
123
+ for (const [id, doc] of this.docs) {
124
+ let hit = false;
125
+ for (const t of qTrigrams) {
126
+ if (doc.trigrams.has(t)) {
127
+ hit = true;
128
+ break;
129
+ }
130
+ }
131
+ if (!hit) {
132
+ // Guard: keep a doc that shares an exact query token even with
133
+ // no trigram overlap (short tokens / edge normalisation).
134
+ for (const t of qTermSet) {
135
+ if (doc.tf.has(t)) {
136
+ hit = true;
137
+ break;
138
+ }
139
+ }
140
+ }
141
+ if (hit) candidates.push(id);
142
+ }
143
+
144
+ const scored = candidates
145
+ .map((id) => ({ id, score: this.score(qTerms, id) }))
146
+ .filter((r) => r.score > 0);
147
+ scored.sort((a, b) => (b.score - a.score) || (a.id < b.id ? -1 : a.id > b.id ? 1 : 0));
148
+ return scored;
149
+ }
150
+
151
+ /** Document count — for the caller's tripwire / diagnostics. */
152
+ get size(): number {
153
+ return this.n;
154
+ }
155
+ }
@@ -1,15 +1,19 @@
1
1
  /**
2
- * Default-flip decision gate (Phase 6).
2
+ * Default-flip / demotion decision gate (Phase 6 → telemetry-demotion).
3
3
  *
4
- * Pure, no-I/O. Encodes the Phase-6 falsification gate: the SHIPPED default for
5
- * `subagents.auto` flips toward `on` ONLY when a real benchmark shows a net
6
- * token-or-time win at held quality, and only on hosts with a subagent
7
- * primitive. Honest-null exit (no win, or quality regressed) keeps the
8
- * conservative default. Contract:
4
+ * Pure, no-I/O. Originally the Phase-6 falsification gate: the SHIPPED default
5
+ * for `subagents.auto` was to flip toward `on` ONLY on a passed benchmark.
6
+ *
7
+ * As of 2026-07-09 the shipped default IS `on` on subagent-capable hosts
8
+ * (ADR-117; agents/settings/contexts/orchestration-default-flip-verdict.md
9
+ * § 2026-07-09) — flipped on a bounded-downside re-evaluation, not a passed
10
+ * benchmark. This helper is therefore now the telemetry-driven DEMOTION gate:
11
+ * a `fail` verdict from accumulated real-world orchestration telemetry demotes
12
+ * the default back to `ask` (conservative). Contract:
9
13
  * `src/agent-src/contexts/execution/orchestration-benchmark-gate.md`.
10
14
  *
11
- * This helper decides; it never runs the benchmark. The measurement is the
12
- * empirical bench:ab step, authorised + run out of band.
15
+ * This helper decides; it never runs the measurement. The signal is realized
16
+ * orchestration telemetry, aggregated + evaluated out of band.
13
17
  */
14
18
 
15
19
  export interface BenchmarkResult {