Stop Claude Code from wasting your time and crashing your machine.
SaneProcess is a hook-based enforcement framework for Claude Code. It kills orphaned processes, stops doom loops, and forces research before edits.
412 tests. MIT licensed. Ruby. macOS + Linux.
Claude Code spawns subagents and MCP server processes that outlive their parent sessions. They accumulate silently until your machine crawls or crashes.
SaneProcess kills them automatically on every session start β without touching your active sessions.
π§Ή Cleaned up 3 orphaned Claude sessions
π§Ή Cleaned up 7 orphaned MCP daemons
π§Ή Cleaned up 2 orphaned subagents
It uses process tree traversal (BFS) to identify which processes belong to your current session and leaves them alone. Only orphans whose parent sessions have died get cleaned up.
Claude guesses the same broken fix over and over. You watch it burn through tokens on the same error 10 times.
SaneProcess trips a circuit breaker after 3 consecutive failures or 3 identical error signatures. All edit operations are blocked until you acknowledge the problem.
π΄ CIRCUIT BREAKER TRIPPED
3 consecutive failures with same error signature
Say "reset breaker" after fixing the root cause.
The breaker persists across session restarts β Claude can't bypass it by restarting.
Claude assumes APIs exist without checking. It writes code using methods that don't exist, then fails, then tries a different nonexistent method.
SaneProcess blocks all edits until research is done across four categories:
π΄ BLOCKED: Research incomplete
β
docs β
web β github β local
Complete all 4 categories before editing.
Read-only tools (Read, Grep, Glob, search) are never blocked. The gate only applies to mutations.
# Clone the repo
git clone https://github.com/sane-apps/SaneProcess.git
# Run the installer from your project directory
cd /path/to/your-project
/path/to/SaneProcess/scripts/init.shThe installer copies hooks into your project's scripts/hooks/ directory and creates .claude/settings.json with hook registration.
Or configure manually β add to ~/.claude/settings.json (global) or .claude/settings.json (per-project):
{
"hooks": {
"SessionStart": [{ "hooks": [{ "type": "command", "command": "ruby /path/to/hooks/session_start.rb", "timeout": 15000 }] }],
"UserPromptSubmit": [{ "hooks": [{ "type": "command", "command": "ruby /path/to/hooks/saneprompt.rb" }] }],
"PreToolUse": [{ "hooks": [{ "type": "command", "command": "ruby /path/to/hooks/sanetools.rb" }] }],
"PostToolUse": [{ "hooks": [{ "type": "command", "command": "ruby /path/to/hooks/sanetrack.rb" }] }],
"Stop": [{ "hooks": [{ "type": "command", "command": "ruby /path/to/hooks/sanestop.rb" }] }]
}
}Verify:
ruby scripts/hooks/saneprompt.rb --self-test # 176 tests
ruby scripts/hooks/sanetools.rb --self-test # 38 tests
ruby scripts/hooks/sanetrack.rb --self-test # 23 testsFive hooks map to Claude Code's lifecycle events:
| Hook | Event | Purpose |
|---|---|---|
session_start.rb |
SessionStart | Kills orphans, resets state, bootstraps session |
saneprompt.rb |
UserPromptSubmit | Classifies intent, sets research requirements |
sanetools.rb |
PreToolUse | Blocks edits until research is done |
sanetrack.rb |
PostToolUse | Tracks failures, trips circuit breaker |
sanestop.rb |
Stop | Captures session summary |
All state lives in a single HMAC-signed JSON file (.claude/state.json). File-locked for concurrent access. Tamper-detected via HMAC key (macOS Keychain or ~/.claude_hook_secret on Linux). Atomic writes via tempfile + rename.
On every session start, three cleanup passes run:
- Parent sessions β finds
claudeprocesses not in your current process tree - MCP daemons β finds known MCP patterns (context7, apple-docs, xcodebuild, github, serena, etc.) not in your session tree
- Subagents β finds
claude --resumeprocesses whose parent sessions are dead
Uses BFS process tree traversal. Your active session and any other active terminal sessions are never touched.
After tool execution, error signatures are normalized and tracked:
- 3 consecutive failures β breaker trips
- 3 identical error signatures β breaker trips
When tripped, all edit/write operations are blocked. Say reset breaker or rb- to clear after fixing the root cause.
Before any mutation (Edit, Write, Bash with side effects), research categories must be satisfied:
| Category | Satisfied By | Required? |
|---|---|---|
| docs | apple-docs MCP, context7 MCP | Only if MCP installed |
| web | WebSearch, WebFetch | Always |
| github | GitHub MCP | Only if MCP installed |
| local | Read, Grep, Glob | Always |
The gate adapts to your setup. With no MCPs, only web + local are required. With apple-docs and GitHub MCPs installed, all 4 categories enforce. The installer shows which MCPs you have and gives install commands for the rest.
| Category | Examples | Blocked Until |
|---|---|---|
| Read-only | Read, Grep, Glob, search | Never |
| Local mutation | Edit, Write | Research complete |
| Sensitive files | CI/CD, entitlements, Dockerfiles | Confirmed per-file per-session |
| External mutation | GitHub push | Research complete |
- HMAC-signed state β
state.jsonis signed to detect tampering. Key stored in macOS Keychain (macOS) or~/.claude_hook_secretwith 600 permissions (Linux). - Blocked system paths β Prevents edits to
/etc/,.ssh/,.aws/,.gnupg/ - Inline script detection β
python -c,ruby -e,node -eblocked as bash mutations - Sensitive file confirmation β First edit to CI/CD configs, entitlements, Dockerfiles requires confirmation
- Fail-safe defaults β If a hook errors internally, it allows the operation (exit 0). Never blocks randomly.
412 tests across two frameworks:
Tier tests (175) β end-to-end enforcement scenarios:
| Tier | Count | What |
|---|---|---|
| Easy | 61 | Basic functionality |
| Hard | 55 | Edge cases, state transitions |
| Villain | 59 | Adversarial bypass attempts |
Self-tests (237) β per-hook unit tests:
| Hook | Tests |
|---|---|
| saneprompt | 176 |
| sanetools | 38 |
| sanetrack | 23 |
# Run all tier tests
ruby scripts/hooks/test/tier_tests.rb
# Run per-hook self-tests
ruby scripts/hooks/saneprompt.rb --self-test
# Run a specific tier
ruby scripts/hooks/test/tier_tests.rb --tier villainConfigurable via scripts/hooks/core/config.rb:
| Setting | Default | What |
|---|---|---|
| Circuit breaker threshold | 3 | Consecutive failures before trip |
| File size warning | 500 lines | Yellow warning on edit |
| File size limit | 800 lines | Block the edit |
| Blocked paths | /etc/, .ssh/, .aws/ |
System path protection |
The hook is working correctly. Complete the required research categories before editing. The gate adapts β categories whose MCPs you don't have auto-skip. With no MCPs, only web + local are required.
Say reset breaker or rb- in Claude after fixing the root cause.
Check that .claude/settings.json contains hook entries pointing to your scripts/hooks/ directory. Re-run init.sh if needed.
- macOS or Linux (process cleanup uses POSIX
ps; HMAC key uses Keychain on macOS, file-based on Linux) - Ruby (ships with macOS;
apt install rubyordnf install rubyon Linux) - Claude Code (
npm install -g @anthropic-ai/claude-code)
scripts/
βββ hooks/ # All enforcement hooks
β βββ session_start.rb # SessionStart β orphan cleanup, state reset
β βββ saneprompt.rb # UserPromptSubmit β classify, set requirements
β βββ sanetools.rb # PreToolUse β block until research done
β βββ sanetrack.rb # PostToolUse β track failures, circuit breaker
β βββ sanestop.rb # Stop β session summary
β βββ core/ # Shared infrastructure
β β βββ config.rb # Paths, thresholds, settings
β β βββ state_manager.rb # Signed state file management
β β βββ context_compact.rb
β βββ test/ # Test suites
β βββ tier_tests.rb # 175 enforcement tests
βββ init.sh # Project installer
βββ qa.rb # QA runner
.claude/
βββ rules/ # Path-specific guidance (installed by init.sh)
β βββ hooks.md # Hook conventions
β βββ scripts.md # Ruby script conventions
βββ settings.json # Hook registration
Remove hook entries from .claude/settings.json. Delete scripts/hooks/. Delete .claude/state.json.
No global state modified. No daemons installed. No system changes.
MIT License. See LICENSE.
Built by SaneApps. Used in production across 7 projects.
