pydantic-ai-trace
Use pydantic-ai-trace when you need to inspect an agent run from a JSON dump. Give it a pydantic-ai list[ModelMessage] dump and it opens the run in a browser view.
It is a lightweight local tool. Point it at a trace or a directory of traces and it reads the files from disk, reloads them when they change, and exports individual traces as self-contained HTML files. Your traces stay on disk, with no hosted service or account.
What you can inspect
- The full request and response sequence, including prompts, text, thinking, tool calls, tool results, and unknown parts
- Tool calls paired with their results, including results in later messages
- Model, provider, timing, and token usage
- A searchable directory tree for
.jsonand.jsonltraces - Collapsible large values, rendered Markdown, and keyboard navigation
- One-click copying as a compact text transcript that preserves request and response order
- CLI rendering of the same compact transcript for use by people, scripts, and AI agents
Run from a checkout
This project uses pixi. Build the bundled frontend once, then run paitrace with a trace file or directory.
pixi run build-frontend
pixi run paitrace trace.json
Usage
# View one trace
pixi run paitrace trace.json
# Browse a directory tree of traces
pixi run paitrace ./my-traces/
# Browse an explicit collection of trace files with live reload
pixi run paitrace first.json second.json runs/multi.jsonl
# Write one trace to a standalone HTML file
pixi run paitrace export trace.json -o trace.html
# Choose a trace line when exporting a multi-trace JSONL file
pixi run paitrace export runs.jsonl --line 2
# Print the browser's compact text representation to stdout
pixi run paitrace text trace.json
# Print a compact, structured trajectory for jq and other tools
pixi run paitrace json trace.json
# Read a trace from stdin; `-` can also be used explicitly
curl https://example.test/my-traj.json | pixi run paitrace json | jq '.messages[]'
curl https://example.test/my-traj.json | pixi run paitrace text
# Select a trace from JSONL, or write the text to a file
pixi run paitrace text runs.jsonl --line 2
pixi run paitrace text trace.json -o trace.txt
# JSON output supports the same selection and output options
pixi run paitrace json runs.jsonl --line 2
pixi run paitrace json trace.json -o compact.json
# Convert every trace in JSONL to one compact JSON object per line
pixi run paitrace json runs.jsonl --all -o compact.jsonl
# Convert multiple JSON files to compact JSONL in argument order
pixi run paitrace json first.json second.json -o compact.jsonl
# Mix JSON and JSONL inputs; --all expands every JSONL source
pixi run paitrace json first.json runs.jsonl --all -o compact.jsonl
# Indent one compact trajectory for direct inspection
pixi run paitrace json trace.json --pretty
# Export or view a trace received on stdin
curl https://example.test/my-traj.json | pixi run paitrace export -o trace.html
curl https://example.test/my-traj.json | pixi run paitrace --no-open
paitrace text writes only the transcript to stdout by default, so it can be piped directly into
another command. Repeated request instructions are omitted until they change. Multi-trace JSONL
files require --line, just as HTML export does.
paitrace json emits a token-efficient trajectory document. It preserves request and response
order, native tool arguments and results, tool-call IDs, model and token metadata, and unknown
variants. It omits display headings, repeated instructions, provider response identifiers, and
binary payloads. It retains the provider name. Tool calls and results remain separate events
linked by id.
Pass --all to convert every trace in a JSONL file or stream. The output remains JSONL, with one
compact trajectory per line. --all cannot be combined with --line or --pretty. Pass
--pretty to indent single-trace output by two spaces.
Multiple .json inputs also produce compact JSONL, in argument order. When multiple inputs include
JSONL, pass --all to expand each JSONL source. Multiple inputs cannot use stdin, --line, or
--pretty. The browser also accepts multiple explicit .json and .jsonl files and watches each
source for changes. text and export remain single-input commands.
Query compact JSON with jq
# Extract the final assistant text
pixi run paitrace json trace.json \
| jq -r '[.messages[].parts[] | select(.type == "text") | .content] | last'
# Extract tool calls, results, and retries in chronological order
pixi run paitrace json trace.json \
| jq '[.messages[].parts[] | select(.type == "tool_call" or .type == "tool_result" or .type == "retry")]'
# Pair tool calls with their result or retry by call ID
pixi run paitrace json trace.json | jq '
[.messages[].parts[]] as $parts
| [$parts[] | select(.type == "tool_result" or .type == "retry")] as $results
| [$parts[] | select(.type == "tool_call")
| . as $call
| {
id,
name,
args,
result: ($results | map(select(.id == $call.id)) | first)
}
]
'
# Read aggregate model-call and token statistics
pixi run paitrace json trace.json | jq '.stats'
# Collect several compact trajectories into one JSON array
pixi run paitrace json first.json second.json | jq -s '.'
The viewer, text, json, and export commands accept a trace from piped stdin when their input
is omitted. Pass - to request stdin explicitly. Stdin can contain one JSON trace or JSONL traces;
use --line to select from multi-trace JSONL. HTML export from stdin requires -o.
The viewer binds to 127.0.0.1:1205 and opens your browser. Pass --port, --host, or --no-open to change that behavior.
Trace files
The viewer reads the JSON emitted by ModelMessagesTypeAdapter.dump_json(messages):
.json: one bare JSON array ofModelMessageobjects.jsonl: one such array per line
When you open a directory, each line in a multi-trace .jsonl file is available as a separate trace.
Development
Run the API and frontend in separate terminals while working on the viewer.
pixi run dev-api ./trace.json # API with reload on port 1205
pixi run dev-web # Vite with HMR, proxying /api
pixi run test # pytest and vitest
pixi run lint # ruff, prettier, and eslint
pixi run typecheck # pyright and TypeScript
pixi run build # bundled frontend plus sdist and wheel
Releasing
Create and publish a GitHub release with a vX.Y.Z tag. The package version is derived from that
tag, so no source file needs a version bump. Publishing the release triggers GitHub Actions to run
the full check suite, build the frontend into the wheel and source distribution, publish both to
PyPI using trusted publishing, and attach them to the GitHub release. Configure a pypi
environment in GitHub and add this repository as a trusted publisher for the pydantic-ai-trace
project on PyPI before the first release.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pydantic_ai_trace-0.1.8.tar.gz.
File metadata
- Download URL: pydantic_ai_trace-0.1.8.tar.gz
- Upload date:
- Size: 193.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
16756617e38b3f892d5901cf9d3279d4daeb1b1768be8b55400748498c77948a
|
|
| MD5 |
28fcd4fed46869267433bd87e10b1ca2
|
|
| BLAKE2b-256 |
87897fa59b843cbde992191a0a9008b7be68d58f410f01f2903f87dfd0ecdf2a
|
Provenance
The following attestation bundles were made for pydantic_ai_trace-0.1.8.tar.gz:
Publisher:
release.yml on moritzwilksch/pydantic-ai-trace
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pydantic_ai_trace-0.1.8.tar.gz -
Subject digest:
16756617e38b3f892d5901cf9d3279d4daeb1b1768be8b55400748498c77948a - Sigstore transparency entry: 2501174704
- Sigstore integration time:
-
Permalink:
moritzwilksch/pydantic-ai-trace@f567063f5e8d58654476794a3008b24899d99676 -
Branch / Tag:
refs/tags/v0.1.8 - Owner: https://github.com/moritzwilksch
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@f567063f5e8d58654476794a3008b24899d99676 -
Trigger Event:
release
-
Statement type:
File details
Details for the file pydantic_ai_trace-0.1.8-py3-none-any.whl.
File metadata
- Download URL: pydantic_ai_trace-0.1.8-py3-none-any.whl
- Upload date:
- Size: 84.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f0e6ce9659c687ec94776f8230c357d7a54da87a24c4bfe11302ca7f7a1b3024
|
|
| MD5 |
c174e9abdbf5bbaf9fe0ae5cad980816
|
|
| BLAKE2b-256 |
38b657ac74f66ccfbd592ae1760a8fd07863f6ef08a14f17e3b0eee0af9f6f9a
|
Provenance
The following attestation bundles were made for pydantic_ai_trace-0.1.8-py3-none-any.whl:
Publisher:
release.yml on moritzwilksch/pydantic-ai-trace
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pydantic_ai_trace-0.1.8-py3-none-any.whl -
Subject digest:
f0e6ce9659c687ec94776f8230c357d7a54da87a24c4bfe11302ca7f7a1b3024 - Sigstore transparency entry: 2501174717
- Sigstore integration time:
-
Permalink:
moritzwilksch/pydantic-ai-trace@f567063f5e8d58654476794a3008b24899d99676 -
Branch / Tag:
refs/tags/v0.1.8 - Owner: https://github.com/moritzwilksch
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@f567063f5e8d58654476794a3008b24899d99676 -
Trigger Event:
release
-
Statement type: