Skip to main content

redbg — gdb for agent sessions

Record tool-calling agent sessions, then debug them like a program: step forward/back through tool calls, inspect the exact prompt/response at each step, diff two runs to find where they diverged, and fork a session at any step to explore what-if scenarios. Local-first, zero dependencies.

$ redbg diff monday.jsonl tuesday.jsonl

✗ First divergence at A:3 / B:3: same tool 'read_file' with same args,
  but A succeeded and B FAILED

    A      B     tool (A → B)                  note
───────────────────────────────────────────────────────────────────────
    1      1  =  read_file                     output same
    2      2  =  read_file                     output same
    3      3  ≠  read_file                     status changed; output DIFFERS
    4      4  ~  exec                          args changed; output DIFFERS

── args diff at divergence ──
...

Install

pip install redbg

Python 3.9+. No runtime dependencies — it installs anywhere.

Quickstart

1. Record. Wrap your tool-calling loop with Recorder:

from redbg import Recorder

with Recorder("session.jsonl", agent="my-agent") as rec:
    rec.prompt("user", "Summarize main.py")
    call = rec.tool_call("read_file", {"path": "main.py"})
    try:
        text = open("main.py").read()
    except OSError as exc:
        rec.tool_result(call, ok=False, error=str(exc))
    else:
        rec.tool_result(call, ok=True, output=text)
    rec.response("main.py prints hello.")

Or decorate tool functions — calls and results are recorded automatically, exceptions become failed results:

with Recorder("session.jsonl") as rec:
    @rec.wrap
    def read_file(path): ...

2. Replay. Step through like a debugger:

$ redbg replay session.jsonl
(redbg –/4) n        # step into the first tool call
(redbg 1/4) s        # show full details: args, output, duration, context
(redbg 1/4) /main.py # search tool/args/output
(redbg 1/4) t        # timing table for all steps
(redbg 1/4) q

Non-interactive: --list, --show N, --cmd "n;n;s", --export-md report.md.

3. Diff. Find where two runs diverged:

$ redbg diff monday.jsonl tuesday.jsonl

Aligns the step streams (LCS sequence alignment), headlines the first divergence, prints a side-by-side table (= same, ~ args changed, ! tool changed, ≠ status changed, +/- added/removed), then a field-level diff at the divergence point.

4. Fork. Re-run the tail of a session with modified input:

$ redbg fork tuesday.jsonl --at 3 \
    --override-args '{"path": "main.py"}' \
    --tools my_tools.py \
    --save fork.jsonl

my_tools.py defines TOOLS = {"read_file": callable, ...} (and optionally MODEL for live mode). Two strategies:

  • playback (default): recorded model responses are replayed verbatim; tool calls are re-executed against your implementations. Deterministic and free — answers "with this different input, does my loop logic still behave?"
  • live: your MODEL(messages) is actually called each turn. Answers "what would the model do now?" — non-deterministic, may cost money.

Every forked trace carries provenance (forked_from, at_step, strategy) so a fork is never mistaken for an original recording.

More commands

redbg info session.jsonl            # summary: steps, failures, tool time
redbg scan session.jsonl            # audit for likely secrets (exit 1 if found)
redbg redact raw.jsonl -o clean.jsonl   # strip secrets before sharing
redbg import otel.json -o out.jsonl     # convert OTel/Langfuse-shaped traces

redbg reads .jsonl.gz transparently everywhere a trace is accepted.

Python API

from redbg import Session, Navigator, render_diff, ForkSpec, fork_session

a, b = Session.load("monday.jsonl"), Session.load("tuesday.jsonl")
print(render_diff(a, b, use_color=False))

nav = Navigator(a)
nav.next(); nav.prev(); nav.goto(3)

spec = ForkSpec(at_step=3, strategy="playback",
                override_args={"path": "main.py"},
                tool_impls={"read_file": lambda args: open(args["path"]).read()})
forked = fork_session(b, spec)
forked.save("fork.jsonl")

Trace format

One JSON object per line (JSONL), append-only, stream-written — a crashed run still leaves a usable partial trace. Event types: session_start, prompt, response, tool_call, tool_result, note, session_end. A step is one tool_call/tool_result pair. Unknown event types are preserved on load (a newer recorder's trace still opens) but ignored by the step engine. See examples/sample-a.jsonl.

Importing existing traces

redbg import converts OTel-shaped spans and Langfuse-shaped observations ({"observations": [...]} / {"spans": [...]} / {"traces": [...]}) into redbg format. It is heuristic and lossy by design — spans whose names mention tools become tool steps, generation spans become responses, everything else becomes notes. Always verify with redbg info afterward.

Secrets

The recorder redacts by default: values of keys matching api_key|secret|token|password|... and strings shaped like known tokens (sk-…, ghp_…, xox…, AKIA…, PEM keys). Tool outputs are truncated at 20,000 chars (configurable via max_output_chars) with a SHA-256 of the full output retained so diffs still detect changes. Run redbg scan before sharing any trace, and redbg redact to clean one.

Limitations (honest)

  • Playback forks don't model the model. Replaying recorded model text with different tool inputs shows you what your loop logic does, not what the LLM would have said. Use live for true what-if on model behavior — and accept that live forks are non-deterministic experiments, not reproductions.
  • No framework auto-instrumentation. redbg won't monkeypatch LangChain, AutoGen, or the Claude Agent SDK — explicit Recorder hooks only. Adapters are a documented v2 extension point, not a v1 feature.
  • Diff aligns sequences; it doesn't understand intent. Reordered steps surface as deletions + insertions (never a fabricated "moved"). Semantically equivalent but textually different args (e.g. {"a":1} vs {"a": 1.0}) count as changed.
  • Single-agent sessions. Multi-agent / swarm traces (parallel tool calls across agents) load, but the step engine treats them as one flat sequence.
  • Timestamps are wall-clock. Cross-machine comparison of durations is approximate; mono deltas are only meaningful within one recording host.
  • Import is lossy. Anything the heuristics don't recognize becomes a note — check the result before trusting a diff built on imported data.

Roadmap (v2, not promised)

Framework adapters · full TUI · SQLite export for ad-hoc queries · remote trace ingestion · multi-agent step views.

Metadata

Release files for redbg 0.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for redbg 0.1.1
File Size Uploaded Provenance
redbg-0.1.1.tar.gz 37.6 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for redbg 0.1.1
File Interpreter ABI Platform
redbg-0.1.1-py3-none-any.whl Python 3 none any Details

Total release size: 67.3 kB

Release files / redbg-0.1.1.tar.gz

Download URL redbg-0.1.1.tar.gz
Size 37.6 kB
Tags Source
SHA-256 checksum
How to use checksums
6b630499306fd2c4356742af575627adff1deebff934b7d7301960e9e5e14ac3
BLAKE2b-256 checksum
How to use checksums
8257b45c9b29e4106d48025559a7b6cb07704ca717205df0b9fae165bbd18e07
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.11.15

Release files / redbg-0.1.1-py3-none-any.whl

Download URL redbg-0.1.1-py3-none-any.whl
Size 29.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
8bd0bd3d27af8cf3579564dc99cceec061fe8022cad82cc2af6aca9c36a6490f
BLAKE2b-256 checksum
How to use checksums
ee51604b02b4bfe9bad4eab4ff4747550270c85f0b2d8cbf08776d946c719259
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.11.15

Security for redbg 0.1.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Release history Release notifications | RSS feed

This release

0.1.1 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page