flight

Your traceback tells you where Python died. flight tells you why — a crash you can open, ask "why is this value what it is?", and re-run. The black box for Python.

reads locally Rust core · sys.monitoring ~65 ns / event MIT

Why it exists

The real debugging loop is: add prints → try to reproduce → fail to reproduce → add more prints → wait for it to happen again. A traceback tells you where a program died, almost never why. flight records what actually happened, so the bug report writes itself — and it's cheap enough to leave on in production.

How it works

One path in, one file out, many ways to read it.

   your program
        │   sys.monitoring (PEP 669) — native Rust callbacks, no Python frame
        ▼
   in-process · hot path · Rust
   ┌──────────────────────────────────────────────────────────┐
   │  is-this-mine? cache  →  lock-free ring buffer  →  clock   │
   └───────────────────────────┬──────────────────────────────┘
                               │   uncaught exception · or capture()
                               ▼
        object graph (aliasing ↔) + frames + source + exception chain
                               ▼
                       crash.flight   msgpack + zstd · versioned · shareable
             ┌─────────────────┼──────────────────────────┐
             ▼                 ▼                           ▼
       flight inspect    browser viewer (WASM)      why · diff · fix · what-if
  1. Record cheap enough to leave on. CPython's sys.monitoring calls straight into native Rust — no Python callback frame, no FFI hop. The hot path takes no lock.
  2. On a crash, write a black box — not a trace. The object graph is serialized identity-first, so the same object in two frames is one, marked ; every local, the exception chain and the source come too.
  3. Read it anywhere. The .flight is the spine: the CLI, the offline WASM viewer, and every analysis only ever speak to the file — never to a live process.

What you can do with a .flight

inspect

See the crash

Frames, locals, object graph and aliasing () — the whole last moment.

why

Backward slice

Ask why is this value what it is? and get the chain of writes back to the origin.

diff

Compare two runs

The first point a good run and a bad run diverged — the cause boundary.

bisect

Find the commit

Which commit introduced the bug — by fingerprint, or by replaying against each commit.

generalize

The boundary

The exact value at which a recorded input flips the failure on and off.

fix

A proven patch

Propose a fix and verify it by replaying the recorded tape with it applied.

what-if

Rewrite the past

Change a past value, re-execute over the same recorded world, see the counterfactual.

serve

Fleet mode

A dashboard aggregating thousands of black boxes, with regression detection.

What it is (and isn't)

It is a scoped, post-mortem recorder with a first-class viewer, evolving toward time-travel debugging. It is not an APM, a live debugger (that's pdb), or a profiler.