Watching a session as it runs¶
Two commands keep generated output current while Claude Code is still writing to a transcript.
Markdown (or HTML) on disk¶
With no arguments this watches the project for the current directory — which is what you want when running it alongside a live session. It converts once up front, then re-converts whenever a transcript changes. Anything that reloads files picks the changes up: an editor, Obsidian, a browser refresh.
For an Obsidian vault:
A tick regenerates only the session that changed, so a vault indexer sees one file move, not the whole projection.
Obsidian auto-updates, but doesn't auto-scroll, so expect something like this:
The served page, updating itself¶
Open a session page and it grows as messages arrive — roughly a second behind the CLI, without a reload. Your scroll position, folded sections and open disclosures all survive, and new messages fade in.
A follow button (⏬) joins the buttons down the right-hand edge once the page is being served. Click it to keep the page pinned to the newest message; while you are not following, it shows a count of how many have arrived since you last looked.
It is the session pages that track a live session. Watch ticks leave
the combined pages alone, for the same reason watch defaults to
--combined no: regenerating them is what forces a tick to reload the
whole project rather than just the session that grew. The combined pages
written at startup stay on disk and keep serving — they simply stop
tracking the live session until you restart. Their "View All Sessions"
back-link keeps working throughout — it points at a page that exists and
is still served, just one that stopped growing.
Sub-agents update while they run, not only when they finish: a
synchronous agent's transcript grows in its own file while the session
waits for it, and each tick picks that up. With --theme minimal (see
Themes) the branch layout follows along — lanes you interleaved or put in a column
stay that way across updates, a sub-agent that has not returned yet is
drawn as running (its lane carries on to the newest message with an
open end and a pulsing running label) and turns into an ordinary merge
when its result arrives, and a rewind adds its fork lane without moving
the main line. An agent waiting on something slow — a background process,
a watcher — keeps reading as running however long it takes; once it has
been silent for a minute its label says for how long (running · quiet
42m). "Running" needs a live page: a page opened from file:// (or a
session nothing has moved in for over a week) shows such an agent as
having ended without a result instead, and so does one the session
stopped with TaskStop.
In either theme, a message-type filter or a search you have set also applies to messages as they arrive, without moving you to the newest match.
To follow the combined page live as well, run claude-code-log watch
--combined yes (with the same --theme) beside serve: the server
serves whatever is on disk, and that watch keeps the combined page
current.
This works only over the server. A page opened from file:// cannot
fetch anything at all — not even itself — so it stays static, exactly as
before. Nothing about the generated HTML changes.
This is how following a session looks like:
What "real-time" can and cannot mean here¶
It cannot show tokens arriving. Claude Code writes a transcript entry exactly once, when the message is complete — it never rewrites a line, so there is no partial message on disk to display. The finest granularity available anywhere in this tool is one whole message, appearing promptly after it finishes. The fade-in is there to make that arrival legible, not to imitate streaming.
Everything else follows from that. A message typically appears within a second or so of completing: the watcher waits briefly for the burst of entries in a turn to settle (a turn writes several), converts, and the page notices on its next poll.
Tuning¶
| Flag | Default | What it does |
|---|---|---|
--interval |
0.25 |
Seconds between filesystem polls |
--quiet-period |
0.3 |
Wait for changes to settle before converting |
--max-latency |
2.0 |
Convert anyway after this long, so a long unbroken stream still surfaces |
--all-projects |
off | Watch the whole archive instead of one project |
--combined |
no |
no keeps ticks cheap: only the changed session is regenerated |
--theme |
$CLAUDE_CODE_LOG_THEME, else default |
HTML theme: classic (current look), minimal, or default (the built-in default, currently classic). Also on serve |
Raise --quiet-period if conversions feel too frequent on a large
project; lower --interval if you want changes noticed sooner.
Switching --theme rewrites every page in the new theme on the first
tick — including a combined page that --combined no would otherwise
leave alone, so its session pages never link back into a page of the
other theme. Later ticks are cheap again.
Cost¶
A tick re-converts only what changed. On a 319 MB, 217-file archive a
tick is about a second; on a small project it is hundredths of a second.
While nothing is changing, the browser's poll is a HEAD for the page's
own metadata — about a millisecond, and no body — and the watcher is a
stat of the project directory. The page is re-fetched in full only
once that metadata says it moved.