@event4u/agent-config 9.3.0 → 9.4.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 (72) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/CHANGELOG.md +78 -0
  3. package/CONTRIBUTING.md +14 -0
  4. package/README.md +12 -4
  5. package/dist/agent-src/commands/contribution-precheck.md +100 -0
  6. package/dist/agent-src/commands/team.md +4 -0
  7. package/dist/agent-src/contexts/model-recommendations.md +6 -0
  8. package/dist/agent-src/rules/token-efficiency.md +7 -0
  9. package/dist/agent-src/skills/adversarial-review/SKILL.md +5 -0
  10. package/dist/agent-src/skills/ai-council/SKILL.md +3 -0
  11. package/dist/agent-src/skills/build-buy-partner/SKILL.md +1 -0
  12. package/dist/agent-src/skills/decision-record/SKILL.md +35 -1
  13. package/dist/agent-src/skills/decision-record/evals/triggers.json +82 -12
  14. package/dist/agent-src/skills/decision-record/references/weighted-matrix.md +119 -0
  15. package/dist/agent-src/skills/evaluate-llm-feature/SKILL.md +142 -0
  16. package/dist/agent-src/skills/judge-synthesis/SKILL.md +1 -0
  17. package/dist/agent-src/skills/learning-tutor/SKILL.md +215 -0
  18. package/dist/agent-src/skills/rice-prioritization/SKILL.md +1 -0
  19. package/dist/agent-src/skills/stakeholder-tradeoff/SKILL.md +3 -1
  20. package/dist/agent-src/skills/subagent-orchestration/SKILL.md +2 -1
  21. package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
  22. package/dist/discovery/deprecation-report.md +1 -1
  23. package/dist/discovery/discovery-manifest.json +94 -24
  24. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  25. package/dist/discovery/discovery-manifest.summary.md +4 -4
  26. package/dist/discovery/orphan-report.md +1 -1
  27. package/dist/discovery/packs.json +13 -10
  28. package/dist/discovery/trust-report.md +3 -3
  29. package/dist/discovery/workspaces.json +9 -6
  30. package/dist/mcp/registry-manifest.json +3 -3
  31. package/docs/CLAIMS.md +16 -2
  32. package/docs/announcements/2026-07-honest-cost-sweep-launch.md +84 -0
  33. package/docs/anti-reskin-gate.md +60 -0
  34. package/docs/architecture.md +2 -2
  35. package/docs/catalog.md +303 -278
  36. package/docs/command-flows.md +2 -1
  37. package/docs/comparison.yaml +10 -0
  38. package/docs/contracts/adoption-signal-floor.md +17 -0
  39. package/docs/contracts/ai-council-config.md +25 -0
  40. package/docs/contracts/mcp-tool-inventory.md +25 -22
  41. package/docs/contracts/tier-3-contrib-plugin.md +12 -4
  42. package/docs/featured-skills.md +2 -2
  43. package/docs/getting-started-by-role.md +1 -1
  44. package/docs/getting-started.md +1 -1
  45. package/docs/governance-advantage.md +1 -1
  46. package/docs/proof.md +10 -6
  47. package/docs/self-review-gate.md +14 -0
  48. package/docs/setup/per-ide/antigravity.md +8 -3
  49. package/docs/us-vs-the-category.md +38 -0
  50. package/docs/wedge/production-validator/README.md +24 -0
  51. package/docs/wedge/production-validator/first-run-check.sh +42 -0
  52. package/package.json +1 -1
  53. package/src/scripts/_lib/catalog_score.ts +64 -0
  54. package/src/scripts/_lib/shingle_similarity.ts +146 -0
  55. package/src/scripts/ai_council/clients.ts +50 -1
  56. package/src/scripts/ai_council/config.ts +28 -3
  57. package/src/scripts/ai_council/low_impact.ts +16 -0
  58. package/src/scripts/ai_council/necessity.ts +11 -0
  59. package/src/scripts/ai_council/orchestrator.ts +78 -26
  60. package/src/scripts/ai_council/pricing.ts +59 -0
  61. package/src/scripts/ai_council/stance_tally.ts +42 -5
  62. package/src/scripts/build_catalog_index.ts +188 -0
  63. package/src/scripts/council_cli.ts +56 -1
  64. package/src/scripts/generate_index.ts +6 -3
  65. package/src/scripts/lint_originality.ts +464 -0
  66. package/src/scripts/mcp_server/catalog_tools.ts +114 -0
  67. package/src/scripts/mcp_server/consumer_tool_catalog.json +46 -0
  68. package/src/scripts/schemas/flow.schema.json +17 -0
  69. package/src/scripts/schemas/skill.schema.json +166 -32
  70. package/src/scripts/self_review_gate.test.ts +48 -0
  71. package/src/scripts/self_review_gate.ts +73 -5
  72. package/src/scripts/validate_flow_teams.ts +127 -0
@@ -7,7 +7,7 @@
7
7
 
8
8
  > Every command is classified in `src/flows/surface-map.yaml` (coverage enforced by `scripts/lint_command_flow_coverage.py`). The four user-work flows carry rich definitions in `src/flows/<flow>.yaml`.
9
9
 
10
- **189 commands** across **10 surfaces** (4 user-work flows + 6 platform/domain surfaces).
10
+ **190 commands** across **10 surfaces** (4 user-work flows + 6 platform/domain surfaces).
11
11
 
12
12
  ## User-work flows
13
13
 
@@ -170,6 +170,7 @@ _The system/admin surface (NOT a flow): memory · analytics · governance · con
170
170
  - `context` — Context orchestrator — routes to create, refactor
171
171
  - `context-create` — Analyze a codebase area and create a structured context document
172
172
  - `context-refactor` — Analyze, update, and extend an existing context document
