Every route in src/api/routes/** now flows through defineCapability() — 618 routes, 0 inline registrations, hot path included
2026-05-13
LOCKSTEP TRACEABILITY MATRIX --- api_endpoints: ["none"] sdk_methods_updated: ["none"] mcp_tools_updated: ["none"] ---
What We Built
Migrated every inline app.{get,post,put,delete,patch}() route under src/api/routes/** to the defineCapability() contract abstraction. The hot path — POST /v1/chat/completions and POST /v1/messages — was the final and most consequential surface, completing a months-long effort to make defineCapability() the single registration mechanism for every external endpoint.
A capability declaration is a self-describing route: schema, auth mode, permission, protocol surface (REST + MCP), examples, and handler all in one TypeScript value. The runtime adapter (hono-adapter.ts) walks the ALL_CAPABILITIES array at boot and registers each one on the top Hono app. There are no more route factories returning sub-apps, no more app.route("/", subApp) mounts for the production surface, and no more "where does this URL get registered" archeology.
The src/api/routes/ tree still contains some files — admin.ts keeps a factory exported for a test fixture, and routes/completions/index.ts keeps completionsRoute() for the legacy test suites that mount it directly — but these are explicitly allowlisted by _no-inline-routes.test.ts, which now runs recursively across the tree and fails CI if any non-allowlisted file reintroduces an inline registration.
Why It Matters
This unifies how every route is described, mounted, and verified. The capability schema is the single artifact that the contract compiler (forthcoming) will consume to emit OpenAPI specs, TypeScript SDKs, Python SDKs, MCP tool manifests, and llms.txt entries — instead of those five surfaces drifting independently from hand-maintained sources. Today there are 15 representations of the BR API contract; the migration is the foundation that lets them collapse to one source plus generators.
For the hot path specifically: POST /v1/chat/completions (the customer-facing OpenAI-compatible endpoint that every paying user hits) is now expressed as a defineCapability() value with auth: "apiKey", permission: "completions.create", and a thin handler that delegates to the existing 1200-line handleCompletion function. The handler was hoisted out of a closure inside completionsRoute(opts) to a top-level export, and opts became an explicit parameter rather than a captured variable. Capability handlers call it directly with the original Hono Context, so c.var.apiKey and every other piece of upstream-middleware state flows through correctly.
How It Works
The capability runtime is a module-scope deps registry. At boot, server.ts calls setCapabilityRuntime({...}) with the router, sentinel, circuit breaker, intelligence systems, and other singletons that capability handlers need. Capability handlers read from it via getCapabilityRuntime() instead of taking constructor arguments. For the completions migration, the runtime was extended with four new fields — budgetTracker, memoryExtractionEnqueue, siemEnqueue, skillAccumulator — and setCapabilityRuntime was changed from a full-overwrite to a partial-merge so register-routes.ts can populate boot-stage-derived deps (like skillAccumulator, which depends on agentProfileStore + workflowDb) after server.ts has populated router-level deps.
The Anthropic ↔ OpenAI translation sandwich for /v1/messages lives entirely inside the capability handler now: read the body, translate to OpenAI shape, set the _parsedBody + _anthropicMode + _anthropicRequestModel context vars, call the shared handleCompletion pipeline, then translate the JSON response back to Anthropic shape (or pass through unchanged for SSE streaming, where the inline streamSSE callback handles per-chunk translation). The legacy sub-app's pre/post middleware sandwich is gone; the capability handler is the entire pipeline.
// src/api/capabilities/completions/completions.ts
export const chatCompletionsCapability = defineCapability({
id: "completions.create",
protocols: { rest: { method: "POST", path: "/v1/chat/completions" } },
auth: "apiKey",
permission: "completions.create",
request: z.object({}).passthrough(),
bind: { rawBody: true }, // skip body parsing; handler reads it itself
response: z.record(z.string(), z.unknown()),
errors: [],
examples: [{ name: "chat", request: {}, response: {} }],
handler: async (c) => {
const opts = buildOptsFromRuntime();
return (await handleCompletion(c, opts)) as never;
},
});
The Numbers
- 618 routes in
site/public/routes.jsonafter the migration — exactly the same count as before, confirming the capability paths are a 1-for-1 replacement of the legacy paths. - 0 inline route registrations remain in
src/api/routes/**outside the 2-file allowlist (admin.tsfor the slack-webhook test fixture,completions/index.tsfor the legacy test mounts). - 13 legacy factory files deleted — every
register*Routesfactory underroutes/auth/plus theauthRoute()shim androutes/auth.ts. - 7,403 / 7,403 unit tests pass. No skips, no flakes.
- 10m 3s ECS deploy time for the 41,218-insertion / 46,979-deletion change. Net −5,791 lines.
- 218ms p50 latency for
GET /healthpost-deploy.POST /v1/chat/completions(non-streaming) returned in 3.5s for a real gpt-4.1-nano roundtrip — within normal range. - 6 / 6 smoke tests green in production:
/health,/v1/models,POST /v1/chat/completions(streaming + non-streaming),POST /v1/messages(Anthropic shape),GET /v1/messages(token validation).
Competitive Edge
Code-first contract abstractions exist elsewhere — TypeSpec (Microsoft) and Fern are the closest comparables — but neither has BR's per-route routing-outcome signal to attach to capability declarations. The Shadow Comparator records every routing decision against a static counterfactual; the capability declaration is the natural place to expose that signal back to agents as a queryable health endpoint, which no other gateway can do because no other gateway has the closed-loop learned routing substrate underneath. This migration is the structural prerequisite for the contract compiler that will make BR's routing intelligence first-class in the developer interface.
Lockstep Checklist
> _You MUST check these boxes [x] and verify the corresponding files are updated BEFORE committing this log._
- [x] API Routes:
src/api/routes/— all 618 routes migrated todefineCapability(); 2-file allowlist enforced by gate test. - [x] TS SDK: No changes — capabilities preserve the same external HTTP surface, so existing SDK methods continue to work unchanged.
- [x] Python SDK: No changes — same reason.
- [x] MCP Schemas: No changes — capability declarations include MCP protocol surfaces but no new tools were added in this migration.
- [x] Master Record: No changes — same external API surface; the migration is a refactor of how routes are _registered_, not what they expose.