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.
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
yto approve permission prompts,ito type input to sessions - Auto-approve — Press
atwice to enable auto-approve for trusted sessions - Tab switching — Press
Tabto jump to a session's terminal tab (7 terminals supported) - Session launcher — Press
nto start a new Claude Code session from within claudectl - Grouped view — Press
gto group sessions by project with aggregate stats - Detail panel — Press
Enterto 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_COLORsupport) - Task orchestration — Run multiple Claude sessions with dependency ordering (
--run) - Diagnostic logging — Structured debug output for troubleshooting (
--log)
Install
Homebrew (macOS)
Quick install (macOS / Linux)
|
From source
Nix
Usage
# Launch the TUI dashboard
# Print session list and exit
# Export JSON for scripting
# Stream status changes (no TUI)
# Session history and cost analytics
# Launch a new Claude session
# Budget enforcement
# Notifications and webhooks
# Theme and diagnostics
# Run multiple tasks from a file
# Show resolved configuration
Configuration
claudectl loads settings from ~/.config/claudectl/config.toml (global) and .claudectl.toml (per-project). CLI flags override config file values.
[]
= 1000
= true
= true
= "cost"
= 5.00
= false
[]
= "https://hooks.slack.com/..."
= ["NeedsInput", "Finished"]
[]
= 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
[]
= "say 'Claude needs your attention'"
[]
= "terminal-notifier -title 'claudectl' -message '{project} finished (${cost})'"
[]
= "echo '{pid},{project},{model}' >> ~/claude-sessions.csv"
[]
= "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:
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, andwaiting_for_taskeventsps— 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_taskprogress 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(orsocket-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 --versionoutput- Your terminal (
echo $TERM_PROGRAM) and OS - Steps to reproduce
- If possible, attach a log file:
claudectl --log /tmp/claudectl-debug.logand 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
Development workflow
- Check existing issues — look for
good first issueor comment on something you'd like to work on - Fork and branch — create a feature branch from
main - Write tests — new functionality should include tests in
tests/integration_tests.rsor as module-level#[cfg(test)]tests - Pass all checks before submitting:
- 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