# tau-cli
`tau session stats --session <id>` reads the session membership journal and only
the journals of agents that ever belonged to that session. It emits versioned TOON
by default with exact turn, tool, token, model/effort, and captured estimated-cost
counts. Estimated API costs appear as `estimated_api_cost_dollars`, rounded to the
nearest microdollar for readable output; internal aggregation retains exact
picodollars. `complete: false` plus `missing_data` identifies pre-contract or
missing facts; corrupt journals fail the command instead of producing partial
totals.
`tau-cli` is Tau's terminal application layer. It connects to the harness daemon, owns the interactive chat loop, interprets application commands, and renders protocol events through `tau-cli-term`.
## Event flow
The interactive UI has three main flows:
1. the socket reader receives `tau-proto` events from the harness,
2. `EventRenderer` folds those events into terminal-visible state and writes blocks through `tau-cli-term`,
3. the input loop reads high-level prompt events and sends application commands or prompts back to the harness.
The long-term direction is a single UI model/reducer that owns protocol state, with the input loop sending typed commands instead of sharing mutable mirrors of renderer state. Current code still has some shared `Arc<Mutex<_>>` snapshots for completions and prompt editor context; prefer reducing those when touching nearby code.
## Tool UI policy
UI code must render tool calls through generic `ToolUseState`, `ToolUsePayload`, progress counters, and fallback tool displays. Do not add tool-name-specific rendering for ordinary extension tools.
Harness sub-agent activity is rendered from generic events, not
delegation-specific UI paths. `agent.watches_updated` identifies which agents
are observed; current-session structured work status keeps a watched row
visible while it is unreported, working, waiting, blocked, or unknown, and removes it
only after done. The complete `agent.stats_updated` detailed activity decides its turn emoji,
while binary runtime remains navigation authority. Individual provider invocations are
inner model rounds, and prompt/provider events are only a pre-stats
compatibility fallback. `agent.stats_updated` also provides generic counters
and provider response stats provide live response throughput details for that
running turn. An idle watched target retains its status row, and one that
watches an active descendant adds `watching -> @descendant`. This recursive
projection is exact over the live watch graph. It shows the full visible
deduplicated closure through eight rows, then falls back to every direct watch
without truncating that direct set. Indirect rows attribute their chosen
predecessor before the watched target as `@parent -> @watched`; watched-agent
metadata follows the watched target. Activity projection separately contributes unique
effective targets to the session-wide bottom `@N` chip. Merely live, selectable,
non-suspended, or idle leaf agents do not appear as active watched-agent work or
contribute to that count.
Prompt navigation modes are harness-owned current-session daemon memory:
ordinary agents default to `active`, delegated agents default to `active-auto`,
and any attached UI can request `suspended`, `active`, or `active-auto` with
`:agent suspend`, `:agent resume`, or `:agent auto`. Complete
`agent.stats_updated` snapshots update each UI cache. Selection, transcript,
drafts, and presentation remain UI-local. Explicit overrides are not persisted;
cold restore recomputes defaults from existing provenance. Selecting, picking, or
focusing a hidden agent alone does not change its mode. A successfully admitted
visible user prompt to an existing target is an implicit absolute `active` write;
the harness publishes the resulting complete stats before queue or dispatch.
The public `tau agent list <session-id>` command reads a directed harness roster
and emits stable headerless TSV; it does not infer membership or navigation from
renderer state. The C-b picker, `:pick-agent`, and C-j/C-k navigation ring use
the effective-active rule: `active` agents remain eligible while idle, and
`active-auto` agents are eligible only while running. `:pick-agent-all` instead
lists every current live agent, including idle `active-auto` and explicitly
suspended agents. Both pickers render work status and current-turn state as
compact emoji; lifecycle and role remain
available from `tau agent list` but are omitted from picker presentation. The
overview is non-interactive: use `:new` or `:agent new` to enter the explicit
new-agent composer. A genuinely empty fresh session starts in that composer
automatically. The underlying picker actions remain configurable, and the
all-agent action has no default key binding.
`tau agent trace <agent-id>` operates offline and projects from a stable,
validated snapshot of existing durable agent journals. It defaults to the compact
`agent-tools-toon` semantic timeline in lite mode, which keeps exact content
sizes and at most 4 KiB of each assistant/reasoning/message text and terminal
output rather than complete forensic evidence. Explicit `tau-jsonl` is the
complete native
artifact and preserves every persisted event and its journal-local ordering.
`otlp-json` is a lossy OpenTelemetry/OpenInference visualization adapter: it
derives spans only from durable IDs and journal wall-clock timestamps, while
retaining every raw journal occurrence as a span event.
`agent-tools-toon` and `agent-tools-jsonl` provide compact relative/absolute
journal timelines over provider-declared calls, assistant prose/reasoning,
explicit directional messages, activations, and typed causal relationships.
`--mode lite` is the default and reports complete text/output byte/line counts,
bounded content, and explicit completeness; `--mode full` includes complete
semantic text and rendered output.
`agent-performance-jsonl` is always content-free and reports ordinary and
standalone provider usage/cost, tool/background and typed-wait lifecycle,
outer-turn boundaries, qualified journal recorded-at wall intervals, and
per-agent summaries. `--mode full` is invalid for this format.
See [`docs/agent-trace.md`](../../docs/agent-trace.md) for the output contracts,
failure behavior, and sensitive-data warning.
`tau agent export chat <agent-id>` emits the selected durable branch as a human
conversation: metadata followed by authenticated user prompts and assistant
response text. Markdown is the default; `--toons` selects the existing strict
TOON serializer, and `--markdown` selects Markdown explicitly. The projection
omits reasoning, tools, cross-agent messages, and internal prompts.
`tau session list` prints one escaped row per distinct current session id
reported by responsive local harnesses. Runtime paths only locate socket
candidates; each daemon reports its in-memory current session and immutable
canonical startup project root through a directed local control RPC, and
persisted session directories never add rows.
Backslash, tab, newline, carriage return, and other control characters use the
same `\\`, `\t`, `\n`, `\r`, and `\u{hex}` escaping as agent-list fields.
This makes records line- and ANSI-control-safe; it does not normalize general
Unicode format characters.
`tau session list --dir DIR` canonicalizes an existing directory and returns
only exact project-root matches. `--json` emits one array whose records contain
required `session_id` and `project_root` strings; empty results are `[]`, and
duplicate records are retained when multiple responsive harnesses report the
same identity.
`tau session kill SESSION` connects to that exact running session as an
ordinary admitted UI and requests the same graceful canonical shutdown as
interactive `:quit-session`. It preserves durable history and reports success
only after confirming that the connected daemon process exited. It never sends
a signal, deletes session data, or bypasses runtime socket access policy.
Relative `--dir` values resolve from the caller's current directory. Missing,
inaccessible, and non-directory values are CLI errors with exit status 2.
Zero, one, and multiple verified matches are successful, and a closed output
pipe is also success. If an individual contended claim is incompatible,
unresponsive, or otherwise cannot complete exact-session admission, Tau omits
it, preserves the plain or JSON stdout rows from compatible responders, and
prints one count-bearing warning on stderr. Claim-directory traversal,
whole-call discovery, serialization, and non-broken-pipe output failures return
nonzero. Discovery and serialization failures occur before stdout is touched; a
stdout write failure can leave a written prefix because arbitrary output streams
cannot be rolled back. The command only inspects runtime candidates and does not
create or clean up state.
There is also a narrow temporary action-input redaction exception:
content-enabled prompt drafts represent a recognizable `:email auth google
finish ...` buffer as exactly `:email auth google finish <redacted>` during
composition. After submission, every history/editor presentation uses that same
fixed line. The pasted Gmail loopback URL contains a one-time OAuth authorization
code and the action schema does not yet provide sensitive-argument metadata.
Only the active editor, immediate routing stack, and exact owning action
extension retain the raw line; this UI special case should be replaced with
schema/protocol metadata when available.
## Threading and shutdown direction
The current implementation has a socket reader thread, renderer path, redraw/timer helpers, and a blocking prompt input loop. Remote disconnect handling is not yet fully unified with prompt input wakeup. Future changes should move toward explicit UI event ownership: daemon disconnect, terminal input, timers, and shutdown should be represented as events that drive one loop or a clearly joined set of owned workers.
## Command paths
Interactive chat, `tau dev send`, and `--prompt-stdin` should share socket/session setup and prompt construction wherever possible. Mode-specific command capabilities are fine, but avoid duplicating protocol handshakes or command parsing in separate paths.
Bare `:tree` is a one-shot exception to fire-and-forget `tau dev send`: it
waits for and prints the harness's single requester-directed multiline notice.