html/exporter

The trace exporter renders one persisted lash session (plus any child sessions created by spawn_agent) into a single self-contained HTML document. The visual language matches the rest of the docs (warm-iron / fast-amber). The forensic affordance is two-edge-aware: continue_as AgentFrame switches are linear seams inside the same session view; subagents are drill-in cards into child-session views.

The two-edge model

continue_as and spawn_agent both create a visible boundary, but only spawn_agent creates another session. continue_as appends an AgentFrame record inside the same session; spawn_agent creates a child session with SessionRelation::Child. Flattening those under one shape is what made the previous exporter feel wrong, so the renderer mirrors the runtime distinction.

Edge Tool Cardinality Lifecycle Visual treatment
AgentFrameSwitch continue_as 1 → 1 terminal Current frame ends; the new frame takes over with seed and task. Inline divider. The frame's entries continue in the same session view, behind a sodium-bracketed seam that names the boundary.
Subagent spawn_agent 1 → N blocking Parent waits for the child to finish, then resumes. Drill-in card. Click into the subagent's own full view (same hero, same controls). Breadcrumb tracks the path back.

Inline AgentFrame switch seam

Continue_as is linear, so the natural reading is one transcript that crosses an AgentFrame boundary inside the same session. The seam is a full-width band with sodium hairlines top and bottom: the task in display type, the seed broken into projected vs global entries, and a hairline-divided stat strip. Those four pieces of state show the reader what was carried forward and what was left behind.

↪ continued as Synthesise the audit into a ranked compliance plan.
s1·a47e s4·e51a

Take the auth-file inventory and the migration summary; produce a single ranked list of compliance touchpoints. Each item gets a one-line rationale and an effort estimate. Stop when the list is < 12 items.

seed · 4 entries
problemprojected auth_filesglobal · 4 paths migration_summaryglobal · 1.4k findingsglobal · 12 entries
parent ctx78% seed2.8 kb turns8 reasoncontinue_as

Subagent drill-in card

Spawn_agent is blocking but its result is a separate unit of work. Inlining the child transcript inside the parent's tool entry would force a width-cascade and lose the subagent's full hero / controls / minimap. Instead, the exporter gives the subagent its own full view reached by click-through navigation. The card below shows the affordance; in the shipped exporter the lineage strip and breadcrumb carry the [data-go] targets. The lichen accent keeps the child visually subordinate to the sodium AgentFrame switch seam.

▾ subagent · spawn_agent db_migrations · explore

Summarise migrations/ schema changes since v3. Flag any change that touches identity, session, or token columns.

ok turns5 spawned1 · migration_v5 tokens7.8k
s3·d23f 22.7s

Live demo

An end-to-end mockup with three views (rootdb_migrationsmigration_v5) backed by synthetic but realistic content. Click any drill-in card or breadcrumb step to navigate. Browser back works through history.pushState. Resize the iframe to see responsive behavior.

open export-design.html ↗ · scroll inside the frame to see the inlined AgentFrame switch divider

Implementation map

The renderer is additive; single-session export still works as it always did. Child-session detection is automatic, and AgentFrame dividers come from the owning session's tool-control records.

  1. Tree discovery

    Given a root .db path and a trace JSONL, tree::load_tree_from_paths scans the sessions directory, keeps every child store reachable through parent_session_id chains, and partitions LlmPromptSnapshots by context.session_id. Child sessions are classified from persisted SessionRelation::Child metadata and anchored back to the parent's spawn_agent tool call when possible. continue_as no longer participates in tree discovery because its AgentFrame records live inside the same session store.

  2. View topology

    A view is one persisted session: the root or a spawned subagent. html::tree::write_view writes one <section class="view"> per session: hero, lineage strip, minimap spine, and transcript. continue_as AgentFrame switches stay inline in that session's transcript (they never split the view), and spawned subagents are reachable through [data-go] navigation in the lineage strip and breadcrumb that targets child-session views.

  3. View switching

    Each view is rendered up-front and toggled by a tiny IIFE that reads window.__lashTraceTree (a serialized list of {id, label, sid, parent}, one entry per view head (root and each subagent), not one per session; id and parent are view IDs, sid is the head session's short id). Click handlers on [data-go] elements (drill-in cards, breadcrumb segments, lineage pills) call history.pushState and swap the active .view. The browser back button does the right thing through popstate.

  4. Visual discipline

    Sodium is reserved for the active edge: AgentFrame switch seams, the breadcrumb's current step, the user's intent. Lichen marks the subagent affordance: drill rails, drill arrows, child status pills. Filter chips read as quiet chalk by default and gain a sodium strikethrough only when the user has actively filtered something off, so the controls strip never floods the page with accent. Ash structural lines do everything else.

Source map

Single self-contained HTML; tokens, fonts, CSS, and JS all inlined.

lash-export

Tree discovery and edge classification. Returns a LoadedSessionTree with one LoadedSessionNode per discovered session; each carries its own chronological projection, partitioned LLM prompts, and the list of subagent edges anchored by parent call_id.

lash-export

The public render_tree(tree, format) is the multi-view entry point; the writers in the html::tree submodule (write_crumb_bar, write_view, write_view_hero, write_lineage, and render_tree_data_script) own the multi-view elements, while render_node_entries reuses the existing message/tool/RLM-step renderers unchanged.

lash-export

Tokens are appended at the bottom under "multi-view: breadcrumb, lineage, drill, AgentFrame switch". The base trace stylesheet stays intact for single-session exports; multi-view rules only activate when the page contains .view sections.

lash-export

The view-switcher IIFE at the bottom reads window.__lashTraceTree, wires [data-go] click handlers, renders the breadcrumb, and listens for popstate. It exits cleanly if the tree global is absent (single-session export).

read on ·