140 Commits
Author SHA1 Message Date
github-actions[bot] c2ed24b3e5 chore: sync SKILL.md copies and auto-activation rules [skip ci] v1.6.0 2026-04-15 12:50:24 +00:00
Julius BrusseeandClaude Opus 4.6 5ad8f6d684 fix(security): harden flag-file reads and refuse sensitive-file compression
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>
2026-04-15 14:49:26 +02:00
Julius Brussee 4c82699c26 docs(CLAUDE.md): document hook system updates from merged PRs
- safeWriteFlag helper in caveman-config.js
- CLAUDE_CONFIG_DIR env var support
- hooks/package.json CommonJS marker
- natural-language activation in mode tracker
- per-turn reinforcement output
- key rules: route writes through safeWriteFlag, respect CLAUDE_CONFIG_DIR
2026-04-15 14:44:38 +02:00
Julius Brussee d8d53115d0 fix(hooks): safeWriteFlag check immediate parent not full chain
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.
2026-04-15 14:44:38 +02:00
Julius Brusseeandtuanaiseo 205e537103 Merge PR #71: strengthen safeWriteFlag with parent-chain check
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>
2026-04-15 14:44:38 +02:00
Julius Brusseeandtuanaiseo adafaba5cd Merge PR #70: symlink-safe flag file writes
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>
2026-04-15 14:44:34 +02:00
Julius Brussee e50325b040 Merge PR #119: per-turn reinforcement in UserPromptSubmit 2026-04-15 14:44:20 +02:00
Julius Brussee 23ce800ad6 Merge PR #120: natural language activation/deactivation 2026-04-15 14:44:20 +02:00
Julius Brussee 4fe5a5d70a Merge PR #169: fix README links 2026-04-15 14:27:57 +02:00
Julius Brussee 507ec0af22 Merge PR #153: replace broken symlinks with real files 2026-04-15 14:27:50 +02:00
Julius Brussee 4345efd45a Merge PR #146: respect CLAUDE_CONFIG_DIR 2026-04-15 14:27:23 +02:00
Julius Brussee 7e89c6a3cd Merge PR #148: fix codex hook config shape 2026-04-15 14:27:13 +02:00
Julius Brussee b1ca6818f9 Merge PR #171: quote CLAUDE_PLUGIN_ROOT for paths with spaces 2026-04-15 14:27:07 +02:00
Julius Brussee 5af591a028 Merge PR #174: isolate hooks as CommonJS 2026-04-15 14:27:02 +02:00
Dmitrii Malakhov b50aa6d4b3 fix: isolate hooks as CommonJS so they survive ESM parent package.json
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.
2026-04-15 10:49:52 +02:00
mukunda katta fea439dc14 Fix: quote ${CLAUDE_PLUGIN_ROOT} so hooks work on paths with spaces
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
2026-04-14 23:04:28 -07:00
nervana21 d63b47673c docs: Fix skill anchor links in README
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.
2026-04-14 21:21:21 -04:00
Arkadiusz Gładki 3897f40b97 docs: clarify source of truth for compress skill 2026-04-14 13:15:35 +02:00
Arkadiusz Gładki 52fec218a5 fix(compress): replace broken symlinks with real files
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.
2026-04-14 13:08:42 +02:00
Arkadiusz Gładki 1e0fb7f3dd fix(compress): replace broken symlinks with real files
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.
2026-04-14 12:59:00 +02:00
David Young e192972632 fix(codex): update hook config shape
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.
2026-04-14 09:18:29 +02:00
Brendan Izu 7b4649fad0 fix: respect CLAUDE_CONFIG_DIR env var across all hooks
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
2026-04-13 21:21:48 -07:00
Julius BrusseeandGitHub 63e797cd75 Update GitHub Sponsors username in FUNDING.yml 2026-04-12 19:59:23 +02:00
Matthias HumtandClaude Opus 4.6 f7ef823b91 fix: guard natural language activation against off default mode
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>
2026-04-12 13:19:09 +02:00
Matthias HumtandClaude Opus 4.6 4c6dad829a fix: skip reinforcement for independent modes (commit/review/compress)
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>
2026-04-12 13:18:45 +02:00
Matthias HumtandClaude Opus 4.6 56f4047ab3 fix: detect natural language activation/deactivation in mode tracker
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>
2026-04-12 13:12:11 +02:00
Matthias HumtandClaude Opus 4.6 3ed7b732b0 fix: add per-turn reinforcement to UserPromptSubmit hook
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>
2026-04-12 13:11:15 +02:00
Julius Brussee 600e8efcd6 Load SKILL.md; handle independent modes
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.
v1.5.1
2026-04-12 00:17:07 +02:00
Julius Brussee 80a317e472 Expand caveman ruleset and add intensity levels
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.
2026-04-12 00:11:14 +02:00
Jayesh PatelandGitHub 6a6c144f28 docs: consolidate Cursor/Windsurf/Cline/Copilot install details into one block (#106)
Consolidate four near-identical Cursor/Windsurf/Cline/Copilot detail blocks into one table. -53/+9 lines.
2026-04-12 00:02:30 +02:00
Jimmy CrakCrnandGitHub 8be1bdd4c7 fix(docs): use ANSI-C quoting for bash statusline badge example (#57)
Fix ANSI-C quoting in hooks/README.md statusline example — escape sequences need $'...' syntax to render in bash.
2026-04-12 00:02:27 +02:00
Julius BrusseeandClaude Opus 4.6 8bab5c739e fix: prevent /caveman from writing "off" to flag file
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>
2026-04-11 18:27:41 +02:00
Julius BrusseeandClaude Opus 4.6 c80f8d7fe1 feat: add "off" default mode to disable auto-activation
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>
v1.5.0
2026-04-11 18:23:42 +02:00
Julius BrusseeandClaude Opus 4.6 12e78c5201 feat: add caveman-help skill for quick-reference card
/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>
2026-04-11 18:03:23 +02:00
Julius BrusseeandClaude Opus 4.6 ea89000141 feat: make default caveman mode configurable
Add caveman-config.js shared config resolver. Default mode resolves via:
CAVEMAN_DEFAULT_MODE env var > XDG config file > 'full'.

Updated all install/uninstall scripts (bash + PowerShell) and tests.

Closes #86

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 17:56:45 +02:00
Julius BrusseeandClaude Opus 4.6 24e6ee9ea8 fix: replace compress skill symlinks with real files for Windows/Codex compatibility
Symlinks in plugins/caveman/skills/compress/ were checked out as plain
text path stubs on Windows (core.symlinks=false), causing Codex to reject
SKILL.md as missing YAML frontmatter. Replace with verbatim copies of
source files and add CI sync step to keep them in sync.

Closes #92

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
v1.4.1
2026-04-11 15:31:01 +02:00
Julius BrusseeandGitHub 0bbd46c390 Remove local verification section from README
Removed local verification instructions and related text.
2026-04-11 12:33:04 +02:00
github-actions[bot] a311eab867 chore: sync SKILL.md copies and auto-activation rules [skip ci] 2026-04-11 10:30:01 +00:00
Julius Brussee bce42f7294 docs(readme): fix install behavior claims v1.4.0 2026-04-11 12:27:39 +02:00
Julius Brussee 8783f63296 Require statusLine and fix PS5.1 parsing
Make the installer require a configured statusLine before treating hooks as already installed and ensure PowerShell 5.1 compatibility. hooks/install.ps1: stop using -AsHashtable, adjust hooks access, track presence of settings.statusLine and only skip installation when SessionStart, UserPromptSubmit and statusLine are present. hooks/install.sh: add HAS_STATUSLINE check and update the Node-based settings validation to require settings.statusLine. tests/test_hooks.py: add test_install_reconfigures_missing_statusline to verify installer adds a missing statusLine. tests/verify_repo.py: add a manifest path to the verification list and assert that -AsHashtable is not used in install.ps1 to preserve compatibility with Windows PowerShell 5.1.
2026-04-11 12:22:07 +02:00
Julius Brussee 7e2c94c541 Add Windows statusline & robust hook install
Add a PowerShell statusline script (hooks/caveman-statusline.ps1) and update activation/installer logic to support Windows and avoid clobbering custom statuslines. install.sh and install.ps1 now check for a full set of hook files and wired hook entries before short-circuiting, wire a managed statusline path, and prefer not to overwrite user statusLine settings. Uninstall scripts now remove the managed statusline only when it was installed. caveman-activate.js updated to detect existing statusLine entries and emit a platform-appropriate snippet. Add tests (tests/test_hooks.py) and a local verification runner (tests/verify_repo.py) to validate install/uninstall/activation flows and caveman-compress fixtures. Also update README and caveman-compress docs and stats (token savings ~45%→~46%) and clarify auto-activation and statusline behavior.
2026-04-11 12:14:46 +02:00
Julius Brussee 8fb2f013a9 Improve hooks safety, validation, and docs
Make several robustness and clarity fixes across scripts and docs:

- README: Clarify agent-specific behavior (Codex, Cursor/Windsurf) and note Codex uses $caveman and lacks some bundled plugins.
- caveman-compress: Avoid division-by-zero when computing token savings; skip unclosed markdown fences when extracting code blocks to prevent false positives.
- hooks (install/uninstall, PowerShell and shell): Pass settings and hooks paths via environment variables to avoid injection issues with special characters, quote generated command paths, use safer here-strings in PowerShell, and ensure settings.json is written via the resolved path. Also remove installer backup files during uninstall and add explanatory comments.

These changes improve security, correctness, and developer-facing documentation.
2026-04-11 11:59:05 +02:00
Julius Brussee e8015c384c Add CLAUDE.md (caveman README) and backup
Add a new caveman-styled README (CLAUDE.md) documenting project overview, file ownership, CI sync workflow, hook system, skill system, agent distribution, evals, and benchmarks. Also add CLAUDE.original.md as the original, more formal copy for reference/backup.
2026-04-11 11:56:02 +02:00
Julius Brussee b6a7a3f584 Add auto-activation rules and sync workflow
Enable automatic caveman mode activation across agents and keep skill copies in sync. Adds activation rule files (.clinerules, .codex/hooks.json, .cursor/rules/caveman.mdc, .windsurf/rules/caveman.md, .github/copilot-instructions.md, rules/caveman-activate.md), new command prompts (commands/caveman{,-commit,-review}.toml), and updates SKILL.md copies (skills/, caveman/, plugins/, .cursor/, .windsurf/) to add persistent behavior and tweak auto-clarity wording. Updates README with agent-specific auto-activation docs and expands compatibility table. Updates GitHub Actions workflow to sync SKILL.md, copy activation rules, rebuild caveman.skill, and commit any changes. Includes updated caveman.skill binary.
2026-04-11 11:48:34 +02:00
Julius Brussee 79fa46a4a0 Add windsurf skill, hooks, and install docs
Add .windsurf/skills/caveman SKILL.md and update the sync workflow to copy and commit the new file. Expand README install docs with agent-specific install instructions and standalone hook usage; update AGENTS.md and GEMINI.md to use the new caveman-compress path. Add Windows PowerShell installers (hooks/install.ps1 and hooks/uninstall.ps1) and enhance shell installers (hooks/install.sh, hooks/uninstall.sh) to support --force, plugin detection, clearer statusline wiring messages, and idempotent JSON merging/removal of hook entries. Provides uninstall guidance for other agents and improves overall install/uninstall robustness.
2026-04-11 11:30:34 +02:00
Julius Brussee cfd76590bd Add statusline badge, hooks, and compress fixes
Add statusline support and installer/uninstaller hooks, improve compression tooling and docs. Key changes:

- Add caveman statusline badge script (hooks/caveman-statusline.sh) and wire it into install/uninstall (hooks/install.sh, hooks/uninstall.sh); installer now requires node, backs up settings.json, and makes the statusline executable.
- Enhance SessionStart hook (hooks/caveman-activate.js) to detect missing statusline config and emit a setup nudge; update hooks README with statusline usage and setup instructions.
- Add gemini-extension.json, AGENTS.md, and GEMINI.md to register skills and support Gemini CLI installation.
- Update README to mention statusline badge, Gemini CLI install, and agent list.
- Improve caveman-compress: rename skill (caveman-compress), clarify CLI path/usage in SKILL.md, return on validation failure without overwriting, bump benchmark encoding, and make compressor robust to LLM outer fences by stripping wrapping fences and expanding max_tokens; add explicit rule to avoid wrapping entire output in fences.
- Strengthen code-block extraction in validate.py to handle variable-length fences (```/~~~), nested fences, and CommonMark rules.
- Minor SKILL.md tweak: resume caveman mode when user asks to clarify or repeats question.

These changes integrate a visible status badge for Claude Code users, improve install/uninstall reliability, extend Gemini support, and make the compressor/validator more robust when interacting with LLM outputs.
2026-04-11 11:15:03 +02:00
tuanaiseo 5580f8e28f fix(security): mode tracker flag file write also vulnerable to sy
The UserPromptSubmit hook similarly writes to `~/.claude/.caveman-active` without checking whether the path is a symlink. This duplicates the same local file-clobber risk in another execution path.

Affected files: caveman-mode-tracker.js

Signed-off-by: tuanaiseo <221258316+tuanaiseo@users.noreply.github.com>
2026-04-10 20:34:08 +07:00
tuanaiseo 7906016383 fix(security): hook writes to predictable path without symlink pr
The SessionStart hook writes to `~/.claude/.caveman-active` using `fs.writeFileSync` on a predictable path. If that path is replaced with a symlink, Node will follow it and overwrite the symlink target. A local attacker (or another process running as the same user) could abuse this to modify unintended files writable by the user.

Affected files: caveman-activate.js, caveman-mode-tracker.js

Signed-off-by: tuanaiseo <221258316+tuanaiseo@users.noreply.github.com>
2026-04-10 20:33:24 +07:00
tuanaiseo 9449c8a05a fix(security): hook writes to predictable path without symlink pr
The SessionStart hook writes to `~/.claude/.caveman-active` using `fs.writeFileSync` on a predictable path. If that path is replaced with a symlink, Node will follow it and overwrite the symlink target. A local attacker (or another process running as the same user) could abuse this to modify unintended files writable by the user.

Affected files: caveman-activate.js, caveman-mode-tracker.js

Signed-off-by: tuanaiseo <221258316+tuanaiseo@users.noreply.github.com>
2026-04-10 20:33:23 +07:00
Julius Brussee 92f892f2b9 Update README.md v1.3.5 2026-04-09 21:25:34 +02:00