Turn an LLM agent conversation into a Mermaid sequence diagram, a Markdown timeline, or a plain-text trace — so you can actually see what your agent did.
Agent logs are a wall of JSON. When a run goes wrong — a tool got the wrong arguments, a result came back as an error, the model looped — you scroll through nested messages arrays trying to reconstruct the story. tracegram reads that JSON (OpenAI or Anthropic format, auto-detected) and renders the turn-by-turn flow of messages and tool calls in a form you can read at a glance, paste into a PR, or drop into a bug report.
- 🔁 Auto-detects OpenAI Chat Completions and Anthropic Messages JSON.
- 🧜 Mermaid output renders natively on GitHub — paste it straight into an issue or README.
- 📝 Markdown and plain-text outputs for docs and terminals.
- 🧰 Surfaces tool calls, tool results, and errors (⚠) as first-class events.
- 📊 Optional one-line stats (message counts, tool usage, rough token estimate).
- 📦 Zero dependencies. Pure ESM. Works as a CLI and as a library.
Run it instantly with npx:
npx tracegram run.jsonOr install globally / as a dependency:
npm install -g tracegram # for the CLI
npm install tracegram # to use the libraryRequires Node.js ≥ 18. No build step, no API keys, nothing to configure.
tracegram [file] [options]
cat conversation.json | tracegram [options]| Option | Description |
|---|---|
-f, --format <fmt> |
mermaid (default), markdown, or text |
-p, --provider <name> |
Force openai or anthropic (default: auto-detect) |
-m, --max-len <n> |
Max characters per label in Mermaid output (default: 60) |
-s, --stats |
Prepend a one-line stats summary |
--no-system |
Omit the system prompt from the output |
-h, --help |
Show help |
-v, --version |
Show the version |
Given an OpenAI conversation with a tool call (examples/openai-weather.json):
tracegram examples/openai-weather.jsonproduces this Mermaid, which GitHub renders as a live diagram:
sequenceDiagram
participant U as User
participant A as Assistant
participant T as Tools
Note over A: System: You are a concise weather assistant.
U->>A: What should I wear in Paris today?
A->>U: Let me check the current conditions.
A->>T: get_weather({"city":"Paris","units":"metric"})
T-->>A: {"temp_c":12,"condition":"light rain","wind_kph":18}
A->>U: It's 12°C with light rain and a brisk wind in Paris. Wear a…
Prefer a quick terminal view, with stats?
$ tracegram examples/anthropic-research.json -f text --stats
# messages=3 tool_calls=2 tool_errors=1 tools=[unit_convert, wiki_search] ~tokens=93
SYSTEM │ You are a research agent. Use tools to gather facts before answering.
USER │ How tall is the Eiffel Tower, and when was it built?
ASSISTANT │ I'll look that up.
CALL │ wiki_search({"query":"Eiffel Tower height"})
RESULT │ wiki_search: Height: 330 m (including antennas). Completed: 1889.
CALL │ unit_convert({"value":330,"from":"m","to":"ft"})
ERROR │ unit_convert: service unavailable
ASSISTANT │ The Eiffel Tower is 330 m tall (about 1,083 ft) and was completed in 1889.import { render } from 'tracegram';
const conversation = {
messages: [
{ role: 'user', content: 'Hi' },
{ role: 'assistant', content: null, tool_calls: [
{ id: 'c1', function: { name: 'ping', arguments: '{}' } },
] },
{ role: 'tool', tool_call_id: 'c1', content: 'pong' },
{ role: 'assistant', content: 'All good.' },
],
};
console.log(render(conversation, { format: 'markdown' }));import {
render, // (input, opts?) -> string high-level: normalize + render
normalize, // (input, provider?) -> Conversation
detectProvider, // (input) -> 'openai' | 'anthropic'
toMermaid, // (conv, opts?) -> string
toMarkdown, // (conv, opts?) -> string
toText, // (conv) -> string
stats, // (conv) -> { messages, toolCalls, toolErrors, tools, estTokens, ... }
} from 'tracegram';render(input, opts) accepts a conversation object, a bare messages array, or a JSON string.
Options: format ('mermaid' | 'markdown' | 'text'), provider (force a provider), maxLen (Mermaid label cap), includeSystem (default true), title (Markdown heading).
Both providers are normalized into one provider-agnostic shape, so the renderers — and your own code — never have to special-case a vendor:
Conversation = { provider, system, events }
Event =
| { kind: 'message', role: 'user' | 'assistant', text }
| { kind: 'tool_call', id, name, args }
| { kind: 'tool_result', id, name, text, isError }- OpenAI —
{ messages: [...] }or a bare[...]array withsystem/user/assistant/toolroles,tool_calls, andtool_call_id. - Anthropic —
{ system, messages: [...] }with string or block content (text,tool_use,tool_result, includingis_error).
Tool results are matched back to their originating call so the tool name appears on both sides.
git clone https://github.com/Ayubjon/tracegram.git
cd tracegram
node --test # run the test suiteMIT © 2026 Ayubjon
If this project is useful to you, you can support its development with a crypto tip — thank you!
USDT — Ethereum (ERC-20):
0xad39bdf2df0b8dd6991150fcea0a156150ed19b8
Send only on the Ethereum (ERC-20) network.