- CPython 3.11+ (
requires-pythoninpyproject.tomlis>=3.11,<4;.python-versionpins a contributor default for uv, currently 3.12). CI runs that pinned release on Ubuntu and Windows. - Git
- uv (recommended): single tool for venvs, installs, and
uv run(installation). On Windows you can usepy -3 -m pip install uvif you do not use the standalone installer.
Note: search hits like flightdeck-1.0.1.dist-info under .venv/ are normal install metadata (distribution name + version), not references to another repository.
From the repository root:
uv sync --extra devThis creates .venv/ (gitignored), installs flightdeck editable plus pytest and ruff, and pins versions from uv.lock.
Optional extras (telemetry, SDK helpers, PostgreSQL driver, integration test deps): e.g.
uv sync --extra dev --extra telemetry, uv sync --extra dev --extra postgres, or
uv sync --extra dev --extra integrations-ci (LangChain / Temporal / OpenAI Agents for
tests/test_integrations_langchain.py and the same lock resolution CI job uses).
Local driver test helper (Docker optional): scripts/run_postgres_tests.ps1 (see script header).
| Extra | Packages installed | When to use |
|---|---|---|
dev |
pytest, pytest-cov, ruff |
Development and CI; required to run tests and lint |
openai |
openai>=1.0 |
If you want to use the OpenAI Python client alongside the SDK in your own agent code (not required by FlightDeck core) |
anthropic |
anthropic>=0.20 |
Same, for the Anthropic Python client |
telemetry |
opentelemetry-api, -sdk, -exporter-otlp |
Forward-looking OTLP integration; FlightDeck core does not import OpenTelemetry at runtime |
all |
openai + anthropic + telemetry |
All optional packages in one shot |
integrations-langchain |
langchain-core |
Optional FlightDeckLangChainCallbackHandler (see docs/sdk-integrations.md) |
integrations-temporal |
temporalio |
Optional worker-side typing helpers; core does not import Temporal |
integrations-openai-agents |
openai-agents |
Optional mapping from Agents SDK run results |
integrations-ci |
langchain-core + temporalio + openai-agents |
CI / local parity for integration tests (uv lock resolves this group) |
FlightDeck's core package (flightdeck-ai) does not import OpenAI, Anthropic, or OpenTelemetry at runtime. These extras exist so your project can declare a single dependency (flightdeck-ai[openai]) and get a compatible version of both without resolving conflicts manually.
flightdeck.integrations (experimental — see AGENTS.md and docs/sdk-integrations.md) ships thin mappers behind the integrations-* extras above. There is no declared crewai extra: install CrewAI in your own environment if you use crewai_bridge, to avoid pulling a very large dependency tree into uv.lock.
Note on listed core dependencies: pyproject.toml currently lists sqlalchemy, aiosqlite, and rich as direct (non-optional) dependencies, but src/flightdeck/ does not import any of them — the package uses the standard-library sqlite3 module and plain click output. These entries are carried over from earlier prototypes and are scheduled for removal in a future cleanup release.
python -m venv .venv
# Windows: .venv\Scripts\activate
# Unix: source .venv/bin/activate
python -m pip install -e ".[dev]"With uv:
uv sync --frozen --extra dev
uv run python -m ruff check src tests
uv run python -m pytest
uv run flightdeck --help
uv run flightdeck doctor
uv run flightdeck-quickstart-verifyWith an activated venv (pip or after uv sync):
python -m ruff check src tests
python -m pytest
flightdeck --help
flightdeck doctor
flightdeck demo
flightdeck-quickstart-verifyFast path for contributors: flightdeck demo runs the same core ledger steps as below in a temp workspace (fixtures from examples/quickstart, or flightdeck/_bundled_quickstart inside an installed wheel). flightdeck-quickstart-verify adds release verify + doctor.
Match CI’s CLI smoke: flightdeck --help must run successfully after changes to the CLI surface.
Full command flags and exit codes: README.md. Cross-platform quickstart parity: flightdeck-quickstart-verify / python -m flightdeck.quickstart_smoke (also run in CI). HTTP API reference: docs/http-api.md. Python SDK: docs/sdk.md.
flightdeck-quickstart-verify (entry point for src/flightdeck/quickstart_smoke.py) runs the full
quickstart workflow end-to-end in an isolated temp directory:
flightdeck init(bundled OpenAI / Anthropic / Google snapshot + catalog; additive with the imports below)- Import both pricing tables from
examples/quickstart/ flightdeck policy set- Register baseline and candidate releases — capture the
release_idprinted to stdout - Substitute
__BASELINE_RELEASE_ID__/__CANDIDATE_RELEASE_ID__placeholders in the quickstart JSONL event files and write them to the temp directory flightdeck runs ingestfor both event filesflightdeck release diff(7-day window)flightdeck release promotebaseline →localflightdeck release historyflightdeck release verify(checksum check against the on-disk bundle)flightdeck doctor
All subprocesses use subprocess.run(..., check=True). Any non-zero exit prints stderr and causes
the verifier to exit non-zero. On success it prints quickstart_smoke: OK.
Executable resolution: prefers flightdeck on PATH (shutil.which); falls back to
sys.executable -m flightdeck.cli.main so it works inside a bare uv run context without a
console-scripts install.
JSON Schemas: when src/flightdeck/ models or scripts/generate_schemas.py change wire contracts, regenerate and match CI:
uv run python scripts/generate_schemas.py
git diff --exit-code schemas/Lockfile: when you change pyproject.toml dependencies or extras, run uv lock and commit uv.lock so CI stays --frozen-reproducible.
The browser UI under flightdeck serve / is built from web/ into src/flightdeck/server/static/ (committed artifacts). After changing UI source, rebuild and commit the static output so CI passes:
cd web
npm ci
npm run build
cd ..
git diff --exit-code src/flightdeck/server/static/If that git diff fails, git add / commit everything under src/flightdeck/server/static/ (hashed assets/*.js, index.html, etc.)—CI uses the same check after npm run build.
Playwright: from web/, npx playwright install chromium once, then npm run test:e2e (matches CI after the static/ diff gate; see web/README.md).
npm run dev: proxies /v1 to flightdeck serve on 127.0.0.1:8765 by default; copy web/.env.example to web/.env.local to set VITE_FLIGHTDECK_LOCAL_API_TOKEN when testing mutations against a token-protected server.
See web/README.md for PR-split guidance when iterating with agents.
Before pushing to an org remote, follow the maintainer checklist in CONTRIBUTING.md (origin = personal research, org = flightdeckdev).
Merging to main does not publish packages — PyPI uploads are tag-driven (workflow .github/workflows/release-pypi.yml). The PyPI project is flightdeck-ai (pip install flightdeck-ai); the flightdeck CLI and import flightdeck layout are unchanged.
- PyPI: add a trusted publisher for github.com/flightdeckdev/flightdeck — workflow
release-pypi.yml. If PyPI offers Environment name: (Any), you can still use a GitHub Environment namedpypifor approval gates; otherwise match whatever you register on PyPI (trusted publishers). - GitHub: Settings → Environments → create
pypi(optional: required reviewers / wait timer before OIDC publish). - Bump
versioninpyproject.tomlandsrc/flightdeck/__init__.py, updateCHANGELOG.md, merge tomain. git tag vX.Y.Z(must matchpyproject.tomlexactly, e.g.v1.2.0) thengit push origin vX.Y.Z.
The workflow runs ruff, pytest, schema drift, uv build, publishes sdist + wheel to PyPI via OIDC (no long-lived API token in repo secrets), enables publish attestations, and creates a GitHub Release with generated notes and dist/* assets.
If PyPI rejects attestations for your project, set attestations: false on pypa/gh-action-pypi-publish in .github/workflows/release-pypi.yml until the registry side is sorted.
One command (uses bundled examples/quickstart fixtures; no sed):
flightdeck demoManual (same story as flightdeck demo, in your cwd):
flightdeck init
flightdeck pricing import examples/quickstart/pricing-baseline.yaml
flightdeck pricing import examples/quickstart/pricing-candidate.yaml
flightdeck policy set examples/quickstart/policy.yaml
BASELINE=$(flightdeck release register examples/quickstart/baseline-release)
CANDIDATE=$(flightdeck release register examples/quickstart/candidate-release)
sed "s/__BASELINE_RELEASE_ID__/${BASELINE}/g" examples/quickstart/baseline-events.jsonl > baseline-events.jsonl
sed "s/__CANDIDATE_RELEASE_ID__/${CANDIDATE}/g" examples/quickstart/candidate-events.jsonl > candidate-events.jsonl
flightdeck runs ingest baseline-events.jsonl
flightdeck runs ingest candidate-events.jsonl
flightdeck release diff "$BASELINE" "$CANDIDATE" --window 7d
flightdeck release promote "$BASELINE" --env local --window 7d --reason "initial baseline"
flightdeck release history --agent agent_support --env localFor a fully runnable demo that generates matching run events after release registration:
./scripts/smoke.shscripts/smoke.sh is a Bash script for Unix/macOS/Git Bash that mirrors the manual demo above. It creates a fresh temporary workspace, registers both quickstart releases, writes a pair of synthetic run events (one baseline, one candidate) with the assigned release IDs substituted inline, ingests them, runs release diff, promotes the baseline, and shows history. It does not run release verify or doctor — use flightdeck-quickstart-verify for the full end-to-end check including those steps.
| Script | Platform | What it covers |
|---|---|---|
flightdeck-quickstart-verify (or scripts/quickstart_smoke.py) |
All (Python) | Full workflow: init → pricing → policy → register → ingest → diff → promote → history → verify → doctor. Used in CI. |
scripts/smoke.sh |
Unix / Git Bash | Abbreviated demo: same workflow minus verify and doctor. Generates events inline so it needs no pre-substituted fixtures. |
examples/ci/ledger_gate.py |
All (Python) | Policy-gate CI gate only: init → pricing → register → ingest → diff (--fail-on-policy). No promote. Used in CI workflow. |
Migrations are forward-only numbered steps in src/flightdeck/storage.py. The current
highest version is tracked by LATEST_SCHEMA_MIGRATION_VERSION.
-
Add the migration block inside
Storage.migrate(). Follow the existing pattern:# v4: short description of what this migration does. apply(4, [ "ALTER TABLE some_table ADD COLUMN new_col TEXT;", ])
For migrations that need data-backfill or conditional DDL (like v3's
ALTER TABLE+PRAGMA table_infocheck), write the logic inline before inserting intoschema_migrations, similar to theif 3 not in applied:block. -
Bump
LATEST_SCHEMA_MIGRATION_VERSIONat the top ofstorage.py:LATEST_SCHEMA_MIGRATION_VERSION = 4 # was 3
-
Add a
doctor/test_doctor.pyassertion if the migration introduces a new invariant thatflightdeck doctorshould verify (e.g. a contiguous sequence or a foreign-key pointer). Updatetest_doctor.pyto expect the new migration version. -
Update
docs/operations-and-policy.md § Schema migrationstable to document the new version number and what it changes. -
Run the full test suite to confirm the migration applies cleanly on a fresh DB and on a DB that already has the previous version applied:
uv run python -m pytest tests/test_doctor.py tests/test_spine.py -v
- All migrations are additive; never drop columns or rename them without a new
api_versionmajor bump. - Migrations are applied inside the same
conn.executeautocommit context as theCREATE TABLE IF NOT EXISTSblock; for large backfills consider usingtransaction()explicitly to avoid partial writes. Storage.migrate()is idempotent — calling it multiple times on the same DB is safe.flightdeck doctorcalls it at startup as its first step.
flightdeck init creates flightdeck.yaml. By default, local SQLite data lives at:
.flightdeck/flightdeck.db
If your OS temp directory is restricted, set TMPDIR, TEMP, or TMP to a repo-local .tmp
directory before running tests.
On some Windows setups, pytest may fail to create or clean its temp directories under the default
%TEMP% path. If you see PermissionError errors mentioning pytest-of-... or pytest, point temp
dirs at the repo-local .tmp/ directory:
$env:TEMP = (Resolve-Path .tmp).Path
$env:TMP = $env:TEMP
$env:TMPDIR = $env:TEMP
uv run python -m pytestBy default, tests/conftest.py creates .tmp/ at import (for --basetemp=.tmp/pytest) and redirects TEMP/TMP into that folder during pytest on Windows. Set
FLIGHTDECK_USE_SYSTEM_TEMP=1 if you want to force pytest to use your normal OS temp directory instead.
If your shell does not activate virtual environments in the same way as the examples, use the virtual environment's Python executable directly:
.venv/bin/python -m pytestUse uv run python -m pytest from the repo root so imports like from tests.test_spine import … resolve the same way as in CI. CI adds --cov=flightdeck --cov-fail-under=80 (see [tool.coverage.run] in pyproject.toml for omit — integrations shims, the quickstart entrypoint, and the HTTP SDK client are excluded so the gate tracks core ledger/diff/policy code).
| Variable | Component | Description |
|---|---|---|
FLIGHTDECK_LOCAL_API_TOKEN |
Server | When set, POST /v1/promote and POST /v1/rollback require Authorization: Bearer <token>. Read endpoints and POST /v1/events are unaffected. See docs/http-api.md and SECURITY.md. |
FLIGHTDECK_USE_SYSTEM_TEMP |
Tests | Set to 1 to force pytest to use the OS default temp directory instead of the repo-local .tmp/ directory. Useful on developer machines where %TEMP% works correctly (see Troubleshooting above). |
USER / USERNAME |
CLI | Used to populate the actor field on promote, rollback, and pricing import audit records. USER is checked first (Unix/macOS), then USERNAME (Windows); falls back to "unknown". |
VITE_FLIGHTDECK_LOCAL_API_TOKEN |
Web dev server | Build-time variable for the React UI dev server (Vite). Copy web/.env.example → web/.env.local to set it when testing mutations through npm run dev against a token-protected server. |
VITE_DEV_PROXY_TARGET |
Web dev server | Overrides the Vite proxy target for /v1 (default: http://127.0.0.1:8765). |
TMPDIR / TEMP / TMP |
Tests / OS | Standard temp directory environment variables. Set any of these to a repo-local .tmp/ path if the OS default is restricted or permissions cause pytest failures. |
The Markdown under docs/ is also built as a static site for GitHub Pages (workflow .github/workflows/pages.yml). To preview locally:
pip install -r docs/requirements.txt
mkdocs serveThen open the URL MkDocs prints (usually http://127.0.0.1:8000/). The build output directory site/ is gitignored; CI uploads it as the Pages artifact.