caveman-shrink@0.1.0 is now live on npm (pre-1.0). Restore the original
default-on behavior for --with-mcp-shrink / -WithMcpShrink. Keep the
`npm view caveman-shrink` probe — a transient registry outage now degrades
to a clean manual-config skip instead of registering a `npx -y caveman-shrink`
entry that would have spawned-failed.
Also: sync `model: haiku` onto cavecrew investigator/reviewer canonicals
so the top-level agents/ matches the synced plugins/caveman/agents/.
README + CLAUDE.md flipped back to "On by default."
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
install.sh:
- detect_match: replace `awk -v RS='||'` (rejected by macOS BSD awk:
"illegal primary in regular expression") with bash parameter expansion.
Compound detection specs were silently failing, so cursor / windsurf /
continue / and 28 other compound-spec providers were never detected.
- --with-mcp-shrink: flip default OFF + probe `npm view caveman-shrink`
before registering. Was registering a config that 404s on first spawn.
install.ps1: mirror the MCP-shrink default flip + npm probe.
tests: update statusline tests for default-on suffix behavior. Add a
regression for fresh installs where the suffix file is absent.
Add npm-pkg-fix formatting to package.json.
cavecrew: promote agents/cavecrew-*.md to top-level canonical, refine
subagent contracts (sharper output formats, terminal refusal
lines, model: haiku for read-only roles). CI workflow syncs
agents/ + skills/cavecrew/ into plugins/caveman/.
docs: README & CLAUDE.md align with new opt-in MCP-shrink policy.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- caveman-stats: dollar math via per-million model pricing, --share
tweetable line, lifetime log via symlink-safe appendFlag, --all and
--since N[d|h] aggregation, opt-in statusline savings suffix, and
detection of *.original.md compress backups for input-side savings.
- install.sh / install.ps1 at repo root: smart multi-agent installer
that detects Claude Code, Gemini, Codex, Cursor, Windsurf, Cline,
Copilot and runs each one's native install. Idempotent, --dry-run,
--only, --force.
- cavecrew: skills/cavecrew + three Claude Code subagents
(investigator / builder / reviewer) for caveman-style machine-to-
machine handoffs.
- cavepack: tools/caveman-init.js drops the always-on caveman rule
into Cursor / Windsurf / Cline / Copilot / AGENTS.md in one shot,
idempotent, with a sentinel check so re-runs never duplicate.
- caveman-shrink: MCP middleware proxy + pure-Node prose compressor
that strips articles/filler/hedging from tools/list descriptions
while preserving code, URLs, paths, and identifiers byte-for-byte.
59 tests passing (27 stats, 8 init, 12 mcp-shrink, 12 symlink-flag).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
New slash command that reads the active Claude Code session JSONL
(.claude/projects/**/*.jsonl), sums output_tokens and
cache_read_input_tokens from assistant turns, and shows an estimated
savings figure when the active mode is 'full'.
Real numbers, not the model's guess:
Caveman Stats
──────────────────────────────────
Session: ...projects/my-app/abc123.jsonl
Turns: 47
──────────────────────────────────
Output tokens: 3,210
Cache-read tokens: 128,400
──────────────────────────────────
Est. without caveman: 9,171
Est. tokens saved: 5,961 (~65%)
Savings est. from benchmarks/ (mean per-task). Actual varies by task.
Implementation:
* hooks/caveman-stats.js — script. Run directly with
`node hooks/caveman-stats.js`, or via `--session-file <path>`.
Falls back to most-recent JSONL under .claude/projects/ when no
session file is passed.
* hooks/caveman-mode-tracker.js — `/caveman-stats` triggers an
execFileSync call to caveman-stats.js with the hook's transcript_path,
and the output is returned via `decision: "block"` so the user sees
the stats inline without a model round-trip.
* install.sh / install.ps1 / uninstall.{sh,ps1} include
caveman-stats.js in HOOK_FILES.
* skills/caveman-stats/SKILL.md (+ plugin mirror) for skill listing.
* README install matrix and Caveman Skills section updated.
Compression ratio (0.65) is the mean per-task figure from
benchmarks/results/*.json (avg_savings: 65 across 10 tasks). Only 'full'
mode has measured data — lite/ultra/wenyan show no estimate.
Tests: 6 passing in tests/test_caveman_stats.js covering direct
invocation, full-mode estimate math, non-full skip, no-session error,
mode-tracker block behavior, and flag preservation.
Closes#305 (re-implementation; takes the design from
@DeeptimaanB but rewritten against current main).
Co-Authored-By: Deeptimaan Banerjee <DeeptimaanB@users.noreply.github.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Codex install line now says "Open Codex in repo" before /plugins,
removing first-time-user ambiguity (#226 by @cirops).
* Windows manual fallback section: PowerShell block to copy SKILL.md
into the plugin path and patch marketplace.json by hand when
automated install fails (#258 by @Abbasam8910). Plugin-skill only;
doesn't install standalone hooks/statusline.
Skipped from this batch:
* #290 (75% → 50% headline numbers) — leaving the headline figure as is.
* #295 (Pages link) — not advertising the Pages site in the README.
Co-Authored-By: Ciro Plá <cirops@users.noreply.github.com>
Co-Authored-By: ABBAS A M <Abbasam8910@users.noreply.github.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Three small SKILL.md edits batched:
* Ultra mode: spell out that abbreviation applies to prose only, never to
code symbols, function names, API names, or error strings (#238 by
@AnthoHansen). Stops models from rendering literal `fn` in code where
the user wrote `function`.
* Auto-clarity (#239 by @AnthoHansen): bullet list replaces run-on
sentence; adds explicit trigger for compression-induced ambiguity in
technical sequences (e.g. "migrate table drop column backup first").
* Typst + LaTeX (#243 by @wildwestrom): add .typ, .typst, .tex to
COMPRESSIBLE_EXTENSIONS in caveman-compress/scripts/detect.py and to
the boundaries lists in SKILL.md / README.md.
Synced SKILL.md to caveman/, plugins/caveman/skills/caveman/,
.cursor/skills/caveman/, .windsurf/skills/caveman/, and rebuilt
caveman.skill ZIP.
Co-Authored-By: Anthony Domínguez <AnthoHansen@users.noreply.github.com>
Co-Authored-By: West <wildwestrom@users.noreply.github.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two converging hook fixes:
* /caveman arg parser uses VALID_MODES whitelist (#314 by @jgttech).
Drops the silent fallback to getDefaultMode() on unknown args. Three
bugs collapsed: /caveman full was impossible if defaultMode was set
to anything else, /caveman off had no effect, and typos like
/caveman fulll silently clobbered state. Now: bare /caveman activates
default; /caveman off|stop|disable removes flag; unknown args leave
flag untouched (no silent overwrite); independent modes (commit,
review, compress) cannot be selected as args.
* safeWriteFlag through symlinked ~/.claude (#224 by @voidborne-d,
closes#207). Earlier hardening (5ad8f6d) refused every symlinked
parent including legitimate ~/.claude → /opt/shared-claude or
/mnt/d/claude-config patterns. Now resolves the parent via
realpathSync, verifies ownership on Unix (uid match) or under-home
on Windows, and uses the resolved path for the atomic write. Flag
file itself still must not be a symlink — that's the actual clobber
vector. CAVEMAN_DEBUG=1 emits stderr diagnostics on refusal.
12 regression tests in tests/test_symlink_flag.js — all pass.
Verified:
/caveman / lite / full / ultra / wenyan{,-lite,-full,-ultra} → mode set
/caveman off / stop / disable → flag deleted
/caveman commit → no flag (rejected)
/caveman fulll (typo) → no flag (rejected)
symlink ~/.claude → owned dir → write succeeds in real dir
symlink ~/.claude → other-user dir → refused
Co-Authored-By: Jonathon Tech <jgttech@users.noreply.github.com>
Co-Authored-By: voidborne-d <voidborne-d@users.noreply.github.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
PowerShell 5.1 mangles the multiline $nodeScript when passed to
node -e — the embedded `"` after `node ` terminates the argument
early, causing SyntaxError mid-install. Hook files copy but
settings.json never updates, leaving caveman non-functional.
Write the script to %TEMP%\caveman-install-<pid>.js, run it, clean
up in a finally block. Verified clean install on Windows 11 /
PowerShell 5.1 / Node 24.
Closes#249.
Co-Authored-By: Scott Converse <scottconverse@users.noreply.github.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Five user-contributed fixes consolidated:
* UTF-8 stdout (#289 by @ousamabenyounes) — reconfigure stdout/stderr at the
top of cli.py so Windows cp1252 consoles don't crash on the ❌ glyph in
error/validation branches and mask the real error.
* Empty / unchanged compression guards (#292 by @ousamabenyounes, closes#237)
— refuse empty input, refuse empty/whitespace/identical Claude output,
read back the backup before touching the input. Five regression tests in
tests/test_compress_safety.py.
* Inline backtick validation (#309 by @hireblackout) — validate_inline_codes
closes the silent-overwrite gap where `npm install` → `yarn install`
passed validation. Wired into validate(); 11 unit tests in
tests/test_validate_inline.py.
* Frontmatter angle-bracket fix (#268 by @Bortlesboat, closes#266) —
caveman-compress/SKILL.md description now uses FILEPATH instead of
<filepath>, plus verify_repo gains a new
verify_skill_frontmatter_upload_compatibility check, UTF-8 hardening for
Windows, and the activation-banner regex no longer requires a trailing
period.
* Two test fixtures (claude-md-project.md, mixed-with-code.md) updated so
the new inline-backtick validator passes — they were silently dropping
`server/src/`, `type(scope): description`, and `status` references in
compression. The fixture is documentation of "good" compression, so the
fix is to preserve those references.
Co-Authored-By: Ben Younes <ousama.benyounes@oratelecom.net>
Co-Authored-By: hireblackout <hireblackout@users.noreply.github.com>
Co-Authored-By: Andrew Barnes <Bortlesboat@users.noreply.github.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Add consistent ecosystem banner near the top and a unified
"Caveman Ecosystem" section near the bottom so visitors of any repo
can discover and reach the others.
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Writes were hardened via safeWriteFlag (PRs #70/#71) but readers still
trusted whatever the flag contained. A local attacker with write access
to ~/.claude/ could symlink the flag at a secret file and have the
per-turn reinforcement inject its bytes into model context, or the
statuslines echo ANSI escapes to the terminal on every keystroke.
- caveman-config.js: new readFlag() — lstat symlink refuse, 64-byte cap,
O_NOFOLLOW, VALID_MODES whitelist. Returns null on any anomaly.
- caveman-mode-tracker.js: per-turn reinforcement routes through
readFlag() instead of fs.readFileSync.
- caveman-statusline.sh / .ps1: symlink + size refuse, strip to
[a-z0-9-], whitelist-validate before rendering.
- compress.py (3 synced copies): is_sensitive_path() denylist refuses
.env*, .netrc, keys/certs, ~/.ssh|.aws|.gnupg|.kube|.docker, and any
basename containing secret/credential/password/apikey/token/privatekey
(separator-insensitive). Fails loudly before read — no silent exfil
of credentials to the Anthropic API.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Parent-chain walk produced false positives: macOS /tmp -> /private/tmp
and symlinked home dirs broke all flag writes. Check only the immediate
parent directory and the target itself — that covers the threat model
(attacker replacing the flag with a symlink) without breaking legit
paths.
Extend safeWriteFlag() in caveman-config.js with:
- hasSymlinkInPath() walks every ancestor component and refuses
if any is a symlink (protects against parent-dir redirect)
- Atomic write via temp file + rename
- O_EXCL on temp open to prevent race
Removes duplicate local helper from mode-tracker.
Co-Authored-By: tuanaiseo <221258316+tuanaiseo@users.noreply.github.com>
Consolidate write protection into safeWriteFlag() helper in
caveman-config.js. Applied to all flag write sites:
- caveman-activate.js (SessionStart)
- caveman-mode-tracker.js slash command
- caveman-mode-tracker.js natural-language activation
Refuses symlink targets via lstat, opens with O_NOFOLLOW where
supported, writes with 0600.
Co-Authored-By: tuanaiseo <221258316+tuanaiseo@users.noreply.github.com>
When ~/.claude/package.json (or any ancestor) contains "type": "module",
Node treats every .js file under that tree as an ES module. The caveman
hooks use require() and crash with:
ReferenceError: require is not defined in ES module scope
surfaced as:
SessionStart:clear hook error / UserPromptSubmit hook error
Failed with non-blocking status code: .../caveman-activate.js:9
This pins the hooks directory to CommonJS via a local package.json, so
module resolution no longer depends on whatever the user's ~/.claude
directory declares. Also wires the new file into install/uninstall
scripts so standalone installs (curl | bash / Invoke-WebRequest)
copy it into ~/.claude/hooks/ alongside the JS files.
Addresses the ESM sub-case flagged in #167 (comment by mrx-arafat).
Does not fix the Windows path-with-spaces expansion issues in #167/#78/#72
which have a separate root cause in plugin.json ${CLAUDE_PLUGIN_ROOT}
quoting.
Both SessionStart and UserPromptSubmit hook commands passed
${CLAUDE_PLUGIN_ROOT} unquoted, so the shell split the expansion
on whitespace whenever a user's plugin root contained a space
(e.g. /Users/Tyler Laprade/...). Node received a truncated path
and errored with "Cannot find module '/Users/Tyler'", preventing
the plugin from loading.
Wrapping the variable in double quotes keeps the path intact on
any POSIX-style shell and has no effect on paths without spaces.
Fixes#157
Fragment targets #caveman-commit / #caveman-review were missing.
Replace skills table with ### subsections, triggers inline on each
blurb; add /caveman:compress trigger on compress lead-in.
Gemini CLI fails to load skills through symlinks. Replace symlinks
in skills/compress/ with actual file copies and update CI to keep
them in sync. Remove redundant root compress/ directory.
Gemini CLI fails to load skills through symlinks. Replace symlinks
in skills/compress/ with actual file copies and update CI to keep
them in sync. Remove redundant root compress/ directory.
Enable repo-local Codex hooks and use the current nested SessionStart
matcher format. Document macOS/Linux auto-start, the Windows hook limit,
and the feature flag needed when copying the hook to other repos.
All hook files hardcoded ~/.claude as the Claude config directory.
Users who set CLAUDE_CONFIG_DIR (e.g. for XDG compliance) had hooks
writing to the wrong location. Now all hooks check CLAUDE_CONFIG_DIR
first, falling back to ~/.claude.
Closes#140
Mirror the /caveman command path: skip writing flag file when
getDefaultMode() returns 'off'. Without this, "talk like caveman"
with CAVEMAN_DEFAULT_MODE=off would write 'off' to the flag file,
making statusline/reinforcement inconsistent.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Independent modes have their own skill behavior — emitting base caveman
rules ("Drop articles, fragments OK") on every turn conflicts with the
specialized format those modes expect.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
README tells users they can say "talk like caveman" to activate, but the
UserPromptSubmit hook only matched /caveman commands. This meant the flag
file and statusline badge stayed out of sync when users activated via
natural language — the model would speak caveman (it reads the prompt)
but the hook never wrote the flag file.
Now matches: "activate caveman", "turn on caveman mode", "talk like
caveman", "disable caveman", "turn off caveman", etc. Uses a negative
guard so "stop caveman" doesn't trigger activation first.
Uses getDefaultMode() for natural language activation to respect
CAVEMAN_DEFAULT_MODE and config.json, same as /caveman command.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The SessionStart hook injects caveman rules once, but models lose them
when other plugins (output styles, learning modes) inject competing
style instructions on every turn. Recency and repetition win in LLM
attention — a one-shot injection loses to per-turn reinforcement.
Emit a short structured reminder via hookSpecificOutput on every user
message when caveman is active. Uses the same JSON format Claude Code
expects from hooks, keeping the full ruleset from SessionStart in
context while this reminder keeps it top-of-mind.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace hardcoded intensity table and examples with runtime loading of skills/caveman/SKILL.md (single source of truth). Strip YAML frontmatter and filter the intensity table and examples to include only the active mode; fall back to a minimal built-in ruleset when SKILL.md is missing (standalone installs). Add INDEPENDENT_MODES (commit, review, compress) to short-circuit and emit a brief activation line for modes that use their own skill files. Normalize the wenyan alias to wenyan-full. Overall simplifies maintenance and prevents duplicated, stale rule text in the hook.
Replace the terse one-line caveman activation message with a full, structured ruleset and examples. Introduces INTENSITY and EXAMPLES maps (lite/full/ultra + wenyan variants), selects the active level from mode with a fallback, and builds a detailed output covering persistence, rules, examples, auto-clarity and boundaries. Rationale: anchor terse response behavior more reliably to prevent drift and provide selectable verbosity/compression profiles while preserving exact code/commit formatting.
Mode tracker wrote getDefaultMode() result to flag file even when it
returned "off". Now guards against it — same pattern as caveman-activate.
Added test coverage for off mode in both activate and tracker paths.
Also: fix swapped step comments in uninstall.sh, update stale CLAUDE.md
description for /caveman default.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Set CAVEMAN_DEFAULT_MODE=off or {"defaultMode":"off"} in config to
skip session-start activation. No flag file written, no rules injected.
User can still manually activate with /caveman.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
/caveman-help displays all modes, skills, triggers, config options,
and deactivation — one-shot display, no mode change.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>