claudectl 0.10.1

TUI for monitoring and managing Claude Code CLI agents
Documentation

claudectl

A fast, lightweight TUI for monitoring and managing multiple Claude Code CLI sessions running across terminals.

Built in Rust. ~1MB binary. Sub-50ms startup.

claudectl demo

Features

  • Live dashboard — PID, project, status, context window %, cost, $/hr burn rate, elapsed time, CPU%, memory, token counts, activity sparkline
  • Smart status detection — Processing / Needs Input / Waiting / Idle / Finished, inferred from JSONL events, CPU usage, and message timestamps
  • Cost tracking — Per-session and total USD estimates based on model pricing (Opus, Sonnet, Haiku) with burn rate
  • Budget enforcement — Per-session budget alerts at 80%, optional auto-kill at 100%
  • Approve/input — Press y to approve permission prompts, i to type input to sessions
  • Auto-approve — Press a twice to enable auto-approve for trusted sessions
  • Tab switching — Press Tab to jump to a session's terminal tab (7 terminals supported)
  • Session launcher — Press n to start a new Claude Code session from within claudectl
  • Grouped view — Press g to group sessions by project with aggregate stats
  • Detail panel — Press Enter to expand session details (tokens, cost, model, paths)
  • Notifications — Desktop notifications when sessions need input (--notify)
  • Webhooks — POST JSON to Slack/Discord/URL on status changes (--webhook)
  • Watch mode — Stream status changes without TUI (--watch)
  • Session history — Persist completed sessions and view cost analytics (--history, --stats)
  • Configuration file — Persistent settings via ~/.config/claudectl/config.toml
  • Theme system — Dark, light, and monochrome themes (--theme, NO_COLOR support)
  • Task orchestration — Run multiple Claude sessions with dependency ordering (--run)
  • Diagnostic logging — Structured debug output for troubleshooting (--log)

Install

Homebrew (macOS)

brew tap mercurialsolo/tap
brew install claudectl

Quick install (macOS / Linux)

curl -fsSL https://raw.githubusercontent.com/mercurialsolo/claudectl/main/install.sh | sh

From source

cargo install --path .

Nix

nix run github:mercurialsolo/claudectl

Usage

# Launch the TUI dashboard
claudectl

# Print session list and exit
claudectl --list

# Export JSON for scripting
claudectl --json

# Stream status changes (no TUI)
claudectl --watch
claudectl --watch --json

# Session history and cost analytics
claudectl --history --since 24h
claudectl --stats --since 7d

# Launch a new Claude session
claudectl --new --cwd ~/projects/my-app --prompt "Fix the auth bug"

# Budget enforcement
claudectl --budget 5 --kill-on-budget

# Notifications and webhooks
claudectl --notify
claudectl --webhook https://hooks.slack.com/... --webhook-on NeedsInput,Finished

# Theme and diagnostics
claudectl --theme light
claudectl --log /tmp/claudectl.log

# Run multiple tasks from a file
claudectl --run tasks.json --parallel

# Show resolved configuration
claudectl --config

Configuration

claudectl loads settings from ~/.config/claudectl/config.toml (global) and .claudectl.toml (per-project). CLI flags override config file values.

[defaults]
interval = 1000
notify = true
grouped = true
sort = "cost"
budget = 5.00
kill_on_budget = false

[webhook]
url = "https://hooks.slack.com/..."
events = ["NeedsInput", "Finished"]

[context]
warn_threshold = 75  # Fire on_context_high when context window exceeds this %

Event Hooks

Run shell commands automatically when session events occur. Add hooks to your config file:

# ~/.config/claudectl/config.toml

[hooks.on_needs_input]
run = "say 'Claude needs your attention'"

[hooks.on_finished]
run = "terminal-notifier -title 'claudectl' -message '{project} finished (${cost})'"

[hooks.on_session_start]
run = "echo '{pid},{project},{model}' >> ~/claude-sessions.csv"

[hooks.on_status_change]
run = "echo '[{project}] {old_status} → {new_status}' >> ~/claude-activity.log"

Events

Event Trigger
on_session_start New session discovered
on_status_change Any status transition
on_needs_input Session needs user approval/input
on_finished Session process exited
on_budget_warning Session hit 80% of budget
on_budget_exceeded Session hit 100% of budget
on_idle Session went idle (>10 min)
on_context_high Context window usage crossed threshold (default 75%)
on_conflict_detected 2+ sessions share the same working directory

Template variables

{pid}, {project}, {status}, {cost}, {model}, {cwd}, {tokens_in}, {tokens_out}, {elapsed}, {session_id}, {old_status}, {new_status}, {context_pct}

Use claudectl --hooks to verify your configured hooks.

Verified Hooks

We maintain a curated set of officially verified hooks at mercurialsolo/claudectl-hooks. Only verified hooks are endorsed for production use.

To submit a hook for verification, open an issue on the claudectl-hooks repository with:

  • Hook name and description
  • The [hooks.*] config snippet
  • What problem it solves
  • Any dependencies (e.g., terminal-notifier, jq)

Submitted hooks are reviewed for security, reliability, and usefulness before being added to the verified collection.

Task Orchestration

