Watching a program
thunc watch runs your program with a live dashboard in the terminal: the calls waiting on a model, retries and why each reply was rejected, each agent's steps as they happen, and a report when it ends. Use it with the mouse or the keys.
New in thunc 0.3. The dashboard is new; its screens and options may change in a later release as feedback comes in. A program needs nothing added to be watched.
Install
The dashboard is a compiled program in its own package, thunc-watch, so thunc itself stays pure Python with no dependencies. Install it as an extra:
pip install "thunc[watch]"There are prebuilt wheels for macOS, Linux and Windows. Without the package, thunc watch says how to install it.
Watch a program
Run your program through thunc watch the way you'd run it with thunc run:
thunc watch support_inbox.py --limit 20 # a script and its arguments
thunc watch -m myapp.triage # a module, as with python -m
thunc watch -- uv run app.py # any commandScripts and modules run on the Python thunc is installed in; pass --python PATH for another. The dashboard takes over the terminal while the program runs. When the program ends, it opens the report. When you quit, it prints what the program printed, then the report, and exits with the program's exit code.
thunc watch support_inbox.py claude-code/sonnet 00:18.0 ● running
1 Overview 2 Agents 3 Calls 4 Summary
────────────────────────────────────────────────────────────────────────────────────────────
IN FLIGHT 4 running
⠙ draft_reply ticket="Password reset email never… attempt 1 4.2s ████████████
⠙ urgency ticket="Refund still not showing a… attempt 2 4.1s ██████████░░
⠙ draft_reply ticket="Where is order A-1043? It … attempt 1 3.1s █████████░░░
⠙ draft_reply ticket="Any plans for a public API… attempt 1 2.4s ███████░░░░░
FUNCTION CALLS CACHED RETRIES FAILED MEAN P95 MODEL RECENT
category 8 0 0 0 1.5s 2.5s 11.7s ▃▄▅█▆▇▃▄
urgency 7 0 1 0 2.4s 4.7s 16.9s ▂▄▄▆▃█▅
find_order 7 0 0 0 2.1s 3.4s 15.0s ▅▃█▇▇▅▄
draft_reply 4 0 0 0 3.6s 4.4s 14.5s ▆▆█▇
AGENTS 0 running
✓ repo-guide tests_for(feature="caching") finished · 6 steps 12.4s
ACTIVITY results per second, last 30s ▁▁▁▁▁▁▁▁▁▁▁▁▆▆▃█▃▃▆▃▆▃▆▃▆█▃▃▁▁ overlap 4.7x
EVENTS
17:38:11 ✓ urgency → 4 4.7s
17:38:12 ✓ find_order → None 2.7s
17:38:12 ✓ category → bug 1.1s
17:38:12 ✓ urgency → 3 2.4s
17:38:13 ✓ find_order → Order(id='A-1043') 1.8s
17:38:14 ✓ find_order → None 1.6s
17:38:15 ↻ urgency attempt 1: not valid JSON: 'high' 2.8s
────────────────────────────────────────────────────────────────────────────────────────────
↑↓ or click to select · ⏎ or click again to open p Pause f Failures ? Help q Quit
The overview, 18 seconds into a run: four calls waiting on the model, one of them on its second attempt after a reply that wasn't valid JSON.
The screens
| Screen | What's on it | Opening a row shows |
|---|---|---|
| Overview | Calls in flight, a table per function (calls, cache hits, retries, failures, mean and p95 time), running agents, results per second, recent events | A function's calls, one call, or an agent run |
| Agents | Every run, and the selected run's steps: each tool, its target, its result and how long it took, the command running now, the files it changed and anything its permissions refused | |
| Calls | Recent calls, and each attempt of the selected one: the reply, and why it was rejected (a parse error, or a failing ensure=) | |
| Summary | The same tables as thunc run --profile | A function's calls, or an agent run |
| Output | What the program printed, with stderr in blue |
Mouse and keys
Everything works both ways. Click a row, or move to it with ↑ ↓, to select it; click it again, or press ⏎, to open it. esc goes back to where you opened it from. The buttons along the bottom pause the display, show only failures, open the help and quit.
| Key | Does |
|---|---|
1–5, ← →, tab | Switch screens |
↑ ↓, j k | Move the selection (also PgUp PgDn, Home End, or the mouse wheel) |
⏎ | Open the selected row |
esc | Go back, or clear the filters |
f | Show only retries, failures and denied actions |
p, space | Pause the display; the program keeps running and its events wait |
o | What the program printed |
? | Every key and mouse action |
q | Quit. If the program is still running, it asks first, because quitting stops it |
Ctrl+C | Stop the program, as it would in its own terminal |
While the dashboard has the mouse, select text by holding Shift (Option on macOS) as you drag, or start it with --no-mouse.
Following agent runs from anywhere
--agents follows the runs recorded in an agents folder, from any process: another terminal, a web app, a worker on this machine.
thunc watch --agents # ./.thunc_agents, or THUNC_AGENTS_DIR
thunc watch --agents path/to/agents # another folderIt finds the folder the same way thunc does, so a configure(agents_dir=...) in your code isn't visible to it: pass the same folder. A run counts as running while its record has no end and the process holding the agent's lock is alive. A run whose process died partway through shows as interrupted. Run records are written to the second and don't time the model, so in this mode a step's time is the gap between its line and the one before, and model and tool time aren't split.
In CI and pipes: --plain
--plain prints one line per result, retry and agent step, then the report. It's also what you get when the output isn't a terminal.
thunc watch --plain support_inbox.pythunc 10:25:31 retry urgency attempt 1 rejected after 1.9s: not valid JSON: 'seven'
thunc 10:25:33 call urgency → 4 (4.1s, 2 attempts)
thunc 10:25:34 call urgency → 2 (1.2s)These lines go to stderr and the program's own output to stdout, so the two don't mix in a pipe.
Saving and replaying a run
thunc watch --save-events run.jsonl app.py # keep the events after the run
thunc watch --replay run.jsonl # play it back; --speed 4 for faster
thunc watch --replay .thunc_agents/repo-guide/sessions/<run>.jsonl # one agent run's recordA saved events file is a good thing to attach to a bug report. To watch a program you start some other way, set THUNC_EVENTS yourself and follow the file:
THUNC_EVENTS=events.jsonl python app.py # in one terminal
thunc watch --events events.jsonl # in anotherWhat it reads, and what's in it
When THUNC_EVENTS names a file, thunc appends one JSON line to it for each call start, model reply, call end, agent tool call and agent end. thunc watch sets it to a temporary file for the program it runs. When it isn't set, nothing is written.
Inputs, replies and values are cut to 120-character previews. --capture (or THUNC_EVENTS_CAPTURE=1) sends them whole, and the Calls screen then shows them in full. Like a trace, they can contain personal data from your inputs, so treat a saved events file like the data you send.
Options
| Option | Does |
|---|---|
--agents [DIR] | Follow agent runs in DIR instead of running a program |
--events FILE | Follow a file another process writes with THUNC_EVENTS=FILE |
--replay FILE | Play back an events file or an agent run's record; --speed N sets the pace (0 plays it at once) |
--plain | One line per event instead of the dashboard |
--capture | Whole inputs and replies, not previews |
--save-events FILE | Keep the program's events in FILE |
--python PATH | The Python for scripts and -m (default: the one thunc is installed in) |
--no-mouse | Leave the mouse to the terminal, for selecting text |
thunc watch --help lists them too. The dashboard is also on your PATH as thunc-watch, with the same options.