Engineering note · 3 of 6

One funnel. Refuse insecure start.

Every run admission path — Agent Protocol, stream/wait, cron, agent-to-agent, MCP tools/call — goes through createRunCtx. And runkite serve will not listen at all until the plane can prove a production-safe posture.

createRunCtx is the choke point

Handlers stay thin. The shared funnel does the work that must never diverge across entry points:

Fail-closed serve

An earlier default let serve boot on SQLite + in-process + no runner tokens + no client auth — still green on /readyz, so Kubernetes happily sent production traffic. That is gone.

Before listening, admission checks:

Any miss → clear error, exit 1, never listen. Escape hatches are explicit: RUNKITE_ALLOW_INSECURE_SERVE=1, RUNKITE_MODE=test, or runkite dev for the zero-dependency laptop path.

Fail-closed ≠ fail-open everywhere

Serve admission and policy Decide deny when unsure (security). Rate limiting fails open on a Redis blip (availability). Same word, different risk preference — do not conflate them.

If you cannot prove every create path shares one gate — and that serve will not start half-wired — you do not have a control plane; you have N slightly different APIs and a lucky readiness probe.

Fencing Subscribe-before-enqueue createRunCtx Poison pill FinOps holds Postgres RLS grant