# Tool discovery registry — capability cards, suggest band, telemetry

Source request: owner directive 2026-08-14, "322 tool-ish executables ship
here; AGENTS.md names almost none. Agents rebuild what exists." Full request
text preserved verbatim in session transcript; summarized below with acceptance.

Status: ACTIVE. Worktree `wt/tool-registry` at `.worktrees/tool-registry`.

## Problem

Only channel today is `tools.json` DENY band, read by `deny-gate.mjs`
(PreToolUse hook) — fires only AFTER a wrong command, never advertises
capability, and has no reach into codex/cursor (no hook system there; only a
`git` PATH shim exists, wrapping destructive-verb guarding, not discovery).

## Owner's 3-tier classification

- Tier 1 GLOBAL: ~15-20 overdeck-specific tools on PATH every agent must
  know: land, local-gate, deckctl, e2e-remote, od-worktree, deck-sudo,
  list-sessions, ft, factory, model-test-fixture, agent-sessions, od-wip,
  bb-status, cdx. Goes into repo-root `AGENTS.md` as trigger-phrase lines.
- Tier 2 MODULE-LOCAL: executables under `modules/<m>/`, not on PATH. Belong
  in that module's own `CLAUDE.md`. Only `harness` and `security` have one
  today; `workstation`, `monitor`, `buildbox`, `gptbridge`, `systray`,
  `sandbox` need one created.
- Tier 3 REGISTRY: everything else — capability cards, discoverable by hook
  and by query, never auto-loaded.

## Count reconciliation (measured, this session)

Owner's stated per-module counts (workstation 69, harness 48, monitor 42,
security 14, buildbox 12, gptbridge 11, systray 11, sandbox 10; 217 total;
108 PATH; 322 grand total) do **not** reproduce from
`find modules/<m> -type f -perm -u+x`, excluding `venv/` and
`node_modules/`:

| module | measured | owner-stated |
|---|---:|---:|
| workstation | 101 | 69 |
| harness | 64 | 48 |
| monitor | 47 | 42 |
| security | 14 | 14 |
| buildbox | 33 | 12 |
| gptbridge | 9 | 11 |
| systray | 11 | 11 |
| sandbox | 11 | 10 |

Gap is real, not a typo — `workstation`'s count includes
`modules/workstation/claude/bin/**`, which is the SAME set as Tier-1 PATH
tools (symlinked onto PATH from there), so raw per-module find double-counts
Tier-1 against Tier-2. A correct generator must subtract PATH-symlink targets
from module-local counts before classifying. This plan does NOT invent a
corrected headline number without building that generator; the index-drift
gate (below) is the actual source of truth going forward, not a one-time count.

## Acceptance criteria (MVP slice — this plan's DONE bar)

1. Card schema (JSON, sibling `<tool>.card.json` next to the executable's
   source file — never edits the executable body) with fields: id, command,
   summary, intent_phrases[], replaces[], preconditions, effects, risk,
   example, help_probe.
2. Cards seeded for the Tier-1 set above + every tool already named as a
   wrapper in `tools.json` deny entries (`ccr-up.sh`, `na.sh`,
   `model-test-fixture`, `od-worktree`, `cdx --profile`) — ceiling 20-30
   cards, not all 322.
3. Generated index (`modules/workstation/claude/tool-index.json`) from the
   cards, with a regenerate-and-diff drift test.
4. `tools.json` gains a `band` field (`deny` default, `suggest`). Shared
   rule-evaluation library (`hooks/lib/tool-rules.mjs`) used by BOTH:
   - `deny-gate.mjs` (Claude PreToolUse hook): suggest band → allow +
     `permissionDecisionReason` advisory, never blocks.
   - a new callable, `hooks/lib/tool-suggest-check.mjs`, wired into the
     existing `git` PATH shim (covers codex via `AGENT_BUILD_SCOPE_ACTIVE`)
     so the SAME matcher fires through both channels.
5. Telemetry reuses the collector's existing activity-source idiom
   (`collector/src/activity/sources/*.ts` + `registry.ts`) — a new
   `toolSuggest.ts` source reading a JSONL log, not a new store.
6. `deck tools <query>` — ~50-line reader over the index (list / grep /
   name+`--help`).
7. Live demonstration: a raw command shape from tonight's session (git
   worktree add) produces a suggest-band hint through (a) the Claude
   PreToolUse hook path and (b) the `git` PATH shim (codex-covering) path.
