Stream Claude Code's hidden output (thinking, tool calls, subagents) to a separate terminal in real-time (Rust port)
Stars
★ 20
Forks
⑂ 1
Language
Rust
Size
550 kB
Last Push
20d ago
Forged
4mo ago
agentsclauderusttui
# claude-esp-rs
[](https://crates.io/crates/claude-esp)
Stream Claude Code's hidden output (thinking, tool calls, subagents) to a separate terminal in real-time.

> **Note:** This is a Rust port of the [Go version](https://github.com/phiat/claude-esp). The binary is named `claude-esp-rs` to allow running both versions side-by-side.
## The Problem
When using Claude Code interactively, tool outputs and thinking are collapsed by default and require pressing `Ctrl+O` to toggle visibility. This tool lets you watch all that output in a **separate terminal** with a nice TUI, without interrupting your main Claude Code session.
## Features
- **Multi-session support** - Watch all active Claude sessions simultaneously
- **Hierarchical tree view** - Sessions with nested Main/Agent nodes
- **Real-time streaming** - See thinking, tool calls, and outputs as they happen
- **Subagent tracking** - Automatically discovers and displays subagent activity
- **Session events** - Compaction boundaries, hook output, post-edit LSP diagnostics, and PR-link events surfaced inline
- **Agent type labels** - Shows agent types (Explore, code-reviewer, etc.) from `.meta.json`
- **Token usage tracking** - Cumulative input/output token counts in the header bar
- **Per-agent context size** - Each Main/subagent row shows current context as a percentage of the model's max context window (`Main 18%`, `Explore 9%`). Denominator is the model's *max window* (1M for opus-4-7 / sonnet-4-6, 200k for haiku-4-5), **not** the auto-compact threshold
- **Tool execution duration** - Shows how long each tool call took
- **Background task visibility** - See background tasks (⏳/✓) under spawning agent
- **Filtering** - Toggle visibility of thinking, tools, outputs per session/agent
- **Auto-scroll** - Follows new output, or scroll freely through history
## Requirements
- Rust 1.86 or later
## Installation
```bash
# Install from crates.io
cargo install claude-esp
# Or clone and build from source
git clone https://github.com/phiat/claude-esp-rs.git
cd claude-esp-rs
cargo build --release
# Optional: install to PATH
cp target/release/claude-esp-rs ~/.local/bin/
```
### Pre-built binaries
Download pre-built binaries from the [Releases](https://github.com/phiat/claude-esp-rs/releases) page. Available for Linux (amd64, arm64), macOS (amd64, arm64), and Windows (amd64).
## Usage
```bash
# In your main terminal: run Claude Code as normal
claude
# In a second terminal/tmux pane: run the watcher
claude-esp-rs
```
### Options
| Option | Description |
| ------------ | --------------------------------------------- |
| `-s <ID>` | Watch a specific session by ID |
| `-n` | Start from newest (skip history, live only) |
| `-l` | List recent sessions |
| `-a` | List active sessions |
| `-p <ms>` | Poll interval in ms (fallback mode only, default 500) |
| `-w <secs>` | Active window in seconds (default `300` = 5 min) |
| `-m <N>` | Max sessions to show in tree (default 0 = unlimited) |
| `-c <secs>` | Auto-collapse sessions inactive ≥ secs (default 0 = disabled, e.g. `120` for 2 min) |
| `-D` | Debug: surface raw `type:subtype` for every JSONL line type the parser would otherwise drop |
| `-V` | Show version |
| `-h` | Show help |
### Environment Variables
| Variable | Description |
| ------------- | --------------------------------------------------- |
| `CLAUDE_HOME` | Override Claude config directory (default: `~/.claude`) |
### Examples
```bash
# Watch all active sessions
claude-esp-rs
# Skip history, only show new output
claude-esp-rs -n
# List active sessions
claude-esp-rs -a
# Watch a specific session
claude-esp-rs -s 0b773376
# Faster poll interval (200ms)
claude-esp-rs -p 200
# List recent sessions
claude-esp-rs -l
```
## Keybindings
| Key | Action |
| --------- | ----------------------------------------- |
| `t` | Toggle thinking visibility |
| `i` | Toggle tool input visibility |
| `o` | Toggle tool output visibility |
| `x` | Toggle text/response visibility |
| `a` | Toggle auto-scroll |
| `h` | Hide/show tree pane |
| `A` | Toggle auto-discovery of new sessions |
| `tab` | Switch focus between tree and stream |
| `j/k/↑/↓` | Navigate tree or scroll stream |
| `space/enter` | On session: collapse/expand (pins on manual expand) · On agent: toggle visibility · On bg task: load output |
| `s` | Solo selected session/agent (toggle) |
| `g/G` | Go to top/bottom of stream |
| `q/Ctrl+c`| Quit |
## Auto-Collapse
Run with `-c 120` to automatically collapse sessions that have been idle for 2
minutes. Collapsed sessions show `▸` instead of `▾` in the tree and display the
count of hidden subagents (e.g. `📂▸ my-session (+2)`). Children of collapsed
sessions are also filtered out of the stream pane — the whole point is to stop
sleeping sessions from dominating your view.
Press `space` on a collapsed session to expand it manually. Manual expansion
**pins** the session — it won't auto-collapse again until it wakes up (receives
new activity) and then goes idle once more. Press `s` to solo a session; if
it's collapsed, Solo force-expands and pins it so you can see its output.
## How It Works
Claude Code stores conversation transcripts as JSONL files in:
```
~/.claude/projects/<project-path>/<session-id>.jsonl
```
Subagents are stored in:
```
~/.claude/projects/<project-path>/<session-id>/subagents/agent-<id>.jsonl
```
Background task outputs are stored in:
```
~/.claude/projects/<project-path>/<session-id>/tool-results/toolu_*.txt
```
The watcher:
1. Discovers active sessions (modified in last 5 minutes)
2. Uses OS-native filesystem notifications ([notify](https://docs.rs/notify)) to detect file changes in real-time (inotify on Linux, kqueue/FSEvents on macOS)
3. Falls back to polling (configurable with `-p`) on filesystems that don't support notifications (NFS, some cross-FS WSL2 setups)
4. Debounces rapid writes (50ms window) to efficiently handle burst output
5. Parses JSON lines and extracts thinking/tool_use/tool_result
6. Discovers background tasks and correlates them with spawning agents
7. Renders them in a TUI with tree navigation and filtering
## tmux Setup
Recommended tmux layout:
```bash
# Create a new tmux session with two panes
tmux new-session -s claude \; \
split-window -h \; \
send-keys 'claude-esp-rs' C-m \; \
select-pane -L \; \
send-keys 'claude' C-m
```
Or add to your `.tmux.conf`:
```
bind-key C-c new-window -n claude \; \
send-keys 'claude' C-m \; \
split-window -h \; \
send-keys 'claude-esp-rs' C-m \; \
select-pane -L
```
Then press `prefix + Ctrl+C` to open a Claude Code workspace.
## Project Structure
```
claude-esp-rs/
├── Cargo.toml
├── src/
│ ├── main.rs # CLI entry point
│ ├── lib.rs # Library exports
│ ├── types.rs # Data structures
│ ├── parser.rs # JSONL parsing
│ ├── watcher.rs # File monitoring
│ └── tui/
│ ├── mod.rs # Ratatui main app
│ ├── tree.rs # Session/agent tree view
│ ├── stream.rs # Scrollable output stream
│ └── styles.rs # Colors and styling
└── tests/
└── integration_test.rs
```
## Development
Built with [Ratatui](https://github.com/ratatui/ratatui) and [Tokio](https://tokio.rs/). Issue tracking was done with [beads](https://github.com/steveyegge/beads).
```bash
# Run tests
cargo test
# Build release
cargo build --release
# Check formatting
cargo fmt --check
# Lint
cargo clippy
```
## License
MIT