The harness meant to be deleted. Bootstrap a fresh machine or repair your broken coding setup, then get back to your usual tools.
See the codeThe harness meant to be deleted.
You have a fresh VM or a new Mac. No GitHub CLI, no configured coding agent, no API key handy. Or your usual agent broke, and you need a working one to fix it.
Bailout gets you a small, independent harness in one command. Use it to bootstrap the machine or repair your setup, get back to your normal tools, then delete it.
curl -fsSL https://bailout.dev/install.sh | bash
bailout
No account, local API key, Git, Node, Python, or existing agent required. Apple Silicon macOS, x64 Linux, and ARM64 Linux. Bring Bash, curl, internet access, and the usual base utilities (including tar and a SHA-256 utility).
Website · Setup & recovery guide · Releases
Watch the full-size video. A prepared config failure, repaired by real public Auto inference in an Ubuntu ARM64 container. No local API key. Other settings and the original config backup are checked; OpenCode answers after Bailout is removed. Waits shortened; terminal output unchanged. Reproduce it.
A clean slate. Boot an EC2 instance, a GCP VM, or a new Mac. Ask bailout to inspect the machine, install missing tools, help you sign in to GitHub, clone your repo, and get Codex, Claude Code, Pi, or OpenCode ready to use.
A broken setup. Your normal agent no longer starts. A config is malformed, a runtime moved, or an update broke something. Use an independent harness to inspect what changed, back up the config, repair it, and verify that your main tool works.
A quick exit. The useful outcome is your usual setup working again. Bailout has no daemon, account setup, persistent conversation store, or project scaffolding. It is one native binary: 638.6 KB on Apple Silicon in v0.7.3. Every release stays under 6,000,000 bytes. Linux releases are statically linked with musl.
$ bailout
bailout v0.7.3
~
› auto · free models · full access
Fresh machine? Broken setup? Tell me what needs to work.
/shell local terminal /new fresh conversation /help
› this is a fresh Ubuntu VM. help me set up gh and OpenCode
Other starting points:
bailout 'pi stopped launching after a config change. diagnose and repair it'
bailout 'check what is missing before I can use my usual dev tools here'
Bash is the only model tool. Commands run automatically with your account's permissions, including file changes, package installation, and network access. This is not a sandbox. The agent is instructed to inspect first, preserve working setup, back up configuration before repair, and verify the result.
Bailout provides its own free inference. The tools you set up still use your own accounts and credentials.
For sign-in, sudo, or key entry, the Bash tool can hand you the real terminal with
interactive: true. That command's input and output are not captured for the model;
only its exit status is returned. You can also enter /shell for a local Bash
session, then type exit to return. Don't paste passwords or API keys into chat.
Normal Bash output is captured, so never ask the agent to print credential files.
For example, GitHub CLI's login flow can run in the local terminal handoff. Authentication still needs your participation. Bailout cannot manufacture an account or recover an unavailable secret.
bailout uninstall
This removes only the running bailout binary. The tools you installed, repositories you cloned, and configurations you repaired remain in place. It does not remove other tools, credentials, or directories. Reinstall with the same curl command whenever you need it again.
| In a session | Action |
|---|---|
/shell | Open local Bash for private or interactive setup; exit returns |
/last | Expand the last command's captured output |
/new | Start a fresh conversation |
/help / /exit | Show help or quit |
Ctrl-C stops a model request or Bash process group. At the prompt, it clears a draft or exits when empty. Up/Down browses history; Ctrl-J or Alt-Enter inserts a newline. Replies stream as they arrive. Questions can be answered directly, without a Bash call. Commands execute only after their complete tool call is validated.
Each Bash call starts a fresh shell in the session directory unless workdir is
specified. Shell state does not persist between calls. Ordinary commands default
to a two-minute timeout; interactive commands default to ten minutes. Models can
request up to thirty minutes. --max-steps N changes the default 50 model steps.
Routing is automatic. NO_COLOR=1 disables colors.
Bailout's Bash calls skip shell startup files, and its curl transport ignores
.curlrc, so those customizations do not have to work before bailout can help.
The hosted FastAPI service on Cloudflare Python Workers owns provider keys. The client never receives them. The OpenRouter adapter applies these checks: For every model request, including subsequent agent steps and fallback attempts:
:free
model, native tool support, and exactly zero in every reported pricing field.allow_fallbacks: false,
require_parameters: true, and a hard zero max_price for prompt, completion,
request, and image charges. This cap also covers the gap between checking and sending.The $1 key limit alone would still permit paid requests. The checks and upstream zero-price cap are what enforce this app's free-only policy. Like any client, the app depends on OpenRouter honoring its published prices and routing contract.
The router qualifies models using Bailout's own setup-and-repair benchmark. Models need at least 80% success on a complete ten-task run, native Bash calls, and no critical failures. Repeat runs refresh that evidence; reproduced live regressions can hold a model out even when its synthetic score passes. Unrecognized models remain outside production. Rankings combine measured task success with aggregate route health; context length, model names and marketing copy do not earn intelligence points. The nightly workflow publishes versioned results atomically, retaining the last valid snapshot on failure. See qualification, context handling and staged rollout. The hosted service admits only models with genuine passing qualification evidence.
Auto remembers the working model for the terminal session and avoids failed routes. The backend shares cooldowns across users and reserves request/token capacity for every attempt, including retries. Recovery preserves completed Bash results and never replays commands. Partial tool calls are discarded. A known account quota can use a separately enabled free provider; policy refusals and the hosting cutoff stop recovery. No prompt logs or installation IDs are introduced. The terminal explains temporary capacity waits and retries with backoff for up to five minutes, with at most eight HTTP attempts. Ctrl-C cancels the wait. Every attempt is metered; daily exhaustion and hosting-budget refusals stop promptly. See recovery and the API protocol.
Adapters cover OpenRouter, Groq, Mistral, Z.AI and Vercel AI Gateway.
Groq and Mistral require expiring attestations of verified Free accounts with paid
billing and top-ups disabled. Z.AI requires fresh, explicit Free pricing in all
four published token-price columns. Vercel requires zero input/output/other fees,
native tools, a free capability, and providerOptions.gateway.has: ["free"] on
every inference. Credit balances and spending limits never make a paid model eligible.
Unknown or changed eligibility skips that route. See operator setup.
The client preserves history instead of silently removing old turns. Every route
must support at least 32K context and fit this conversation plus answer space and
headroom. Near a limit, Auto announces a switch to a fitting qualified free model.
If none fits, it returns context_exhausted; /new starts a fresh task. The first
implementation uses a conservative byte-based token estimate and can switch early.
Free capacity is shared and best effort. OpenRouter's account quota and provider
availability still apply. A final HTTP 429 means wait for the indicated capacity reset;
the app never pays to bypass it. The public gateway enforces 60 requests/minute, 600/hour and 2,000/day per IP,
plus a globally shared allowance. IPv6 /64s and users behind a NAT share limits.
At the hosting cutoff, HTTP 503 budget_exhausted explains when capacity returns;
the CLI displays it without automatically retrying. See limits and error codes.
Source contracts: OpenRouter provider routing, OpenRouter limits, Cloudflare Workers pricing.
Prompts, model-selected file contents, and captured Bash output are sent through the hosted Worker to the selected configured provider (OpenRouter and its upstream provider, or an enabled Groq, Mistral, Z.AI or Vercel route). Provider data policies apply; free does not mean zero data retention. The Worker does not store conversations or log request bodies. The gateway retains short-lived daily IP hashes, quota reservations, cooldowns, and aggregate model availability/latency; see retention details. Worker observability is disabled. Do not include credentials in prompts or ask the agent to read secret files.
The homepage publishes aggregate download and model-request totals. Downloads come from GitHub's public binary-asset counts (including updates and repeats). The request counter starts when enabled; it counts hosted chat requests accepted by the backend, including streams that may fail later. There are no analytics cookies, installation IDs, location analytics, or additional CLI telemetry calls. See how the public counters work.
From the published v0.7.3 assets, verified against SHA-256 checksums:
| Platform | Native binary (uncompressed) | Download (.tar.gz) |
|---|---|---|
| macOS ARM64 | 638,592 bytes | 318,119 bytes |
| Linux x64 | 844,576 bytes | 417,262 bytes |
| Linux ARM64 | 790,784 bytes | 397,031 bytes |
cargo test --locked
cargo clippy --locked --all-targets -- -D warnings
cargo build --release --locked
python3 scripts/check-size.py target/release/bailout
python3 scripts/smoke.py target/release/bailout
python3 scripts/test-installer.py
(cd api && uv sync && uv run pytest)
(cd worker && npm ci && npm test && npm run build:site)
python3 bench/test_bench.py
Optional live file-write verification (uses shared free quota):
python3 scripts/live-smoke.py target/release/bailout.
For the recovery use case: python3 scripts/live-recovery.py target/release/bailout
diagnoses a broken fixture agent, backs up its configuration, and verifies repair.
Three direct Rust dependencies: serde_json, libc, and rustyline. System curl
handles TLS; Bash handles everything the model does. The API is FastAPI on
Cloudflare Python Workers. A separate Worker serves the static landing page and
forwards legacy API URLs through the budget gateway. The Python service is private;
a SQLite Durable Object reserves capacity atomically before forwarding requests.
The smoke test drives a real controlling terminal. It verifies Ctrl-C as a keypress while editing, waiting on a model, running a child process, and at the empty prompt, plus history, multiline input, Auto routing, local interactive authentication without credential capture, shell handoff, uninstall, and recovery after interruption.
CI runs the tests and real binary smoke checks on all three supported platforms.
Tagging vX.Y.Z builds native release assets, tests them, enforces the size ceiling,
and publishes SHA-256 checksums. The installer pins one resolved release version,
verifies the archive checksum, checks its contents and binary size, then installs
atomically. Set BAILOUT_VERSION=v0.7.3 or BAILOUT_INSTALL_DIR=/your/bin to override.
It prefers an existing writable PATH location and never uses sudo or modifies shell rc files.
Starting in v0.4.0, each launch checks the official GitHub stable release. A newer
release is downloaded, SHA-256 verified, installed atomically, and restarted with
the same arguments, working directory, input and backend setting. Failed checks
keep the existing binary. Use bailout update to check manually or
BAILOUT_NO_UPDATE=1 to disable automatic updates. Custom-backend builds manage
their own updates. Older releases need the installer once to gain this feature.
Worker and browser sources use strict TypeScript. npm run build:site in worker
emits plain JavaScript and copies static assets to dist/site; Wrangler runs that
build automatically for the website. The Rust binary and Python API need no JS runtime.
The site uses self-hosted Space Grotesk and IBM Plex Mono, with their OFL licenses included. No analytics, external fonts, or frontend framework. The visual language is inspired by neobrutalism.dev.
Use Python 3.13+, uv 0.12.3+, and Node (for Wrangler). Choose your own Worker name
in api/wrangler.jsonc before deploying. Keep Python private. In
worker/gateway.wrangler.jsonc, choose your gateway name and domain and point its
API binding at your Python Worker. Keep workers.dev and preview URLs disabled.
Bind the Python Worker’s CAPACITY namespace to BudgetGuard in that gateway.
For a new deployment, first deploy the gateway with an empty services array and
SERVICE_PAUSED=true so its Durable Object exists. Then deploy Python with the
CAPACITY binding, restore the gateway’s API service binding, and unpause it.
For an existing deployment, use the staged qualification rollout before switching the public backend. An empty registry fails closed.
The Python API needs Workers Paid on Cloudflare. Its JSON processing and streaming exceed the Free plan's 10 ms CPU allowance; requests can otherwise be terminated midway through a reply. Paid starts at $5/month plus usage. This is hosting cost, separate from the strict zero-cost model routing. See Cloudflare's current pricing and CPU limits. You can also run the same FastAPI app on an existing server with Uvicorn.
cd api
uv sync
uv run pywrangler login
uv run pywrangler deploy
uv run pywrangler secret put OPENROUTER_API_KEY
Enter the OpenRouter key at the secret prompt. Never put it in source or config.
For edge development, place it in a gitignored .dev.vars file and run
uv run pywrangler dev. For ordinary local FastAPI protocol development, run uv run uvicorn app:app --app-dir src --reload. Production qualification and quotas require the Durable Object binding; local mode has no qualified models by default.
The API exposes /health, /v1/models, /v1/chat, /docs, and /openapi.json.
Chat accepts {model, messages, stream} and optional Auto-only preferred_model
and avoid_models session hints. With stream: true, it returns NDJSON
model, text, and done events, or an error event. Only the done event
contains a validated message that is safe to pass to the tool dispatcher.
An additive retry: true field on a model event marks recovery or a preemptive switch;
clients should display its notice and separate any partial text from the new response. The complete
conversation message comes only from done, never concatenated text deltas.
Deploy the guard with npm ci && npx wrangler deploy --config gateway.wrangler.jsonc
in worker. To deploy the site, point the service binding in worker/wrangler.jsonc
at your gateway Worker, then run npm run deploy. Set your own domains in both
configs. The public gateway additionally exposes /v1/status.
export BAILOUT_API_URL=https://api.your-domain.example
bailout
BAILOUT_DEFAULT_API at compile time changes
the binary's built-in backend URL. Runtime API overrides require HTTPS, except localhost
for development. The public service intentionally requires no login, so use your own
Worker and key if you need a separate quota. Cloudflare hosting costs and limits are
separate from model prices.
74 commits
Python
55.0%
TypeScript
23.0%
Rust
12.6%
HTML
8.5%
The harness meant to be deleted. Bootstrap a fresh machine or repair your broken coding setup, then get back to your usual tools.
See the codeThe harness meant to be deleted.
You have a fresh VM or a new Mac. No GitHub CLI, no configured coding agent, no API key handy. Or your usual agent broke, and you need a working one to fix it.
Bailout gets you a small, independent harness in one command. Use it to bootstrap the machine or repair your setup, get back to your normal tools, then delete it.
curl -fsSL https://bailout.dev/install.sh | bash
bailout
No account, local API key, Git, Node, Python, or existing agent required. Apple Silicon macOS, x64 Linux, and ARM64 Linux. Bring Bash, curl, internet access, and the usual base utilities (including tar and a SHA-256 utility).
Website · Setup & recovery guide · Releases
Watch the full-size video. A prepared config failure, repaired by real public Auto inference in an Ubuntu ARM64 container. No local API key. Other settings and the original config backup are checked; OpenCode answers after Bailout is removed. Waits shortened; terminal output unchanged. Reproduce it.
A clean slate. Boot an EC2 instance, a GCP VM, or a new Mac. Ask bailout to inspect the machine, install missing tools, help you sign in to GitHub, clone your repo, and get Codex, Claude Code, Pi, or OpenCode ready to use.
A broken setup. Your normal agent no longer starts. A config is malformed, a runtime moved, or an update broke something. Use an independent harness to inspect what changed, back up the config, repair it, and verify that your main tool works.
A quick exit. The useful outcome is your usual setup working again. Bailout has no daemon, account setup, persistent conversation store, or project scaffolding. It is one native binary: 638.6 KB on Apple Silicon in v0.7.3. Every release stays under 6,000,000 bytes. Linux releases are statically linked with musl.
$ bailout
bailout v0.7.3
~
› auto · free models · full access
Fresh machine? Broken setup? Tell me what needs to work.
/shell local terminal /new fresh conversation /help
› this is a fresh Ubuntu VM. help me set up gh and OpenCode
Other starting points:
bailout 'pi stopped launching after a config change. diagnose and repair it'
bailout 'check what is missing before I can use my usual dev tools here'
Bash is the only model tool. Commands run automatically with your account's permissions, including file changes, package installation, and network access. This is not a sandbox. The agent is instructed to inspect first, preserve working setup, back up configuration before repair, and verify the result.
Bailout provides its own free inference. The tools you set up still use your own accounts and credentials.
For sign-in, sudo, or key entry, the Bash tool can hand you the real terminal with
interactive: true. That command's input and output are not captured for the model;
only its exit status is returned. You can also enter /shell for a local Bash
session, then type exit to return. Don't paste passwords or API keys into chat.
Normal Bash output is captured, so never ask the agent to print credential files.
For example, GitHub CLI's login flow can run in the local terminal handoff. Authentication still needs your participation. Bailout cannot manufacture an account or recover an unavailable secret.
bailout uninstall
This removes only the running bailout binary. The tools you installed, repositories you cloned, and configurations you repaired remain in place. It does not remove other tools, credentials, or directories. Reinstall with the same curl command whenever you need it again.
| In a session | Action |
|---|---|
/shell | Open local Bash for private or interactive setup; exit returns |
/last | Expand the last command's captured output |
/new | Start a fresh conversation |
/help / /exit | Show help or quit |
Ctrl-C stops a model request or Bash process group. At the prompt, it clears a draft or exits when empty. Up/Down browses history; Ctrl-J or Alt-Enter inserts a newline. Replies stream as they arrive. Questions can be answered directly, without a Bash call. Commands execute only after their complete tool call is validated.
Each Bash call starts a fresh shell in the session directory unless workdir is
specified. Shell state does not persist between calls. Ordinary commands default
to a two-minute timeout; interactive commands default to ten minutes. Models can
request up to thirty minutes. --max-steps N changes the default 50 model steps.
Routing is automatic. NO_COLOR=1 disables colors.
Bailout's Bash calls skip shell startup files, and its curl transport ignores
.curlrc, so those customizations do not have to work before bailout can help.
The hosted FastAPI service on Cloudflare Python Workers owns provider keys. The client never receives them. The OpenRouter adapter applies these checks: For every model request, including subsequent agent steps and fallback attempts:
:free
model, native tool support, and exactly zero in every reported pricing field.allow_fallbacks: false,
require_parameters: true, and a hard zero max_price for prompt, completion,
request, and image charges. This cap also covers the gap between checking and sending.The $1 key limit alone would still permit paid requests. The checks and upstream zero-price cap are what enforce this app's free-only policy. Like any client, the app depends on OpenRouter honoring its published prices and routing contract.
The router qualifies models using Bailout's own setup-and-repair benchmark. Models need at least 80% success on a complete ten-task run, native Bash calls, and no critical failures. Repeat runs refresh that evidence; reproduced live regressions can hold a model out even when its synthetic score passes. Unrecognized models remain outside production. Rankings combine measured task success with aggregate route health; context length, model names and marketing copy do not earn intelligence points. The nightly workflow publishes versioned results atomically, retaining the last valid snapshot on failure. See qualification, context handling and staged rollout. The hosted service admits only models with genuine passing qualification evidence.
Auto remembers the working model for the terminal session and avoids failed routes. The backend shares cooldowns across users and reserves request/token capacity for every attempt, including retries. Recovery preserves completed Bash results and never replays commands. Partial tool calls are discarded. A known account quota can use a separately enabled free provider; policy refusals and the hosting cutoff stop recovery. No prompt logs or installation IDs are introduced. The terminal explains temporary capacity waits and retries with backoff for up to five minutes, with at most eight HTTP attempts. Ctrl-C cancels the wait. Every attempt is metered; daily exhaustion and hosting-budget refusals stop promptly. See recovery and the API protocol.
Adapters cover OpenRouter, Groq, Mistral, Z.AI and Vercel AI Gateway.
Groq and Mistral require expiring attestations of verified Free accounts with paid
billing and top-ups disabled. Z.AI requires fresh, explicit Free pricing in all
four published token-price columns. Vercel requires zero input/output/other fees,
native tools, a free capability, and providerOptions.gateway.has: ["free"] on
every inference. Credit balances and spending limits never make a paid model eligible.
Unknown or changed eligibility skips that route. See operator setup.
The client preserves history instead of silently removing old turns. Every route
must support at least 32K context and fit this conversation plus answer space and
headroom. Near a limit, Auto announces a switch to a fitting qualified free model.
If none fits, it returns context_exhausted; /new starts a fresh task. The first
implementation uses a conservative byte-based token estimate and can switch early.
Free capacity is shared and best effort. OpenRouter's account quota and provider
availability still apply. A final HTTP 429 means wait for the indicated capacity reset;
the app never pays to bypass it. The public gateway enforces 60 requests/minute, 600/hour and 2,000/day per IP,
plus a globally shared allowance. IPv6 /64s and users behind a NAT share limits.
At the hosting cutoff, HTTP 503 budget_exhausted explains when capacity returns;
the CLI displays it without automatically retrying. See limits and error codes.
Source contracts: OpenRouter provider routing, OpenRouter limits, Cloudflare Workers pricing.
Prompts, model-selected file contents, and captured Bash output are sent through the hosted Worker to the selected configured provider (OpenRouter and its upstream provider, or an enabled Groq, Mistral, Z.AI or Vercel route). Provider data policies apply; free does not mean zero data retention. The Worker does not store conversations or log request bodies. The gateway retains short-lived daily IP hashes, quota reservations, cooldowns, and aggregate model availability/latency; see retention details. Worker observability is disabled. Do not include credentials in prompts or ask the agent to read secret files.
The homepage publishes aggregate download and model-request totals. Downloads come from GitHub's public binary-asset counts (including updates and repeats). The request counter starts when enabled; it counts hosted chat requests accepted by the backend, including streams that may fail later. There are no analytics cookies, installation IDs, location analytics, or additional CLI telemetry calls. See how the public counters work.
From the published v0.7.3 assets, verified against SHA-256 checksums:
| Platform | Native binary (uncompressed) | Download (.tar.gz) |
|---|---|---|
| macOS ARM64 | 638,592 bytes | 318,119 bytes |
| Linux x64 | 844,576 bytes | 417,262 bytes |
| Linux ARM64 | 790,784 bytes | 397,031 bytes |
cargo test --locked
cargo clippy --locked --all-targets -- -D warnings
cargo build --release --locked
python3 scripts/check-size.py target/release/bailout
python3 scripts/smoke.py target/release/bailout
python3 scripts/test-installer.py
(cd api && uv sync && uv run pytest)
(cd worker && npm ci && npm test && npm run build:site)
python3 bench/test_bench.py
Optional live file-write verification (uses shared free quota):
python3 scripts/live-smoke.py target/release/bailout.
For the recovery use case: python3 scripts/live-recovery.py target/release/bailout
diagnoses a broken fixture agent, backs up its configuration, and verifies repair.
Three direct Rust dependencies: serde_json, libc, and rustyline. System curl
handles TLS; Bash handles everything the model does. The API is FastAPI on
Cloudflare Python Workers. A separate Worker serves the static landing page and
forwards legacy API URLs through the budget gateway. The Python service is private;
a SQLite Durable Object reserves capacity atomically before forwarding requests.
The smoke test drives a real controlling terminal. It verifies Ctrl-C as a keypress while editing, waiting on a model, running a child process, and at the empty prompt, plus history, multiline input, Auto routing, local interactive authentication without credential capture, shell handoff, uninstall, and recovery after interruption.
CI runs the tests and real binary smoke checks on all three supported platforms.
Tagging vX.Y.Z builds native release assets, tests them, enforces the size ceiling,
and publishes SHA-256 checksums. The installer pins one resolved release version,
verifies the archive checksum, checks its contents and binary size, then installs
atomically. Set BAILOUT_VERSION=v0.7.3 or BAILOUT_INSTALL_DIR=/your/bin to override.
It prefers an existing writable PATH location and never uses sudo or modifies shell rc files.
Starting in v0.4.0, each launch checks the official GitHub stable release. A newer
release is downloaded, SHA-256 verified, installed atomically, and restarted with
the same arguments, working directory, input and backend setting. Failed checks
keep the existing binary. Use bailout update to check manually or
BAILOUT_NO_UPDATE=1 to disable automatic updates. Custom-backend builds manage
their own updates. Older releases need the installer once to gain this feature.
Worker and browser sources use strict TypeScript. npm run build:site in worker
emits plain JavaScript and copies static assets to dist/site; Wrangler runs that
build automatically for the website. The Rust binary and Python API need no JS runtime.
The site uses self-hosted Space Grotesk and IBM Plex Mono, with their OFL licenses included. No analytics, external fonts, or frontend framework. The visual language is inspired by neobrutalism.dev.
Use Python 3.13+, uv 0.12.3+, and Node (for Wrangler). Choose your own Worker name
in api/wrangler.jsonc before deploying. Keep Python private. In
worker/gateway.wrangler.jsonc, choose your gateway name and domain and point its
API binding at your Python Worker. Keep workers.dev and preview URLs disabled.
Bind the Python Worker’s CAPACITY namespace to BudgetGuard in that gateway.
For a new deployment, first deploy the gateway with an empty services array and
SERVICE_PAUSED=true so its Durable Object exists. Then deploy Python with the
CAPACITY binding, restore the gateway’s API service binding, and unpause it.
For an existing deployment, use the staged qualification rollout before switching the public backend. An empty registry fails closed.
The Python API needs Workers Paid on Cloudflare. Its JSON processing and streaming exceed the Free plan's 10 ms CPU allowance; requests can otherwise be terminated midway through a reply. Paid starts at $5/month plus usage. This is hosting cost, separate from the strict zero-cost model routing. See Cloudflare's current pricing and CPU limits. You can also run the same FastAPI app on an existing server with Uvicorn.
cd api
uv sync
uv run pywrangler login
uv run pywrangler deploy
uv run pywrangler secret put OPENROUTER_API_KEY
Enter the OpenRouter key at the secret prompt. Never put it in source or config.
For edge development, place it in a gitignored .dev.vars file and run
uv run pywrangler dev. For ordinary local FastAPI protocol development, run uv run uvicorn app:app --app-dir src --reload. Production qualification and quotas require the Durable Object binding; local mode has no qualified models by default.
The API exposes /health, /v1/models, /v1/chat, /docs, and /openapi.json.
Chat accepts {model, messages, stream} and optional Auto-only preferred_model
and avoid_models session hints. With stream: true, it returns NDJSON
model, text, and done events, or an error event. Only the done event
contains a validated message that is safe to pass to the tool dispatcher.
An additive retry: true field on a model event marks recovery or a preemptive switch;
clients should display its notice and separate any partial text from the new response. The complete
conversation message comes only from done, never concatenated text deltas.
Deploy the guard with npm ci && npx wrangler deploy --config gateway.wrangler.jsonc
in worker. To deploy the site, point the service binding in worker/wrangler.jsonc
at your gateway Worker, then run npm run deploy. Set your own domains in both
configs. The public gateway additionally exposes /v1/status.
export BAILOUT_API_URL=https://api.your-domain.example
bailout
BAILOUT_DEFAULT_API at compile time changes
the binary's built-in backend URL. Runtime API overrides require HTTPS, except localhost
for development. The public service intentionally requires no login, so use your own
Worker and key if you need a separate quota. Cloudflare hosting costs and limits are
separate from model prices.
74 commits
Python
55.0%
TypeScript
23.0%
Rust
12.6%
HTML
8.5%