Run multiple Claude sessions with dependency ordering:

{
  "tasks": [
    {
      "name": "Add auth middleware",
      "cwd": "./backend",
      "prompt": "Add JWT auth middleware to all API routes"
    },
    {
      "name": "Update tests",
      "cwd": "./backend",
      "prompt": "Update API tests for the new auth middleware",
      "depends_on": ["Add auth middleware"]
    },
    {
      "name": "Update docs",
      "cwd": "./docs",
      "prompt": "Document the new auth flow"
    }
  ]
}
claudectl --run tasks.json --parallel

Keybindings

Key Action
j/k or Up/Down Navigate sessions
Tab Switch to session's terminal tab
Enter Toggle detail panel
y Approve (send Enter to NeedsInput session)
i Input mode (type text to session)
d/x Kill session (double-tap to confirm)
a Toggle auto-approve (double-tap to confirm)
n Launch new Claude session
g Toggle grouped view by project
s Cycle sort column (Status, Context, Cost, $/hr, Elapsed)
r Force refresh
? Toggle help overlay
q/Esc Quit

Status Colors

Status Color Meaning
Needs Input Magenta Waiting for user to approve/confirm a tool use
Processing Green Actively generating or executing tools
Waiting Yellow Done responding, waiting for user's next prompt
Idle Gray No recent activity (>10 min since last message)
Finished Red Process exited

How It Works

claudectl reads Claude Code's local data:

  • ~/.claude/sessions/*.json — One file per running Claude process with PID, session ID, working directory, and start time
  • ~/.claude/projects/{slug}/*.jsonl — Conversation logs with token usage, model info, stop_reason, and waiting_for_task events
  • ps — CPU%, memory, TTY, and command args for each process
  • /tmp/claude-{uid}/{slug}/{sessionId}/tasks/ — Subagent task files

Status is inferred from multiple signals:

  • waiting_for_task progress event → Needs Input (needs user confirmation)
  • CPU > 5% → Processing (overrides all other signals)
  • stop_reason: tool_use + low CPU + age >5s → Needs Input (permission prompt)
  • stop_reason: end_turn + recent activity → Waiting
  • Last message > 10 minutes ago → Idle

Terminal Support

Terminal Tab Switch Approve/Input Method
Ghostty Background Background Native AppleScript API
Kitty Background Background kitty @ remote control
tmux Background Background tmux send-keys
WezTerm Background - CLI JSON API
Warp Focus switch Focus switch Command Palette + System Events
iTerm2 Focus switch Focus switch AppleScript + System Events
Terminal.app Focus switch Focus switch AppleScript + System Events

Terminal-specific notes

  • Ghostty: Best support. Native AppleScript with working directory and TTY matching. No extra config needed.
  • Kitty: Requires allow_remote_control yes (or socket-only) in ~/.config/kitty/kitty.conf.
  • Warp: Requires Accessibility permission (System Settings > Privacy & Security > Accessibility). Approve/input briefly switches focus to the Claude tab, sends the keystroke, then you can switch back.
  • tmux: Auto-detected when running inside tmux. Works alongside the outer terminal's support.

Requirements

  • macOS or Linux
  • Claude Code CLI installed and running
  • Rust 2024 edition (to build from source)

Issues & Feature Requests

Found a bug or have an idea? Open an issue.

Bug reports — please include:

  • claudectl --version output
  • Your terminal (echo $TERM_PROGRAM) and OS
  • Steps to reproduce
  • If possible, attach a log file: claudectl --log /tmp/claudectl-debug.log and reproduce the issue

Feature requests — describe the use case, not just the solution. What are you trying to accomplish? Knowing the "why" helps us find the best approach.

Contributing

Contributions are welcome! Here's how to get started:

Setup

git clone https://github.com/mercurialsolo/claudectl.git
cd claudectl
cargo build
cargo test --all-targets

Development workflow

  1. Check existing issues — look for good first issue or comment on something you'd like to work on
  2. Fork and branch — create a feature branch from main
  3. Write tests — new functionality should include tests in tests/integration_tests.rs or as module-level #[cfg(test)] tests
  4. Pass all checks before submitting:
    cargo test --all-targets
    cargo clippy --all-targets -- -D warnings
    cargo fmt --all -- --check
    
  5. Open a PR — describe what changed and why. Link to any related issues.

Architecture

The codebase is organized into focused modules:

Module Purpose
session.rs Session data structures and formatting
discovery.rs Session file scanning and JSONL path resolution
monitor.rs JSONL parsing, token counting, status inference
process.rs Process introspection via ps
app.rs Core app state, refresh loop, event handling
config.rs TOML config file loading and layering
theme.rs Color palette and theme modes
history.rs Session history persistence and analytics
orchestrator.rs Multi-session task runner
logger.rs Diagnostic file logging
terminals/ Terminal-specific switching and input injection
ui/ TUI rendering (table, detail, help, status bar)

Guidelines

  • No new dependencies without strong justification — the project stays lightweight
  • Test behavior, not implementation — focus on what the code does, not how
  • Match existing patterns — look at similar code in the repo before writing new code
  • Keep commits atomic — one logical change per commit with a clear message

License

MIT