8. Zero new failures in `bun test` (collector, hooks) and factory pytest.
9. Two dead tools removed: `kiro-cli-chat`, `kiro-cli-term`.
10. `modules/gptbridge/venv/**` excluded in the index generator's
    enumeration code (not just by convention).

## Explicitly deferred (NOT built this session — say so, don't fake it)

- The 6 missing module `CLAUDE.md` files (workstation, monitor, buildbox,
  gptbridge, systray, sandbox) — real content needs the corrected
  PATH-vs-module-local split from the generator, not a hand count.
- Failure-triggered hints (nonzero exit matched against a card's failure
  signature) — needs exec-not-exec-replace change in the git shim
  (currently `exec`s the real binary, so no exit code is observable after).
  Flagged as a follow-up IDLE task, not silently dropped.
- Full 322-tool coverage, WARNING-band gate for uncarded executables on an
  install manifest (no install manifest exists yet as enumeration source —
  needs its own design).
- Rollout to "advisory" / "selective enforcement" stages — this slice ships
  the suggest band **measurement mode**: it logs and hints but stays inert
  unless explicitly toggled, per the consultation's rollout order.

## Execution steps

1. `hooks/lib/tool-rules.mjs` extracted from `deny-gate.mjs`, `band` field
   added. `deny-gate.mjs` rewired, existing behavior unchanged (regression
   guarded by existing `model-test-fixture-gate.test.mjs` +
   `say-the-word-gate.test.mjs` staying green).
2. `hooks/test/tool-rules.test.mjs` — new bun:test covering deny band
   (unchanged), suggest band (allow + reason), fail-open on malformed rule.
3. Card schema + `docs/tool-cards/SCHEMA.md` + first card batch under
   `modules/workstation/claude/bin/*.card.json` and similar for harness/
   security wrappers named in `tools.json`.
4. `modules/workstation/claude/scripts/gen-tool-index.mjs` +
   `tool-index.json` + drift test.
5. `modules/workstation/claude/bin/deck-tools` reader.
6. `tools.json`: one new `band:"suggest"` demo rule (raw `git worktree add`
   *inside* the repo — today un-denied — advertises `od-worktree` for
   consistency/tracking even when not unsafe).
7. `git` shim: call `tool-suggest-check.mjs` before the final `exec`,
   <100ms budget, fail-open, stderr-only.
8. Collector: `activity/sources/toolSuggest.ts` + registry wiring + test,
   modeled on `notifGate.ts`.
9. AGENTS.md: ~15-20 Tier-1 trigger-phrase lines.
10. Remove `kiro-cli-chat`, `kiro-cli-term`.
11. Install before landing: symlink farm already resolves `~/.claude` →
    `modules/workstation/claude` in the deploy clone, so landing IS the
    install step here (git ceremony deploys the hook/shim/index/AGENTS.md
    together) — no separate copy step.
12. `bash .claude/scripts/ship.sh land wt/tool-registry <worktree>` from
    `/home/user/Projects/overdeck`. Land queue congested — wait, do not
    retry/kill/direct-land.

## Current receipt

2026-08-14 (2nd pass, committed incrementally after the first pass's
uncommitted worktree was idle-reaped): all execution steps 1-10 complete and
committed as 4 checkpoints on `wt/tool-registry`:
`162642c80` plan registration, `3f2a571e0` suggest-band matcher + hook +
shim wiring + regression tests (34 hook tests green, deny band unchanged,
model-test-fixture-gate regression suite untouched), `43baf30fb` collector
tool-suggest activity source (typecheck clean, 831/831 collector tests pass,
0 fail), `c60e5d631` AGENTS.md Tier-1 trigger lines + kiro-cli-chat/
kiro-cli-term removal (checked: no other references in repo). Live
demonstration run: raw `git worktree add .worktrees/x x` produces the same
suggest-band advisory through (a) deny-gate.mjs stdin/stdout hook protocol
and (b) tool-suggest-check.mjs called from the actual `_git-guard-shim.sh`
(confirmed via `bash -x` trace — shim invokes the checker with the correct
reconstructed command before `exec`ing real git). Full factory pytest
(194 passed) also run since a card landed under modules/harness/.
Deferred items (module CLAUDE.md x6, failure-triggered hints, full 322-tool
coverage, WARNING-band, advisory/enforcement rollout stages) unchanged from
plan — not built this session, stated explicitly above.

## Next executable action

Land via `.claude/scripts/ship.sh land wt/tool-registry <worktree>` from
`/home/user/Projects/overdeck`. Queue may be congested — wait for it, do not
retry/kill/direct-land per repo doctrine.
