ClaudeMods
☰
EN
● 0 online · Views 0 times
SponsorsSubmit a project
GitHub repositories · by josippapez

dev-core

Everyday defaults for Claude Code: repo grounding, the always-on engineering rules, core skills, and the specialist agents.

josippapez@josippapez

josippapez/ai-setup/tree/main/claude/plugins/dev-core

Translated

About this mod

dev-core

Everyday defaults for Claude Code: repo grounding, the always-on engineering rules, core skills, and the specialist agents. Claude-compatible mirror of the OpenCode interactive-mcp custom plugin, which keeps the older name.

  • Repo grounding comes from the separate repo-docs plugin, not from this one. find_docs/list_docs/read_doc/find_libs/get_blast_radius/get_file_dependents live in claude/plugins/repo-docs, shared with orchestrate so both use one MCP server and one tool namespace (mcp__plugin_repo-docs_repo-docs__*) instead of each bundling an identical copy. claude/install.sh installs repo-docs automatically alongside this plugin; if its tools are not callable, tell the user to run claude plugin install repo-docs@ai-setup. See claude/plugins/repo-docs/README.md.

  • .mcp.json registers interactive (@rawwee/interactive-mcp, a question tool subagents can reach since Claude Code withholds AskUserQuestion from them; --disable-tools message_complete_notification,intensive_chat leaves only request_user_input, since the main agent is told to use AskUserQuestion and nothing here uses intensive chat, so the other tools were roster weight nobody could call), plus bundled third-party MCP servers that should be available by default in every project: context7 (@upstash/context7-mcp), chrome-devtools (chrome-devtools-mcp) and computer-use (computer-use-mcp, mouse/keyboard/screenshot control of the real desktop for anything with no API and no DOM behind it: native app UI, OS dialogs, browser chrome outside the page, and seeing what actually rendered; it also rescues a chrome-devtools call stuck on the native remote-debugging dialog, which no timeout cuts short). Documented by the computer-use skill. These ship enabled with the plugin so they need no per-machine MCP config. Project- or secret-specific servers (e.g. Figma, a local Storybook endpoint) are intentionally kept out of the plugin and live at user scope in ~/.claude.json.

  • WCAG lookups are a CLI, not an MCP. Accessibility criteria/techniques/failures come from @rawwee/wcag-cli, invoked over Bash and documented by the bundled accessibility skill. A skill + on-demand CLI costs nothing until used, whereas an always-registered MCP spawns a subprocess every session — the same pattern as opensrc and rtk. Prefer this shape for any stateless reference lookup; keep an MCP only where the server holds real state (a warm index, a browser session), as repo-docs and chrome-devtools do.

  • skills/ mirrors the OpenCode skills.

  • Rules come in three layers: an always-on kernel, a per-prompt digest, and tool-triggered cards. Claude Code has no native plugin "rules" loader and nothing a plugin ships reaches the system prompt except an output style, so a hook publishes the kernel as user-scope rules and the other two layers arrive as hook-injected additionalContext.

    rules/ is the kernel: evidence-first, external-facts, proactive-execution. Only what applies to every turn regardless of which tool runs. hooks/link-rules.cjs runs on SessionStart, refreshes every rules/*.md in the plugin's data dir file by file through a rename (emptying the directory first made a concurrently starting session report every rule missing) (${CLAUDE_PLUGIN_DATA}/rules/) and points ~/.claude/rules/dev-core at the copy. From the next launch Claude Code loads them natively: into the main agent and every subagent (measured with a no-tools probe subagent), listed under Memory files in /context, reloaded after compaction. The data dir is the one path Claude Code deletes on uninstall, so the rules leave with the plugin; the dangling link is skipped silently (measured).

    Two gaps, both measured, both closed by the same script. Rules load before SessionStart hooks run, so the session that publishes the link has no native copy and neither do its subagents (measured: a subagent spawned after the link appeared still reported nothing): in that one session the script emits the rules as additionalContext on both SessionStart and SubagentStart, sharded under the 10,000-character cap, keyed on a first-session marker in the data dir that holds the publishing session_id. And claude plugin disable runs nothing of the disabled plugin, so the script also sweeps ~/.claude/rules/ for links into ~/.claude/plugins/data/*/rules whose plugin claude plugin list --json (0.3 s) reports disabled or no longer lists, and removes them; rules-index carries a byte-identical copy so the sweep still runs when dev-core itself is the one disabled. If the user has their own real directory at ~/.claude/rules/dev-core, it is left alone and the rules keep arriving as context every session.

    hooks.json registers 3 shard slots per event (2 in use). This replaced hooks/inject-rules.cjs, which emitted the kernel as sharded context on every session and every subagent spawn.

    rules-digest.md is the second layer: a ~250-token restatement of the kernel, emitted on every UserPromptSubmit by hooks/inject-rules-digest.cjs. The kernel is ~2.5k tokens and sits in the launch context, so repeating it every prompt is unaffordable and leaving it alone lets its pull fade. The digest carries no rule text of its own; it points at the copy already in context and says the full rules govern where the two differ. concise-output ships the identical script against its own digest, which is why a session shows two [rules-reminder] blocks.

    rule-cards/ is the third layer: guidance that only matters next to a specific tool, delivered by the mod in hooks/rule-cards.ts, which attaches the card to the tool call's result. Its triggers (tools, a fire regex, a skip regex) live in rule-cards/triggers.json, checked by rule-cards/triggers.test.cjs. It replaced a PreToolUse command hook that started a Node process per card on every matching call (0.05 to 0.06 s each, five per Bash call with the git mv guard). The kernel lands at turn 0 and is far from the work by turn 40; a card arrives adjacent to the action instead.

    | Card | Fires on | Skips when | | --- | --- | --- | | writing-code — simplicity, surgical scope, root cause, what a reviewer checks | Edit/Write/NotebookEdit, or a Bash sed -i, tee, or redirect into a file | — | | reading-libraries — opensrc over assumption | any tool call or Bash command touching a node_modules/ path | the path appears only in an exclusion (-not -path, --exclude-dir, -g '!node_modules', -prune) | | git-commit — what has to be true before it lands | a Bash git commit | — |

    Naming a path is not working on it. The skip column came from this plugin's own audit, where find . -type f -not -path "./node_modules/*" fired the opensrc card. The trigger's skip regex suppresses it; a false skip costs nothing, a false fire costs context every two minutes, so the skip pattern wins over the fire pattern.

    Every card has a Bash trigger as well as a tool-name one, and that is not optional. Benchmarked 2026-09-14 over five prompts in a fixture repo: across 39 tool calls the model made zero Edit, Write, Read, Grep, and Glob calls. Every file read, write, search, and move went through Bash (cat -n, cat >> f <<EOF, sed -i, grep -rn, find, mv). With tool-name matchers alone exactly one card fired; with the Bash patterns added, all four fired in the same run.

    Each card is debounced: it reappears at most once every two minutes, per card, per agent. Injected context does not leave the conversation, it only moves further back, so re-injecting on every user prompt just piles up duplicate copies. Measured over the five-prompt bench run under the original per-prompt keying: 8 injections carrying only 4 distinct bodies, 14,240 characters, half of it a repeat of text already in context. A card may declare requires: <path> to skip itself unless that path exists under the session cwd. The debounce is kept in the mod's memory, so /reload-plugins re-arms every card.

    Cost: the always-on bundle went from 30.5 KB (~7.6k tokens) to 9.9 KB (~2.5k tokens), loaded natively at launch for the main agent and each subagent. The cards total 6.9 KB, and only the one matching the tool is ever sent.

  • git mv is enforced, not suggested. hooks/mv-guard.ts is a mod tool.call hook on Bash that denies a plain mv whose source is tracked by git, and names the git mv to run instead. Guidance alone did not hold: the rule is read at session start and forgotten at the moment it matters, and a plain mv plus git add records the move as a delete and an add. It splits the command on unquoted &&, ||, ;, |, and newlines and checks every segment, because the whole-command version never fired once: asked to rename a tracked file, the model wrote mv src/utils.js src/helpers.js && sed -i '' ... && echo ... on the first try. Within a segment it denies only a two-argument mv, optional short flags, source tracked in the git work tree at the session cwd. Globs, multi-source moves, untracked or ignored sources, temp paths, and non-git directories all run untouched, because a false deny costs the user a blocked command.

    Verified live: the model hit the deny, read the reason, and re-ran with git mv, landing the change as R100 src/utils.js -> src/helpers.js. Worth knowing that git add -A plus git's own rename detection often recovers a plain mv anyway — in the control arm it did. The guard makes the rename deterministic rather than dependent on similarity detection.

