← All needs

[Feature] Optional Claude Code mods (plugin hooks) to enforce token discipline: read guard, stage-filtered catalogue, engine-trimmed skills, zero-toke

## Summary Recent Claude Code builds can load **plugin hook modules** ("mods"): TypeScript hooks that sit on the model-facing path itself (tool calls, the agent and skill listings, skill text, subagent spawns, slash commands answered locally). The studio's current hooks are bash scripts that validate and log; none of them can reduce what the model is sent. This proposes **five small, optional mods**, shipped under `.claude/mods/` and loaded with `--plugin-dir`. Each one enforces a rule the template already states, or removes text that cannot matter for the configured engine and stage. Nothing about the agents, the skills or the workflow changes for a user who does not load them. It is the **enforcement side of #136**. #136 sets the rule (pin tiers, add `effort`, read design documents by section). Mods 1 and 3 below make that rule hold without relying on each brief to restate it. ## Type - [ ] New agent - [ ] New skill (slash command) - [x] New hook - [ ] New rule - [ ] New template - [x] Improvement to existing component - [ ] Other: ## Problem / Motivation Measured on the same downstream project as #136 (Godot, design phase, 39 agents, 74 skills, v1.1.2): - **Whole-document reads dominate spend.** The GDDs total ~11 MB, and the largest is 1.7 MB. One unbounded `Read` of a 225 KB GDD costs ~60 K tokens. The "read by section" discipline lives in prose (briefs, `coordination-rules.md`). Agents follow it most of the time, and the exceptions are the expensive calls. - **Fixed per-request cost of the catalogue.** Agent descriptions (~5.6 KB) and skill descriptions (~10 KB) go out with every request of every session and every subagent. During *Systems Design*, the release, live-ops, network, store and launch agents and skills cannot be the right answer. They are cached, so the gain is in cache reads and context room more than raw price, but they also add noise to routing. - **Skills carry all three engines.** 38 of 74 skills contain Unity/Unreal branches (~340 lines). On a Godot project those lines are read and paid for every time the skill expands. - **Session-start status costs a model turn.** "Where are we?" is answered by the model reading `active.md` and the progress file. That is a deterministic read that needs no model at all. - **No visibility.** Nothing tells the user what a turn or a subagent cost, so nobody can tell whether a rule saves anything. ## Proposed Solution Five independent mods. Each one is a folder with `.claude-plugin/plugin.json`, `hooks/hooks.json` and one `register.ts`, plus a `*.test.ts` run by `claude plugin test`. | # | Mod | Hook(s) | What it does | Driven by | |---|---|---|---|---| | 0 | `token-meter` | `turn.complete`, `agent.spawn`, `$.ui.status` | Status line: tokens this turn / session, cache-read ratio. Per-subagent-type cost appended to `production/session-logs/`. | — | | 1 | `read-guard` | `tool.call` on `Read` | Denies an unbounded `Read` of a file above a threshold under `design/`, `docs/architecture/` and session state. The deny message tells the agent to locate headings with `grep -n "^#"` and read the range. Bounded reads (`offset`/`limit`) always pass. | `project.yaml` → `mods.read_guard.max_kb`, `paths`, `exempt` | | 2 | `stage-catalogue` | `agent.offer` | Hides agent types that are irrelevant to the current stage (e.g. release/live-ops/network during Concept → Systems Design). The agents still exist and can be called by name. | `project.yaml` → `stage`, plus a per-stage table in `.claude/docs/` | | 3 | `engine-trim` | `skill.prompt` | Strips engine-specific blocks that do not match `engine.name` from an expanded skill. Requires the blocks to be fenced, e.g. ` … `. | `project.yaml` → `engine.name` | | 4 | `status-local` | `command.run` | `/status-local` renders the session-state checkpoint and the progress summary in a pane. The mod reads the files with `$.fs`, so no model call is made: zero tokens. | existing session-state files | Rules all five follow: - **Opt-in.** Nothing loads unless the user starts Claude Code with `--plugin-dir .claude/mods/ ` (or `CLAUDE_CODE_PLUGIN_DIRS`). `settings.json` is unchanged. - **Config from `project.yaml`** through the existing `resolve_config` keys, with safe defaults. A mod that cannot read its config does nothing, rather than blocking anything. - **No content changes.** Mods 2 and 3 filter what the model sees. They never edit agent or skill files, so template upgrades stay a plain merge. - **Engine-agnostic.** Only mod 3 reads the engine, and it works the same for Godot, Unity and Unreal. ## Alternatives Considered - **Bash `PreToolUse` hook for the read guard.** It is possible for mod 1 alone (deny by exit code). But it cannot tell the agent *how* to proceed as cleanly, and it cannot touch listings, skill text or local commands. Mods 2–4 have no bash equivalent. - **Split skills per engine.** It triples maintenance and makes every upstream change a three-way edit. Fenced blocks plus `engine-trim` keep one source. - **Delete out-of-stage agents and skills.** This breaks stage moves and upgrades. Hiding them from the listing is reversible and per-project. - **Keep it all as prose rules (#136 Proposal 2 alone).** It works most of the time; the guard covers the rest. ## Additional Context ### Compatibility - Requires a Claude Code build with plugin hook modules (tested on 2.1.289). On older builds the folder is simply never loaded, and the studio behaves exactly as today. The README should state the minimum version. - Windows native, Git Bash and macOS/Linux behave the same: mods run in Claude Code's own runtime, not in a shell. ### What I can contribute One PR per mod, starting with 0 and 1, each with its test file and a short section in the README. Following CONTRIBUTING, I will wait for a go-ahead here before opening any PR. ### Suggested verification Run one real task twice, with and without `token-meter` + `read-guard` loaded (e.g. one `/design-review` section on a large GDD). Compare the tokens reported and the defects found. The guard must not lower findings; if it does, its threshold or exemptions are wrong. Related: #136 (tiers, effort, read by section), #137 (`/doc-condense`), #130 (progress-board — `status-local` would read it when present).