fix: natural language activation/deactivation in mode tracker#120
Conversation
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>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 56f4047ab3
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| fs.mkdirSync(path.dirname(flagPath), { recursive: true }); | ||
| fs.writeFileSync(flagPath, getDefaultMode()); |
There was a problem hiding this comment.
Skip writing flag when default mode is off
Natural-language activation writes getDefaultMode() directly to the flag file, but unlike the /caveman command path it does not treat off as a special case. If CAVEMAN_DEFAULT_MODE=off (or config default is off), prompts like "talk like caveman" create ~/.claude/.caveman-active containing off, which makes statusline/reporting inconsistent with the intended "off means no active flag" behavior. Mirror the existing /caveman logic by guarding mode !== 'off' (or deleting the flag when mode is off).
Useful? React with 👍 / 👎.
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>
The NL activation regexes (introduced in JuliusBrussee#120) match too broadly: - "start" + "caveman" anywhere triggers activation, catching unrelated prompts like "How do I start a caveman fire?" - "normal mode" deactivates without requiring "caveman" in the prompt, so "switch from normal mode to debug mode" silently kills caveman - Negation words like "don't" are not checked, so "don't activate caveman" still activates Changes: - Replace broad "start.*caveman" with exact "\bstart caveman\b" - Require "caveman" alongside "normal mode" for deactivation - Add "don't", "do not", "no" to the negative guard
The problem
The README tells users they can say "talk like caveman" to activate. And they can — the model reads the prompt and starts speaking caveman. But the
UserPromptSubmithook only matched/cavemancommands, so the flag file never got written and the statusline badge never appeared.In other words: the model was in caveman mode, but the hook system didn't know about it. The flag file and statusline were out of sync with actual behavior.
The fix
The mode-tracker now matches natural language activation phrases: "activate caveman", "turn on caveman mode", "talk like caveman", "enable caveman", etc. Same for deactivation: "stop caveman", "disable caveman", "turn off caveman mode".
A negative guard prevents "stop caveman" from triggering activation (it contains "caveman" after all). Deactivation runs after activation in the control flow, so even if both somehow matched, deactivation wins.
Natural language activation uses
getDefaultMode()to respectCAVEMAN_DEFAULT_MODEandconfig.json, same as the/cavemancommand path.What changes
hooks/caveman-mode-tracker.js:/cavemancommand block