@lucid-agents/hono
Hono adapter for a completed Lucid HTTP runtime.
The Hono adapter binds a completed Lucid HTTP runtime to a Hono application. It delegates to the canonical route plan owned by @lucid-agents/http; the adapter does not create a second entrypoint registry, manifest builder, task runtime, or paywall.
Installation
bun add @lucid-agents/core @lucid-agents/http @lucid-agents/hono honoAdd @lucid-agents/payments when the runtime receives x402 payments. No Hono-specific payment package is required.
Basic usage
import { z } from 'zod';
import { createAgent } from '@lucid-agents/core';
import { http } from '@lucid-agents/http';
import { createAgentApp } from '@lucid-agents/hono';
const runtime = await createAgent({
name: 'my-agent',
version: '1.0.0',
})
.use(http())
.addEntrypoint({
key: 'greet',
input: z.object({ name: z.string() }),
async handler({ input }) {
return { output: { message: `Hello, ${input.name}!` } };
},
})
.build();
const { app } = await createAgentApp(runtime);
export default {
port: 3000,
fetch: app.fetch,
};Always install http() before creating the app. Call await runtime.close() during shutdown so extension-owned resources are released.
API reference
createAgentApp(runtime, options?)
Creates a Hono app and mounts every route in runtime.http.routes.
const { app, runtime, agent, addEntrypoint } =
await createAgentApp(runtime, options);| Property | Description |
|---|---|
app | Configured Hono application. |
runtime | The same completed runtime passed to the adapter. |
agent | The runtime's protocol-agnostic agent core. |
addEntrypoint | Typed delegate to runtime.entrypoints.add(). |
Adding an entrypoint through either API updates the canonical registry and invalidates the generated Agent Card.
CreateAgentAppOptions
type CreateAgentAppOptions = {
beforeMount?: (app: Hono) => void;
afterMount?: (app: Hono) => void;
};Use beforeMount for middleware that must wrap agent routes. Use afterMount for additional routes or error handlers.
const { app } = await createAgentApp(runtime, {
beforeMount(app) {
app.use('*', async (context, next) => {
context.header('X-Service', 'agent');
await next();
});
},
afterMount(app) {
app.get('/custom', context => context.json({ custom: true }));
},
});Canonical routes
Paths below are relative to http({ basePath }). The default base path is empty.
| Method | Route | Description |
|---|---|---|
GET | / | Landing page when enabled. |
GET | /health | Health status. |
GET | /entrypoints | Discoverable entrypoints. |
POST | /entrypoints/:key/invoke | Invoke an entrypoint. |
POST | /entrypoints/:key/stream | Stream SSE envelopes. |
GET | /.well-known/agent.json | Legacy Agent Card path. |
GET | /.well-known/agent-card.json | Agent Card. |
GET | /.well-known/oasf-record.json | OASF record, or 404 when identity is not enabled. |
GET | /favicon.svg | Agent favicon. |
When the runtime includes a2a(), the same plan also mounts:
| Method | Route | Description |
|---|---|---|
POST | /tasks | Create and start a task. |
GET | /tasks | List tasks owned by the access token. |
GET | /tasks/:taskId | Read an owned task. |
POST | /tasks/:taskId/cancel | Cancel an owned running task. |
GET | /tasks/:taskId/subscribe | Subscribe to owned task updates over SSE. |
Task creation accepts a 20–256 character Task-Access-Token header or generates a token and returns it with the task. All later task operations require that token. Task routes are omitted when a2a() is not installed.
Payments and authentication
Payments are a runtime capability, not adapter middleware:
import { createAgent } from '@lucid-agents/core';
import { http } from '@lucid-agents/http';
import { payments, paymentsFromEnv } from '@lucid-agents/payments';
import { createAgentApp } from '@lucid-agents/hono';
const runtime = await createAgent({
name: 'paid-agent',
version: '1.0.0',
})
.use(payments({ config: paymentsFromEnv() }))
.use(http())
.addEntrypoint({
key: 'premium',
price: '0.01',
async handler() {
return { output: { result: 'premium content' } };
},
})
.build();
const { app } = await createAgentApp(runtime);The HTTP runtime uses one authorization path for invoke, stream, and task creation. x402, MPP, SIWX entitlements, payment-policy admission, settlement, and idempotency therefore behave the same in Hono, Express, and TanStack. If both x402 and MPP are installed, each priced entrypoint must set paymentProtocol: 'x402' | 'mpp'.
Running the server
Bun
export default {
port: Number(process.env.PORT ?? 3000),
fetch: app.fetch,
};Node.js
import { serve } from '@hono/node-server';
const server = serve({
fetch: app.fetch,
port: Number(process.env.PORT ?? 3000),
});Cloudflare Workers
export default { fetch: app.fetch };Exports
export { createAgentApp } from '@lucid-agents/hono';
export type { CreateAgentAppOptions } from '@lucid-agents/hono';