From dotclaude-self
Use when picking, vendoring, porting, or syncing agents, skills, commands, hooks, or rules from any upstream source (ECC = everything-claude-code, anthropic-skills, claude-code plugins, mcp-servers, wshobson/agents, or other external repos) into this dotclaude project's claudekit/ directory. Trigger on phrases like "pick X from ECC", "vendor this skill", "add agent from upstream", "port this component", "sync component from source", "import this hook", "bring in this rule from ECC", "vendor from claude-code", or any time the user references an upstream component to add to claudekit/. This skill covers the full 8-step pipeline: browse → evaluate → cross-reference scan → vendor → sidecar → preset → install → verify. Also trigger for upgrade or sync tasks ("check if X has updates", "sync X from upstream").
How this skill is triggered — by the user, by Claude, or both
Slash command
/dotclaude-self:dotclaude-component-pickerThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Full pipeline for picking a component from any upstream source and integrating it into `dotclaude`. Follow all 8 steps — each step's output feeds the next.
Full pipeline for picking a component from any upstream source and integrating it into dotclaude. Follow all 8 steps — each step's output feeds the next.
Bundled references (read when you need the full schema or deeper context):
references/sidecar.md — sidecar schema, layout rules, dependency resolution, modify/upgrade workflowsreferences/presets.md — preset schema, extends: semantics, settings_patch, install flags| Upstream alias | Submodule path | claudekit/<source>/ target | Available types |
|---|---|---|---|
| ECC | upstream/everything-claude-code/ | claudekit/everything-claude-code/ (source alias: everything-claude-code) | agents, skills, commands, hooks, rules |
| anthropic-skills | upstream/anthropic-skills/ | claudekit/anthropic-skills/ (source alias: anthropic-skills) | skills |
| claude-code | upstream/claude-code/plugins/<name>/ | claudekit/everything-claude-code/ (until a dedicated alias exists) | agents, skills, commands, hooks |
| mcp-servers | upstream/mcp-servers/ | reference only | — |
| anthropic-cookbook | upstream/anthropic-cookbook/ | reference only | — |
| Source alias | On-disk folder | Purpose |
|---|---|---|
dotclaude-self | claudekit/dotclaude/dotclaude-self/ | This picker, preset-wizard, preset-debugger, plugin-discovery, dotclaude-setup |
workflow | claudekit/dotclaude/workflow/ | w-* dev workflow (w-task, w-fix, w-pr, w-status, w-reset, w-setup, w-checkpoint, workflow-setup) |
figma | claudekit/dotclaude/figma/ | f-* Figma suite (f-import, f-ui-kit, f-page, f-review, f-setup) |
private | claudekit/private/ (gitignored) | per-project / hilab overrides |
Layout note (source-grouped): Components live under
claudekit/<source>/<type>/<name> — not the legacy flat claudekit/<type>/<name>.
When vendoring, pick the source folder matching the upstream. When referencing
in preset.yaml, every entry is a {name, source} object — the resolver uses
source to locate the file.
Note for claude-code: components live inside plugins/<plugin-name>/.claude-plugin/ (not top-level). Browse with:
ls upstream/claude-code/plugins/
ls upstream/claude-code/plugins/<name>/.claude-plugin/
cat upstream/claude-code/plugins/<name>/.claude-plugin/plugin.json
First, bring the submodule to the latest remote state:
git submodule update --remote upstream/<alias>
Then survey what's available and what's already vendored:
# Available in upstream
ls upstream/<alias>/agents/
ls upstream/<alias>/skills/
ls upstream/<alias>/commands/
ls upstream/<alias>/hooks/
# Already vendored in claudekit — scan the matching source folder
SRC=everything-claude-code # or anthropic-skills / dotclaude-self / workflow / figma / private
ls claudekit/$SRC/agents/ 2>/dev/null
ls claudekit/$SRC/skills/ 2>/dev/null
ls claudekit/$SRC/commands/ 2>/dev/null
ls claudekit/$SRC/hooks/ 2>/dev/null
Note: component name, whether it's a folder or file component, and whether it already exists in claudekit/<source>/. If it already exists, compare commits and decide whether to upgrade (see Upgrade workflow in references/sidecar.md).
Read the component's primary documentation:
SKILL.md inside the folder.md fileConfirm before vendoring:
LICENSE.txt in the component folder or the upstream rootpnpm sync <type>/<name>) and decide whether to upgradedependencies.externalEvaluate how broadly the component applies across languages/stacks. Record findings — they go into the sidecar in Step 4.
Signals that indicate language-specific coverage:
npm, npx, jest, vitest, pip, pytest, cargo, go test, mvn — language/runtime-specificpackage.json, requirements.txt, go.mod)Coverage verdicts:
| Verdict | When | Sidecar value |
|---|---|---|
js-only | Tooling or commands require npm/Node/Jest — will fail on non-JS projects | coverage: [js-only] |
js-example-heavy | Concept is cross-stack but all worked examples use TypeScript/JS | coverage: [js-example-heavy] |
python-only, go-only etc. | Analogous to js-only for other stacks | coverage: [<lang>-only] |
| universal | No language-specific tooling or examples | omit coverage |
Tag to add when relevant:
js-specific (or python-specific, etc.) — if the tooling itself is language-lockedframework-preset-candidate — if the component is best suited for a language-specific framework preset rather than a cross-stack core presetThis step ensures the component's dependencies are correctly mapped and met before vendoring. Do it every time, even when the component looks self-contained — the scan often surfaces shared scripts or implicit skill invocations.
Run these greps against the component's source in upstream (before copying):
COMP=upstream/<alias>/<type>/<name> # e.g. upstream/anthropic-skills/skills/docx
# References to other skills/agents by name
grep -rni "skill\|agent\|use_skill\|invoke\|require\|depends" "$COMP/" | grep -v "LICENSE\|\.yaml:"
# Python imports that might pull from other claudekit components
grep -rn "^from \.\|^import \." "$COMP/scripts/" 2>/dev/null
# Shell scripts calling other claudekit hooks or commands
grep -rn "\.sh\b\|source \." "$COMP/" 2>/dev/null | grep -v "^Binary\|LICENSE"
# Detect shared scripts — compare subtrees with existing claudekit components
for candidate in claudekit/skills/*/scripts/ claudekit/hooks/; do
diff -rq "$COMP/scripts/" "$candidate" 2>/dev/null && echo "IDENTICAL to $candidate"
done
| Situation | Action |
|---|---|
Referenced component not in claudekit/, exists in upstream | Vendor it first (loop back to Step 1 for that component). Then add to dependencies.required. |
Referenced component already in claudekit/, same upstream source & commit range | Confirm it's current. Add to dependencies.required. No further action. |
Referenced component already in claudekit/, different upstream or diverged commit | Inspect the divergence: if the interface/API matches what this component needs, add to dependencies.required and note the divergence in notes:. If it conflicts, vendor a renamed copy or resolve before proceeding. |
| Reference is optional (skill degrades gracefully without it) | Add to dependencies.optional. |
| Reference is an external binary/package (python3, node, soffice) | Add to dependencies.external with type and reason. |
| Reference not traceable to any upstream source | Add to dependencies.external with type: unknown and document in notes:. |
When a component's scripts/ subtree is identical to an existing claudekit component (e.g., docx, xlsx, and pptx all duplicate scripts/office/):
notes: field so future upgraders know to sync all affected skills together: "scripts/office/ is identical to docx and pptx — sync together"When a dependency is already in claudekit/ and you're about to declare it in dependencies.required:
source.repo match where this component expects to pull from?
cat claudekit/<type>/<dep-name>/SOURCE.yaml | grep "repo\|commit"
notes:) cover what the new component needs?dependencies.required, no further worknotes: fields, confirm the interface still works, then proceedRun this scan whenever the component includes .js or .ts source files:
COMP=upstream/<alias>/<type>/<name> # or claudekit/<type>/<name> after vendoring
# CommonJS — relative local requires
grep -rn "require('\." "$COMP/" 2>/dev/null | grep -v "node_modules"
# ESM — relative local imports
grep -rn "^import .* from '\." "$COMP/" 2>/dev/null
# Relative imports going UP the tree (cross-dir dependencies)
grep -rn "require('\.\." "$COMP/" 2>/dev/null
grep -rn "^import .* from '\.\." "$COMP/" 2>/dev/null
# External npm packages (non-relative, non-builtin)
grep -rn "require('[^./]" "$COMP/" 2>/dev/null | grep -v "require('node:"
grep -rn "^import .* from '[^./]" "$COMP/" 2>/dev/null | grep -v "from 'node:"
Decision matrix for each import/require found:
| Pattern | Meaning | Action |
|---|---|---|
require('./lib/...') or import from './lib/...' | Shared lib subdir inside same component-type dir (e.g. hooks/lib/) | Verify claudekit/hooks/lib/ exists. The installer auto-copies hooks/lib/ in copy mode — no manual step needed at install time. Still vendor the lib files into claudekit if not present. Note in sidecar: "Requires hooks/lib/utils — co-installed automatically". |
require('./other-file') within same dir | Intra-type sibling dependency | Vendor the referenced file too. Add to dependencies.required.<type>. |
require('../...') going up the tree | Cross-dir dependency — won't resolve after copy/install | Flag immediately. The installed file won't have this relative path structure. Either the component must be self-contained or the path must be rewritten. Note under modifications: in the sidecar. |
require('some-npm-pkg') (non-relative, non-node:) | External npm package | Add to dependencies.external with type: npm and reason. |
require('node:fs'), require('fs'), require('path') etc. | Node.js built-in | No action needed. |
require('child_process'), require('os') etc. | Node.js built-in (old-style) | No action needed. |
hooks/lib/ pattern — known shared runtime:
claudekit/hooks/lib/ contains shared utilities (utils.js, hook-flags.js, etc.) used by nearly all hooks via require('./lib/utils'). When vendoring a hook that references ./lib/, confirm these files are present in claudekit/hooks/lib/. The installer handles co-copying automatically since 2026-05-12 — but vendoring still requires the files to exist in claudekit/hooks/lib/ as source.
Get the upstream commit hash first — you need it for the sidecar:
git -C upstream/<alias> rev-parse HEAD
Resolve the target source folder:
Upstream <alias> | Target <source> (folder = claudekit/<source>/) |
|---|---|
| everything-claude-code | everything-claude-code |
| anthropic-skills | anthropic-skills |
| claude-code | everything-claude-code (until a dedicated alias exists) |
(For brand-new self-authored components, pick a dotclaude sub-source: dotclaude-self /
workflow / figma — its on-disk folder is claudekit/dotclaude/<sub>/<type>/.)
Folder component (skill with SKILL.md + assets, multi-file agent):
cp -r upstream/<alias>/<type>/<name>/ claudekit/<source>/<type>/<name>/
File component (single .md agent, single command, hook script):
cp upstream/<alias>/<type>/<name>.md claudekit/<source>/<type>/<name>.md
# or for shell scripts:
cp upstream/<alias>/<type>/<name>.sh claudekit/<source>/<type>/<name>.sh
If Step 2.5 identified dependencies not yet in claudekit/, vendor those first
before vendoring the primary component (each into the source folder that
matches its upstream).
The sidecar records provenance and drives dependency resolution at install time. Read references/sidecar.md for the full schema — here's the quick version.
Sidecar location:
SOURCE.yaml inside the folder: claudekit/<source>/<type>/<name>/SOURCE.yaml<name>.source.yaml next to the file: claudekit/<source>/<type>/<name>.source.yamlMinimal template (see references/sidecar.md for all fields including tags/categories):
# yaml-language-server: $schema=../../../presets/schema/sidecar.schema.json
source:
repo: https://github.com/<org>/<repo> # no trailing .git
commit: <40-char-hex> # from `git -C upstream/<alias> rev-parse HEAD`
path: <type>/<name> # path within upstream repo
ref: main
imported_at: "<YYYY-MM-DD>" # quoted — bare dates get parsed as Date objects
license: MIT
modified: false
modifications: null
notes: >-
What the component does, key files, any quirks for future sync decisions.
If scripts/office/ (or similar) is shared with other skills, note it here.
dependencies:
required:
agents: []
skills: [] # populated from Step 2.5 scan results
commands: []
hooks: []
rules: []
optional:
agents: []
skills: []
commands: []
hooks: []
rules: []
external: [] # system binaries / PyPI / npm packages
tags: []
categories: {}
External dependency format:
external:
- name: python3
type: system_binary # npm | system_binary | python_pkg
reason: "scripts/*.py require Python 3.9+"
- name: claude
type: system_binary
reason: "calls claude -p via subprocess"
Populate tags and categories from Step 2f findings:
tags:
- js-specific # add if tooling is npm/Jest/etc. locked (from Step 2f)
- framework-preset-candidate # add if better suited for a language-specific preset
# other descriptive tags (nodejs, typescript, jest, vitest, playwright, etc.)
categories:
stacks:
- nodejs # list applicable stacks from Step 2f
- typescript
coverage:
- js-only # or js-example-heavy, python-only, go-only — from Step 2f verdict
# omit coverage entirely if universal
If the sidecar notes field names a cross-language alternative (e.g., "use security-bounty-hunter for non-JS projects"), this is the signal that preset-wizard and dotclaude-setup will use to auto-propose replacements — write it explicitly.
After creating the sidecar, verify it parses correctly:
pnpm typecheck
If you later edit the vendored component, set modified: true and add a modifications: description — this is how the sync tool knows the local copy diverges from upstream.
Add the component to an existing preset or create a new one. Read references/presets.md for the full schema.
Coverage pre-check before adding to a preset:
Read the sidecar (SOURCE.yaml / <name>.source.yaml) for the component being added. Check categories.coverage and tags:
| Sidecar signal | Target preset kind | Action |
|---|---|---|
coverage: [js-only] or tag js-specific | core / cross-stack | ⚠ Warn: "This component is JS-specific. Sidecar notes suggest: <alternative from notes>" — confirm with user before adding |
coverage: [js-only] or tag js-specific | framework with matching stack | ✓ Proceed — good fit |
tag framework-preset-candidate | core / cross-stack | 📌 Note: "Better placed in a framework/<stack> preset" — confirm intent |
coverage: [js-example-heavy] | core / cross-stack | ℹ Note: "Examples are JS-focused but concept applies broadly" — no block |
| No coverage signal | any | ✓ Proceed |
Add to an existing preset — edit the .yaml in presets/. Each entry is an
object with the component's name and the source alias for the folder it
lives in:
components:
skills:
- name: <component-name> # or agents:, commands:, hooks:, rules:
source: everything-claude-code # or anthropic-skills / dotclaude-self / workflow / figma / private
Create a new preset — copy an existing one as a template:
KIND=core # or: framework, purpose
NAME=<preset-name>
mkdir -p presets/$KIND/$NAME
cp presets/core/developer/preset.yaml presets/$KIND/$NAME/preset.yaml
cp presets/core/developer/README.md presets/$KIND/$NAME/README.md
$EDITOR presets/$KIND/$NAME/preset.yaml # update name/kind/description/components/tags
Validate the preset:
pnpm validate <preset-name> --kind <core|framework|purpose>
# Into this project (.claude/ at repo root)
pnpm install:project <preset-name> --symlink --force
# Into user-level (~/.claude/)
pnpm install:user <preset-name> --symlink --force
--force overwrites in-place without creating .bak backups. --symlink keeps the installed component as a pointer back to claudekit/ (edits to the source are immediately live).
Pitfall:
pnpm install <preset>is intercepted by pnpm as an npm install. Always usepnpm install:projectorpnpm install:user.
If the preset has a settings_patch (e.g., hooks), the installer merges it into .claude/settings.json automatically. Check the result:
cat .claude/settings.json
pnpm validate <preset-name> --kind <kind>
pnpm typecheck && pnpm test
Confirm the component exists at its expected target location:
.claude/<type>/<name>/ or .claude/<type>/<name>.md (symlink or copy)~/.claude/<type>/<name>/One commit per vendor operation — keep them small and easy to revert:
git add claudekit/<source>/<type>/<name>/ presets/<kind>/<preset>.yaml presets/<kind>/<preset>.md
git commit -m "feat(<type>): vendor <name> from <upstream-alias>"
Conventional commits, English headers. Do not bundle multiple unrelated vendors in one commit.
If a component is already in claudekit/ and you want to pull upstream changes:
pnpm sync <type>/<name> # shows diff between sidecar.commit and upstream HEAD
# Review diff, manually merge desired changes into claudekit/<source>/<type>/<name>/
# Then update sidecar: bump source.commit, set modified: true if diverged
pnpm typecheck && pnpm test
Provides CDSS development patterns for drug interaction checking, dose validation, clinical scoring (NEWS2, qSOFA), and alert classification integrated into EMR workflows.
npx claudepluginhub phantien133/dotclaude --plugin dotclaude-self