9.3 KiB
Contributing to caveman
Thanks for considering a contribution. Caveman is a multi-agent skill that makes 30+ AI coding agents talk in compressed caveman-style prose. Most contributions fall into one of three buckets:
- Editing skill prose — change how caveman speaks, what intensity levels do, what slash commands trigger.
- Adding a new agent — wire a fresh editor/CLI/IDE into the unified installer.
- Fixing the hooks or installer — Claude Code hooks, the Node installer, the per-repo init script.
Caveman like simple. Small focused PR > big rewrite.
Quick orientation
The repo distributes one skill (caveman) plus a handful of sub-skills
(caveman-commit, caveman-review, caveman-compress, cavecrew-*) to many
agents through different distribution mechanisms (Claude Code plugin, Codex
plugin, Gemini extension, Cursor/Windsurf/Cline rule files, npx skills for
the long tail). A single Node installer at bin/install.js detects which
agents are on the user's machine and installs the right thing for each.
Sources of truth live at the top level of the repo. Agent-specific
copies live under plugins/caveman/ and similar mirror dirs — those are
rebuilt by CI and edits there are reverted.
What to edit (sources of truth)
| I want to change... | Edit this file |
|---|---|
| Caveman behavior (intensity levels, voice, rules) | skills/caveman/SKILL.md |
| Caveman commit-message format | skills/caveman-commit/SKILL.md |
| Caveman code-review format | skills/caveman-review/SKILL.md |
| Caveman compress logic | skills/caveman-compress/SKILL.md and skills/caveman-compress/scripts/ |
| Caveman quick-reference card | skills/caveman-help/SKILL.md |
| Cavecrew decision guide (when to delegate to subagents) | skills/cavecrew/SKILL.md |
| cavecrew subagent definitions | agents/cavecrew-investigator.md, agents/cavecrew-builder.md, agents/cavecrew-reviewer.md |
| Auto-activation rule body (Cursor/Windsurf/Cline/Copilot) | src/rules/caveman-activate.md |
| Add support for a new agent | bin/install.js (PROVIDERS array) |
| Per-repo init script (drops rule files into a user's repo) | src/tools/caveman-init.js |
| Claude Code hooks | src/hooks/caveman-activate.js, src/hooks/caveman-mode-tracker.js, src/hooks/caveman-config.js, src/hooks/caveman-statusline.sh, src/hooks/caveman-statusline.ps1 |
| Settings.json read/write helpers | bin/lib/settings.js |
| MCP shrink server | src/mcp-servers/caveman-shrink/ |
That's it. Every other markdown file with SKILL.md in the path is a copy.
What NOT to edit (CI-generated mirrors)
Edits to these files are wiped by the next CI run. The
.github/workflows/sync-skill.yml job rebuilds them from the sources above
on every push to main.
| Path | Rebuilt from |
|---|---|
plugins/caveman/skills/caveman/SKILL.md |
skills/caveman/SKILL.md |
plugins/caveman/skills/caveman-compress/{SKILL.md, scripts/} |
skills/caveman-compress/{SKILL.md, scripts/} |
plugins/caveman/skills/cavecrew/SKILL.md |
skills/cavecrew/SKILL.md |
plugins/caveman/agents/cavecrew-*.md |
agents/cavecrew-*.md |
dist/caveman.skill |
ZIP of skills/caveman/ (gitignored; rebuilt by CI on each push to main) |
caveman-commit, caveman-review, caveman-help, and caveman-stats are not mirrored under plugins/caveman/skills/ by CI. Claude Code reaches them through the standalone hook + skill install path and npx skills carries them to other agents. If you see plugins/caveman/skills/caveman-stats/ checked in, treat it as a legacy hand-committed copy — the workflow in .github/workflows/sync-skill.yml does not touch it.
When in doubt: if the file lives under plugins/, dist/, or any agent
dotdir mirror, it's a build artifact. Edit the top-level source instead.
Adding a new agent
The unified Node installer at bin/install.js is the single source of
truth for the supported-agent list. The README and INSTALL.md install
tables mirror it by hand — bash and PowerShell shims at the repo root just
delegate to it.
- Confirm the agent has a distribution path. Either:
- it has a profile slug in upstream vercel-labs/skills (most common), or
- it has a native plugin / extension / rule-file mechanism we can target.
- Append a row to the
PROVIDERSarray inbin/install.js. Each row needs:id— short kebab-case identifier (e.g.windsurf)label— human display name (e.g.Windsurf)mech— distribution mechanism (plugin,extension,rules-file,skills-cli, …)detect— clause spec likecommand:foo||dir:$HOME/xdescribing how to detect the agentprofile— the vercel-labs/skills slug, if applicablesoft: true— set when detection is config-dir-only (best-effort)
- Run
node bin/install.js --listand confirm the new row renders correctly. Soft probes should show as(soft). - Add a row to the install tables in
README.mdandINSTALL.md. - No CI changes needed — the workflow re-reads
bin/install.jsautomatically.
Bad slug? npx skills add fails at install runtime, not at install-script
load. Always verify the slug against the vercel-labs/skills README before
merging.
Adding a new skill
- Create
skills/<name>/SKILL.mdwith frontmatter:--- name: <name> description: <one sentence, present tense> --- - Create
skills/<name>/README.md— human-facing summary, install hint, example. - Add
skills/<name>/scripts/if the skill ships helpers (Python or Node). - If the skill should be in the Claude Code plugin, add a sync step to
.github/workflows/sync-skill.ymlso CI mirrors it intoplugins/caveman/skills/<name>/. - If it's user-invocable as a slash command, add a row to the slash-command table in
README.mdandINSTALL.md. - Add an eval prompt to
evals/prompts/en.txtif you want the eval harness to score it.
Running tests
# Installer unit + e2e tests (Node)
npm test
# Compress-skill safety tests (Python)
python3 -m unittest tests.test_compress_safety
# Per-repo init tests
node tests/test_caveman_init.js
# Flag-file symlink-safety tests
node tests/test_symlink_flag.js
CI runs all of the above on every PR. If any test depends on a network or external SDK, it must skip cleanly when the dependency is missing — never gate the whole suite on optional creds.
Running benchmarks and evals
Benchmarks hit the real Claude API and record raw token counts:
uv run python benchmarks/run.py # needs ANTHROPIC_API_KEY in .env.local
Evals are a three-arm offline harness (__baseline__, __terse__, each skill):
python evals/llm_run.py # regenerates evals/snapshots/results.json
python evals/measure.py # reads snapshot, prints token deltas
Snapshots are committed to git. Only regenerate when a SKILL.md or
evals/prompts/en.txt changes. Numbers in README.md and any docs come from
real runs — never invent or round.
Pull-request guidelines
- Conventional Commits for the commit subject. See
skills/caveman-commit/SKILL.mdfor the format we use here. - One concern per PR. A README copy-edit and an installer fix go in separate PRs.
- Update
package.jsonfilesif you add a new top-level directory the installer needs to ship to npm. Files outside that array don't get published. - Show before/after for prose changes to any
SKILL.md. One sentence on why the new wording is better. - Mention the CI sync. If you edited a source-of-truth file, note it: "CI will resync
plugins/caveman/skills/...on merge."
PR descriptions don't need to be long. Caveman style fine. Just say what change, why.
Code style
A handful of invariants that have bitten us before. Keep them.
- Hooks must silent-fail on filesystem errors. A
try/catchthat swallows the error is correct here. A hook that throws blocks Claude Code session start — that's user-facing breakage. See existing patterns insrc/hooks/caveman-activate.js. - Settings.json reads and writes go through
bin/lib/settings.js. It tolerates JSONC comments. DirectJSON.parseon a user'ssettings.jsonwill crash on a single// comment. - Validate hook entries before writing. Use
validateHookFields()inbin/lib/settings.js. Claude Code's Zod schema silently discards the entiresettings.jsonon a single bad hook entry — one malformed write poisons the user's whole config. - Symlink-safe flag writes via
safeWriteFlag()insrc/hooks/caveman-config.js. The flag file lives at a predictable path under$CLAUDE_CONFIG_DIR/; withoutO_NOFOLLOWand a parent-symlink check, a local attacker can clobber any file the user can write. - Honor
CLAUDE_CONFIG_DIR. Hooks, the installer, and the statusline scripts must respect it — never hardcode~/.claude. install.shandinstall.ps1at the repo root are 30-line shims that delegate tobin/install.js. Don't re-add per-OS install logic to them. Quoting bugs that way lie.
Ideas
See issues labeled good first issue
for starter tasks. Or grep TODO / FIXME in src/hooks/, bin/, src/tools/ —
each one is a real lead.
Caveman like contribution. You bring rock, caveman put rock in pile. Pile get bigger. Brain still big.