173
+ - `contribution-precheck` — Contributor self-service precheck — run the PR-relevant lint subset (skill linter, originality gate, frontm…
173
174
  - `cost` — Cost orchestrator — routes to report (session token cost + budget ladder) and profile (change the rule_load…
174
175
  - `cost-profile` — Change the rule_loading_tier in .agent-settings.yml — shows each profile's meaning and applies the selection
175
176
  - `cost-report` — Capture token cost from the active Claude Code session, append to the local sessions store, and surface the…
@@ -33,3 +33,13 @@ rows:
33
33
  our_evidence: "tests/scripts/witness/check_refs_relative_gap.test.ts"
34
34
  their_evidence: "Published known-limitation surfaces backed by reproducing tests are not a standard artifact in this category."
35
35
  checkable: true
36
+
37
+ - claim: "A 30-second single-file wedge exists — one read-only subagent, one command, verdict with file:line — and its promise is a scoped, published eval, not a feature list."
38
+ our_evidence: "internal/bench/orchestration/pv-a3-results.md#token_delta_provenance: measured"
39
+ their_evidence: "Category entry points typically install the full platform (profiles, packs, runtime) before the first felt win; single-artifact entries with a published eval behind the promise are not a standard artifact."
40
+ checkable: true
41
+
42
+ - claim: "The persona-identity question was tested and published as an honest null (identity swap ~zero effect, provider choice ~15x larger) instead of being shipped as theater."
43
+ our_evidence: "internal/bench/reports/persona-placebo.json#honest-null"
44
+ their_evidence: "Named-persona prompts are shipped as a feature across the category without a published A/B separating identity from method."
45
+ checkable: true
@@ -84,6 +84,23 @@ must clear before the code lands:
84
84
  Until all four gates are written and reviewed, consumer-side
85
85
  telemetry is **forbidden** even as a discussion item in roadmaps.
86
86
 
87
+ ## Extraction demand gate — lint_originality standalone probe
88
+
89
+ Added 2026-07-20 (road-to-originality-gate-and-contributor-funnel Phase 3,
90
+ council 2026-07-20: extraction is demand-gated; the floor IS the demand gate,
91
+ applied post-probe). Uses **allowed public signals only** — inbound GitHub
92
+ issues/PRs and their authors; no consumer telemetry, consistent with the Iron
93
+ Law above.
94
+
95
+ | Field | Value |
96
+ |---|---|
97
+ | **Probe surface** | [`docs/anti-reskin-gate.md`](../anti-reskin-gate.md) — run-from-clone recipe + signal instructions |
98
+ | **Signal definition** | A distinct external (non-maintainer) GitHub account opening an issue titled `anti-reskin gate: standalone request`, or referencing `lint_originality` in an inbound issue/PR about their own catalog |
99
+ | **Floor** | ≥ 3 distinct external signals |
100
+ | **Window** | 90 days from the probe page landing on `main` |
101
+ | **Floor met** | Extract `lint_originality` as a standalone zero-config npx package (`--changed` mode, no repo coupling, regression suite included); npm publish remains a maintainer decision (name, scope, moment) |
102
+ | **Floor missed** | Extraction **cancelled** — recorded via decision-record; not relitigated without new evidence |
103
+
87
104
  ## Re-audit cadence
88
105
 
89
106
  Re-audit on each of:
@@ -679,6 +679,31 @@ regression breaks `task consistency`, never the live council.
679
679
  `parse_corpus_strict` (Markdown). It runs **before** `task sync`
680
680
  rebuilds the lockfile, so it must read whatever the user just edited.
681
681
 
682
+ ## `model_downgrade` — auto-tiering + the A1↔A3 cache coupling
683
+
684
+ Since the A3 slice of `road-to-api-cost-optimization` (2026-07-20):
685
+
686
+ ```yaml
687
+ model_downgrade:
688
+ enabled: true # default; false disables the size-fit gate entirely
689
+ auto_apply: true # DEFAULT since A3 — auto-downgrade is opt-OUT
690
+ model_tier_override: # per-run escape hatch: member -> pinned model id
691
+ anthropic: claude-sonnet-4-5
692
+ ```
693
+
694
+ - Small / low-complexity artefacts (per `necessity.classify_size_fit`,
695
+ character-based) auto-downgrade one ladder rung; the `debate` lens never
696
+ downgrades.
697
+ - **Cache coupling:** a downgrade is applied only when the model saving beats
698
+ the forfeited model-scoped prompt-cache reads
699
+ (`pricing.downgrade_coupling`: `downgrade_savings > lost_cache_savings`,
700
+ expected reads = rounds − 1). One-shot paths (the low-impact fast-path)
701
+ have no reads to lose and downgrade to the CHEAPEST ladder rung outright.
702
+ - `model_tier_override` pins a member to a model for the run — classifier and
703
+ coupling both skipped. Set it per artefact when a specific tier is needed.
704
+ - Requires `model_ladder` on the member (smallest → largest, must include the
705
+ active `model`).
706
+
682
707
  ## `api_key_ref` forms
683
708
 
684
709
  Exactly two forms. Raw keys in the yml are a hard validation error.
@@ -14,22 +14,22 @@ keep-beta-until: 2026-08-14
14
14
 
15
15
  ## Summary
16
16
 
17
- - **Total tools:** 28
17
+ - **Total tools:** 31
18
18
  - **By transport:** stdio=19
19
- - **By side-effect:** fs-write=8, ro=17, shell=3
20
- - **Discovery-only stubs (no implementation):** 9
19
+ - **By side-effect:** fs-write=8, ro=20, shell=3
20
+ - **Discovery-only stubs (no implementation):** 12
21
21
 
22
22
  ## Tools
23
23
 
24
24
  | Tool | Side-effect | Transports | Catalog | Handler |
25
25
  |---|---|---|---|---|
26
- | `lint_skills` | `ro` | stdio | [`consumer_tool_catalog.json:7`](../../src/scripts/mcp_server/consumer_tool_catalog.json#L7) | [`tools.ts:1200`](../../src/scripts/mcp_server/tools.ts#L1200) |
27
- | `chat_history_append` | `fs-write` | stdio | [`consumer_tool_catalog.json:24`](../../src/scripts/mcp_server/consumer_tool_catalog.json#L24) | [`tools.ts:1228`](../../src/scripts/mcp_server/tools.ts#L1228) |
28
- | `chat_history_read` | `ro` | stdio | [`consumer_tool_catalog.json:43`](../../src/scripts/mcp_server/consumer_tool_catalog.json#L43) | [`tools.ts:1289`](../../src/scripts/mcp_server/tools.ts#L1289) |
29
- | `memory_lookup` | `ro` | stdio | [`consumer_tool_catalog.json:63`](../../src/scripts/mcp_server/consumer_tool_catalog.json#L63) | [`tools.ts:1365`](../../src/scripts/mcp_server/tools.ts#L1365) |
30
- | `memory_get` | `ro` | stdio | [`consumer_tool_catalog.json:81`](../../src/scripts/mcp_server/consumer_tool_catalog.json#L81) | [`tools.ts:1432`](../../src/scripts/mcp_server/tools.ts#L1432) |
31
- | `memory_signal` | `fs-write` | stdio | [`consumer_tool_catalog.json:95`](../../src/scripts/mcp_server/consumer_tool_catalog.json#L95) | [`tools.ts:1541`](../../src/scripts/mcp_server/tools.ts#L1541) |
32
- | `memory_status` | `ro` | stdio | [`consumer_tool_catalog.json:111`](../../src/scripts/mcp_server/consumer_tool_catalog.json#L111) | [`tools.ts:1456`](../../src/scripts/mcp_server/tools.ts#L1456) |
26
+ | `lint_skills` | `ro` | stdio | [`consumer_tool_catalog.json:7`](../../src/scripts/mcp_server/consumer_tool_catalog.json#L7) | [`tools.ts:1198`](../../src/scripts/mcp_server/tools.ts#L1198) |
27
+ | `chat_history_append` | `fs-write` | stdio | [`consumer_tool_catalog.json:24`](../../src/scripts/mcp_server/consumer_tool_catalog.json#L24) | [`tools.ts:1226`](../../src/scripts/mcp_server/tools.ts#L1226) |
28
+ | `chat_history_read` | `ro` | stdio | [`consumer_tool_catalog.json:43`](../../src/scripts/mcp_server/consumer_tool_catalog.json#L43) | [`tools.ts:1287`](../../src/scripts/mcp_server/tools.ts#L1287) |
29
+ | `memory_lookup` | `ro` | stdio | [`consumer_tool_catalog.json:63`](../../src/scripts/mcp_server/consumer_tool_catalog.json#L63) | [`tools.ts:1363`](../../src/scripts/mcp_server/tools.ts#L1363) |
30
+ | `memory_get` | `ro` | stdio | [`consumer_tool_catalog.json:81`](../../src/scripts/mcp_server/consumer_tool_catalog.json#L81) | [`tools.ts:1430`](../../src/scripts/mcp_server/tools.ts#L1430) |
31
+ | `memory_signal` | `fs-write` | stdio | [`consumer_tool_catalog.json:95`](../../src/scripts/mcp_server/consumer_tool_catalog.json#L95) | [`tools.ts:1539`](../../src/scripts/mcp_server/tools.ts#L1539) |
32
+ | `memory_status` | `ro` | stdio | [`consumer_tool_catalog.json:111`](../../src/scripts/mcp_server/consumer_tool_catalog.json#L111) | [`tools.ts:1454`](../../src/scripts/mcp_server/tools.ts#L1454) |
33
33
  | `skill_trigger_eval` | `ro` | _(stub)_ | [`consumer_tool_catalog.json:118`](../../src/scripts/mcp_server/consumer_tool_catalog.json#L118) | _stub-only_ |
34
34
  | `suggest_command` | `ro` | _(stub)_ | [`consumer_tool_catalog.json:134`](../../src/scripts/mcp_server/consumer_tool_catalog.json#L134) | _stub-only_ |
35
35
  | `suggest_skill_for_task` | `ro` | _(stub)_ | [`consumer_tool_catalog.json:149`](../../src/scripts/mcp_server/consumer_tool_catalog.json#L149) | _stub-only_ |
@@ -37,20 +37,23 @@ keep-beta-until: 2026-08-14
37
37
  | `update_form_request_messages` | `fs-write` | _(stub)_ | [`consumer_tool_catalog.json:178`](../../src/scripts/mcp_server/consumer_tool_catalog.json#L178) | _stub-only_ |
38
38
  | `sync_gitignore` | `fs-write` | _(stub)_ | [`consumer_tool_catalog.json:193`](../../src/scripts/mcp_server/consumer_tool_catalog.json#L193) | _stub-only_ |
39
39
  | `sync_agent_settings` | `fs-write` | _(stub)_ | [`consumer_tool_catalog.json:206`](../../src/scripts/mcp_server/consumer_tool_catalog.json#L206) | _stub-only_ |
40
- | `run_tests` | `shell` | stdio | [`consumer_tool_catalog.json:220`](../../src/scripts/mcp_server/consumer_tool_catalog.json#L220) | [`tools.ts:1716`](../../src/scripts/mcp_server/tools.ts#L1716) |
40
+ | `run_tests` | `shell` | stdio | [`consumer_tool_catalog.json:220`](../../src/scripts/mcp_server/consumer_tool_catalog.json#L220) | [`tools.ts:1714`](../../src/scripts/mcp_server/tools.ts#L1714) |
41
41
  | `run_quality_checks` | `shell` | _(stub)_ | [`consumer_tool_catalog.json:234`](../../src/scripts/mcp_server/consumer_tool_catalog.json#L234) | _stub-only_ |
42
- | `list_skills` | `ro` | stdio | [`consumer_tool_catalog.json:247`](../../src/scripts/mcp_server/consumer_tool_catalog.json#L247) | [`tools.ts:1470`](../../src/scripts/mcp_server/tools.ts#L1470) |
43
- | `list_commands` | `ro` | stdio | [`consumer_tool_catalog.json:254`](../../src/scripts/mcp_server/consumer_tool_catalog.json#L254) | [`tools.ts:1485`](../../src/scripts/mcp_server/tools.ts#L1485) |
44
- | `list_rules` | `ro` | stdio | [`consumer_tool_catalog.json:261`](../../src/scripts/mcp_server/consumer_tool_catalog.json#L261) | [`tools.ts:1500`](../../src/scripts/mcp_server/tools.ts#L1500) |
42
+ | `list_skills` | `ro` | stdio | [`consumer_tool_catalog.json:247`](../../src/scripts/mcp_server/consumer_tool_catalog.json#L247) | [`tools.ts:1468`](../../src/scripts/mcp_server/tools.ts#L1468) |
43
+ | `list_commands` | `ro` | stdio | [`consumer_tool_catalog.json:254`](../../src/scripts/mcp_server/consumer_tool_catalog.json#L254) | [`tools.ts:1483`](../../src/scripts/mcp_server/tools.ts#L1483) |
44
+ | `list_rules` | `ro` | stdio | [`consumer_tool_catalog.json:261`](../../src/scripts/mcp_server/consumer_tool_catalog.json#L261) | [`tools.ts:1498`](../../src/scripts/mcp_server/tools.ts#L1498) |
45
45
  | `compile_router` | `shell` | _(stub)_ | [`consumer_tool_catalog.json:268`](../../src/scripts/mcp_server/consumer_tool_catalog.json#L268) | _stub-only_ |
46
- | `read_resource_body` | `ro` | stdio | [`consumer_tool_catalog.json:281`](../../src/scripts/mcp_server/consumer_tool_catalog.json#L281) | [`tools.ts:1516`](../../src/scripts/mcp_server/tools.ts#L1516) |
47
- | `roadmap_progress` | `fs-write` | stdio | [`consumer_tool_catalog.json:295`](../../src/scripts/mcp_server/consumer_tool_catalog.json#L295) | [`tools.ts:1575`](../../src/scripts/mcp_server/tools.ts#L1575) |
48
- | `roadmap_archive` | `fs-write` | stdio | [`consumer_tool_catalog.json:308`](../../src/scripts/mcp_server/consumer_tool_catalog.json#L308) | [`tools.ts:1598`](../../src/scripts/mcp_server/tools.ts#L1598) |
49
- | `capabilities_index` | `fs-write` | stdio | [`consumer_tool_catalog.json:315`](../../src/scripts/mcp_server/consumer_tool_catalog.json#L315) | [`tools.ts:1614`](../../src/scripts/mcp_server/tools.ts#L1614) |
50
- | `doctor_report` | `ro` | stdio | [`consumer_tool_catalog.json:328`](../../src/scripts/mcp_server/consumer_tool_catalog.json#L328) | [`tools.ts:1637`](../../src/scripts/mcp_server/tools.ts#L1637) |
51
- | `conformance_check` | `ro` | stdio | [`consumer_tool_catalog.json:335`](../../src/scripts/mcp_server/consumer_tool_catalog.json#L335) | [`tools.ts:1651`](../../src/scripts/mcp_server/tools.ts#L1651) |
52
- | `telemetry_report` | `ro` | stdio | [`consumer_tool_catalog.json:342`](../../src/scripts/mcp_server/consumer_tool_catalog.json#L342) | [`tools.ts:1665`](../../src/scripts/mcp_server/tools.ts#L1665) |
53
- | `council_estimate` | `ro` | stdio | [`consumer_tool_catalog.json:355`](../../src/scripts/mcp_server/consumer_tool_catalog.json#L355) | [`tools.ts:1687`](../../src/scripts/mcp_server/tools.ts#L1687) |
46
+ | `read_resource_body` | `ro` | stdio | [`consumer_tool_catalog.json:281`](../../src/scripts/mcp_server/consumer_tool_catalog.json#L281) | [`tools.ts:1514`](../../src/scripts/mcp_server/tools.ts#L1514) |
47
+ | `roadmap_progress` | `fs-write` | stdio | [`consumer_tool_catalog.json:295`](../../src/scripts/mcp_server/consumer_tool_catalog.json#L295) | [`tools.ts:1573`](../../src/scripts/mcp_server/tools.ts#L1573) |
48
+ | `roadmap_archive` | `fs-write` | stdio | [`consumer_tool_catalog.json:308`](../../src/scripts/mcp_server/consumer_tool_catalog.json#L308) | [`tools.ts:1596`](../../src/scripts/mcp_server/tools.ts#L1596) |
49
+ | `capabilities_index` | `fs-write` | stdio | [`consumer_tool_catalog.json:315`](../../src/scripts/mcp_server/consumer_tool_catalog.json#L315) | [`tools.ts:1612`](../../src/scripts/mcp_server/tools.ts#L1612) |
50
+ | `doctor_report` | `ro` | stdio | [`consumer_tool_catalog.json:328`](../../src/scripts/mcp_server/consumer_tool_catalog.json#L328) | [`tools.ts:1635`](../../src/scripts/mcp_server/tools.ts#L1635) |
51
+ | `conformance_check` | `ro` | stdio | [`consumer_tool_catalog.json:335`](../../src/scripts/mcp_server/consumer_tool_catalog.json#L335) | [`tools.ts:1649`](../../src/scripts/mcp_server/tools.ts#L1649) |
52
+ | `telemetry_report` | `ro` | stdio | [`consumer_tool_catalog.json:342`](../../src/scripts/mcp_server/consumer_tool_catalog.json#L342) | [`tools.ts:1663`](../../src/scripts/mcp_server/tools.ts#L1663) |
53
+ | `catalog_search` | `ro` | _(stub)_ | [`consumer_tool_catalog.json:355`](../../src/scripts/mcp_server/consumer_tool_catalog.json#L355) | _stub-only_ |
54
+ | `catalog_inspect` | `ro` | _(stub)_ | [`consumer_tool_catalog.json:372`](../../src/scripts/mcp_server/consumer_tool_catalog.json#L372) | _stub-only_ |
55
+ | `catalog_load` | `ro` | _(stub)_ | [`consumer_tool_catalog.json:387`](../../src/scripts/mcp_server/consumer_tool_catalog.json#L387) | _stub-only_ |
56
+ | `council_estimate` | `ro` | stdio | [`consumer_tool_catalog.json:401`](../../src/scripts/mcp_server/consumer_tool_catalog.json#L401) | [`tools.ts:1685`](../../src/scripts/mcp_server/tools.ts#L1685) |
54
57
 
55
58
  ## Glossary
56
59
 
@@ -16,7 +16,7 @@ promotion path from Tier-3 → Tier-2, and the non-implementation
16
16
  guarantee. Does **not** ship code: `agents/manifests/contrib/` is
17
17
  unmanifested until a user asks for an entry by name.
18
18
 
19
- Last refreshed: 2026-05-12.
19
+ Last refreshed: 2026-07-16.
20
20
 
21
21
  ## Tier definitions
22
22
 
@@ -35,8 +35,16 @@ Tier-3 is the explicit overflow bucket.
35
35
  The following surfaces are Tier-3 candidates as of 2026-05-12. They
36
36
  were surfaced during the
37
37
  [`2026-05-12-installer-expansion`](../../agents/runtime/council/sessions/2026-05-12-installer-expansion/synthesis.md)
38
- council round and have **no entries** in `_VALID_TOOLS`,
39
- `USER_SCOPE_PATHS`, `SCOPE_SUPPORT`, or the bash `VALID_TOOLS` set.
38
+ council round and had **no entries** in `_VALID_TOOLS`,
39
+ `USER_SCOPE_PATHS`, `SCOPE_SUPPORT` or the bash `VALID_TOOLS` set at
40
+ proposal time.
41
+
42
+ **Status update (2026-07-16):** the candidates below have since been
43
+ promoted to shipped hosts — each now has entries in `_VALID_TOOLS`,
44
+ `USER_SCOPE_PATHS` and `SCOPE_SUPPORT`, deployed as the universal
45
+ global skill bundle. The bullets are kept as the frozen proposal-time
46
+ record; their rationales describe the pre-promotion state and no
47
+ longer reflect current shipping status.
40
48
 
41
49
  - `qoder` — community fork, no public adoption signal
42
50
  - `trae` — ByteDance IDE, behind login wall
@@ -44,7 +52,7 @@ council round and have **no entries** in `_VALID_TOOLS`,
44
52
  - `codebuddy` — Tencent-internal, no public install path
45
53
  - `droid` — proposed CLI agent, alpha
46
54
  - `warp` — terminal-with-AI; integration shape unclear (PTY vs file marker)
47
- - `antigravity` — Google research project, no shipping surface
55
+ - `antigravity` — Google's agentic IDE (public since 2026); shipped as a global bundle host (see status update above)
48
56
 
49
57
  Inclusion in this list is **not** a commitment to ship. Promotion
50
58
  requires a real user asking by name (issue, PR, council session, or
@@ -1,6 +1,6 @@
1
1
  # Featured Skills
2
2
 
3
- A curated subset of the 276 skills. Three tiers, one per primary audience. Full catalog lives in [`dist/agent-src/skills/`](../dist/agent-src/skills/); see also [`docs/catalog.md`](catalog.md) for the complete index and [`docs/featured-commands.md`](featured-commands.md) for command-level highlights.
3
+ A curated subset of the 278 skills. Three tiers, one per primary audience. Full catalog lives in [`dist/agent-src/skills/`](../dist/agent-src/skills/); see also [`docs/catalog.md`](catalog.md) for the complete index and [`docs/featured-commands.md`](featured-commands.md) for command-level highlights.
4
4
 
5
5
  > **Eval-gated messaging note.** Until `task bench --corpus non-dev` reports `selection_accuracy >= 0.60` (see `road-to-product-adoption.md` Phase 1), this page is documentation, not marketing. The entries below are the candidates the corpus tests against; their description quality is what the eval validates.
6
6
 
@@ -92,4 +92,4 @@ task lint-featured-skills
92
92
 
93
93
  CI runs this in `taskfiles/ci-fast.yml`. Stale entries (renamed / removed skill or command) fail the build. See [`scripts/lint_featured_skills.py`](../src/scripts/lint_featured_skills.py) for the matcher.
94
94
 
95
- → Browse all 276 skills: [`dist/agent-src/skills/`](../dist/agent-src/skills/) · all 189 commands: [`dist/agent-src/commands/`](../dist/agent-src/commands/)
95
+ → Browse all 278 skills: [`dist/agent-src/skills/`](../dist/agent-src/skills/) · all 190 commands: [`dist/agent-src/commands/`](../dist/agent-src/commands/)
@@ -2,7 +2,7 @@
2
2
 
3
3
  > Pick the entry that matches what you do day-to-day. Each section names the three skills you will reach for first and shows whether MCP (no terminal) or CLI (terminal) is the simpler install path for that role.
4
4
 
5
- `agent-config` ships 276 skills, 105 governed rules, and 189 commands. You do not need all of them. Each role below filters to the slice that pays back in week one; the rest stays available and shows up on demand when a task references it.
5
+ `agent-config` ships 278 skills, 105 governed rules, and 190 commands. You do not need all of them. Each role below filters to the slice that pays back in week one; the rest stays available and shows up on demand when a task references it.
6
6
 
7
7
  > **Taglines at a glance →** [`docs/role-experiences.md`](role-experiences.md) — the one-line pitch per role experience, in one table.
8
8
 
@@ -174,7 +174,7 @@ Your agent now understands slash commands:
174
174
  | `/fix quality` | Run and fix all quality checks |
175
175
  | `/chat-history import` | Pull a prior session into the current chat (resume) |
176
176
 
177
- → [Browse all 184 active commands](../dist/agent-src/commands/)
177
+ → [Browse all 190 active commands](../dist/agent-src/commands/)
178
178
 
179
179
  ---
180
180
 
@@ -33,7 +33,7 @@ the host lacks (a static host gives it no runtime attention guarantee, but a
33
33
  runtime-only system gives it nothing at all here). A runtime-only system contributes *nothing* on these hosts.
34
34
 
35
35
  ### 2. Intent routing, not a 500-artefact dump
36
- A prompt does not load all 276 skills. `dist/router.json` (101 routed rules, intent →
36
+ A prompt does not load all 278 skills. `dist/router.json` (101 routed rules, intent →
37
37
  skill, keyword/phrase/path triggers) carries the right skill on intent. The
38
38
  governance value is *selection discipline* — the host gets the relevant rule
39
39
  set, not the whole catalogue as context ballast.
package/docs/proof.md CHANGED
@@ -27,7 +27,7 @@ evidence pointer, or `task check-claims` fails the build.
27
27
  | Claim | Kind | Evidence | Resolves |
28
28
  |---|---|---|---|
29
29
  | The release process is documented as an inheritable runbook + succession doc, and the project's bus-factor (trailing-90-day distinct human reviewers) is tracked and reported truthfully — currently 1, not implied to be more. | qual | `docs/succession.md#trailing 90 days` | ✅ |
30
- | 189 commands. | quant | `src/scripts/check_artefact_count_messaging.ts#Artefact-count messaging gate` | ✅ |
30
+ | 190 commands. | quant | `src/scripts/check_artefact_count_messaging.ts#Artefact-count messaging gate` | ✅ |
31
31
  | A MEASURED-BUT-NOT-SHIPPED experiment — the thin rule projection reduced eager rule load 78,513 → 13,881 GPT-tokens (whole always-loaded projection 98,529 → 33,897, ~65.6%), but FAILED the quality gate (thin win-rate 36.2% vs required 48%) and does not ship; it un-defers only behind `discipline_profile: essential`. Shipped behavior does NOT include this reduction. Method: `agent-config benchmark` over the pinned token baseline; the baseline is the honest "what the user pays if everything loads eagerly", NOT a synthetic full-corpus strawman (council Q4); quality gate per the Phase-0 paired judge run. | quant | `internal/bench/reports/token-baseline.json#eager_rule_load` | ✅ |
32
32
  | The first cross-vendor parity pass (5 orchestration-corpus tasks × 2 vendors × 3 repeats, identical prompts via the council transport, $0.16) measured real per-host finding-count differences — claude-sonnet-4-5 surfaced ~2× the findings of gpt-4o on the multi-file analysis task (median 11 vs 5) while both vendors were identical on the planted hollow-implementation task (2 vs 2) and perfectly silent on the clean-code negative control (0 vs 0, no spurious findings). The per-task `finding_floor` values are calibrated from the cross-host lower envelope and the gate is armed. | quant | `internal/bench/reports/parity-count.json#min over hosts of median` | ✅ |
33
33
  | On a weak host (claude-haiku-4-5) the package produces a significant, placebo-controlled discipline lift on scope/downstream traps; on a strong host the same measurement is a published null — the package transplants discipline a weak model lacks, not model intelligence. | quant | `docs/benchmark.md#weak-host-specific` | ✅ |
@@ -40,15 +40,17 @@ evidence pointer, or `task check-claims` fails the build.
40
40
  | A hand-rolled, dependency-free BM25 + trigram lexical index resolves the "recalls but does not rank" gap: on the retrieval-precision corpus (9 keyword-overlapping-confuser tasks) it drives the mean top tie-set from 3.333 (the `_score` bucket scorer) to 1.0 — every needed decision uniquely top-ranked — with precision@1 and precision@5 unchanged at 1.0. Method: deterministic, model-free re-ranking of the SAME retrieved entry set; both scorers measured over the identical store via `measure_lexical_ranking.ts`. | quant | `internal/bench/reports/lexical-ranking.json` | ✅ |
41
41
  | The whole layer is compiled into host agents with zero runtime daemon. | qual | `docs/contracts/no-runtime-boundary.md#file-first, no-runtime suite` | ✅ |
42
42
  | On a 12-fixture option-decision corpus (3 arms × 2 providers, blind rubric judge claude-opus-4-8, pre-registered hypotheses), famous-figure identity framing added nothing beyond the underlying method text (method 5.04 vs figure 4.88, Δ=0.17, sign-test p=0.607), and provider diversity moved judged quality ~15× more than persona identity (provider Δ=2.58 vs identity Δ=0.17); the whole persona layer lifted only +0.08 over bare prompts. Honest null — persona panel-mode stays CUT, evidence-closed. | quant | `internal/bench/reports/persona-placebo.json#honest-null` | ✅ |
43
+ | The only agent layer that publishes the runs where it changed nothing. Deliberately falsifiable — if a reader finds a comparable agent layer publishing its own honest-null benchmark runs, this line updates; that is the point. | comparative | `docs/benchmark.md#honest` | ✅ |
43
44
  | On the live end-to-end retrieval benchmark (9 tasks × 3 arms × 3 seeds on claude-haiku, fixture store with keyword-overlapping confusers), the memory retrieval substrate scored precision@5 = 100% (9/9) with 100% poisoned-entry rejection, and the retrieval-on arm passed 27/27 model-scored tasks vs 2/27 with retrieval off and 4/27 with a placebo injection. Known limit stays published: mean tie-set 4.1 means top-k ties break by store order, not relevance (the ADR-116/FTS5 signal). | quant | `internal/bench/reports/second-brain-retrieval.json#retrieval-on` | ✅ |
44
45
  | 105 governed rules. | quant | `src/scripts/check_artefact_count_messaging.ts#Artefact-count messaging gate` | ✅ |
45
46
  | On a deterministic multi-session recall corpus, the memory substrate produces a measured, placebo-controlled recall lift — memory-on 27/27 vs no-memory 10/27 and vs equal-byte placebo 9/27 (claude-haiku-4-5, n=9 tasks x 3 seeds, sign test p=0.031 for BOTH pairings). Scoped honestly: this is the context-value upper bound (perfect retrieval on a one-fact-per-task corpus), not retrieval precision under a large store. | quant | `internal/bench/reports/second-brain-delta.json` | ✅ |
46
47
  | Removing the perfect-retrieval assumption, the substrate's REAL keyword retrieval recalls the needed decision into the top-5 under keyword-overlapping confusers (precision@5 9/9) and the model disambiguates it from the co-injected confusers — retrieval-on 27/27 vs no-memory 5/27 and vs equal-count placebo 5/27 (claude-haiku-4-5, 9 tasks x 3 seeds, sign test p=0.008 both). Named limit: retrieval RECALLS but does not RANK (mean tie-set 3.3, ties broken by store order, not relevance) — the discrimination gap that motivates the SQLite-FTS5 activation path (ADR-116) at larger scale. | quant | `internal/bench/reports/second-brain-retrieval.json` | ✅ |
47
48
  | Every artifact the package ships — source AND the condensed projection that reaches consumers — is machine-scanned in CI for hidden-Unicode, mixed-script-confusable, and instruction-smuggling payloads (the rules-file-backdoor class); a finding blocks the release before `npm publish`, not just the merge. | qual | `.github/workflows/publish-npm.yml#lint_agent_security` | ✅ |
48
- | 276 skills. | quant | `src/scripts/check_artefact_count_messaging.ts#Artefact-count messaging gate` | ✅ |
49
+ | 278 skills. | quant | `src/scripts/check_artefact_count_messaging.ts#Artefact-count messaging gate` | ✅ |
49
50
  | Removes only its own keys from a shared host config (matched by JSON-pointer + SHA-256), never a neighbour tool's entries. | qual | `docs/contracts/install-layout.md#JSON-pointer` | ✅ |
51
+ | On the A3 orchestration eval (deterministic verify, measured token deltas), the production-validator subagent returned the correct verdict on both fixtures — NOT READY with the exact `file:line` citation on a planted hollow implementation, READY with zero spurious findings on the clean control — while consuming ~45k fewer tokens than the inline-host baseline on each task. Scope: two planted fixtures on a Claude Code host, not a broad hit-rate. | quant | `internal/bench/orchestration/pv-a3-results.md#token_delta_provenance: measured` | ✅ |
50
52
 
51
- **21 backed claim(s)** — all evidence pointers resolve in CI.
53
+ **23 backed claim(s)** — all evidence pointers resolve in CI.
52
54
 
53
55
  Artefact counts in public prose (skills, commands, governed rules,
54
56
  guidelines, personas) are **generated from source and CI-drift-checked**:
@@ -77,11 +79,11 @@ shipping theater; the full per-cell data is committed at
77
79
  `internal/bench/reports/persona-placebo.json`.
78
80
 
79
81
  **Behavioural-eval coverage — the honest baseline.** Skill *quality* is only
80
- as good as its measurement. Today **42 of 276** skills carry a behavioural
82
+ as good as its measurement. Today **42 of 278** skills carry a behavioural
81
83
  `evals.json`; the highest-traffic / highest-cost tiers (default-surface +
82
84
  `rich` + routers) are **fully covered (35 of 35)**, the long tail
83
- (7 of 241) is not. We publish that gap rather than imply
84
- "276 evaluated skills": coverage is measured per tier
85
+ (7 of 243) is not. We publish that gap rather than imply
86
+ "278 evaluated skills": coverage is measured per tier
85
87
  (`./scripts-run src/scripts/skill_eval_coverage`), **CI-ratcheted so it can
86
88
  only rise**, and the priority tiers carry a hard **tier floor**: every
87
89
  rich / default-surface / router skill MUST have a behavioural eval or an
@@ -152,6 +154,8 @@ that (`task check-comparison`), so this column can never lie.
152
154
  | Capability/benchmark results are published — including the runs where the package changed nothing. | [`docs/benchmark.md`](../docs/benchmark.md) | A category headline figure (e.g. an '84.8%' score) appears across marketing surfaces with no reproducible methodology published — so it cannot be verified either way. | ✅ |
153
155
  | Every public claim binds to machine-checked evidence. | [`docs/CLAIMS.md`](../docs/CLAIMS.md) | Marketing claims in this category are not bound to a machine-checked ledger a reader can reproduce. | ✅ |
154
156
  | Skills publish their own known limits, each with a witness test. | [`tests/scripts/witness/check_refs_relative_gap.test.ts`](../tests/scripts/witness/check_refs_relative_gap.test.ts) | Published known-limitation surfaces backed by reproducing tests are not a standard artifact in this category. | ✅ |
157
+ | A 30-second single-file wedge exists — one read-only subagent, one command, verdict with file:line — and its promise is a scoped, published eval, not a feature list. | [`internal/bench/orchestration/pv-a3-results.md#token_delta_provenance: measured`](../internal/bench/orchestration/pv-a3-results.md) | Category entry points typically install the full platform (profiles, packs, runtime) before the first felt win; single-artifact entries with a published eval behind the promise are not a standard artifact. | ✅ |
158
+ | The persona-identity question was tested and published as an honest null (identity swap ~zero effect, provider choice ~15x larger) instead of being shipped as theater. | [`internal/bench/reports/persona-placebo.json#honest-null`](../internal/bench/reports/persona-placebo.json) | Named-persona prompts are shipped as a feature across the category without a published A/B separating identity from method. | ✅ |
155
159
 
156
160
  ## 5. Verify it yourself
157
161
 
@@ -37,6 +37,20 @@ no-op** (never a failing check) — exactly the `cross-model-canary.yml` pattern
37
37
  `enforce: false` (advisory always returns `0` and reports the would-block
38
38
  set).
39
39
 
40
+ ## Escalation on large / claim-affecting diffs
41
+
42
+ The two in-session lenses are a floor. A **large** diff (≥ 400 changed lines
43
+ across reviewable files) or one that touches a **claim-affecting surface**
44
+ (`docs/CLAIMS.md`, `docs/proof.md`, `docs/comparison.yaml`, or `README.md`)
45
+ warrants the full `ai-council` advisor panel — a spend-bearing multi-model run.
46
+
47
+ Per blocker `self-review-gate-cost`, the paid council stays governed by the
48
+ standing spend-authorization discipline **at run time**. So the gate does not
49
+ fire council calls itself: `escalationReasons(files, changedLines)` (pure,
50
+ unit-tested) DETECTS the condition, the dry-run plan prints it, and the posted
51
+ review RECOMMENDS a maintainer `/council:pr` run. Detection is deterministic
52
+ and zero-spend; the multi-model run is the maintainer's run-time act.
53
+
40
54
  ## Arming it (maintainer, one flip)
41
55
 
42
56
  1. Add the `ANTHROPIC_API_KEY` repo secret (per-PR budget sign-off) — turns
@@ -2,8 +2,9 @@
2
2
 
3
3
  Antigravity (Google's agentic IDE) reads the Anthropic-shaped
4
4
  markdown skill bundle from its user-scope anchor `~/.agents/`. The
5
- package deploys via the universal skill convention; project-scope
6
- bridge is not yet wired (Phase 2.4 anchor).
5
+ package deploys the universal skill bundle at global scope, the same
6
+ projection its other bundle hosts get (codex, continue, roocode and
7
+ the rest) — global-only by design, not a pending gap.
7
8
 
8
9
  ## Prerequisites
9
10
 
@@ -25,7 +26,11 @@ Populates:
25
26
  - `~/.agents/personas/` — review-lens personas
26
27
 
27
28
  (Project-scope `--tools=antigravity` is rejected with exit code 1
28
- — Antigravity has no documented project-discovery convention yet.)
29
+ — every bundle host is global-only; the package writes the shared
30
+ bundle to a user-scope anchor, not into the project. Antigravity does
31
+ have a native project `.agents/` convention (`skills/`, `agents.md`,
32
+ `workflows/`), but a project-scope projection is not part of the
33
+ shipped surface.)
29
34
 
30
35
  ## How to use
31
36
 
@@ -0,0 +1,38 @@
1
+ # Us vs. the category — the honest version
2
+
3
+ <!-- claim:positioning-honest-nulls -->**The only agent layer that publishes
4
+ the runs where it changed nothing.**<!-- /claim --> That line is deliberately
5
+ falsifiable: find a comparable agent layer publishing its own honest-null
6
+ benchmark runs and it updates — that is the point. The category's growth
7
+ playbook is headline numbers nobody can re-run; ours is a claims ledger CI
8
+ refuses to let drift.
9
+
10
+ This page is the adoption-context frame around the CI-locked comparison table.
11
+ The table itself lives on the proof page — every "our evidence" pointer is
12
+ resolved by `task check-comparison` on every build, the category column only
13
+ ever describes what is publicly observable, and no competitor is named or
14
+ counter-claimed:
15
+
16
+ **→ [The comparison table, CI-checked on every build](proof.md#4-what-is-checkable--us-vs-the-category)**
17
+
18
+ ## What the rows mean for an adopter
19
+
20
+ - **No runtime.** Nothing to keep alive, nothing that writes state behind
21
+ you — the whole layer compiles into your host agent's own config surface.
22
+ - **Published nulls.** The benchmark page keeps the runs where the package
23
+ changed *nothing* — including the persona-theater question: swapping the
24
+ advisor identities was measured at ~zero effect while the provider choice
25
+ mattered ~15× more, so persona identity was published as a placebo
26
+ (<!-- claim:persona-identity-placebo-null -->the persona-identity A/B is a
27
+ backed honest null<!-- /claim -->) instead of shipped as a feature. A
28
+ council implementation with falsifiable verdicts — including about itself.
29
+ - **A wedge, not a funnel trap.** The 30-second entry is one read-only
30
+ subagent with a scoped, published eval behind its promise
31
+ ([what it catches](wedge/production-validator/README.md)) — the platform is
32
+ the second date, not the first.
33
+
34
+ ## Verify it yourself
35
+
36
+ Every command on the [proof page § Verify it yourself](proof.md#5-verify-it-yourself)
37
+ runs on a fresh checkout. If a claim here does not resolve, CI is red before
38
+ you ever read it.
@@ -7,6 +7,14 @@ system — not just green tests over hollow code.
7
7
 
8
8
  One file. No install of anything else. No runtime, no daemon, no account.
9
9
 
10
+ <!-- claim:wedge-hollow-detection -->On its published eval it returned the
11
+ correct verdict on both fixtures — `NOT READY` with the exact `file:line` on a
12
+ planted hollow implementation, `READY` with zero spurious findings on the clean
13
+ control — at ~45k fewer tokens per task than the same check run inline
14
+ ([evidence](../../../internal/bench/orchestration/pv-a3-results.md)). Two
15
+ planted fixtures on a Claude Code host — a scoped, reproducible promise, not a
16
+ hit-rate.<!-- /claim -->
17
+
10
18
  ## What it does
11
19
 
12
20
  Before you call a feature done, `@production-validator` greps the shipped path
@@ -46,6 +54,22 @@ production-validator
46
54
  Final gate: NOT READY — refund() is a stub; validate against the real provider.
47
55
  ```
48
56
 
57
+ ## Optional: record your first run (local-only, opt-in)
58
+
59
+ Nothing is measured unless you run it. After your first verdict, you can keep a
60
+ private local record — one aggregate line, written into YOUR repo, no network:
61
+
62
+ ```bash
63
+ bash <(curl -fsSL https://raw.githubusercontent.com/event4u-app/agent-config/main/docs/wedge/production-validator/first-run-check.sh) ready
64
+ ```
65
+
66
+ Outcomes: `ready` · `not-ready` · `abandoned`. The log
67
+ (`.claude/wedge-first-run.local.log`) never leaves your machine — the package
68
+ runs zero telemetry by default
69
+ ([contract](../../contracts/adoption-signal-floor.md)). The same outcome
70
+ vocabulary feeds the proctored install-friction study
71
+ (`agents/recruit-sessions/_install-friction-runbook.md`).
72
+
49
73
  ## Why this one
50
74
 
51
75
  It carries an anti-hallucination discipline (Evidence-First): "done" is a claim
@@ -0,0 +1,42 @@
1
+ #!/usr/bin/env bash
2
+ # Opt-in, local-only first-run check for the production-validator wedge.
3
+ #
4
+ # Default-off by construction: nothing runs unless YOU invoke this script.
5
+ # It writes ONE aggregate line to a local log in your repo and never opens a
6
+ # network connection — consistent with the package's no-telemetry posture
7
+ # (docs/contracts/adoption-signal-floor.md). Delete the log any time.
8
+ #
9
+ # Usage (after your first @production-validator verdict):
10
+ # bash first-run-check.sh ready # first verdict was READY
11
+ # bash first-run-check.sh not-ready # first verdict was NOT READY
12
+ # bash first-run-check.sh abandoned # you gave up before a verdict
13
+ #
14
+ # The same outcome vocabulary feeds the B9 install-friction study
15
+ # (agents/recruit-sessions/_install-friction-runbook.md) when a session is
16
+ # proctored; unproctored users simply keep a private local record.
17
+ set -euo pipefail
18
+
19
+ OUTCOME="${1:-}"
20
+ case "$OUTCOME" in
21
+ ready|not-ready|abandoned) ;;
22
+ *)
23
+ echo "usage: bash first-run-check.sh <ready|not-ready|abandoned>" >&2
24
+ exit 2
25
+ ;;
26
+ esac
27
+
28
+ AGENT_FILE=".claude/agents/production-validator.md"
29
+ LOG_FILE=".claude/wedge-first-run.local.log"
30
+
31
+ if [ ! -f "$AGENT_FILE" ]; then
32
+ echo "NOT INSTALLED — $AGENT_FILE missing. Install first:" >&2
33
+ echo " mkdir -p .claude/agents && curl -fsSL https://raw.githubusercontent.com/event4u-app/agent-config/main/docs/wedge/production-validator/production-validator.md -o $AGENT_FILE" >&2
34
+ exit 1
35
+ fi
36
+
37
+ # One aggregate line: date + outcome. No user, host, repo, or content data.
38
+ printf '%s wedge=production-validator first_run=%s\n' \
39
+ "$(date -u +%Y-%m-%dT%H:%M:%SZ)" "$OUTCOME" >> "$LOG_FILE"
40
+
41
+ echo "Recorded locally in $LOG_FILE (never leaves this machine)."
42
+ echo "Add it to .gitignore if you don't want it committed."
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@event4u/agent-config",
3
- "version": "9.3.0",
3
+ "version": "9.4.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,
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Catalog search scoring — a thin field-boosted wrapper over the shared
3
+ * `LexicalIndex` (BM25 + trigram prefilter).
4
+ *
5
+ * DECISION (road-to-persona-library-harvest.md Phase 2.3): the roadmap sketched
6
+ * porting the upstream Hermes `_score` (token overlap + name/description
7
+ * boosts). We do NOT — `_lib/lexical_index.ts` already ships a calibrated BM25
8
+ * core (ADR-061-sanctioned, dependency-free) with a coverage² multi-term
9
+ * weighting and a trigram candidate prefilter. Maintaining a second lexical
10
+ * scorer would be duplication. Instead we reuse `LexicalIndex` and get the
11
+ * field boost by REPEATING the name (×3) and description (×2) terms in each
12
+ * doc's indexed text, so a query term hitting the name outranks the same term
13
+ * buried in a tag. No new scorer.
14
+ */
15
+ import type { CatalogIndexEntry } from '../build_catalog_index.js';
16
+ import { LexicalIndex } from './lexical_index.js';
17
+
18
+ export interface CatalogFilter {
19
+ cls?: CatalogIndexEntry['cls'];
20
+ /** Match against the entry's tags (packs/domain/tier). */
21
+ pack?: string;
22
+ limit?: number;
23
+ }
24
+
25
+ export interface CatalogHit {
26
+ entry: CatalogIndexEntry;
27
+ score: number;
28
+ }
29
+
30
+ /** Field-boosted searchable text: name ×3, description ×2, tags ×1. */
31
+ function _docText(e: CatalogIndexEntry): string {
32
+ return [e.name, e.name, e.name, e.description, e.description, ...e.tags].join(' ');
33
+ }
34
+
35
+ function _filter(entries: readonly CatalogIndexEntry[], f: CatalogFilter): CatalogIndexEntry[] {
36
+ return entries.filter((e) => {
37
+ if (f.cls && e.cls !== f.cls) return false;
38
+ if (f.pack && !e.tags.includes(f.pack)) return false;
39
+ return true;
40
+ });
41
+ }
42
+
43
+ /**
44
+ * Rank catalog entries against a free-text query. The index is built over the
45
+ * (filtered) candidate set so IDF reflects the searched scope. Empty or
46
+ * whitespace query → no hits (a search tool must not dump the catalog).
47
+ */
48
+ export function searchCatalog(
49
+ entries: readonly CatalogIndexEntry[],
50
+ query: string,
51
+ filter: CatalogFilter = {},
52
+ ): CatalogHit[] {
53
+ const q = query.trim();
54
+ if (q.length === 0) return [];
55
+ const candidates = _filter(entries, filter);
56
+ if (candidates.length === 0) return [];
57
+
58
+ const index = new LexicalIndex(candidates.map((e) => ({ id: e.id, text: _docText(e) })));
59
+ const byId = new Map(candidates.map((e) => [e.id, e]));
60
+ const limit = filter.limit && filter.limit > 0 ? filter.limit : 8;
61
+
62
+ const ranked = index.rank([q]).filter((r) => r.score > 0);
63
+ return ranked.slice(0, limit).map((r) => ({ entry: byId.get(r.id) as CatalogIndexEntry, score: r.score }));
64
+ }