Skip to main content

retrial

Git for agent trajectories. Branch, diff, and bisect LLM agent runs — backed by real re-execution, not static logs.

When an agent does something wrong, most debugging is scrolling through logs. retrial lets you go back to step N, change one fact — a tool result, a retrieved doc, an intermediate decision — and re-run your real agent from there to see what it actually would have done differently. With the real model, not a guess. Validated end to end against live claude-opus-4-8.

Why it's different

  • Real re-execution, not log branching. A fork re-enters your live agent loop and makes real model calls from the fork point onward. It does not relabel stored JSON and call it a branch.
  • Zero-export integration. A decorator on your loop, not a JSON schema to hand-build.
  • Narrow and deep. One thing — branch/diff/bisect by real execution — done well.
  • Python-native, local-first. No account, no telemetry, no dashboard. One SQLite file in .retrial/.

Install

pip install retrial

Integrate

retrial needs two things from your loop: the function that calls the model, and the function that runs tool calls. You pass both in — no monkey-patching of your SDK, so every recorded step traces back to a line you wrote.

from retrial import record

@record(session_name="booking-agent")
def run_agent(messages, tools=TOOLS, call_model=call_model, execute_tools=execute_tools):
    while True:
        response = call_model(messages, tools)
        messages.append({"role": "assistant", "content": response.content})
        if response.stop_reason != "tool_use":
            return response
        messages.append({"role": "user", "content": execute_tools(response)})

The one rule: messages must be a parameter, not a list created inside the function. That's what lets a fork seed your loop with edited history and get genuine re-execution. Give the other parameters defaults to fork from the CLI. Then just run it; steps log as the loop runs, with no export step. Async agents work too — decorate the async def and await it as usual; fork, bisect, ablate, sweep, and rerun re-execute async agents from the CLI or any synchronous caller.

A bundled example under examples/ forks, diffs, and bisects with no API key.

Example: fork, then diff

Every step gets a content-hash SHA, addressable by a short prefix like git:

$ retrial log s_a8d4f64945
  4f0c1e2  step 0  model_call  (312ms, 450 tok)
  a1b2c3d  step 1  tool_call   ran search_flight
  9e77b10  step 2  model_call  (288ms, 544 tok)

Fork step 1 with one fact changed — the edit is a JSON patch — and the real model decides again from there:

$ retrial fork a1b2c3d --agent examples.booking_agent:run_agent --edit-file edit.json
Forked into session s_3f9c02ab1e
$ retrial diff s_a8d4f64945 s_3f9c02ab1e
diverged at d66697c
  cause: replace /output/0/content = flight_price 1200

  - A  book_flight    model_call
  + B  check_budget   model_call

final answer
  A  Confirmed: AUS-SFO booked for $450.
  B  That's over the $600 limit. I need approval before booking.

The fork called check_budget, a tool the original never touched — the kind of divergence only real re-execution produces. The original is never mutated; a fork is a new session, so you can branch the same step as many times as you like.

Also

Same machinery — a fork plus a check — pointed at different questions:

  • bisect — which step doomed a failed run? Binary search over resume points, about log2(steps) re-executions.
  • ablate — which recorded facts did a good run actually need? Perturb each and see if the outcome flips. Causal, not heuristic.
  • sweep — fork one step across many values to find a decision threshold in the model's behavior.
  • rerun — re-execute every recorded run against your current code. Your traces are the regression suite; it exits non-zero on a regression, so CI fails without extra plumbing.
  • cost — token and dollar breakdown per step. An unknown model prices as unpriced, never as a guess.

Bisect and ablate are duals and each refuses the other's job: bisect wants a run that failed, ablate a run that worked.

What retrial refuses to do

The whole product rests on the replay being exactly what happened, so retrial raises rather than guesses when it can't verify that:

  • Your loop transforms a tool result before appending it — the patch would land on a value you never saw.
  • An edit invents or drops a tool result the run never produced.
  • A run crashed mid-loop — the message state after its trailing tool call was never observed.
  • A sync agent is handed an async call_model or execute_tools — a sync loop can't await it, so retrial would record an un-awaited coroutine. (Async agents are fine; this is only the mismatch.)
  • The database was written by a newer retrial, or an imported step's content doesn't match its SHA.

A wrong replay would be worse than no replay. Merge was cut for the same reason: two forks are competing hypotheses, and answers don't merge.

CLI

retrial init                    create .retrial/ + sqlite db
retrial list                    sessions, tree view
retrial log <session>           step-by-step history, SHA per step
retrial show <sha>              full detail on one step
retrial fork <sha> --agent M:F --edit-file e.json
retrial diff <a> <b>            --full to expand shared steps
retrial bisect <session> --check EXPR --agent M:F
retrial ablate <session> --check EXPR --agent M:F
retrial sweep <sha> --values-file v.json --agent M:F
retrial rerun --check EXPR --agent M:F
retrial cost <session>
retrial export <session> > trace.jsonl
retrial import trace.jsonl

SHA prefix matching applies throughout. The store is found by searching upward for .retrial/, the way git finds .git/; override with --db or RETRIAL_DB.

Python API

from retrial import record, fork, diff, bisect, ablate, sweep, rerun, trajectory, Store
from retrial import export, import_

Every function returns a plain dict, so results stay JSON-shaped and printable. The shapes are declared in retrial/types.py and shipped with py.typed, so a typo in a key is a type error, not a KeyError at 3am.

License

MIT

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

retrial-0.1.4.tar.gz (125.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

retrial-0.1.4-py3-none-any.whl (68.9 kB view details)

Uploaded Python 3

File details

Details for the file retrial-0.1.4.tar.gz.

File metadata

  • Download URL: retrial-0.1.4.tar.gz
  • Upload date:
  • Size: 125.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for retrial-0.1.4.tar.gz
Algorithm Hash digest
SHA256 4517627e124be3eb24d89ee087ed67f668f0236ba5c8e5d6e86c638fe2820580
MD5 99c330a0adb7e34ffcf7a7eae14e0319
BLAKE2b-256 5406f54f7911bb0028e0dde0fccbb4990b8e76db05dcd78d737b4631af992be9

See more details on using hashes here.

Provenance

The following attestation bundles were made for retrial-0.1.4.tar.gz:

Publisher: publish.yml on ArcKansupada/retrial

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file retrial-0.1.4-py3-none-any.whl.

File metadata

  • Download URL: retrial-0.1.4-py3-none-any.whl
  • Upload date:
  • Size: 68.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for retrial-0.1.4-py3-none-any.whl
Algorithm Hash digest
SHA256 69f1be3676b8d881620ae18cd30da767f039c8b598313e55e513a374d79a5f88
MD5 04c484e0647c83aed1a6d3017cb99b37
BLAKE2b-256 fd53d73ef8245456bebbd9490034115493fcd474964951402678d97d5e5ea3c4

See more details on using hashes here.

Provenance

The following attestation bundles were made for retrial-0.1.4-py3-none-any.whl:

Publisher: publish.yml on ArcKansupada/retrial

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page