Open source · accepting design partners

Rehearse API failures before you ship, and replay the ones production already hit.

pikopod fails your build when a provider’s spec changes shape, builds a deterministic sandbox from that spec or from their docs page, rehearses the failures their sandbox never produces, and replays the ones production still finds.

pikopod~/api
$ pikopod scenario run examplepay declines retry_storm
 declines — PASSED (4 assertion(s) passed; 0 not evaluated)
    PASSED         declined         POST /charges → 400
    PASSED         recovered        POST /charges → 201
 retry_storm — PASSED (4 assertion(s) passed; 0 not evaluated)
    PASSED         attempt1         POST /charges → 503
    PASSED         attempt2         POST /charges → 503
    PASSED         attempt3         POST /charges → 201
One Go binaryRuns locallyNo accounts, no telemetryNothing leaves unless you configure it
Demo

The whole loop in half a minute

Import a spec, arm a failure, rehearse it, catch the one production still found, and keep it as an offline regression test.

Rehearse

A sandbox you can make fail on purpose

Point staging at pikopod instead of the provider’s sandbox. Import their OpenAPI, Swagger, Postman or GraphQL spec, or a documentation URL: pikopod finds the linked or well-known spec first and only extracts one with a model if you configured your own key. It is deterministic: the same seed returns the same bytes.

Then arm the failure you need. Timeouts, rate limits, malformed responses, connection resets and duplicate webhooks are controlled inputs. Put the sandbox into a scenario’s standing state and your own tests, Postman or a teammate’s browser meet that failure until you clear it. Here timeouts means the sandbox holds every GET /charges. Webhooks arrive wrapped and signed the way the provider sends them, and only for events the docs declare.

pikopod~/api
$ pikopod import examplepay --spec https://docs.examplepay.test
sandbox examplepay registered (sbx_41d959476a09e5f9, 4 endpoints)
serve it with `pikopod up` → http://127.0.0.1:4600/examplepay/...

$ pikopod mode set examplepay timeouts
mode: timeouts (from archetype or pack timeouts)
  armed   latency on GET /charges
point your app at the sandbox and run your own tests; clear it with `pikopod mode clear examplepay`

No proxy, account or authored mock is required to start.

Bind

Failure stories attach to the API you actually have

Eleven provider-agnostic scenarios cover declines, timeouts, retries, partial failures and webhook delivery. pikopod binds each story to operations declared in the imported spec.

If the spec does not contain enough evidence, it refuses the binding and names the missing fact instead of inventing a test. When you know the fact, assert it with --bind and the sandbox stops being a draft.

pikopod~/api
$ pikopod scenario list examplepay
archetypes vs examplepay (4 endpoints):
   declines                   Declines  (1 candidate binding(s))
   timeouts                   Timeouts  (1 candidate binding(s))
   retry_storm                Retry storm with recovery  (1 candidate binding(s))
   rate_limit_backoff         Rate limit and backoff  (4 candidate binding(s))
   duplicate_delivery         Duplicate delivery
      no webhookEvent matching {} for role 'emittedEvent'
Reproduce

Replay last Friday’s 503 on your laptop

The observing agent records a redacted failure. One command arms that same response in the sandbox and replays the recorded request against it.

The result is an ordinary scenario file: inspect it, commit it, and keep the production failure as a regression test. When the agent runs on another host, one command exports the incident as a bundle that reproduce and fix accept on your laptop, with nothing else copied.

pikopod~/api
$ pikopod scenario reproduce fp_14835fa32dfb
reproduced fp_14835fa32dfb (examplepay answered 503 on POST /charges) as pikopod-data/scenarios/incident-14835fa32dfb.yaml
PASSED — 1 assertion(s) passed; 0 not evaluated
the failure now happens locally — fix it, then re-run: pikopod scenario run examplepay incident-14835fa32dfb

Recordings are redacted before they touch disk. Unclassified values are dropped. Each incident says how long it stays reproducible.

Observe

See what changed, then keep the fix

pikopod compares what the provider declares with what your integration receives. Those two signals produce a useful verdict instead of another isolated alert.

Declared

The published contract

One line in CI, nothing installed in your request path. A spec diff fails the build on breaking changes, annotates the GitHub diff inline, follows $ref across files, and ranks every finding by one fixed rule, so the same change never flips between WARN and ERR.

Observed

The responses you received

A fail-open proxy reports incidents immediately and structural drift after a stable baseline exists.

pikopod~/api
$ pikopod replay --ci
examplepay: 37 recordings gated (1 pre-warmup skipped) — 0 finding(s)
clean — no drift against frozen baselines

$ pikopod spec-diff origin/main:openapi.yaml openapi.yaml --fail-on ERR
1 change(s): 1 ERR, 0 WARN, 0 INFO

ERR  GET    /charges/{id}                            endpoint-removed
     endpoint removed from the spec  [fp_bcc85ba9a094]

breaking declared drift at/above ERR — failing the gate (exit 1)

Replay runs offline. Exit 0 is clean, 1 means the check found a failure, and 2 means the tool could not run.

The complete loop

Each result becomes the input to the next step

You can begin with the local sandbox. Observation only enters the path when you decide to add it.

00
Gate

Fail the build when the spec changes shape. No proxy, no account.

Coding agents

The same checks, over MCP

pikopod mcp exposes spec diff, replay, scenarios, faults and webhooks to an agent that just wrote the integration, so it verifies against what the provider actually sends before opening a pull request. Every answer carries a verdict, and UNVERIFIABLE is never reported as clean.

Safety boundary

Observation cannot hold up your traffic

The proxy serves first and observes afterwards through bounded, isolated capture stages. It never retries and initiates no network traffic unless you configure an integration.

Credentials are replaced and identifiers are tokenised before recordings reach disk.

BenchmarkProxyServe 82,041 ns/op BenchmarkProxyServeObserverWedged 81,868 ns/op

Observation fully jammed versus normal serving: under 1% apart in the same loopback benchmark.

Design partners · Q4 2026

Run pikopod against a provider you depend on

pikopod is open source and works today. We are looking for a small number of teams willing to use it against a real production dependency while the hosted layer is built.

What you get

A direct line to the maintainer, influence over provider support, and free hosted access during the program.

What we ask

Use it with one real provider, join a short call every two weeks, and tell us when it is wrong.

Tell us what your integration depends on

Bring one real provider and one failure you need to rehearse.

Send us a short note about your team, the API you use, and what breaks today.

hello@pikopod.com