create-toolkit-installer
Generate install.js for Claude Code toolkit repos with manifest tracking, symlink/copy modes, and uninstall support. Use when creating a new distributable collection of commands, skills, agents, or references.
<essential_principles>
- Symlink-first, local-first. Default mode is symlinks into
./.claude/of the current project.--copyand--globalare opt-in overrides. This meansgit pullin the toolkit repo auto-updates all installations. - Skills get directory-level symlinks. Each skill directory becomes one symlink in link mode (not per-file). Everything else (commands, agents, references) uses individual file symlinks.
- Unmanaged target paths are conflicts. Pre-existing files, directories, or symlinks at install destinations must be treated as conflicts, even on a fresh install. Never silently replace user-owned
.claude/content in non-interactive mode. - INSTALLABLE_DIRS drives everything. A single array constant at the top of the script controls file collection, migration scanning, install counts, orphan protection, and summary output. Adding or removing a directory is a one-line change.
- Manifest per toolkit. Each toolkit stores its manifest in
<target>/<toolkit-name>/.manifest.json. Multiple toolkits coexist at the same target without collision.
</essential_principles>
<process>Step 1: Detect project structure
Scan the current project root for installable content directories:
agents/— subagent configurationscommands/— slash commandsskills/— auto-activating skillsreferences/— reference documents
Only include directories that exist and contain files. These become the INSTALLABLE_DIRS array.
If the project has files that need remapping (e.g., a file at root that should install into references/), note this — but prefer moving the source file into the correct directory rather than adding special-case mappings. The template assumes source structure mirrors install structure.
Step 2: Gather configuration
Determine from project context or ask the user:
- Toolkit name — kebab-case identifier for the manifest directory (e.g.,
flutter-llm-toolkit). Usually matches the repo name. - Repo URL — GitHub clone URL for help text examples.
- Clone directory name — what users name the local clone (e.g.,
my-toolkit). Usually matches the repo name. - Description — one-line description for help text (e.g.,
Flutter/Dart skills and commands for Claude Code). - Legacy name — if this toolkit was renamed from something else, the old name enables manifest migration. Otherwise
null.
Step 3: Generate install.js
Read references/install-script-reference.md for the complete template and gotchas.
- Copy the template from the "Complete Template" section
- Set the 6 configuration constants at the top:
TOOLKIT_NAME— from step 2TOOLKIT_DESCRIPTION— from step 2REPO_URL— from step 2REPO_CLONE_NAME— from step 2INSTALLABLE_DIRS— from step 1LEGACY_MANIFEST_DIR_NAME— from step 2 (ornull)
- No other changes needed — the rest of the script adapts via these constants
Write install.js at the project root. Run chmod +x install.js to make it executable.
Step 4: Verify installer behavior
Run smoke tests in a disposable project directory before considering the installer done:
- Install + uninstall in link mode — confirm skills uninstall by removing only the skill symlink root, not files inside the source repo.
- Broken legacy symlink migration — create a stale symlink under an installable directory and confirm install still succeeds.
- Unmanaged target collision — create a pre-existing
.claude/...file or symlink and confirm non-interactive install stops unless the user runs interactively or passes--force.
Step 5: Generate documentation
README Quick Start section
Adapt this template (replace REPO_URL, REPO_CLONE_NAME with actual values):
## Quick start
Requires Node.js 16.7+ and [Claude Code](https://docs.anthropic.com/en/docs/claude-code).
**Clone once, install anywhere:**
\```bash
git clone REPO_URL ~/toolkits/REPO_CLONE_NAME
\```
**Install into a project** (default — symlinks into `./.claude/`):
\```bash
cd your-project
~/toolkits/REPO_CLONE_NAME/install.js
\```
**Install globally** (available in all projects):
\```bash
~/toolkits/REPO_CLONE_NAME/install.js --global
\```
**Copy mode** (for team sharing via git):
\```bash
cd your-project
~/toolkits/REPO_CLONE_NAME/install.js --copy
\```
**Uninstall:**
\```bash
cd your-project
~/toolkits/REPO_CLONE_NAME/install.js --uninstall
\```
Symlinks are the default — a `git pull` in the toolkit repo updates all installations automatically. Use `--copy` when you need to commit the files into your project. Not supported on Windows (use `--copy`).
CLAUDE.md install snippet
Add to the project's CLAUDE.md under conventions:
- To install the toolkit, run `install.js` from the target project directory (or use `--global` for `~/.claude/`):
- Default: symlinks into `./.claude/` of the current project (auto-updates with `git pull`)
- `--global` installs to `~/.claude/` (all projects)
- `--copy` copies files instead of symlinking (for team sharing via git)
- `--uninstall` removes all toolkit files from the target scope
</process>
<reference_index>
Supporting files in references/:
install-script-reference.md— complete install.js template, configuration constants table, architecture overview, and 14 gotchas from production use. Read before generating the script.
</reference_index>
<success_criteria>
- Template used verbatim from reference — no manual modifications to universal logic
- install.js uses INSTALLABLE_DIRS constant to drive all directory-dependent behavior (no hardcoded directory lists elsewhere)
-
chmod +x install.jsrun after writing the file - install.js smoke-tested for link-mode install/uninstall, broken legacy symlink migration, and unmanaged target collisions
- CLAUDE.md snippet generated with install instructions
- README Quick Start section generated with correct repo URL and clone name
- Configuration constants at top match the detected project structure and user-provided values
</success_criteria>