Skip to content

mgorkemuz/claude-code-shepherd

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

44 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

shepherd

Track, preserve, and clean up the background processes Claude Code's Bash tool leaves running.

A Claude Code plugin. It watches every npm run dev, next dev, vitest --watch, or long-running command Claude starts in the background, remembers which session spawned it, and gives you single-line controls to stash it, kill it, or bring it back later. When Claude crashes and leaves processes behind, shepherd cleans them automatically on the next launch.

The problem

Claude Code runs background commands through its Bash tool. When a session ends — /clear, a closed terminal, a crashed Claude — those children don't always die. On macOS they reparent to launchd and keep running: holding ports, eating RAM, accumulating across days. An orphaned next dev can grow past 8 GB.

Upstream issues tracking this: anthropics/claude-code#43944, #33947, #33979, #29011, #22978, #7069. No official fix in 2+ years. shepherd fills the gap.

Install

/plugin marketplace add mgorkemuz/claude-code-shepherd
/plugin install shepherd@shepherd

From a local clone for development:

claude --plugin-dir /path/to/claude-code-shepherd

After any plugin update: /reload-plugins.

Requires jq. macOS and Linux supported.

How it actually helps

  • Only tracks what Claude spawned. Uses the Bash tool's shell-snapshot signature to tell Claude-spawned processes apart from processes you started yourself. Kill commands are surgical — they can't touch things outside Claude's tree.
  • Per-session grouping. Multiple Claude sessions (tmux teammates, background agents) each get their own tracked list. kill --session <id> never spills into another session.
  • Orphan detection. Processes whose originating Claude is dead show up under their own block in list.
  • Auto-clean on next launch. If Claude crashes (SIGKILL, terminal closed hard, OOM), the SessionStart hook on the next Claude launch wipes orphans from the crashed session. Default on — orphans are residue by definition. Concurrent sessions are safe: their Claude pid is still alive, so they're not orphans.
  • Stash/unstash. Snapshot a dev server (command + cwd + safe env), kill it to free RAM, respawn later in the original cwd with one command. Like "pause" across a /clear.
  • Port-conflict warnings. Before a Bash command with next dev / vite / uvicorn, shepherd checks if the port is already held by a tracked process and nudges Claude via systemMessage.
  • RAM threshold nudges. When a tracked process crosses 2 GB, shepherd emits additionalContext so Claude can suggest stashing in-conversation.

Slash commands

Invoke from inside Claude with /shepherd:<name> (TAB-completes after /shep).

Command What it does Default (no args)
/shepherd:processes Tracked processes grouped by session, with ports, RAM, uptime, FD count, dev-server label. Show everything (active + orphans).
/shepherd:status One-line count: sessions, processes, orphans.
/shepherd:stash Snapshot + kill background processes. Frees RAM and ports. --current — this session's processes.
/shepherd:stashes Table of saved stash snapshots.
/shepherd:unstash Respawn a stash in its original cwd. --latest --attach — most recent stash, track it in this session.
/shepherd:rm Delete a stash without respawning. --latest
/shepherd:kill Terminate a process tree. Kill the most recently-spawned tracked tree.
/shepherd:cleanup Kill processes older than a duration or using too much RAM. --older-than 24h --dry-run — safe preview.
/shepherd:adopt <pid> Register an externally-spawned pid as tracked (previous Claude, terminal-started, etc). pid required

All commands accept arguments that get forwarded to the CLI. E.g. /shepherd:kill --all, /shepherd:stash --session <id>, /shepherd:cleanup --over-ram 2GB.

Typical flows

Switching projects without losing your dev server:

/shepherd:stash         → snapshot npm run dev + kill it, port 3000 freed
/clear                  → new Claude conversation
…                       → work on something else
/shepherd:unstash       → dev server respawns in the original project

After a Claude crash, next launch:

shepherd auto-cleanup: killed 2 orphan tree(s) from previous session(s):
  pid 39987  next-server (v16.1.0)  (session 214bd4)
  pid 39990  node ...               (session 214bd4)

Investigating RAM:

/shepherd:processes                            → see what's running, what's heavy
/shepherd:kill --session c1b264                → surgical — touches only this session
/shepherd:cleanup --over-ram 2GB               → dry-run preview of fat processes

Config

~/.claude/.shepherd/config.json — optional, defaults used when missing.

{
  "version": 1,
  "awareness": {
    "ram_threshold_kb": 2097152,
    "ram_alert_once_per_crossing": true,
    "port_conflict_warn": true
  },
  "digest": { "enabled": false, "default_since": "7d" },
  "stash": {
    "env_allowlist": ["PATH", "NODE_ENV", "PORT", "NODE_OPTIONS"],
    "env_allowlist_prefix": ["X_", "APP_"]
  },
  "kill": {
    "grace_seconds": 3,
    "safe_pgid_leader": false,
    "auto_orphans_on_session_start": true
  },
  "notifications": { "macos_osascript": false },
  "history": { "max_bytes": 1048576 }
}

Edit with jq or by hand; no restart needed. The commonly-flipped knobs:

  • kill.auto_orphans_on_session_start — set to false if you deliberately leave processes running across Claude restarts and don't want them killed on the next launch.
  • awareness.ram_threshold_kb — threshold for in-conversation RAM nudges. Default 2 GB.
  • digest.enabled — set to true to enable the weekly activity digest.

How it works

Claude Code hooks drive the event stream. The plugin registers:

  • SessionStart — record session_id, cwd, and the Claude pid in ~/.claude/.shepherd/<id>.json. If auto_orphans_on_session_start is on, sweep orphans from previously-crashed sessions.
  • PreToolUse (matcher Bash) — parse the incoming command for port-binding patterns; warn if another tracked session already holds one.
  • PostToolUse (matcher Bash) — walk direct children of the Claude pid whose argv carries the shell-snapshot signature, record them + their subtree. Run the RAM-threshold check.
  • UserPromptSubmit — if the prompt looks like /clear / "start fresh", warn Claude about still-running tracked processes so it can offer to stash them.
  • Stop — at turn end, surface a summary of what's still running and the exact command to stop or stash it.

list intersects tracked pids with live ps output and walks descendants, so it finds children the hook never saw directly (like next-server forked by next dev).

kill sends SIGTERM to the tree deepest-first, waits up to kill.grace_seconds, then SIGKILLs survivors.

stash reads the command + cwd, captures allowlisted env vars (ps -wwE on macOS — returns {} on hardened macOS; /proc/<pid>/environ on Linux), writes a snapshot, then kills. unstash respawns via ( ... & exec env -i ... nohup bash -c ... ) inside the original cwd and re-attaches the new pid to the current session.

Relationship to cc-reaper

theQuert/cc-reaper solves a different problem: it cleans up Claude's own internal spawns (MCP servers, subagents). shepherd targets the processes you told Claude to start in the background. Safe to run side by side.

cc-reaper shepherd
Target Claude's MCP / subagent leaks User's backgrounded commands
Detection PGID + stream-json pattern Shell-snapshot signature + tracked state
Surgical per-session kill No Yes
Port / RAM / FD surfacing Partial Yes
Stash / resume No Yes
Auto-clean on next launch LaunchAgent every 10 min SessionStart hook

Borrowed from cc-reaper with gratitude: the FD count, the TTY-filter orphan heuristic, the PGID-leader safety gate (opt-in via config.kill.safe_pgid_leader).

Testing

for t in test/test-*.sh; do $t; done

All seven tests spawn synthetic processes against a sandbox HOME, covering detection, tree walk, stash/unstash, awareness (port parser + RAM threshold), cleanup + digest parsers, and plugin manifest validation. Regresses in ~10 seconds.

Uninstall

/plugin uninstall shepherd

License

MIT. See LICENSE.

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages