Agent Black Box is a self-hostable flight recorder for OpenAI agents. One Python Agents SDK tracing registration captures turns, tool calls, handoffs, guardrails, and MCP interactions; Phoenix LiveView renders them as a navigable timeline with full-payload inspection, ingest-side secret redaction, and idempotent storage.

A failed run can be replayed against GPT-5.6 through the Responses API. Captured tool outputs are returned as deterministic, side-effect-free stubs, while the original-versus-replay diff streams live so developers can see a red failure turn green.

GPT-5.6 Structured Outputs also synthesizes portable structural assertions from the successful replay of a captured failure. Run all executes each saved eval against a fresh replay and reports structural pass or fail, turning the incident into a permanent regression check.

The system was built solo during OpenAI Build Week with Codex working from an AGENTS.md operating contract and a project-specific Phoenix skill in one primary task, while bounded specialist agents audited the risky paths. Codex accelerated the ingestion pipeline, Python tracing integration, captured-output replay engine, streamed diff UI, evals, production packaging, tests, and adversarial review.

Try the seeded demo at https://blackbox.kopachelli.dev. Open error-bad-tool-args, select the red refund_order span, replay it against GPT-5.6, generate an eval, and Run all.

Demo video: https://youtu.be/rxBLF6QtJkE

Built With

Share this project:

Updates

posted an update

Agent Black Box now has a public product page you can share, with an early-access waitlist — while the judge demo at https://blackbox.kopachelli.dev stays a direct, one-click seeded run.

See it: https://blackbox.kopachelli.dev/openai-build-week

It walks through the full flow — capture, inspect the red span, replay on GPT-5.6, and lock the fix in as a regression eval — in the product's own cockpit design system, then lets developers join the waitlist for self-hosted early access.

Privacy by design: the waitlist is first-party (self-hosted Phoenix + PostgreSQL, no third-party form or tracker). Consent is explicit and unchecked by default, only the normalized email + consent evidence + campaign attribution are stored, and no email is sent in this scope. The page is keyboard-accessible, works down to 320 px, and honors reduced-motion.

Join the waitlist: https://blackbox.kopachelli.dev/openai-build-week

Log in or sign up for Devpost to join the conversation.

posted an update

From a Broken Tool Call to a Regression Test: Building Agent Black Box in Four Days

When an agent fails, the model's final answer is often the least useful thing to inspect. The real cause may be several steps earlier: a bad handoff, malformed function arguments, an unexpected guardrail result, or an MCP call that returned something the next agent misunderstood. Raw JSON contains the evidence, but it rarely tells the story.

That is the problem I built Agent Black Box to solve. It is a self-hostable flight recorder for OpenAI agents: capture a run as structured spans, inspect it as a timeline, replay it safely on GPT-5.6, and turn the corrected behavior into a regression eval.

The project was built solo for OpenAI Build Week 2026, with Codex as the engineering environment and GPT-5.6 as a real runtime dependency. The production-verified demo is live at blackbox.kopachelli.dev, and the 99-second public demo video shows the complete path. The implementation, setup instructions, tests, and design record are in a private judging repository, with the required reviewer accounts invited directly.

Start with the one path that must work

With four days available, a conventional feature backlog would have been dangerous. I instead treated one user journey as sacred:

seeded failing run → timeline → failing span → replay on GPT-5.6 → diff red to green → generate eval → Run all green

The starting state is deliberately small: four captured runs, one visible failure, and no mystery about where to begin.

Every technical choice had to protect that path. Work that threatened it was cut or deferred. The daily milestones followed the same order: trace ingestion and inspection on day one, replay and diff on day two, evals and deployment on day three, then submission media and packaging on day four.

The canonical incident is intentionally small but realistic. A two-agent support flow hands work to a refund agent, which calls refund_order with the malformed amount "12.OO". The matching failure is reproducibly generated through the real Python Agents SDK Runner and tracing lifecycle, using a local scripted model so anyone can produce it without an API key or model variance. The four-run demo dataset uses a curated semantic snapshot of that behavior and validates it through the production ingest contract. The replay, by contrast, is a live GPT-5.6 operation.

That separation gave the demo a reliable red starting point without faking the part that matters: whether a current model can re-drive the captured workflow correctly.

The timeline turns a generic failed run into concrete evidence: refund_order received the string "12.OO" where the tool expected a number.

A thin capture layer, not a second agent framework

The Python integration consumes the Agents SDK's public TracingProcessor callbacks directly. An application registers AbbProcessor, and completed spans are normalized and exported as one authenticated trace batch when the trace ends. Export work runs in a background worker; callback and transport failures do not alter the host agent's behavior.

The wrapper is deliberately thin. Agent Black Box does not replace Runner, rebuild orchestration, or invent its own tracing format. It preserves trace and span identifiers, parentage, timing, errors, and span-specific data, then maps them into five span types: turns, tool calls, handoffs, guardrails, and MCP calls.

At the server boundary, Phoenix performs the less glamorous work that makes an observability tool trustworthy:

  • spans are idempotent on run plus external span ID;
  • retries and continuations reuse the current version, while a materially different completed trace becomes a new immutable run version;
  • input, output, and error bodies are recursively redacted before persistence;
  • raw project keys are never stored, only uniquely indexed SHA-256 digests of high-entropy keys;
  • JSON bodies over 256 KiB become a valid, bounded truncation sentinel rather than broken JSON;
  • PostgreSQL transactions and advisory locks keep concurrent version allocation consistent.

Phoenix PubSub then announces new or changed runs, and LiveView re-queries PostgreSQL as the source of truth. The browser receives a live runs list, an ordered timeline, and an inspector for the exact payload, token counts, truncation state, and error evidence. There is no separate frontend framework or client-side state store to reconcile.

The important replay boundary

“Replay” is easy to describe too broadly. Agent Black Box does not claim that model generation is deterministic. GPT-5.6 remains live and its wording may vary. The deterministic boundary is captured-tool execution.

The replay engine rebuilds the conversation up to the point before the original terminal assistant answer. It reconstructs strict tool definitions, states the captured tool order, and calls GPT-5.6 through the Responses API with Programmatic Tool Calling. When the model emits a client-owned function call, Agent Black Box matches it to the captured sequence and returns the stored tool output as the result. The real tool never runs.

This matters for both safety and reproducibility. Replaying a refund, email, database mutation, or MCP action should not repeat the side effect. The model may generate a fresh answer, but it receives the same captured world at the tool boundary.

The seeded failure exposed a subtle edge case. Its malformed arguments were rejected before refund_order executed, so there was no historical output to return. Rather than falsify the original span, the trace carries an explicitly labeled safe replay_stub_output used only when the captured output is absent. If neither source exists, the engine records divergence and continues with an error result instead of invoking the tool.

Replay is also bounded operationally. It allows a maximum of eight Responses rounds by default, preserves output items for store: false continuations, and streams each step through replay-scoped PubSub. A readiness handshake ensures the Diff LiveView is subscribed before the first model round, so the browser visibly progresses instead of jumping from idle to a completed result.

The final verdict does not require another model call. A failed source followed by a successful child replay is deterministically labeled FAILURE FIXED. Other successful pairs use normalized equality or an explainable token-overlap heuristic. The judge sees a stable verdict while the underlying GPT-5.6 generation remains honestly live.

The model generation is live; the visible verdict is deterministic. Captured tool execution remains side-effect-free.

Turning a debugging session into a test

A green replay is useful once. A saved eval makes it useful on the next deploy.

Agent Black Box compacts the captured source and its latest successful replay, then asks GPT-5.6 for a strict Structured Output. The response must match a closed, versioned assertion schema and pass local semantic validation before anything is inserted.

Automated synthesis focuses on replay-stable structure: a tool was called, a JSON-Pointer argument matched an expected scalar, the replay stayed within a turn bound, and no span ended with an error. The application rejects malformed, refused, incomplete, unknown, structurally weak, or reference-failing output. It does not silently prune a failing assertion to make the UI green.

Run all performs a fresh replay for each saved eval, then evaluates the assertions locally without a model-as-judge call. All assertions must pass. The stored contract is portable JSON rather than an Elixir closure, which leaves a clean path to a future CI runner without coupling eval semantics to Phoenix.

This design came from a real failure during development. The first generated eval copied full prose from a successful replay. A later replay expressed the same result with different Markdown and correctly failed the string checks. The fix was not a looser green button; it was to separate stochastic prose from durable structural behavior.

The regression contract stores structural assertions such as tool calls, JSON-Pointer argument matches, and no span errors; fresh replays finish 2/2 green.

Safety and cost are part of the feature

Captured traces can contain credentials, private prompts, and expensive replay contexts. Agent Black Box therefore treats safety controls as part of the product path, not deployment notes.

Every OpenAI call goes through one audited AgentBlackBox.OpenAI module. Requests default to store: false, pin the standard service tier for predictable accounting, use explicit low reasoning for the demo, and freeze one cacheable replay prefix under a stable non-PII source-run key. The short canonical trace is not padded merely to manufacture cache hits.

Before network I/O, a supervised in-process ledger reserves a conservative cost bound across configured attempts. It settles successful requests from reported usage, accounts conservatively for ambiguous retries, releases calls abandoned before send, and charges the full bound when a sent request's outcome becomes unknowable. The live instance also uses a provider-side project cap as the restart-safe outer limit.

The public seeded deployment runs in demo mode: trace ingestion returns 403, while replay and eval actions remain available on the known dataset. That keeps the judge path interactive without allowing public clients to overwrite its evidence.

Why Phoenix, PostgreSQL, and NixOS worked well together

Phoenix LiveView was a practical deadline choice, not a novelty choice. One application owns ingestion, persistence, replay supervision, PubSub, and the streamed UI. PostgreSQL provides the constraints and transaction semantics for append-only trace history. Tests can replace the OpenAI boundary with Mox while still exercising the complete application path offline.

The hosted instance is the same Phoenix release packaged natively for an existing NixOS fleet. beamPackages.mixRelease builds it; systemd runs it with a dynamic user; sops and LoadCredential deliver secrets; PostgreSQL 17 uses local peer authentication; and Caddy is the only public listener. Release-native setup runs migrations and the idempotent four-run seed before the app starts.

Publication was fail-closed. The new hostname initially returned a Caddy 503 while the app was verified on loopback. Only after database counts, seed fingerprint, ingest rejection, credentials, and service health passed was that hostname-specific gate removed in a second fleet deployment. A clean browser then completed the live failure → replay → eval path over HTTPS with no browser or bounded service-log errors.

Docker Compose remains the portable self-hosted and judge-local route. Its isolated local topology publishes Phoenix only on 127.0.0.1, exposes no PostgreSQL port, uses disposable database storage, and reloads the exact four-run seed on a clean start.

The hosted path is a native NixOS release behind Caddy, with PostgreSQL 17 over local peer authentication and secrets delivered through systemd credentials.

What Codex changed about the build process

Codex did not replace product ownership. It made a disciplined, evidence-heavy solo workflow possible under the deadline.

One primary Codex task held the substantive implementation and produced the required feedback Session ID. An AGENTS.md operating contract defined the sacred path, coding rules, safety boundaries, and session protocol. A project-specific Phoenix skill captured repository conventions. Bounded specialist agents reviewed isolated risks—replay semantics, redaction, deployment, UI behavior, and submission claims—while the primary task remained responsible for integration.

Every unit of work had a Linear issue before implementation. Decisions became immutable MADR records when they were made. The architecture was updated when reality changed, daily worklogs recorded evidence and costs, and the build plan mirrored Linear status. By production acceptance, the Elixir suite had reached 115 passing tests.

The deeper lesson is that an agent works better with explicit invariants than with a vague request to “build the app.” The operating contract turned scope, truthfulness, and completion evidence into inputs the coding system could reason about.

Lessons I would carry into the next agent tool

  1. Build backward from one undeniable outcome. The sacred path made trade-offs obvious and kept infrastructure work subordinate to product value.
  2. Name the deterministic boundary precisely. Captured tools can be deterministic and side-effect-free even when live model generation is not.
  3. Prefer structural evals to prose snapshots. Stable behavioral invariants survive harmless changes in model wording.
  4. Fail closed around money, secrets, and public state. Redaction before persistence, pre-request budget reservations, demo-mode ingest blocking, and gated publication prevented deadline shortcuts from becoming security claims.
  5. Make decisions durable when they happen. The ADR directory is useful to humans and coding agents because it explains not only the current shape, but why tempting alternatives were rejected.

Try the complete path

The zero-setup route is the live seeded demo. Open error-bad-tool-args, select the red refund_order span, replay it against GPT-5.6, generate an eval from the successful replay, and choose Run all.

After AIBLBOX-43's live acceptance is recorded, readers can also use the OpenAI Build Week product page and waitlist. That campaign page adds product context and explicit-consent updates; it does not replace the direct seeded-demo route above.

For local development, follow the README quickstart: clone the repository, copy .env.example to .env, run mix setup, then mix phx.server. The four-run timeline works without an OpenAI key. Live replay and eval synthesis require a dedicated key; use a provider-capped project rather than a general-purpose credential. The README also includes the isolated Docker Compose command and the Python tracing registration.

If you are handing the repository to a coding agent, start with AGENTS.md, then read the PRD, architecture, accepted ADRs, and current build plan. Preserve three invariants above all: all OpenAI traffic crosses the single client boundary, captured real tools never execute during replay, and no unredacted trace body reaches persistence.

Agent Black Box began as a way to make one malformed tool call understandable. The useful result is broader: a concrete pattern for moving from opaque agent history, to safe live replay, to a regression contract that another human—or another coding agent—can inspect and run.

Log in or sign up for Devpost to join the conversation.