Skip to main content
Generated from bd help --doc serve. Serve the beads HTTP API — the same work surface the CLI answers, for automation clients that would otherwise fork a bd subprocess per call. The wire contract is described by an OpenAPI document (/v0); GET /v0/beads/context reports which operations this build actually implements. DEPLOYMENT Pass an explicit port. The default 127.0.0.1:0 takes an ephemeral one, which is right for ad-hoc and test use — where the bound address printed on stdout is read immediately — but carries no mutual exclusion: two serves against one workspace then run side by side on different ports with no way to enumerate them. On a fixed port the second one fails to bind, which is the intended behavior. Concurrent serves are data-safe either way; claims are arbitrated in the SQL server. Run it under a supervisor. bd shuts down gracefully on SIGHUP as well as SIGINT and SIGTERM, so closing the terminal of a foreground bd serve stops it. PROBES GET /healthz is LIVENESS only: it answers from the process and never touches the database, so it stays green while the database is unreachable. For readiness use GET /v0/beads/ready?limit=1 — a real query, where 200 means ready and 503 means live but not ready. AUTHENTICATION Optional, and off by default on loopback — where the trust model is the loopback boundary itself, the same one the database behind it already relies on. —auth-token-file turns it on: every operation except GET /healthz then requires an “Authorization: Bearer <token>” header, GET /v0/beads/context included, because it reports the repo root, beads directory and database name. The file holds ONE TOKEN PER LINE and every line is accepted. That is the rotation mechanism: write the new token alongside the old, roll the clients over, then delete the old line. The file is re-read while the server runs, so both the addition and the removal take effect within about a second and neither needs a restart. Write it atomically (a temp file plus rename; a Kubernetes secret mount already does this). There is deliberately no —auth-token flag. A credential passed as an argument is readable by every local user in the process listing. —allow-non-loopback REQUIRES a token file. Beyond loopback, reaching the address would otherwise be the whole authorization: any peer could read every issue and claim work as any actor. —insecure-no-auth is the explicit, auditable way to say you meant that anyway. The Host allowlist is what a service deployment usually trips over first. The DNS-rebinding check answers only to loopback spellings and the bind address, so a client dialing a service name gets 400 on every request; enumerate the names it dials with —allowed-host (repeatable). Matching is exact — no wildcards — and the startup log line prints the effective allowlist. WHAT THIS DOES NOT DO No TLS. Even with a token, the credential and every issue body travel in plaintext, so a deployment beyond loopback has to supply confidentiality itself — a service mesh, or a network boundary you already trust. Hooks do not fire. A hook is a user-controlled subprocess per mutation: in a concurrent server that is an unbounded latency multiplier and an orphaned child at shutdown, and its working-directory-derived hook lookup is meaningless in a server process. A CLI claim runs on_update; an HTTP claim does not. The per-command auto-commit machinery does not run. Durability is per request: a successful claim commits inside its own transaction, exactly as a proxied CLI claim does today. An actor on an HTTP request is caller-asserted provenance for the audit trail, not authenticated identity — the same thing it has always been on the CLI, where any local process can pass any —actor. It does not run under —readonly, and refuses to start rather than binding. Every server it binds publishes the issue-claim operation, and the capability set it advertises is a property of the build rather than of the flags on the process that started it — so a read-only server would advertise a write it could never land. DESTRUCTIVE OPERATIONS POST /v0/beads/issues:sweep deletes closed beads in bulk — the operation behind bd purge and bd prune — and nothing it deletes comes back. It shares the library surface those commands call, so it inherits their guards: pinned beads are never swept, and a durable sweep with neither a cutoff nor an id pattern is refused rather than clearing every closed bead in the workspace. Combined with the trust model above, that means anyone who can reach this address can erase closed work; bind it accordingly.
Flags: