Context
Today, apps built on BoringOS (e.g. the CRM) hand-write an agent API catalog in a context provider — a markdown string describing each HTTP endpoint so agents know what to curl. This string drifts from the actual Hono routes whenever a developer adds or changes an endpoint.
An initial fix (separate work — agentDocs as a framework primitive on app.route()) reduces the problem by colocating docs with the mount point and shipping a built-in apiCatalogProvider. But the docs are still hand-written prose that can drift from the actual route handler inside each file.
This issue proposes the structural fix: make the route itself the source of truth.
Proposal
Introduce a typed route builder that wraps Hono and accepts per-route schemas:
app.routeTyped("/api/crm/deals", (r) => {
r.post({
summary: "Create a deal",
body: DealCreateSchema, // zod
response: DealSchema,
agentHint: "Use when the user asks to create a new sales opportunity.",
handler: async (ctx) => { ... },
});
r.get("/:id", { params: z.object({ id: z.string().uuid() }), ... });
});
From one declaration, the framework can derive:
- Runtime validation — reject bad bodies/params before the handler runs.
- TypeScript types — handler
ctx.body is typed from the zod schema.
- OpenAPI spec — at
/openapi.json. Unlocks SDK generation, Swagger UI, and external integration.
- Agent docs, auto-generated — the
apiCatalogProvider emits markdown directly from the schema, including param names, body shape, examples derived from z.describe(). No hand-written prose → no drift possible.
- MCP tool descriptors (optional future) — expose routes as typed tools instead of curl commands.
Why this matters
- Drift becomes structurally impossible. Adding a new field to a request body updates validation, types, docs, and the agent prompt in one edit.
- Cross-cutting wins. Frontend SDK, external integrators, and agents all read from the same schema.
- Better agent behavior. Agents get typed shapes instead of prose — fewer malformed requests, fewer retries.
Scope / cost
Non-trivial. Requires:
- Designing the
routeTyped builder API (borrowing ideas from @hono/zod-openapi, trpc, hattip).
- Zod as a new framework-level dependency (or an adapter so callers can bring their own validator).
- Migrating the existing framework routes (
/api/auth, /api/admin, /api/copilot, /api/agent) to the typed builder — and coordinating app-side migrations (the CRM alone has ~40 routes).
Realistic path: ship the builder alongside the existing app.route() so migration is gradual. New routes use the typed builder; old routes keep working until migrated.
Prior art
@hono/zod-openapi — zod-powered route definitions with auto OpenAPI on Hono. Most direct inspiration.
tRPC — schema-first server, but RPC rather than REST.
fastify with @fastify/type-provider-typebox — similar pattern in fastify ecosystem.
elysia.js — type-driven from the ground up.
Open questions
- Zod v3 vs v4 vs Valibot vs StandardSchema? Lean toward StandardSchema to stay validator-agnostic.
- Does the OpenAPI spec need to be served from every app, or is one combined spec (mounted by the framework) enough?
- How do we express auth requirements (admin-only, tenant-scoped, agent-only) declaratively so they show up in both validation and docs?
Filed as a follow-up to the agentDocs primitive work. That unblocks near-term drift prevention; this is the long-term structural answer.
Context
Today, apps built on BoringOS (e.g. the CRM) hand-write an agent API catalog in a context provider — a markdown string describing each HTTP endpoint so agents know what to
curl. This string drifts from the actual Hono routes whenever a developer adds or changes an endpoint.An initial fix (separate work —
agentDocsas a framework primitive onapp.route()) reduces the problem by colocating docs with the mount point and shipping a built-inapiCatalogProvider. But the docs are still hand-written prose that can drift from the actual route handler inside each file.This issue proposes the structural fix: make the route itself the source of truth.
Proposal
Introduce a typed route builder that wraps Hono and accepts per-route schemas:
From one declaration, the framework can derive:
ctx.bodyis typed from the zod schema./openapi.json. Unlocks SDK generation, Swagger UI, and external integration.apiCatalogProvideremits markdown directly from the schema, including param names, body shape, examples derived fromz.describe(). No hand-written prose → no drift possible.Why this matters
Scope / cost
Non-trivial. Requires:
routeTypedbuilder API (borrowing ideas from@hono/zod-openapi,trpc,hattip)./api/auth,/api/admin,/api/copilot,/api/agent) to the typed builder — and coordinating app-side migrations (the CRM alone has ~40 routes).Realistic path: ship the builder alongside the existing
app.route()so migration is gradual. New routes use the typed builder; old routes keep working until migrated.Prior art
@hono/zod-openapi— zod-powered route definitions with auto OpenAPI on Hono. Most direct inspiration.tRPC— schema-first server, but RPC rather than REST.fastifywith@fastify/type-provider-typebox— similar pattern in fastify ecosystem.elysia.js— type-driven from the ground up.Open questions
Filed as a follow-up to the
agentDocsprimitive work. That unblocks near-term drift prevention; this is the long-term structural answer.