{
  "markdown": "# shepherd\n\n> Track, preserve, and clean up the background processes Claude Code's Bash tool leaves running.\n\nA 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.\n\n## The problem\n\nClaude 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.\n\nUpstream issues tracking this: [anthropics/claude-code#43944](https://github.com/anthropics/claude-code/issues/43944), [#33947](https://github.com/anthropics/claude-code/issues/33947), [#33979](https://github.com/anthropics/claude-code/issues/33979), [#29011](https://github.com/anthropics/claude-code/issues/29011), [#22978](https://github.com/anthropics/claude-code/issues/22978), [#7069](https://github.com/anthropics/claude-code/issues/7069). No official fix in 2+ years. shepherd fills the gap.\n\n## Install\n\n```\n/plugin marketplace add mgorkemuz/claude-code-shepherd\n/plugin install shepherd@shepherd\n```\n\nFrom a local clone for development:\n\n```sh\nclaude --plugin-dir /path/to/claude-code-shepherd\n```\n\nAfter any plugin update: `/reload-plugins`.\n\nRequires `jq`. macOS and Linux supported.\n\n## How it actually helps\n\n- **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.\n- **Per-session grouping.** Multiple Claude sessions (tmux teammates, background agents) each get their own tracked list. `kill --session <id>` never spills into another session.\n- **Orphan detection.** Processes whose originating Claude is dead show up under their own block in `list`.\n- **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.\n- **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`.\n- **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`.\n- **RAM threshold nudges.** When a tracked process crosses 2 GB, shepherd emits `additionalContext` so Claude can suggest stashing in-conversation.\n\n## Slash commands\n\nInvoke from inside Claude with `/shepherd:<name>` (TAB-completes after `/shep`).\n\n| Command | What it does | Default (no args) |\n|---|---|---|\n| `/shepherd:processes` | Tracked processes grouped by session, with ports, RAM, uptime, FD count, dev-server label. | Show everything (active + orphans). |\n| `/shepherd:status` | One-line count: sessions, processes, orphans. | — |\n| `/shepherd:stash` | Snapshot + kill background processes. Frees RAM and ports. | `--current` — this session's processes. |\n| `/shepherd:stashes` | Table of saved stash snapshots. | — |\n| `/shepherd:unstash` | Respawn a stash in its original cwd. | `--latest --attach` — most recent stash, track it in this session. |\n| `/shepherd:rm` | Delete a stash without respawning. | `--latest` |\n| `/shepherd:kill` | Terminate a process tree. | Kill the most recently-spawned tracked tree. |\n| `/shepherd:cleanup` | Kill processes older than a duration or using too much RAM. | `--older-than 24h --dry-run` — safe preview. |\n| `/shepherd:adopt <pid>` | Register an externally-spawned pid as tracked (previous Claude, terminal-started, etc). | pid required |\n\nAll commands accept arguments that get forwarded to the CLI. E.g. `/shepherd:kill --all`, `/shepherd:stash --session <id>`, `/shepherd:cleanup --over-ram 2GB`.\n\n## Typical flows\n\nSwitching projects without losing your dev server:\n\n```\n/shepherd:stash         → snapshot npm run dev + kill it, port 3000 freed\n/clear                  → new Claude conversation\n…                       → work on something else\n/shepherd:unstash       → dev server respawns in the original project\n```\n\nAfter a Claude crash, next launch:\n\n```\nshepherd auto-cleanup: killed 2 orphan tree(s) from previous session(s):\n  pid 39987  next-server (v16.1.0)  (session 214bd4)\n  pid 39990  node ...               (session 214bd4)\n```\n\nInvestigating RAM:\n\n```\n/shepherd:processes                            → see what's running, what's heavy\n/shepherd:kill --session c1b264                → surgical — touches only this session\n/shepherd:cleanup --over-ram 2GB               → dry-run preview of fat processes\n```\n\n## Config\n\n`~/.claude/.shepherd/config.json` — optional, defaults used when missing.\n\n```json\n{\n  \"version\": 1,\n  \"awareness\": {\n    \"ram_threshold_kb\": 2097152,\n    \"ram_alert_once_per_crossing\": true,\n    \"port_conflict_warn\": true\n  },\n  \"digest\": { \"enabled\": false, \"default_since\": \"7d\" },\n  \"stash\": {\n    \"env_allowlist\": [\"PATH\", \"NODE_ENV\", \"PORT\", \"NODE_OPTIONS\"],\n    \"env_allowlist_prefix\": [\"X_\", \"APP_\"]\n  },\n  \"kill\": {\n    \"grace_seconds\": 3,\n    \"safe_pgid_leader\": false,\n    \"auto_orphans_on_session_start\": true\n  },\n  \"notifications\": { \"macos_osascript\": false },\n  \"history\": { \"max_bytes\": 1048576 }\n}\n```\n\nEdit with `jq` or by hand; no restart needed. The commonly-flipped knobs:\n\n- `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.\n- `awareness.ram_threshold_kb` — threshold for in-conversation RAM nudges. Default 2 GB.\n- `digest.enabled` — set to `true` to enable the weekly activity digest.\n\n## How it works\n\nClaude Code hooks drive the event stream. The plugin registers:\n\n- **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.\n- **PreToolUse** (matcher `Bash`) — parse the incoming command for port-binding patterns; warn if another tracked session already holds one.\n- **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.\n- **UserPromptSubmit** — if the prompt looks like `/clear` / \"start fresh\", warn Claude about still-running tracked processes so it can offer to stash them.\n- **Stop** — at turn end, surface a summary of what's still running and the exact command to stop or stash it.\n\n`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`).\n\n`kill` sends SIGTERM to the tree deepest-first, waits up to `kill.grace_seconds`, then SIGKILLs survivors.\n\n`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.\n\n## Relationship to cc-reaper\n\n[theQuert/cc-reaper](https://github.com/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.\n\n| | cc-reaper | shepherd |\n|---|---|---|\n| Target | Claude's MCP / subagent leaks | User's backgrounded commands |\n| Detection | PGID + `stream-json` pattern | Shell-snapshot signature + tracked state |\n| Surgical per-session kill | No | Yes |\n| Port / RAM / FD surfacing | Partial | Yes |\n| Stash / resume | No | Yes |\n| Auto-clean on next launch | LaunchAgent every 10 min | SessionStart hook |\n\nBorrowed 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`).\n\n## Testing\n\n```sh\nfor t in test/test-*.sh; do $t; done\n```\n\nAll 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.\n\n## Uninstall\n\n```\n/plugin uninstall shepherd\n```\n\n## License\n\nMIT. See [LICENSE](LICENSE).\n",
  "bytes": 8867,
  "sha": "9ee47d47be057abc1033cbe626a34fae77fda9483fe0feec16f9ac7be6744cae",
  "repo_slug": "mgorkemuz/claude-code-shepherd",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/plg_mgorkemuz_claude_code_shepherd_shepherd_73e1196a/readme"
}