josippapez/ai-setup/tree/main/claude/plugins/dev-core
关于这个 mod
dev-core
Claude Code 的日常默认配置:代码库依据、始终启用的工程规则、核心技能和专业 agents。它是 OpenCode interactive-mcp 自定义插件的 Claude 兼容镜像,并保留旧名称。
-
**代码库依据来自独立的
repo-docs⟧ 插件。**find_docs⟧、list_docs⟧、read_doc⟧、find_libs⟧、get_blast_radius⟧、get_file_dependents⟧ 位于claude/plugins/repo-docs⟧,与orchestrate⟧ 共用一个 MCP server 和mcp__plugin_repo-docs_repo-docs__*⟧ 工具命名空间。claude/install.sh⟧ 会一起安装它;工具无法调用时运行claude plugin install repo-docs@ai-setup⟧。详见 `claude/plugins/repo-docs/README.md⟧。 -
.mcp.json⟧ 注册interactive⟧(@rawwee/interactive-mcp⟧,供 subagents 提问;--disable-tools message_complete_notification,intensive_chat⟧ 只留下request_user_input⟧),以及context7⟧(@upstash/context7-mcp⟧)、chrome-devtools⟧(chrome-devtools-mcp⟧)和computer-use⟧(computer-use-mcp⟧)。后者处理没有 API 或 DOM 的原生界面、OS 对话框、浏览器外壳和实际渲染,也能救回卡在远程调试对话框的 chrome-devtools 调用。项目或密钥专用 server(如 Figma、本地 Storybook endpoint)放在~/.claude.json⟧。 -
WCAG 查询是 CLI,不是 MCP。
@rawwee/wcag-cli⟧ 由 Bash 调用,配套accessibility⟧ skill;按需 CLI 不会在使用前产生费用,而常驻 MCP 每个会话都会启动 subprocess。opensrc⟧ 和rtk⟧ 也遵循这个形态。`skills/⟧ 镜像 OpenCode skills。 -
规则分三层:始终启用的内核、逐提示摘要、工具触发卡片。 Claude Code 没有原生插件规则加载器,所以钩子把内核发布成用户范围规则,其余两层作为 `additionalContext⟧ 注入。
rules/⟧ 是内核:evidence-first⟧、external-facts⟧、proactive-execution⟧。hooks/link-rules.cjs⟧ 在SessionStart⟧ 逐文件刷新rules/*.md⟧,将~/.claude/rules/dev-core⟧ 指向${CLAUDE_PLUGIN_DATA}/rules/⟧。Claude Code 会原生加载它,main agent 与所有 subagent 都能在/context⟧ 的 Memory files 中看到,并在压缩后重新加载;卸载时数据目录随插件删除,悬空链接静默跳过。规则在 SessionStart 钩子前加载,因此发布链接的会话和之后生成的 subagent 没有原生副本。该会话在
SessionStart⟧、SubagentStart⟧ 以分片上下文发布规则,受 10,000 字符上限约束,并以first-session⟧ 和session_id⟧ 为键。claude plugin disable⟧ 不会运行停用插件,所以脚本也会扫描~/.claude/rules/⟧ 到~/.claude/plugins/data/*/rules⟧ 的链接;若claude plugin list --json⟧(0.3 s)显示停用或不在列表中,就删除链接。rules-index⟧ 保留字节相同副本,因此 dev-core 停用时也能扫描;用户自己的~/.claude/rules/dev-core⟧ 目录保持不动。hooks.json⟧ 为每个事件注册 3 个分片槽位(使用 2 个),取代hooks/inject-rules.cjs⟧。rules-digest.md⟧ 是第二层:约 250-token 的内核重述,由hooks/inject-rules-digest.cjs⟧ 在每次UserPromptSubmit⟧ 发出。内核约 2.5k token,摘要只指向已存在副本;concise-output⟧ 使用同一脚本,所以会话显示两个 `[rules-reminder]⟧ 区块。rule-cards/⟧ 是第三层。hooks/rule-cards.ts⟧ 把特定工具旁的指导附在工具结果上,触发器位于rule-cards/triggers.json⟧,由rule-cards/triggers.test.cjs⟧ 检查。它取代了每次匹配调用都启动 Node 的PreToolUse⟧ 钩子(每张卡 0.05 到 0.06 s,带git mv⟧ 防护的 Bash 调用会触发 5 张卡)。内核在回合 0 到达,回合 40 时离工作很远;卡片紧挨动作到达。| 卡片 | 触发条件 | 何时跳过 | | --- | --- | --- | |
writing-code⟧ — 简洁性、手术式范围、根因、审查者检查项 |Edit⟧/Write⟧/NotebookEdit⟧,或 Bash 的sed -i⟧、tee⟧、文件重定向 | — | |reading-libraries⟧ — 先用opensrc⟧ | 触及node_modules/⟧ 的工具调用或 Bash | 只出现在-not -path⟧、--exclude-dir⟧、-g '!node_modules'⟧、-prune⟧ 排除条件中 | |git-commit⟧ — 落地前必须满足的条件 | Bash 的 `git commit⟧ | — |命名路径不等于处理路径。审计中
find . -type f -not -path "./node_modules/*"⟧ 曾触发 opensrc 卡片,skip⟧ 正则会压制它。误跳过没有代价,误触发却每 2 分钟消耗上下文,所以优先 skip。每张卡都必须有 Bash 触发器和工具名称触发器。在 fixture repo 的 5 个提示中,39 次工具调用没有使用
Edit⟧、Write⟧、Read⟧、Grep⟧ 或Glob⟧;所有读写搜索移动都通过cat -n⟧、cat >> f <<EOF⟧、sed -i⟧、grep -rn⟧、find⟧、`mv⟧。只匹配工具名称时触发 1 张卡,加入 Bash 模式后同次运行触发 4 张卡。卡片按 agent 去抖,每张卡最多每 2 分钟出现一次。原始基准中,8 次注入只有 4 份不同内容,共 14,240 字符,其中一半是重复文字。卡片可声明
requires: <path>⟧,cwd 下没有该路径就跳过;去抖状态保存在 mod 的 memory 中,/reload-plugins⟧ 会重新武装。成本: 常驻包从 30.5 KB(约 7.6k token)降到 9.9 KB(约 2.5k token),启动时原生加载到 main agent 和每个 subagent;卡片总计 6.9 KB,只发送匹配项。
-
**
git mv⟧ 是强制执行,不是建议。**hooks/mv-guard.ts⟧ 作为 Bash 上的tool.call⟧ hook 运行:普通mv⟧ 若来源由 git 跟踪就拒绝,并提示git mv⟧。命令会按未加引号的&&⟧、||⟧、;⟧、|⟧ 和换行拆成区段,拒绝双参数mv⟧、短参数和 cwd 工作树内由 git 跟踪的来源;通配符、多来源、未跟踪或忽略来源、临时路径、非 git 目录照常执行。模型第一次尝试的是mv src/utils.js src/helpers.js && sed -i '' ... && echo ...⟧;验证后改用git mv⟧,结果为R100 src/utils.js -> src/helpers.js⟧。git add -A⟧ 加 git 的重命名检测有时能补救普通 `mv⟧,但 guard 让结果不依赖相似度。
测试
node --test claude/plugins/dev-core/hooks/*.test.cjs
Mod
hooks/screenshots.tsx⟧ 会把 chrome-devtools 的 take_screenshot⟧ 结果画成终端记录中的图片(仅 PNG,可内嵌或保存到文件)。JPEG/WebP 和其他界面保持默认行。
安装
请先查看作者 README 确认 marketplace 和插件名称;命令可能随仓库结构改变。
claude plugin marketplace add josippapez/ai-setup claude plugin install dev-core
原文 / 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-docsplugin, not from this one.find_docs/list_docs/read_doc/find_libs/get_blast_radius/get_file_dependentslive inclaude/plugins/repo-docs, shared withorchestrateso both use one MCP server and one tool namespace (mcp__plugin_repo-docs_repo-docs__*) instead of each bundling an identical copy.claude/install.shinstallsrepo-docsautomatically alongside this plugin; if its tools are not callable, tell the user to runclaude plugin install repo-docs@ai-setup. Seeclaude/plugins/repo-docs/README.md. -
.mcp.jsonregistersinteractive(@rawwee/interactive-mcp, a question tool subagents can reach since Claude Code withholdsAskUserQuestionfrom them;--disable-tools message_complete_notification,intensive_chatleaves onlyrequest_user_input, since the main agent is told to useAskUserQuestionand 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) andcomputer-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 achrome-devtoolscall stuck on the native remote-debugging dialog, which no timeout cuts short). Documented by thecomputer-useskill. 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 bundledaccessibilityskill. A skill + on-demand CLI costs nothing until used, whereas an always-registered MCP spawns a subprocess every session — the same pattern asopensrcandrtk. Prefer this shape for any stateless reference lookup; keep an MCP only where the server holds real state (a warm index, a browser session), asrepo-docsandchrome-devtoolsdo. -
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.cjsruns onSessionStart, refreshes everyrules/*.mdin 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-coreat 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
SessionStarthooks 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 asadditionalContexton bothSessionStartandSubagentStart, sharded under the 10,000-character cap, keyed on afirst-sessionmarker in the data dir that holds the publishingsession_id. Andclaude plugin disableruns nothing of the disabled plugin, so the script also sweeps~/.claude/rules/for links into~/.claude/plugins/data/*/ruleswhose pluginclaude plugin list --json(0.3 s) reports disabled or no longer lists, and removes them;rules-indexcarries 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.jsonregisters 3 shard slots per event (2 in use). This replacedhooks/inject-rules.cjs, which emitted the kernel as sharded context on every session and every subagent spawn.rules-digest.mdis the second layer: a ~250-token restatement of the kernel, emitted on everyUserPromptSubmitbyhooks/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-outputships 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 inhooks/rule-cards.ts, which attaches the card to the tool call's result. Its triggers (tools, afireregex, askipregex) live inrule-cards/triggers.json, checked byrule-cards/triggers.test.cjs. It replaced aPreToolUsecommand hook that started a Node process per card on every matching call (0.05 to 0.06 s each, five per Bash call with thegit mvguard). 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 Bashsed -i,tee, or redirect into a file | — | |reading-libraries—opensrcover assumption | any tool call or Bash command touching anode_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 Bashgit 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'sskipregex 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, andGlobcalls. 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-pluginsre-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 mvis enforced, not suggested.hooks/mv-guard.tsis a modtool.callhook on Bash that denies a plainmvwhose source is tracked by git, and names thegit mvto run instead. Guidance alone did not hold: the rule is read at session start and forgotten at the moment it matters, and a plainmvplusgit addrecords 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 wrotemv src/utils.js src/helpers.js && sed -i '' ... && echo ...on the first try. Within a segment it denies only a two-argumentmv, 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 asR100 src/utils.js -> src/helpers.js. Worth knowing thatgit add -Aplus git's own rename detection often recovers a plainmvanyway — 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.
