agentafk
Guides

Inspect a session's evidence

Use witness traces, message journals, facets, and transcript search to understand what an agent did.

AFK records a witness trace of actions, a message journal of conversation and tool content, and a searchable Markdown transcript. Start with the trace when you need to reconstruct a run, then choose the journal or transcript when you need the actual words.

Inspect a run

Find the session and read its trace:

afk trace list
afk trace show latest
afk trace show latest --results

afk trace list --max 50 increases the listing from its default 20 sessions. afk trace show [session] accepts a session label or ID; omit it for the most recently written trace. --all includes low-signal phases and paired tool starts, --limit 40 shows only the last 40 displayed events, and --json emits raw NDJSON.

Narrow an investigation to errors or blocks:

afk witness read latest --errors
afk witness read latest --kinds hook_decision,hook_summary --json
afk witness search "permission-denied" --sessions 50

afk witness read filters one session by event kind, tool name (--tool bash), or errors. afk witness search searches recent traces by case-insensitive substring and supports --kinds and --since. Unlike transcript search, these queries match event payloads, not the full conversation.

Search what was said across sessions:

afk transcript reindex
afk transcript search 'daemon AND cron'
afk transcript search '"rate limit"' --limit 3

Reindex on demand after new sessions. The SQLite FTS5 index supports exact phrases, term*, AND, and OR; results include a matching excerpt. Inside the REPL, /transcript opens the current session's Markdown transcript in your pager.

What the witness trace contains

A trace lives under $AFK_STATE_DIR/witness/<session-label>/trace.jsonl (normally under ~/.afk/state/witness/). It records chronological events with kind, sequence, timestamp, and payload. tool_call rows capture the tool name, timing, byte counts, success or error, and an optional short redacted errorHead on failure. They do not contain full arguments, complete results, or conversation text. Other kinds include hook_decision, hook_summary, subagent_lifecycle, budget, abort, compaction, browser_event, closure, and session_sealed. A session_id_assigned phase connects the trace label to the provider session ID on newer traces.

Subagent events share the root session's trace. Their subagentId identifies the actor; concurrent child events interleave, so whole-file order is not one child's execution sequence. Hook pass-through allowances do not each create a hook_decision row. A sealed session's hook_summary counts them; no summary on a live, crashed, or older trace means unknown, not zero.

afk trace show latest --evasion runs a read-only block-evasion and lost-work analysis. It groups automatic hard blocks and flags a later tool in the same broad effect class within the default 10 tool calls; use --evasion-window 20 to adjust the window. Candidates are not proof of a bypass. Trace data does not identify target files, URLs, or shell arguments, and unrelated calls may have the same effect class. The lost-work signal suggests a blocked effect was not recovered before closure, not that the underlying task was impossible.

For MCP startup timing, inspect afk trace show --all. mcp_connect_start and mcp_connect_done bracket connection, including daemon sessions. Where a trace writer is attached to the MCP manager, mcp_server_start and mcp_server_done help isolate slow servers. The done phase also fires if connection throws; it is not a success verdict. See MCP and plugins.

Skill-forked subagent tool calls and permission denials are attributed to that child in the shared trace. Filter failed tool_call rows by subagentId and inspect failureClass (for example, permission-denied); a trace receipt's toolCalls.refused tallies permission denials, hook blocks, and policy refusals without treating expected refusals as ordinary bugs. Subagent start rows carry agentType and at most the first 80 characters of promptHead. There is no AFK_CAPTURE_SUBAGENT_PROMPTS switch in the current code: full dispatch prompts live in the child journal, not the witness row.

Retrieve full messages and tool results

The root message journal is $AFK_STATE_DIR/sessions/<session-id>/journal.jsonl; child journals are in that session's subagents/<subagent-id>.jsonl. They contain the conversation, full tool inputs and results, and the child's dispatch prompt. Large content can be stored in referenced blobs. Journal entries support resume and fork, but asynchronous writes can be lost on abrupt process termination. Set AFK_MESSAGE_JOURNAL_DISABLED=1 only if you deliberately do not want this record.

afk trace show latest --results associates tool calls with complete results from the message journal; --results-lines 0 removes the default per-result line limit. A trace from before journaling, or with journaling disabled, cannot reconstruct missing output. Treat journal data as sensitive: it may contain user text and full tool arguments. For a shell command whose displayed output was capped, afk captures list locates any retained full output file (captures are stored under the witness directory when output exceeds 100 KB). There is no afk bash search command.

Ask an agent to inspect its own history

Inside a session, ask for a narrow read_witness query, such as kinds: ["tool_call"], tool_name: "bash", errors_only: true, limit: 20. Use where: {"payload.decision":"block"} with kinds: ["hook_decision"] to find blocks. search_witness searches recent sessions by substring and excludes the calling session by default; pass include_current_session: true if needed. It caps results at 200 and can narrow by date, kind, tool, or an exact-match where filter. Neither tool exposes full messages or tool results.

For a compact, validated summary instead, ask the agent to call get_facet with session: "latest" or "current". Facets include tool counts, error categories, subagent invocations, outcome, world changes, and available cost data. latest prefers a sealed session in the caller's current working directory; if none exists it falls back globally. Inspect cwd_mismatch before treating it as the same project. fields limits top-level output but session_cwd, is_current_session, and cwd_mismatch are always included. Use memory for curated facts, not as a replacement for trace forensics.

Retention and limits

A best-effort sweep at root session startup keeps witness data bounded to 30 days and 2 GiB by default, evicting whole old session directories. It protects the active session and directories with content updated within the last hour; a stamp limits sweeps to once every six hours. Tune AFK_WITNESS_MAX_AGE_DAYS or AFK_WITNESS_MAX_BYTES, or disable eviction with AFK_WITNESS_RETENTION_DISABLE=1. A separate sweep retains flat session sidecars for 30 days or up to 1,000 files by default, and also ages out per-session data directories. Its controls are AFK_SESSION_MAX_AGE_DAYS, AFK_SESSION_MAX_COUNT, and AFK_SESSION_RETENTION_DISABLE. Retention means old traces and journals may no longer be available when you investigate them.

On this page