thunc()
Guide · new in 0.3

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 command

Scripts 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
 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

ScreenWhat's on itOpening a row shows
OverviewCalls in flight, a table per function (calls, cache hits, retries, failures, mean and p95 time), running agents, results per second, recent eventsA function's calls, one call, or an agent run
AgentsEvery 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
CallsRecent calls, and each attempt of the selected one: the reply, and why it was rejected (a parse error, or a failing ensure=)
SummaryThe same tables as thunc run --profileA function's calls, or an agent run
OutputWhat 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.

KeyDoes
1–5, ← →, tabSwitch screens
↑ ↓, j kMove the selection (also PgUp PgDn, Home End, or the mouse wheel)
⏎Open the selected row
escGo back, or clear the filters
fShow only retries, failures and denied actions
p, spacePause the display; the program keeps running and its events wait
oWhat the program printed
?Every key and mouse action
qQuit. If the program is still running, it asks first, because quitting stops it
Ctrl+CStop 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 folder

It 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.py
stderr
thunc  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 record

A 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 another

What 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

OptionDoes
--agents [DIR]Follow agent runs in DIR instead of running a program
--events FILEFollow a file another process writes with THUNC_EVENTS=FILE
--replay FILEPlay back an events file or an agent run's record; --speed N sets the pace (0 plays it at once)
--plainOne line per event instead of the dashboard
--captureWhole inputs and replies, not previews
--save-events FILEKeep the program's events in FILE
--python PATHThe Python for scripts and -m (default: the one thunc is installed in)
--no-mouseLeave 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.

Edit this page on GitHub