"Coding agent transcripts are almost incomprehensible — hundreds of pages of raw tool calls, lossy WebFetch summaries, invisible subagent reasoning, and no way to jump to the interesting parts."
— Inspired by pain points from Tim Hua's LessWrong post
Ever tried debugging a coding agent by reading raw JSONL?
It's a nightmare of nested objects, stream deltas, and lost context.
Agent Trace Viewer turns that firehose into a readable, searchable, debuggable conversation. Every tool call, every thought, every result — beautifully laid out, color-coded, and jumpable. 100% local. Zero tracking. Open source.
⬇️ Try it in 30 seconds ⬇️
git clone https://github.com/NullLabTests/agent-trace-viewer.git
cd agent-trace-viewer
pnpm install
pnpm devOpen http://localhost:3000 — the demo loads immediately. No config, no signup, no API keys.
Requires Node.js 18+ · Install pnpm: npm install -g pnpm
① Timeline sidebar — click any turn to jump ② Collapse/expand thinking traces ③ Auto-warnings for errors, slow calls, lossy summaries
| What you get | What you don't get |
|---|---|
| 🎨 Color-coded cards — user, assistant, thinking, tool calls, results, system | 🗑️ Raw JSONL with nested stream deltas |
| 📖 Collapsible sections — expand what matters, collapse the noise | 🤯 One giant wall of text |
| 🖼️ Rich Markdown + LaTeX rendering via KaTeX | ❌ Escaped JSON strings and truncated output |
| 🏷️ Visual hierarchy — icons, badges, timestamps, durations | 🔍 Having to grep for what you need |
Automatic warning badges flag issues as they appear:
| When this happens | You see this |
|---|---|
| Tool call takes >30s | 🔴 Took 45s |
| Tool result contains "error"/"failed"/traceback | 🔴 Tool returned error |
| Tool result is massive (>5,000 chars) | 🟡 Large result |
| WebFetch tool was used (lossy summarization risk) | 🟡 WebFetch summary |
No need to read every line — the warnings tell you where to look.
- Press
/or⌘F— instantly search across the entire transcript - Timeline sidebar — a compact bird's-eye view of every turn, clickable to jump
- Keyboard navigation — arrow keys through search results, Escape to dismiss
- Active turn tracking — the sidebar highlights your current position
- Export as Markdown — a clean, readable document of the session
- Export as JSON — full annotated data for programmatic analysis
- Metadata at a glance — total turns, tool call count, session duration, model name, per-tool usage breakdown
No data ever leaves your machine. Parse, render, and search entirely in your browser. No server, no API calls, no telemetry, no signup. Open the app, load a file, and you're offline.
🔬 Claude Code — click to expand
# Claude Code saves logs by default. Find them here:
cat ~/.claude/logs/<session-id>.jsonl
# Or capture a session in real time:
claude --log-level debug 2>&1 | tee session.jsonlThe format uses role: "user" / role: "assistant" messages with content blocks: text, thinking, tool_use, tool_result.
🦙 Ollama / Local LLMs — click to expand
# Log an Ollama chat session to a file:
curl http://localhost:11434/api/chat -d '{
"model": "llama3.2",
"messages": [{"role": "user", "content": "Hello"}],
"stream": false
}' -o ollama-session.jsonlEach line has model, message.role, message.content, and optional message.tool_calls. Duration and token counts are extracted automatically.
🤖 SWE-agent — click to expand
SWE-agent logs trajectories as JSON arrays with action, observation, and thought fields. Just save the .traj or .json file and load it. Actions are mapped to human-readable tool names.
🧑💻 Aider — click to expand
Aider logs can be JSONL with role, content, toolName, toolArgs, toolResult fields, or markdown with #### User: / #### Assistant: headers. Both are auto-detected.
⚡ Codex / OpenDevin — click to expand
Any JSON or JSONL with message-based structure and tool call/result fields. The generic parser catches these automatically.
📄 Any JSON/JSONL — click to expand
Don't see your agent? Just try loading the file. The generic fallback parser will attempt to extract content from any JSON or JSONL file with role, content, type, or message fields.
Have a custom agent or a format we don't support? Add a parser in less time than it takes to read this section:
// src/lib/parsers/my-agent.ts
import { Parser, Transcript } from '../types';
import { hashId } from '../utils';
export const myParser: Parser = {
name: 'My Agent',
description: 'Parses My Agent log format',
canParse: (content: string, fileName?: string) => {
return fileName?.endsWith('.myagent') || false;
},
parse: (content: string, fileName?: string): Transcript => ({
id: hashId(),
title: fileName || 'My Agent Transcript',
turns: [/* your turn parsing logic */],
source: fileName || 'unknown',
}),
};Then register it:
// src/lib/parsers/index.ts
import { myParser } from './my-agent';
export const parsers: Parser[] = [myParser, /* ... */];That's it. The auto-detection pipeline picks it up automatically. Open a PR and share it!
agent-trace-viewer/
├── src/
│ ├── app/ # Next.js app router
│ │ ├── page.tsx # Main page (header + viewer mount)
│ │ ├── layout.tsx # Root layout (fonts, KaTeX CDN)
│ │ └── globals.css # Tailwind v4 tokens (light + dark)
│ ├── components/
│ │ ├── transcript-viewer.tsx # 🧠 Core orchestrator
│ │ ├── turn-card.tsx # 🃏 Individual turn + warning logic
│ │ ├── sidebar.tsx # 📋 Timeline navigation
│ │ ├── search-dialog.tsx # 🔍 Global search (⌘F)
│ │ ├── theme-toggle.tsx # 🌓 Dark/light switch
│ │ ├── metadata-panel.tsx # 📊 Session stats grid
│ │ └── ui/ # 🧩 Primitives
│ │ ├── badge.tsx, card.tsx, dialog.tsx
│ │ ├── scroll-area.tsx, separator.tsx
│ └── lib/
│ ├── types.ts # 📐 TranscriptTurn, Parser interfaces
│ ├── utils.ts # 🔧 cn(), formatDuration(), hashId()
│ └── parsers/ # 🔌 Parser modules
│ ├── index.ts # Registry + auto-detection
│ ├── claude-code.ts # Claude Code JSONL
│ ├── ollama.ts # Ollama / local LLMs
│ ├── swe-agent.ts # SWE-agent trajectories
│ ├── aider.ts # Aider logs
│ ├── codex.ts # Codex / OpenDevin
│ └── generic.ts # Fallback for any JSON/JSONL
├── public/
│ ├── hero.svg, why.svg, formats.svg, showcase.svg
│ └── demo-transcripts/
│ ├── claude-code-demo.jsonl
│ ├── ollama-demo.jsonl
│ ├── swe-agent-demo.json
│ └── aider-demo.jsonl
├── package.json
├── next.config.ts
└── tsconfig.json
| Category | Choice | Why |
|---|---|---|
| Framework | Next.js 16 (App Router) | File-based routing, fast refreshes, great DX |
| Language | TypeScript (strict mode) | Catch bugs before they ship |
| Styling | Tailwind CSS v4 (Oklch tokens) | Beautiful colors, tiny bundle, great DX |
| UI Primitives | Radix UI | Accessible, unstyled, composable |
| Icons | Lucide React | Clean, consistent, tree-shakeable |
| Markdown | react-markdown + remark-gfm | Standard Markdown + tables |
| LaTeX | rehype-katex + KaTeX CSS | Fast math rendering |
| Dark Mode | next-themes | SSR-safe, persistable, zero-config |
| State | React hooks (useState, useCallback) | Zero external state deps |
- Claude Code parser
- Ollama / Local LLM parser
- SWE-agent parser
- Aider parser
- Codex / OpenDevin parser
- Generic JSON/JSONL fallback
- Global search with keyboard navigation
- Timeline sidebar with jump-to-turn
- Collapsible thinking traces and tool results
- Automatic failure/latency warnings
- Dark/light theme
- Markdown + JSON export
- Session metadata panel
- Multi-demo dropdown
- SVG diagrams and visual README
- Cursor and GitHub Copilot Chat parsers
- Transcript history (localStorage / IndexedDB)
- Virtual scrolling for long transcripts (react-window)
- Keyboard shortcuts:
j/kfor turn navigation - Better error recovery and parsing diagnostics
- Anomaly detection — highlight statistical outliers
- Multi-transcript comparison (side-by-side diff)
- Smart grouping — auto-collapse tool_call + tool_result pairs
- Obsidian / Notion export
- Configurable highlight rules (user-defined regex)
- Self-hosted web version with optional sharing
- Real-time streaming view — watch an agent live
- Plugin system for custom visualizers
Contributions are the lifeblood of open source. Here's how you can help:
| Area | How |
|---|---|
| New parsers | ~10 lines of code — see the guide above |
| Better warnings | Improve toolCallNeedsWarning() in turn-card.tsx |
| UI polish | Animations, responsive, accessibility |
| Bug fixes | Open an issue or PR |
| Docs | Improve the README, add examples, fix typos |
git checkout -b feature/my-contribution
git commit -m "Add awesome feature"
git push origin feature/my-contribution
# Then open a PR on GitHub- No virtual scrolling — transcripts >500 turns may feel slower. Collapsible sections mitigate this, but a virtual scroller would be ideal.
- Single file upload — no batch/folder upload yet.
- No Cursor or Copilot Chat parser yet — contributions welcome!
- No backend — client-side by design (privacy first), but no persistence or sharing.
Free for any use — commercial or otherwise.
- Tim Hua — for the LessWrong analysis that directly inspired this project
- Anthropic's Claude Code team — for building an agent powerful enough to need debugging
- shadcn/ui — for component design patterns
- You — for caring about agent transparency
Built with ❤️ for everyone who's ever yelled at an agent log file
Agent Trace Viewer · MIT · No data leaves your machine