"Rules with nunchi — delivered before you have to ask." nunchi is a Claude Code plugin that turns CLAUDE.md rules into event listeners.
> /plugin marketplace add seob717/nunchi> /plugin install nunchi@nunchi-marketplace
Repo: seob717/nunchi
What's inside
English | 한국어
"Rules with nunchi — delivered before you have to ask."
nunchi is a Claude Code plugin that turns CLAUDE.md rules into event listeners. Instead of loading every rule at session start and hoping it survives 40 turns and a compaction, each rule is delivered at the exact moment its action fires:

(real session, replayed — the first gh pr create is denied exactly once, with the full rules doc — read from docs/pr-rules.md at that moment — as the deny reason; the retry passes)
One /nunchi:compile turns your CLAUDE.md into trigger-bound rule files; a PreToolUse hook does the delivery from then on. What you get, all measured:
@imports saved ~34k prompt tokens per session start; the full doc is paid only in sessions where its action actually fires./compact, verified across repeated compactions./nunchi:report shows which rule fired when, and what it saved in your repo.Requires Claude Code with plugin support, and Python 3 (the hook engine runs on the standard library only — no external packages).
Option 1 — install as a plugin (recommended: a managed bundle that can stay current on its own):
claude plugin marketplace add seob717/nunchi
claude plugin install nunchi@nunchi-marketplace
(Inside a session, /plugin marketplace add seob717/nunchi and /plugin install nunchi@nunchi-marketplace do the same.)
Auto-update is off by default for third-party marketplaces. To receive each release automatically: run /plugin, open the Marketplaces tab, select nunchi-marketplace, and choose Enable auto-update. Updates ship once per release (release-please bumps the plugin version); Claude Code fetches them in the background after a session starts, and they take effect on the next launch or /reload-plugins. If you prefer manual control, /plugin marketplace update nunchi-marketplace refreshes on demand.
To set up a whole team, commit this to the project's .claude/settings.json — collaborators who trust the repository are prompted to install:
{
"extraKnownMarketplaces": {
"nunchi-marketplace": {
"source": { "source": "github", "repo": "seob717/nunchi" }
}
},
"enabledPlugins": {
"nunchi@nunchi-marketplace": true
}
}
Option 2 — clone and hack (an editable local copy: tweak the engine, commands, or triggers directly):
git clone https://github.com/seob717/nunchi.git
claude --plugin-dir /path/to/nunchi
--plugin-dir is per-invocation, so pass it on each launch. Your local edits apply the next time you start — nothing updates underneath you.
Then, inside your project:
/nunchi:compile — reads CLAUDE.md and the @referenced documents inside it, extracts rules, infers a trigger (tool, regex pattern) for each, and writes them to .claude/rules/*.md./nunchi:report shows what was delivered, when, and what it saved.A rule you write in CLAUDE.md is loaded once, at t=0 when the session starts, and that's it. But the moment that rule actually matters is usually dozens of turns later. As context piles up, the model's attention on a rule from the top of the session fades, and once a compaction (summary) passes through, an explicit rule gets demoted to blurry background. A referenced document like @docs/pr-rules.md ends up furthest from context at exactly the point where the rule is needed (e.g. when running gh pr create). nunchi compiles a rule not as a "declaration at the top of the session" but as an "event listener bound to an action," collapsing the distance between when a rule is needed and when it is delivered to zero.
/nunchi:compile — Reads CLAUDE.md and the @referenced documents inside it, extracts rules, infers a trigger (tool, regex pattern) for each rule, and compiles them into .claude/rules/*.md.source document directly at that moment (the original, not a pasted copy) and delivers it. When several rules match the same tool call, their contents are delivered together in a single block, so one action costs at most one retry.Compilation, end to end — this line in your CLAUDE.md:
All PRs follow the checklist in @docs/pr-rules.md.
becomes .claude/rules/pr-rules.md, bound to the action it governs:
---
name: pr-rules
trigger:
tool: Bash
pattern: gh\s+pr\s+create
source: docs/pr-rules.md
strength: require-read
enabled: true
---
Reflect docs/pr-rules.md before creating a PR.
name: lowercase letters, digits, and hyphens only ([a-z0-9][a-z0-9-]*). A file with an invalid name is rejected with a stderr warning instead of silently misbehaving.trigger.tool / trigger.pattern: which tool call to intercept, and with what regex. By default the pattern matches a Bash rule against the command string and an Edit/Write rule against the file path.trigger.field (optional): match against a specific tool_input field instead of the default. field: new_string on an Edit rule makes content rules expressible — e.g. pattern console\.log fires when the edit being written contains console.log, regardless of the file path.trigger.path (optional): a file-path regex ANDed with pattern — the rule fires only when both match. Scope content rules to code files (path: \.(ts|tsx)$) so example code inside markdown or docs doesn't trigger them; without it, a field: new_string rule blocks any file whose edit contains the pattern — including the rule's own source document.source: the path to the original document, read on the spot at delivery time. If the original changes, the change is reflected automatically from the next delivery on. When several rules share one source, the document travels in full once per session — later deliveries carry the rule's one-line body plus a pointer to the full text already in the transcript, instead of repeating the document.strength: three levels, in decreasing order of enforcement.
block — always block, delivering the rule as the reason. For actions a document marks as absolutely forbidden. Repeat attempts in the same session stay blocked, but with an abbreviated reason (one-line body + a pointer to the full text delivered earlier) — enforcement unchanged, tokens saved.require-read (default) — block once per session with the rule text as the reason, then let the retry through. One retry buys a guaranteed read.inject — deliver the rule via additionalContext alongside the tool call, with zero blocking and zero retry cost. The delivery carries a provenance framing (project-owner hook, registered rule path, source path) because we measured that unframed injected instructions get treated as prompt injection and refused, while framed ones are followed (see pilot/PROBE-inject.md). Softer than require-read: compliance rides on the model's judgment instead of a forced retry. nunchi never returns permissionDecision: allow, so your permission prompts are untouched..claude/rules/ loaderClaude Code itself (v2.0.64+) also reads .claude/rules/*.md: a file without a paths: frontmatter key gets its body loaded into context at session start (verified by probe on v2.1.206). nunchi embraces this rather than fighting it — the two loaders split the work:
This is why rule bodies must stay at one summary line: a long body would be injected at session start and delivered again at trigger time. /nunchi:compile generates bodies this way by default.
Changes to a rule's content need nothing from you — the source document is read fresh at every delivery. What can silently go stale is the trigger structure: a new rule added to the document, a rule rebound to a different action, or a changed prohibition strength, none of which take effect until /nunchi:compile <path> is re-run. Three signals cover this (from #17):
source of a compiled rule, the hook injects a once-per-session note naming the affected rules and the exact recompile command. Non-blocking (additionalContext only), and it reuses the rule list already loaded for matching, so calls that touch nothing pay nothing./nunchi:report candidates — rules whose source document is newer on disk than the compiled rule file are listed as recompile candidates (mtime heuristic; a fresh clone resets mtimes, so treat it as a prompt, not proof).docs/*-rules.md, an ordinary nunchi rule can watch the convention itself and suggest compiling newly created documents (/nunchi:compile offers to generate it; see the compile command's §5.6). No extra config surface — the watcher is just another rule file.The one gap none of these catch is trigger drift with no document change at all (the team switches gh → glab and the PR rules doc never mentions tooling) — that surfaces as a dead rule in /nunchi:report (delivered 0 times), which is why the report flags never-triggered rules.
| Command | Purpose | Argument |
|---|---|---|
/nunchi:compile | Extract rules from CLAUDE.md and its @referenced documents; write trigger-bound .claude/rules/*.md. Skipped content is reported too, split into skill candidates (procedures) and always-on guidance (stays in CLAUDE.md). | Optional document path — recompile just that one document (this is the command the edit-time reminder names). |
/nunchi:report | Aggregate the delivery log into a table: per-rule delivery counts, dead (never-triggered) rules, recompile candidates, and the estimated context savings for your repo. | None. |
FAQ
nunchi is a Claude Code plugin with 1 hand-picked skill for development work, indexed on Flowy. Install it with the command on its page. It includes readme-translate. Its skills do not fire on their own yet. Request auto-invocation to have Flowy route them as you prompt. Free and open source.
Is this plugin yours?
Claim it with GitHubSubmit a pluginPromote it