Skip to content

feat(install): add --skills-dir mode (Claude Code skills-directory plugin)#2

Open
mh0pe wants to merge 5 commits into
ChristopherKahler:mainfrom
mh0pe:feat/install-skills-dir
Open

feat(install): add --skills-dir mode (Claude Code skills-directory plugin)#2
mh0pe wants to merge 5 commits into
ChristopherKahler:mainfrom
mh0pe:feat/install-skills-dir

Conversation

@mh0pe

@mh0pe mh0pe commented Jun 14, 2026

Copy link
Copy Markdown

What

Adds --skills-dir [--dir <path>] to the installer. It writes a self-contained skills-directory plugin that Claude Code auto-loads in place as base@skills-dir:

  • .claude-plugin/plugin.json
  • commands/, skills/, base-framework/
  • hooks/ (the 5 UserPromptSubmit hooks + satellite-detection SessionStart + a SessionStart MCP-deps bootstrapper) with hooks/hooks.json ({hooks:{...}} envelope)
  • mcp/base-mcp/ + a root .mcp.json
  • framework @-includes rewritten to ${CLAUDE_PLUGIN_ROOT}

Default target: <cwd>/.claude/skills/base/.

Why

  • Zero install — no claude plugin install, no marketplace setup.
  • Works in Claude Code Cloud — the cloud env clones the repo's .claude/skills/ but cannot see local marketplace installs; a committed skills-dir plugin is the supported way to ship a plugin to cloud.
  • Version-pins to the project and travels with the repo.

MCP bootstrapping

A skills-dir (or marketplace) plugin has no install step, so the base-mcp npm deps aren't present at launch and node mcp/base-mcp/index.js would fail with ERR_MODULE_NOT_FOUND. The emitted plugin includes a fail-open SessionStart hook that idempotently installs the MCP deps into ${CLAUDE_PLUGIN_DATA} and links them onto the MCP's module-resolution path (base-mcp is ESM, and Node's ESM loader ignores NODE_PATH, so a node_modules symlink is the operative mechanism; .mcp.json also sets NODE_PATH as a harmless CJS fallback). The hook short-circuits when deps already exist and never blocks the session if npm or ${CLAUDE_PLUGIN_DATA} is unavailable.

Verified: after the SessionStart install, the MCP boots cleanly (BASE MCP Server running on stdio, 21 tools) with no ERR_MODULE_NOT_FOUND.

First-session caveat: Claude Code may spawn the MCP concurrently with the SessionStart hook, so on a brand-new install the base-mcp becomes available from the next session (or after a restart) once deps are linked.

Relationship to the workspace-resolution PR

This branch includes the CLAUDE_PROJECT_DIR workspace-resolution fix offered standalone in the companion PR (the hooks need CLAUDE_PROJECT_DIR-aware resolution to work correctly in the .claude/skills/base/hooks/ layout). If the workspace PR is merged first, the overlapping commits apply cleanly; recommend merging that one first.

Notes

  • Existing install / --workspace paths are unchanged. --skills-dir cannot be combined with --global / --local (errors out).
  • Project-runtime refs (@.base/...) are left untouched; only framework @-includes are rewritten. apex-insights is an on-demand command and is intentionally not event-wired.
  • Ref: https://code.claude.com/docs/en/plugins-reference#skills-directory-plugins

🤖 Generated with Claude Code

mh0pe and others added 5 commits June 13, 2026 22:49
Prefer CLAUDE_PROJECT_DIR when set and non-blank; fall back to the
existing __dirname/HOOK_DIR relative resolution unchanged. Never throws
on missing env var. Affected: src/packages/base-mcp/index.js and all
six auto-register hooks (active, backlog, base-pulse-check, operator,
satellite-detection, psmm-injector) plus apex-insights.py.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…lugin

Adds --skills-dir [--dir <path>] flag to bin/install.js (purely additive,
no existing flags changed). Installs a Claude Code skills-directory plugin
at <cwd>/.claude/skills/base/ by default (or --dir <path>). Creates
.claude-plugin/plugin.json, commands/, skills/, base-framework/ (with
hooks/ and packages/), hooks/ + hooks.json (UserPromptSubmit + SessionStart
wiring), and mcp/ + .mcp.json. All @~/.claude/base-framework/ and
@./.claude/base-framework/ refs in copied .md files are rewritten to
${CLAUDE_PLUGIN_ROOT}/base-framework/. Hook and MCP command paths use
${CLAUDE_PLUGIN_ROOT}. Prints load instructions on completion.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…E_PROJECT_DIR hooks, conflict guard)

- Finding 1 (HIGH): move .mcp.json write target from mcp/.mcp.json to
  path.join(targetBase, '.mcp.json') so it lands at the plugin root.
  The arg path \${CLAUDE_PLUGIN_ROOT}/mcp/base-mcp/index.js is unchanged.
- Finding 2 (HIGH): merge origin/feat/workspace-project-dir into this branch
  so all 7 emitted hooks carry CLAUDE_PROJECT_DIR-first workspace resolution
  (falls back to HOOK_DIR.parent.parent when env is unset). base-mcp/index.js
  receives the same layered resolution. Plugin requires CLAUDE_PROJECT_DIR to
  be set at runtime; Claude Code sets it automatically for plugin hooks.
  This branch depends on feat/workspace-project-dir — note for PR description.
- Finding 3 (MEDIUM): add conflict guard — --skills-dir combined with --global
  or --local prints an error and exits non-zero before installSkillsDir() runs.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Emit hooks/install-mcp-deps.py (SessionStart hook) that installs
@modelcontextprotocol/sdk deps into CLAUDE_PLUGIN_DATA and symlinks
PLUGIN_ROOT/mcp/base-mcp/node_modules -> PLUGIN_DATA/node_modules so
Node ESM can resolve bare specifiers from the importing file's directory.

NODE_PATH added to .mcp.json env (CJS fallback; Node ESM requires the
symlink bridge since ESM does not honour NODE_PATH at import time).

- Idempotent: skips install if sdk marker already present; re-asserts symlink
- Fail-open: warns to stderr and exits 0 on any error (npm missing, env unset)
- Keeps all 5 UserPromptSubmit hooks + satellite-detection SessionStart hook
- Adds install-mcp-deps.py as second SessionStart hook entry
- Script emitted inline (not in src/hooks/) so it stays scoped to skills-dir

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@mh0pe

mh0pe commented Jun 14, 2026

Copy link
Copy Markdown
Author

Related PRs — part of a coordinated cross-repo offer (--skills-dir install mode (Claude Code skills-directory plugin)) applied across the carl/base/paul/seed framework forks:

Reviewing them together is recommended; the same change pattern is mirrored per repo.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant