npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

claude-tmux-dog

v0.5.0

Published

24/7 unattended Claude agents + tmux-native message bus. Auto-nudge, auto-recovery, proactive compaction — keep agents running autonomously for days.

Readme

claude-tmux-dog (cdog)

npm version npm downloads license GitHub

English | 中文

24/7 unattended Claude agents + tmux-native message bus.

cdog does two things:

  1. 24/7 unattended operation — Hook-driven lifecycle management + dual-layer context defense keeps a Claude Code agent running autonomously for days or weeks
  2. tmux-native message bus — Each agent runs in its own tmux session; cdog message send injects text into the pane — that's all you need for cross-agent communication

No message broker, no external daemon framework — tmux IS the bus.


Why cdog

Pillar 1 — 24/7 Unattended Operation

cdog turns Claude Code into an autonomous agent that runs for days without human intervention:

  • Auto-nudge — Every time Claude stops (fires Stop hook), cdog automatically sends "continue" (or your custom prompt) to keep it working
  • Auto-recovery — On recoverable API errors (rate limit, timeout, overloaded), cdog breaks to shell, checks token usage, and either runs /compact or nudges
  • Proactive compaction — Pane watcher monitors ↑ tokens in the TUI and compacts at 80% before errors happen
  • Quota-aware — Detects AccountQuotaExceeded with reset time, breaks to shell, and schedules a nudge after the reset
  • Auto-shutdown — Set per_watch_duration: "7d" and cdog will mark the agent completed after 7 days, kill watchers, but keep the tmux session alive (context preserved)
  • Suspend on fatal — Fatal errors (model offline, auth, billing) suspend the agent (stop monitoring, keep tmux/claude alive) for you to inspect, then cdog restart resumes. Recoverable errors never hard-fail: they self-heal via claude's retry or are probed by the stall_timeout health-check (default 5m)

How it works: Claude Code hooks (Stop / StopFailure / SessionStart / SessionEnd) push events to cdog. No polling, no timers, no filesystem watchers — pure event-driven lifecycle management.

Pillar 2 — tmux-Native Message Bus

Each agent runs in its own tmux session. cdog message send injects text directly into the pane — that's all you need for cross-agent communication:

# Agent snow asks agent hermes about progress
cdog message send --to hermes --message "What's the progress on port-map?" --from "snow-agent"

# Agent hermes replies
cdog message send --to snow-agent --message "Backend is done, 3 files merged" --from "hermes"

Output in hermes's pane:

snow-agent: What's the progress on port-map?

Reply chains — Use --reply-method to tell the recipient how to respond:

cdog message send --to hermes \
  --message "Check what bugs are left" \
  --from "snow-agent" \
  --reply-method "cdog message send --to snow-agent --message 'Found N' --from hermes"

Output:

snow-agent: Check what bugs are left
Reply Method: cdog message send --to snow-agent --message 'Found N' --from hermes

No message broker. No external daemon. tmux IS the bus.


Quick Start

# Install
npm install claude-tmux-dog -g

# One-time setup (wires hooks into ~/.claude/settings.json)
cdog init

# Create a config
cat > cdog.json << 'EOF'
{
  "name": "my-agent",
  "cwd": "/path/to/project",
  "md": "task.md",
  "watchdog": {
    "auto_nudge_stop": true,
    "per_watch_duration": "7d",
    "max_tokens": "1m"
  }
}
EOF

# Start
cdog start

# Check status
cdog status

# View logs
cdog log

That's it — your agent is now running 24/7 in a tmux session, auto-nudging on stops, auto-recovering from errors, auto-compacting before context overflows.


How It Works

  1. cdog start reads cdog.json, spawns claude inside a detached tmux session with a UUID --session-id, and starts two watcher subprocesses (pane + log)
  2. Hooks push eventsStop / StopFailure / SessionStart / SessionEnd hooks call cdog notify <json>
  3. cdog dispatches:
    • Stop → auto-nudge (if enabled)
    • StopFailure → classify error → auto-recover (if recoverable) or stop (if fatal)
    • SessionStart → mark running
    • SessionEnd → mark stopped/failed
  4. Dual-layer watchers:
    • Pane watcher (proactive): monitors ↑ tokens, compacts at 80%
    • Log watcher (reactive): tails debug log, triggers recovery on API error threshold
  5. cdog stop flips cdog to detached and (by default) Esc-aborts the in-progress turn; cdog drain detaches without interrupting. Neither kills claude — detached cdog still records status from hooks (observe-only). cdog delete is the only command that kills the tmux session

What cdog Automates For You

| Feature | What it does | Why it matters | | --------------------- | ---------------------------------------------------------- | ----------------------------------------------- | | Auto-nudge | Sends prompt on every Stop hook | Agent keeps working without human nudging | | Auto-recovery | Breaks to shell + compact-or-nudge on API errors | Recovers from transient failures automatically | | Proactive compact | Monitors tokens, compacts at 80% | Prevents API errors before they happen | | Quota scheduling | Detects reset time, schedules nudge after quota resets | No wasted retries while quota is zero | | Stall detection | No real activity for stall_timeout (default 5m) → nudge | Breaks stuck loops + 5xx health-check | | Auto-shutdown | Marks completed after N days, kills watchers, keeps tmux | Long-running tasks eventually stop nudging | | Message bus | Send text to any agent's pane | Cross-agent coordination without infrastructure |


Configuration

Minimal cdog.json

{
  "name": "my-agent",
  "cwd": "/path/to/project"
}

Full cdog.json

{
  "name": "snow-agent",
  "cwd": "/path/to/projects/snow-agent",
  "md": "snow-agent.md",
  "args": ["--dangerously-skip-permissions"],
  "log": "./logs/claude-debug.log",
  "log_file": "./logs/cdog.log",
  "model": "claude-sonnet-4-6",
  "timeformat": "YYYY-MM-DD HH:mm:ss",
  "timeout": 10000,
  "watchdog": {
    "prompt": "continue",
    "per_watch_duration": "7d",
    "max_tokens": "1m",
    "auto_nudge_stop": true,
    "auto_restart": true,
    "stall_timeout": "5m",
    "api_error_auto_compact": {
      "threshold": 3,
      "rate_limit_confirm_minutes": 10
    },
    "pane_watcher": {
      "compact_ratio": 0.8,
      "interval": 30
    }
  },
  "notify": {
    "enabled": true,
    "lang": "default",
    "sound": true,
    "sound_on": {
      "agent-started": true,
      "agent-failed": true,
      "agent-recovered": true,
      "api-error": false,
      "compact": false,
      "max-run-reached": true,
      "nudge": false,
      "task-completed": true
    },
    "open_on_click": true,
    "terminal": "Terminal",
    "command": null,
    "command_timeout": 30,
    "on": {
      "agent-started": true,
      "agent-failed": true,
      "agent-recovered": true,
      "api-error": true,
      "compact": true,
      "max-run-reached": true,
      "nudge": true,
      "task-completed": true
    }
  }
}

Key Fields

| Field | Required | Description | | ---------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | name | ✓ | Agent name (unique, cannot be all) | | cwd | ✓ | Working directory (tmux session created here) | | md | | Task markdown file(s) piped to claude on start | | args | | Extra CLI flags for claude | | env | | Env vars injected into the launched claude process, e.g. {"DISABLE_TELEMETRY": "1", "CLAUDE_CODE_DISABLE_FEEDBACK_SURVEY": "1"}. Prefixed as K=V before claude (applies to claude only). | | log | | Claude debug log path (default: <cwd>/logs/claude-debug.log) | | log_file | | cdog operation log path | | watchdog | | Auto-management policy | | notify | | Desktop notification settings | | stop | | cdog stop behavior |

Stop Configuration

| Field | Default | Description | | ------------ | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | abort_work | true | On cdog stop, when claude is actively working (running/pending), send a single Esc to abort the in-progress turn and set status to waiting — the claude process stays alive (suspend, don't exit). Esc is used instead of Ctrl+C so the process can't be accidentally exited; Ctrl+C stays reserved for the recovery flow. No-op when claude is idle or the tmux session is gone. Default true (stop means halt); set false to detach without interrupting the current turn. |

{
  "name": "my-agent",
  "cwd": ".",
  "stop": { "abort_work": true }
}

Watchdog Configuration

| Field | Default | Description | | ------------------------ | ------------ | -------------------------------------------------------------------------------------------------------------- | | prompt | "continue" | Text sent on each nudge | | per_watch_duration | | Monitor duration (e.g. "7d", "4h"). After this, agent marked completed, watchers killed, tmux kept alive | | max_tokens | 200000 | Max context tokens (200000, "200k", "1m") | | auto_nudge_stop | false | Auto-send prompt on Stop hook | | auto_restart | true | Auto-recover on recoverable StopFailure; fatal errors suspend (keep tmux, wait for cdog restart) | | stall_timeout | "5m" | No real activity (stream/tool) for this long → nudge. Doubles as the 5xx/overloaded health-check interval | | stall_cooldown | "10m" | Cooldown after stall-triggered nudge | | api_error_auto_compact | | Log watcher config (always enabled) | | pane_watcher | | Pane watcher config (always enabled) |

Log Retention & Update Check

| Field / Env | Default | Description | | ------------------------------ | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | log_retention (config) | "7d" | cdog trims its own op-log to this window on cdog start and cdog prune (by per-line timestamp). claude's debug log is left to claude. "0"/"off" disables. | | CDOG_NO_UPDATE_CHECK=1 (env) | off | cdog checks the npm registry for a newer version once per day (cached in ~/.cdog/update-check.json) and prints a non-blocking hint to stderr. Set this env to mute. Never auto-installs. |


Recovery Details

cdog has three recovery paths, all sharing the same breakToShell + compactOrNudge logic:

1. Hook-Driven (StopFailure)

When Claude Code hits an API error, it fires StopFailure hook → cdog:

  1. Classifies error: fatal / timeout / provider / rate_limit / unknown
  2. If recoverable: types cdog-recover marker, sends Ctrl-C, checks marker survived, then runs compactOrNudge
  3. Compact decision: reads last_up_tokens from state → /compact if ≥ 80%, else nudge

2. Log-Watcher-Driven (API Error Threshold)

Log watcher tails the debug log, counts consecutive [ERROR] API error lines per kind:

| Kind | Threshold | Action | | ------------ | --------- | ------------------------------------------------------ | | fatal | immediate | Stop agent (auth failure, model not found) | | timeout | 6 | Compact-or-nudge | | provider | never | Let claude retry (model overloaded, 503) | | rate_limit | never | Break to shell + scheduled nudge if reset time present | | unknown | 3 | Compact-or-nudge |

Fast-path: if pane watcher recorded last_up_tokens ≥ 70%, threshold → 1.

3. Pane-Watcher-Driven (Proactive Compaction)

Monitors ↑ tokens in the TUI. When tokens reach 80% of max_tokens:

↑ 165k tokens (82% of 200k)
↓
send /compact
↓ (wait for PostCompact hook)
PostCompact fires → send prompt nudge

Marker Safety

All three paths use the cdog-recover marker technique:

1. Type "cdog-recover" (no Enter — stays on input line)
2. Send C-c
3. Check if marker survived in pane capture
   ├─ Marker survived → C-c took effect, clear with C-u
   └─ Marker lost → C-c cleared input line, safe to proceed

This prevents C-c from killing the wrong process.


Commands

| Command | Description | | ------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------- | | cdog start [config\|all] | Start agent(s). Auto-runs cdog init if hooks missing | | cdog stop <name\|all> | Detach cdog + Esc-abort in-progress turn (default). Claude → waiting, stays alive | | cdog drain <name\|all> | Detach cdog without interrupting — current turn finishes, then idles | | cdog restart <name\|all> | Re-watch detached agent. Respawns watchers; kicks if idle | | cdog delete <name\|all> | Kill tmux session + remove from state | | cdog status [name] | pm2-style table or detail view | | cdog log [name] [--all\|--cdog\|--claude] [--err] | Tail logs. --err = last N [ERROR] lines across whole log | | cdog message send --to <name> --message <text> [--from F] [--reply-method R] | Send message to agent | | cdog nudge <name\|all> [text] | Send prompt + Enter | | cdog compact <name> | Manually trigger compact-or-nudge | | cdog auto-nudge <enable\|disable> <name\|all> | Toggle auto-nudge (persistent) | | cdog prune [name\|all] | Trim cdog's own op-log to log_retention (default 7d) + clean ~/.cdog. Auto-runs on start | | cdog init | Install hooks into ~/.claude/settings.json | | cdog --version / -v | Print version |

Dual-Track Status

cdog tracks two independent statuses:

  • claude (hook-driven): running / waiting / pending / failed / completed / stoppedUserPromptSubmitrunning (turn start), Stoprunning/waiting, StopFailurefailed, SessionEndstopped/failed
  • cdog (command-driven): watching / detached

watching = cdog auto-nudges/recovers. detached = hands-off (no nudge/recover) but still records claude status from hooks (observe-only). cdog stop/drain → detached; cdog delete kills tmux.


Message Relaying

# Simple message
cdog message send --to snow-agent --message "Keep going" --from "human"
# Output: human: Keep going

# With reply method
cdog message send --to hermes --message "How's progress?" --from "snow-agent" \
  --reply-method "cdog message send --to snow-agent --message '50% done' --from hermes"
# Output:
# snow-agent: How's progress?
# Reply Method: cdog message send --to snow-agent --message '50% done' --from hermes

Formatting is purely concatenative — cdog never modifies the text.


Desktop Notifications

Optional macOS Notification Center alerts:

"notify": {
  "enabled": true,
  "lang": "default",
  "sound": true,
  "open_on_click": true,
  "terminal": "Terminal",
  "on": {
    "agent-failed": true,
    "task-completed": true
  }
}
  • enabled: Master switch. false (default) → no notifications at all. true → each event fires unless turned off in on.
  • sound: Master sound switch. false (default) → silent. true → each event plays sound unless muted in sound_on (chatty events api-error/nudge/compact default to silent).
  • sound_on: Per-event sound override. true → always play, false → never play, unlisted → follow sound default (chatty events silent). Example: "sound_on": { "nudge": true, "agent-failed": false }.
  • on: Per-event notification override. true → notify, false → skip, unlisted → notify (all on by default).
  • command: Shell command run alongside each enabled notification (webhook / chat client / your script). Context via env (CDOG_AGENT/CDOG_EVENT/CDOG_TITLE/CDOG_MESSAGE), never interpolated into the command string. See Custom notify command below for examples.
  • command_timeout: Seconds before a running command is killed. Default 30.
  • open_on_click: Click notification → open/focus tmux session
  • lang: "default" (English) or "zh" (Chinese)
  • terminal: Terminal app for click-to-open (macOS: "Terminal", "iTerm2", "Ghostty", etc.; Linux: "gnome-terminal", "konsole", etc.)

Notification events (set in on; unlisted default to true):

| Event | Fires when | Sound* | | ----------------- | ------------------------------------------------------------------------- | ---------- | | agent-started | Agent launched via cdog start | ✅ | | agent-failed | Fatal error → agent suspended (model offline / auth / billing) | ✅ | | agent-recovered | Agent recovered after a StopFailure / quota reset / compact | ✅ | | api-error | Any [ERROR] API error line in claude's debug log | ❌ (chatty) | | compact | Context compacted (proactive 80%, auto-recover, or manual cdog compact) | ❌ (chatty) | | max-run-reached | per_watch_duration reached → agent marked completed | ✅ | | nudge | Agent nudged (Stop hook auto-nudge, stall health-check, quota reset) | ❌ (chatty) | | task-completed | Agent finished its task | ✅ |

* Sound defaults below assume master sound: true. sound_on overrides per event (see config table). Chatty events (api-error/nudge/compact) default to silent so a 24/7 agent doesn't beep all night; set them true in sound_on if you want them audible.

Custom notify command

notify.command runs a shell command alongside each enabled notification — fan events out to a chat client, webhook, or your own script. It runs via sh -c, so inline commands and script paths both work. Context is passed as env vars (preferred) and positional args, never interpolated into the command string, so message text can't break the command:

  • ENV: CDOG_AGENT CDOG_EVENT CDOG_TITLE CDOG_MESSAGE
  • ARGS: $1=agent $2=event $3=title $4=message

Best-effort: a failing or timing-out command (default 30s, override with command_timeout) is logged and never breaks cdog.

"notify": {
  "enabled": true,
  "on": { "agent-failed": true, "task-completed": true },
  "command": "curl -s \"https://api.telegram.org/bot$TG_TOKEN/sendMessage\" -d chat_id=\"$TG_CHAT\" -d text=\"[$CDOG_AGENT] $CDOG_EVENT: $CDOG_MESSAGE\""
}
// Send to a chat client via a natural-language command
"notify": {
  "enabled": true,
  "command": "hermes chat -q \"send \\\"$CDOG_MESSAGE\\\" to my telegram\" -Q"
}
// Route to a specific chat/user id
"notify": {
  "enabled": true,
  "command": "openclaw channel send --target 123456 --message \"$CDOG_MESSAGE\""
}
// Or just run a script (passing the same env + args)
"notify": {
  "enabled": true,
  "command": "/Users/me/cdog-on-event.sh"
}

Caveats

  • tmux required — cdog manages sessions inside tmux
  • macOS notifications — Interactive notifications use macOS Notification Center. Linux falls back to plain notify-send
  • Hook-based — Hooks must be installed via cdog init. Without them, auto-nudge/recover won't work
  • Watcher subprocessescdog start spawns pane watcher + log watcher as detached children. They're killed on stop/delete/restart via process-group signaling
  • No circuit breaker — Recoverable errors (5xx, overloaded, timeout, unknown) no longer hard-fail after N retries. They self-heal via claude's own retry, get /compact'd on context-full, or are probed by the stall_timeout health-check (default 5m). Only fatal errors (model offline / auth / billing) suspend the agent

Build from Source

npm install
npm run build      # tsc -> dist/
npm run dev        # run via tsx without building

Skill Integration

This repo includes a skill at skills/cdog/. When claude-tmux-dog is installed globally, any AI agent can load this skill to manage cdog agents without leaving the conversation.


Author

SnowAIGirl & LinQuan

License

MIT