Deterministic, judge-free static analyzer for tool-calling agent execution traces.
Project description
tracelint
ESLint/pytest for what your agent actually did. tracelint is a deterministic, judge-free
static analyzer for the execution traces of tool-calling agents. It reads a trace and reports
structural defects — schema-violating tool calls, ignored tool errors, hallucinated arguments,
loops, and redundant calls — each with the exact trace lines as evidence, and returns a CI exit
code. It also ships a fault injector and a per-fault recovery scorecard.
Model-as-judge detection of these defects is unreliable (published trace-error benchmarks show low localization accuracy). Many of these defects are structurally decidable and need no judge — that is the entire premise of this tool. No second model ever judges the trace.
View the live demo report — the constructed
validation suite (one planted instance of every defect, clean controls, and legitimate-but-suspicious
cases) plus the robust-vs-buggy recovery scorecard, generated by tracelint demo.
Limitations (read first)
- Deterministic rules catch structural defects, not whether the final answer was correct.
- Hallucinated-argument, loop, and redundant-call findings are candidates unless structurally
proven — legitimate value transforms and intentional retries can trip them; each is shown with
its evidence for human review, never asserted as a verdict. High-confidence hallucination
detection requires the tool schema to declare field origins (
x-value-origin). - The recovery scorecard needs labeled task outcomes (success oracles); without them it measures behavioral recovery only ("did not crash"), a weaker claim than correctness.
- A trace is only as complete as its instrumentation. A rule whose required field is missing is
suppressed with a stated reason —
tracelintnever lints a partial trace as if complete.
Quick start
The demo runs a keyless validation suite and a recovery scorecard end to end — no API key, no model download:
pip install tracelint
tracelint demo --html demo.html
Lint a trace in CI:
tracelint check ./trace.json --tools ./tools.json # exit 2 on a hard_defect
Exit codes: 0 clean · 2 a structurally-provable defect (hard_defect) · 3 an input error.
Heuristic candidates never fail CI on their own; suppressions are disclosed but are not defects.
The rules
| Rule | Finding | Tiers |
|---|---|---|
| R1 | schema violation — args fail the tool's JSON Schema | hard_defect |
| R2a | tool returned an error | hard_event (structured signal) / candidate (heuristic) |
| R2b | an errored result's value reused by a later side-effecting call | hard_defect / candidate |
| R3 | hallucinated argument — value not derivable from provenance | candidate; hard_defect if the field is annotated provided |
| R4 | loop — N identical no-progress calls (polls/retries excluded) | candidate |
| R5 | redundant call — identical call + identical result, no mutation between | candidate |
hard_event and hard_defect are orthogonal to the finding kind: a tool-error event is a
hard_event from a structured status field but a candidate from an exception-like string in
free-form content.
Input format
A trace is a JSON object (.json, or .jsonl for many):
{
"run_id": "run-1",
"steps": [
{"type": "message", "role": "user", "content": "cancel order 4521 if it hasn't shipped"},
{"type": "tool_call", "call_id": "c1", "name": "get_order_status", "args": {"order_id": "4521"}},
{"type": "tool_result", "call_id": "c1", "content": {"status": "processing"}, "status": "ok"},
{"type": "tool_call", "call_id": "c2", "name": "cancel_order",
"args": {"order_id": "4521", "reason": "not_shipped"}}
],
"final": "Order 4521 has been cancelled."
}
tools.json supplies the ground truth the rules check against:
{
"tools": {
"cancel_order": {
"schema": {"type": "object", "properties": {"order_id": {"type": "string"}},
"required": ["order_id"]},
"metadata": {"side_effecting": true}
}
}
}
An OpenAI adapter (tracelint.adapters.from_openai_messages) normalizes OpenAI chat message lists
into this schema; more adapters are future work.
Recovery scorecard
Measure how an agent behaves under injected faults, scored against deterministic success oracles:
tracelint scorecard --demo --faults timeout,error,rate_limit --runs 5
The baseline must satisfy the oracle first (else recovery is not measured). Each fault type reports a correctness-recovery rate with a Wilson confidence interval; with no oracle it falls back to behavioral recovery, labeled as weaker.
Library
from tracelint import lint_trace, default_rules, Trace, ToolRegistry
trace = Trace.load("trace.json")
registry = ToolRegistry.load("tools.json")
report = lint_trace(trace, default_rules(), registry)
print(report.exit_code) # 0 or 2
for f in report.active_findings:
print(f.rule, f.tier.value, f.summary)
Development
python -m pytest
ruff check src tests
The core is dependency-light (jsonschema + stdlib) and the whole test suite is deterministic and
offline. A real OpenAI trace-generating agent lives behind the opt-in [real-agent] extra and is
never part of the linter. Python 3.10–3.12.
Project details
Release history Release notifications | RSS feed
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 tracelint-0.1.0.tar.gz.
File metadata
- Download URL: tracelint-0.1.0.tar.gz
- Upload date:
- Size: 62.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
52ae4645cb0cafc42ba23f98a592eb8f479c8f432ee5eaea028fa430858e6786
|
|
| MD5 |
49f25f63f8f896266e2424f8ae9bcd4e
|
|
| BLAKE2b-256 |
d6e1193f5a81be404591e3534473e4edf569ad6f8b5b60798c57df6739ce0f23
|
Provenance
The following attestation bundles were made for tracelint-0.1.0.tar.gz:
Publisher:
release.yml on AshwinUgale/tracelint
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
tracelint-0.1.0.tar.gz -
Subject digest:
52ae4645cb0cafc42ba23f98a592eb8f479c8f432ee5eaea028fa430858e6786 - Sigstore transparency entry: 2315653783
- Sigstore integration time:
-
Permalink:
AshwinUgale/tracelint@89049983301a8c956c40044aef06d5cf50881516 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/AshwinUgale
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@89049983301a8c956c40044aef06d5cf50881516 -
Trigger Event:
release
-
Statement type:
File details
Details for the file tracelint-0.1.0-py3-none-any.whl.
File metadata
- Download URL: tracelint-0.1.0-py3-none-any.whl
- Upload date:
- Size: 61.2 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 |
d90389e5f08139989cfcb97beb549611bc8c069f0cfe00fd5b2143f6486f2c2b
|
|
| MD5 |
5d21157708a92510f7b90a41ef3ba156
|
|
| BLAKE2b-256 |
5bc9523981a2f5225fe8442db44e9f27848dbb109e847d6db63e89f704ff5d90
|
Provenance
The following attestation bundles were made for tracelint-0.1.0-py3-none-any.whl:
Publisher:
release.yml on AshwinUgale/tracelint
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
tracelint-0.1.0-py3-none-any.whl -
Subject digest:
d90389e5f08139989cfcb97beb549611bc8c069f0cfe00fd5b2143f6486f2c2b - Sigstore transparency entry: 2315653850
- Sigstore integration time:
-
Permalink:
AshwinUgale/tracelint@89049983301a8c956c40044aef06d5cf50881516 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/AshwinUgale
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@89049983301a8c956c40044aef06d5cf50881516 -
Trigger Event:
release
-
Statement type: