assay turns is the debugging read surface for durable turn logging. It decrypts one sitting (or a filter) and prints the timeline: messages, reasoning, tool calls, tool results, with per-turn cost joined from the ledger. It is read-only. It never mutates the store.

Command

assay turns --session <session-id>
assay turns --principal <id> --limit 50
assay turns --session <session-id> --json
Each block is:
[<time>] <session>#<seq> <kind> (<role>) [tool=<name>]
    <decrypted content>
    cost  $0.12
Cost prints on the last record that shares a span ref, so a tool call and its result are not billed twice.

Filters

Flag
--sessionOne sitting
--principalOne director
--kindmessage / reasoning / tool / …
--rolehuman / agent / …
--taskOne task
--since / --untilTime window
--limitMax turns
--key-fileContent key (default ~/.config/assay/transcript.key)
--jsonArray of decrypted records
--db / --pgWhich store
A shredded principal prints a leading notice and [shredded] per content line. Metadata rows stay. JSON uses null content when shredded or unreadable, and omits content when the turn had none. Empty string is never used as a stand-in for erased text.

In an agent loop

This is the command an agent (or a test) should use to see what was actually logged:
assay turns --session "$SESSION_ID" --json
Parse stdout. On failure, stderr starts with the error and the exit code is non-zero. For a published sitting, do not use assay turns against the live store. Point the agent at the share link. The same URL serves a machine bundle (outline.json, manifest.json, turns.jsonl). See Share.
NeedUse
One sitting in a browserassay dashboard → Sessions → the sitting
Search across sittingsassay search "…" or the Search tab
Rollup costassay show --session <id>
Latest spansassay tail
The session page in the console is the same timeline with folding, type, objective chips, and share. assay turns is the scriptable form.