Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"name": "claude-code-toolkit",
"source": "./",
"description": "Skills: scaffold-mcp (generate a tested MCP server), verify-mcp (check an MCP is green + well-formed with a health report), public-ready (audit + publish a repo), coverage-audit (audit test coverage for negative space, with a completeness validator), handoff (write a PICKUP handoff), design-note (write a structured design note), orchestrate (recommend a good use of subagents), claude-md-audit (trim a CLAUDE.md and move reference material to on-demand skills), memory-audit (keep auto-memory's MEMORY.md under the load cutoff), note (frictionless auto-categorized note-to-self), failure-scan (review a diff against a failure-mode catalog). Plus hooks: failure-mode (auto-flags risky patterns, e.g. unpaginated DynamoDB scans), context-alert (warns when session context crosses a threshold and offers a handoff checkpoint), subagent-nudge (flags parallelizable tasks and offers an orchestration plan), claude-md-curator (flags a CLAUDE.md growing past its budget and offers to move reference to skills), memory-curator (flags MEMORY.md crossing the auto-memory load cutoff), and coverage-nudge (flags source changes with no test changes and offers a coverage audit).",
"version": "0.13.0",
"version": "0.14.0",
"license": "MIT",
"keywords": [
"mcp",
Expand Down
2 changes: 1 addition & 1 deletion .claude-plugin/plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "claude-code-toolkit",
"displayName": "Claude Code Toolkit",
"description": "Skills to scaffold MCP servers, verify an MCP is green and well-formed, audit repos for public release, audit test coverage for negative space, write session handoffs, write structured design notes, recommend a good use of subagents, audit a CLAUDE.md for bloat, audit auto memory for the load-cutoff, capture quick notes-to-self, and review a diff against a failure-mode catalog — plus hooks that auto-flag risky patterns, alert when session context crosses a threshold (offering a handoff checkpoint), nudge when a task looks parallelizable (offering an orchestration plan), nudge when a CLAUDE.md grows past its budget (offering to move reference material to skills), nudge when MEMORY.md crosses the auto-memory load cutoff, and nudge when source changes outpace test changes (offering a coverage audit).",
"version": "0.13.0",
"version": "0.14.0",
"author": {
"name": "Megan Schott"
},
Expand Down
10 changes: 6 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,8 @@ reference).**
line count, no LLM call). Two triggers: **prevention** — on *every* net
addition (≥ `CLAUDE_MD_ADD_LINES`, default 1), it checks the new content on two
axes: **kind** (directive=keep / reference=→ a skill / area-specific=→ a nested
`CLAUDE.md` or `.claude/rules`) and **scope** (team→project file / personal→
`CLAUDE.md` if one dir owns it, or a path-scoped `.claude/rules` file if it
follows a file type across dirs) and **scope** (team→project file / personal→
`~/.claude/CLAUDE.md` / secret-or-local→ `CLAUDE.local.md`). Cheapest bloat to
remove is the bloat that never lands. **Budget** — when the file exceeds
`CLAUDE_MD_LINE_BUDGET` (default 200), it nudges a full audit (debounced once
Expand All @@ -208,9 +209,10 @@ reference).**
`.claude/rules` globs** whose `paths:` match nothing (so the rule silently
never loads). On approval it routes each section: **keep / condense /
extract-to-skill** (the primary release valve) **/ move-to-nested-CLAUDE.md**
(area-specific; `.claude/rules` for path-scoped) **/ re-scope** (personal or
secret content to `~/.claude/CLAUDE.md` or `CLAUDE.local.md`) **/ archive**
(stale → `CLAUDE.archive.md`) **/ remove**. It never splits via `@import`
(area-specific, one dir owns it) **/ move-to-path-scoped-rule** (`.claude/rules`,
when it follows a file type across dirs) **/ re-scope** (personal or secret
content to `~/.claude/CLAUDE.md` or `CLAUDE.local.md`) **/ archive** (stale →
`CLAUDE.archive.md`) **/ remove**. It never splits via `@import`
(those load eagerly). Pairs with the `context-doc-bloat`,
`stated-not-derived-doc-facts`, `conflicting-instructions`, and
`dead-rule-scope` catalog entries.
Expand Down
9 changes: 6 additions & 3 deletions claude-md-curator/hook.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
• Prevention (every addition): when an edit ADDS lines (>= CLAUDE_MD_ADD_LINES,
default 1 — i.e. every net addition) to a context file, nudge Claude to check
the NEW content on two axes — KIND (directive=keep / reference=-> a skill /
area-specific=-> a nested CLAUDE.md or .claude/rules) and SCOPE (team
area-specific=-> a nested CLAUDE.md if a dir owns it, or a path-scoped
.claude/rules file if it follows a file type across dirs) and SCOPE (team
convention=project CLAUDE.md / personal=~/.claude/CLAUDE.md / secret-or-local
=CLAUDE.local.md, gitignored). Cheapest bloat to remove is the bloat that
never lands. (Pure tweaks that replace text net zero added lines, so they
Expand Down Expand Up @@ -177,8 +178,10 @@ def main():
f"{name}: you just added ~{added} line(s). Check the NEW content "
"on two axes. (1) KIND: always-relevant *directive* (keep), "
"*reference* (war story / how-to — move to an on-demand skill), "
"or *area-specific* (move to a nested CLAUDE.md / .claude/rules "
"for that subtree). (2) SCOPE: a team convention -> project "
"or *area-specific* — if one directory owns it, a nested "
"CLAUDE.md for that subtree; if it follows a file type across "
"dirs (e.g. all *.test.*), a path-scoped .claude/rules/ file. "
"(2) SCOPE: a team convention -> project "
"CLAUDE.md; your personal preference -> ~/.claude/CLAUDE.md; a "
"sandbox URL / personal test data / anything secret -> "
"CLAUDE.local.md (gitignored), never the committed file. Move it "
Expand Down
7 changes: 4 additions & 3 deletions claude-md-curator/test_hook.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,11 +80,12 @@ def check(name, cond):
p = json.loads(out)
hso = p.get("hookSpecificOutput", {})
ac = hso.get("additionalContext", "")
acl = ac.lower()
ok = (hso.get("hookEventName") == "PostToolUse"
and "skill" in ac.lower() and "directive" in ac.lower()
and "nested" in ac.lower() and "scope" in ac.lower()
and "skill" in acl and "directive" in acl
and "nested" in acl and "rules" in acl and "scope" in acl
and "systemMessage" in p and "additionalContext" not in p)
check("addition -> prevention nudge w/ kind+scope axes", ok)
check("addition -> prevention nudge w/ kind(+rule)+scope axes", ok)

# Every addition is evaluated now — even a 2-line one fires prevention.
write_file(claude, 50)
Expand Down
34 changes: 21 additions & 13 deletions skills/claude-md-audit/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,12 +80,17 @@ Each section that isn't staying as-is goes to one of these destinations:
relevant (a war story, how-to-run-X, a workflow). Propose a skill name + the
one-line pointer that replaces it. The content survives and is *invoked when
relevant*, at zero per-session cost.
- **Move to a nested CLAUDE.md** — *area-specific* guidance (conventions for one
subtree: `web/`, `mcp/`, `infra/`…). A nested `CLAUDE.md` loads **on-demand
only when Claude works in that subtree**, so it leaves the root entirely. For
rules scoped to specific file globs rather than a whole dir, `.claude/rules/`
(with `paths:` frontmatter) is the finer-grained variant. Propose the target
path + which lines move.
- **Move to a nested CLAUDE.md** — *area-specific* guidance that **one directory
owns** (conventions for `web/`, `mcp/`, `infra/`…). A nested `CLAUDE.md` loads
on-demand when Claude works in that subtree. Propose the target dir + lines.
- **Move to a path-scoped rule** (`.claude/rules/<name>.md` with `paths:`
frontmatter) — *area-specific* guidance that **follows a file type across
directories**, where no single dir owns it (e.g. "all `*.test.*` must be able
to fail," "every `**/dynamodb.ts` paginates its scans"). Loads when Claude
touches a matching file anywhere. The deciding question: *does one directory
own this, or does it follow a file type wherever it lives?* If you'd copy the
same note into three subtrees, it's a rule, not a nested file. Propose the
glob + lines. (`~/.claude/rules/` for a personal cross-project rule.)
- **Re-scope** — right content, wrong file: move a personal preference to user
`~/.claude/CLAUDE.md`, or a sandbox URL / personal test data / secret to
`./CLAUDE.local.md` (gitignored). A secret in a committed file is urgent —
Expand All @@ -95,22 +100,25 @@ Each section that isn't staying as-is goes to one of these destinations:
auto-loaded; recoverable).

Routing rule of thumb: wrong scope (personal/secret in the shared file) →
**re-scope** first; still-true + *broadly* useful → **skill**; still-true but
*only* relevant to one codebase/path → **nested CLAUDE.md / rules**; probably
dead → **archive**; wrong → **remove**.
**re-scope** first; still-true + *broadly* useful → **skill**; area-specific and
*one directory owns it* → **nested CLAUDE.md**; area-specific but *follows a file
type across dirs* → **path-scoped rule**; probably dead → **archive**; wrong →
**remove**.

## 4. Report, then (on approval) apply

Report: current vs projected line count, and a short table — section → verdict
(keep / condense / extract→`skill-name` / nest→`path/CLAUDE.md` / archive /
remove) → one-line why. Lead with the highest-value cuts.
(keep / condense / extract→`skill-name` / nest→`dir/CLAUDE.md` / rule→`glob` /
re-scope / archive / remove) → one-line why. Lead with the highest-value cuts.

**Only after the user agrees**, apply the approved changes:
- **condense**: tighten/merge in place;
- **extract**: create the skill (`skills/<name>/SKILL.md`, with a description so
it loads on-demand) and replace the section with its pointer;
- **nest**: create/append the nested `CLAUDE.md` (or `.claude/rules/<name>.md`)
and replace the section with a pointer to it;
- **nest**: create/append the nested `dir/CLAUDE.md` and replace the section
with a pointer to it;
- **rule**: create `.claude/rules/<name>.md` with `paths:` frontmatter for the
glob and replace the section with a pointer;
- **archive**: append to `CLAUDE.archive.md` with the dated note;
- **remove**: delete.

Expand Down