Tests

node --test claude/plugins/dev-core/hooks/*.test.cjs

Mod

hooks/screenshots.tsx draws a chrome-devtools take_screenshot result as the picture itself in the terminal transcript (PNG only, inline or saved to a file). JPEG/WebP results and other surfaces keep the default row.

Installation

Check the author's README for the marketplace and plugin name first. Commands may change as the repository evolves.

claude plugin marketplace add josippapez/ai-setup
claude plugin install dev-core
Original text / README

dev-core

Everyday defaults for Claude Code: repo grounding, the always-on engineering rules, core skills, and the specialist agents. Claude-compatible mirror of the OpenCode interactive-mcp custom plugin, which keeps the older name.

  • Repo grounding comes from the separate repo-docs plugin, not from this one. find_docs/list_docs/read_doc/find_libs/get_blast_radius/get_file_dependents live in claude/plugins/repo-docs, shared with orchestrate so both use one MCP server and one tool namespace (mcp__plugin_repo-docs_repo-docs__*) instead of each bundling an identical copy. claude/install.sh installs repo-docs automatically alongside this plugin; if its tools are not callable, tell the user to run claude plugin install repo-docs@ai-setup. See claude/plugins/repo-docs/README.md.

  • .mcp.json registers interactive (@rawwee/interactive-mcp, a question tool subagents can reach since Claude Code withholds AskUserQuestion from them; --disable-tools message_complete_notification,intensive_chat leaves only request_user_input, since the main agent is told to use AskUserQuestion and nothing here uses intensive chat, so the other tools were roster weight nobody could call), plus bundled third-party MCP servers that should be available by default in every project: context7 (@upstash/context7-mcp), chrome-devtools (chrome-devtools-mcp) and computer-use (computer-use-mcp, mouse/keyboard/screenshot control of the real desktop for anything with no API and no DOM behind it: native app UI, OS dialogs, browser chrome outside the page, and seeing what actually rendered; it also rescues a chrome-devtools call stuck on the native remote-debugging dialog, which no timeout cuts short). Documented by the computer-use skill. These ship enabled with the plugin so they need no per-machine MCP config. Project- or secret-specific servers (e.g. Figma, a local Storybook endpoint) are intentionally kept out of the plugin and live at user scope in ~/.claude.json.

  • WCAG lookups are a CLI, not an MCP. Accessibility criteria/techniques/failures come from @rawwee/wcag-cli, invoked over Bash and documented by the bundled accessibility skill. A skill + on-demand CLI costs nothing until used, whereas an always-registered MCP spawns a subprocess every session — the same pattern as opensrc and rtk. Prefer this shape for any stateless reference lookup; keep an MCP only where the server holds real state (a warm index, a browser session), as repo-docs and chrome-devtools do.

  • skills/ mirrors the OpenCode skills.

  • Rules come in three layers: an always-on kernel, a per-prompt digest, and tool-triggered cards. Claude Code has no native plugin "rules" loader and nothing a plugin ships reaches the system prompt except an output style, so a hook publishes the kernel as user-scope rules and the other two layers arrive as hook-injected additionalContext.

    rules/ is the kernel: evidence-first, external-facts, proactive-execution. Only what applies to every turn regardless of which tool runs. hooks/link-rules.cjs runs on SessionStart, refreshes every rules/*.md in the plugin's data dir file by file through a rename (emptying the directory first made a concurrently starting session report every rule missing) (${CLAUDE_PLUGIN_DATA}/rules/) and points ~/.claude/rules/dev-core at the copy. From the next launch Claude Code loads them natively: into the main agent and every subagent (measured with a no-tools probe subagent), listed under Memory files in /context, reloaded after compaction. The data dir is the one path Claude Code deletes on uninstall, so the rules leave with the plugin; the dangling link is skipped silently (measured).

    Two gaps, both measured, both closed by the same script. Rules load before SessionStart hooks run, so the session that publishes the link has no native copy and neither do its subagents (measured: a subagent spawned after the link appeared still reported nothing): in that one session the script emits the rules as additionalContext on both SessionStart and SubagentStart, sharded under the 10,000-character cap, keyed on a first-session marker in the data dir that holds the publishing session_id. And claude plugin disable runs nothing of the disabled plugin, so the script also sweeps ~/.claude/rules/ for links into ~/.claude/plugins/data/*/rules whose plugin claude plugin list --json (0.3 s) reports disabled or no longer lists, and removes them; rules-index carries a byte-identical copy so the sweep still runs when dev-core itself is the one disabled. If the user has their own real directory at ~/.claude/rules/dev-core, it is left alone and the rules keep arriving as context every session.

    hooks.json registers 3 shard slots per event (2 in use). This replaced hooks/inject-rules.cjs, which emitted the kernel as sharded context on every session and every subagent spawn.

    rules-digest.md is the second layer: a ~250-token restatement of the kernel, emitted on every UserPromptSubmit by hooks/inject-rules-digest.cjs. The kernel is ~2.5k tokens and sits in the launch context, so repeating it every prompt is unaffordable and leaving it alone lets its pull fade. The digest carries no rule text of its own; it points at the copy already in context and says the full rules govern where the two differ. concise-output ships the identical script against its own digest, which is why a session shows two [rules-reminder] blocks.

    rule-cards/ is the third layer: guidance that only matters next to a specific tool, delivered by the mod in hooks/rule-cards.ts, which attaches the card to the tool call's result. Its triggers (tools, a fire regex, a skip regex) live in rule-cards/triggers.json, checked by rule-cards/triggers.test.cjs. It replaced a PreToolUse command hook that started a Node process per card on every matching call (0.05 to 0.06 s each, five per Bash call with the git mv guard). The kernel lands at turn 0 and is far from the work by turn 40; a card arrives adjacent to the action instead.

    | Card | Fires on | Skips when | | --- | --- | --- | | writing-code — simplicity, surgical scope, root cause, what a reviewer checks | Edit/Write/NotebookEdit, or a Bash sed -i, tee, or redirect into a file | — | | reading-libraries — opensrc over assumption | any tool call or Bash command touching a node_modules/ path | the path appears only in an exclusion (-not -path, --exclude-dir, -g '!node_modules', -prune) | | git-commit — what has to be true before it lands | a Bash git commit | — |

    Naming a path is not working on it. The skip column came from this plugin's own audit, where find . -type f -not -path "./node_modules/*" fired the opensrc card. The trigger's skip regex suppresses it; a false skip costs nothing, a false fire costs context every two minutes, so the skip pattern wins over the fire pattern.

    Every card has a Bash trigger as well as a tool-name one, and that is not optional. Benchmarked 2026-09-14 over five prompts in a fixture repo: across 39 tool calls the model made zero Edit, Write, Read, Grep, and Glob calls. Every file read, write, search, and move went through Bash (cat -n, cat >> f <<EOF, sed -i, grep -rn, find, mv). With tool-name matchers alone exactly one card fired; with the Bash patterns added, all four fired in the same run.

    Each card is debounced: it reappears at most once every two minutes, per card, per agent. Injected context does not leave the conversation, it only moves further back, so re-injecting on every user prompt just piles up duplicate copies. Measured over the five-prompt bench run under the original per-prompt keying: 8 injections carrying only 4 distinct bodies, 14,240 characters, half of it a repeat of text already in context. A card may declare requires: <path> to skip itself unless that path exists under the session cwd. The debounce is kept in the mod's memory, so /reload-plugins re-arms every card.

    Cost: the always-on bundle went from 30.5 KB (~7.6k tokens) to 9.9 KB (~2.5k tokens), loaded natively at launch for the main agent and each subagent. The cards total 6.9 KB, and only the one matching the tool is ever sent.

  • git mv is enforced, not suggested. hooks/mv-guard.ts is a mod tool.call hook on Bash that denies a plain mv whose source is tracked by git, and names the git mv to run instead. Guidance alone did not hold: the rule is read at session start and forgotten at the moment it matters, and a plain mv plus git add records the move as a delete and an add. It splits the command on unquoted &&, ||, ;, |, and newlines and checks every segment, because the whole-command version never fired once: asked to rename a tracked file, the model wrote mv src/utils.js src/helpers.js && sed -i '' ... && echo ... on the first try. Within a segment it denies only a two-argument mv, optional short flags, source tracked in the git work tree at the session cwd. Globs, multi-source moves, untracked or ignored sources, temp paths, and non-git directories all run untouched, because a false deny costs the user a blocked command.

    Verified live: the model hit the deny, read the reason, and re-ran with git mv, landing the change as R100 src/utils.js -> src/helpers.js. Worth knowing that git add -A plus git's own rename detection often recovers a plain mv anyway — in the control arm it did. The guard makes the rename deterministic rather than dependent on similarity detection.

Tests

node --test claude/plugins/dev-core/hooks/*.test.cjs

Mod

hooks/screenshots.tsx draws a chrome-devtools take_screenshot result as the picture itself in the terminal transcript (PNG only, inline or saved to a file). JPEG/WebP results and other surfaces keep the default row.

Similar projects