lucidAGENTS
Packages

@lucid-agents/tanstack

TanStack Start handlers for a completed Lucid HTTP runtime.

The TanStack adapter exposes Fetch-native Lucid HTTP handlers in the context shape expected by TanStack Start route modules. It delegates to the completed runtime.http.handlers; it does not create a second registry, execute handlers directly, or install an adapter-local paywall.

Installation

bun add @lucid-agents/core @lucid-agents/http @lucid-agents/tanstack @tanstack/react-start

Basic usage

src/lib/agent.ts
import { createAgent } from '@lucid-agents/core';
import { http } from '@lucid-agents/http';
import { createTanStackRuntime } from '@lucid-agents/tanstack';

const agent = await createAgent({
  name: 'my-agent',
  version: '1.0.0',
})
  .use(http({ basePath: '/api/agent' }))
  .build();

export const { runtime, handlers, routes } = await createTanStackRuntime(agent);

Always install http() before creating the TanStack wrapper. Call await runtime.close() during server shutdown.

API reference

createTanStackRuntime(runtime)

Returns the original runtime, adapted handlers, and the canonical route plan.

type TanStackRuntime<TRuntime> = {
  runtime: TRuntime;
  handlers: TanStackHandlers;
  routes: readonly AgentHttpRoute[];
};
PropertyDescription
runtimeThe same completed runtime passed to the adapter.
handlersTanStack-context wrappers around runtime.http.handlers.
routesThe same route paths, methods, and capability checks used by Hono and Express.

createTanStackHandlers(runtime)

Creates just the adapted handler collection. createTanStackRuntime() calls this function for you.

type TanStackRequestHandler = (context: {
  request: Request;
}) => Promise<Response>;

type TanStackRouteHandler<Params> = (context: {
  request: Request;
  params: Params;
}) => Promise<Response>;

TanStackHandlers includes:

HandlerParametersPurpose
health{ request }Health response.
entrypoints{ request }Entrypoint discovery.
manifest{ request }Agent Card.
oasf{ request }OASF record or 404.
favicon{ request }SVG favicon.
landing{ request }Optional landing page.
invoke{ request, params: { key } }Canonical invoke flow.
stream{ request, params: { key } }Canonical SSE flow.
tasks{ request }Create a task.
listTasks{ request }List owned tasks.
getTask{ request, params: { taskId } }Read an owned task.
cancelTask{ request, params: { taskId } }Cancel an owned task.
subscribeTask{ request, params: { taskId } }Stream task updates.

Route modules

TanStack route files should pass the original request and validated route parameters to the returned handler. The handler already performs body parsing, schema validation, authorization, idempotency, execution, and response formatting.

src/routes/api/agent/entrypoints/$key/invoke.ts
import { createFileRoute } from '@tanstack/react-router';
import { handlers } from '@/lib/agent';

export const Route = createFileRoute('/api/agent/entrypoints/$key/invoke')({
  server: {
    handlers: {
      POST: async ({ request, params }) => {
        const key = params.key;
        if (typeof key !== 'string') {
          return new Response('Missing or invalid key parameter', {
            status: 400,
          });
        }
        return handlers.invoke({ request, params: { key } });
      },
    },
  },
});

Streaming uses the same delegation; do not build a second ReadableStream or rewrite SSE headers:

src/routes/api/agent/entrypoints/$key/stream.ts
export const Route = createFileRoute('/api/agent/entrypoints/$key/stream')({
  server: {
    handlers: {
      POST: ({ request, params }) =>
        handlers.stream({ request, params: { key: params.key } }),
    },
  },
});

Discovery routes delegate in the same way:

src/routes/[.]well-known/agent-card[.]json.ts
export const Route = createFileRoute('/.well-known/agent-card.json')({
  server: {
    handlers: {
      GET: ({ request }) => handlers.manifest({ request }),
    },
  },
});

Root discovery routes may delegate to a runtime configured with /api/agent because the handler itself is transport-neutral. routes reports the canonical base-path-prefixed plan for inspection and tooling.

Payments and authentication

Payments are configured as a runtime extension. TanStack routes need no payment wrapper:

src/lib/agent.ts
import { createAgent } from '@lucid-agents/core';
import { http } from '@lucid-agents/http';
import { payments, paymentsFromEnv } from '@lucid-agents/payments';
import { createTanStackRuntime } from '@lucid-agents/tanstack';

const agent = await createAgent({
  name: 'paid-agent',
  version: '1.0.0',
})
  .use(payments({ config: paymentsFromEnv() }))
  .use(http({ basePath: '/api/agent' }))
  .addEntrypoint({
    key: 'premium',
    price: '0.01',
    async handler() {
      return { output: { result: 'premium content' } };
    },
  })
  .build();

export const { runtime, handlers, routes } = await createTanStackRuntime(agent);

The HTTP runtime uses one authorization path for invoke, stream, and task creation. x402, MPP, SIWX entitlements, payment-policy admission, settlement, and idempotency therefore match Hono and Express. If both x402 and MPP are installed, each priced entrypoint must set paymentProtocol: 'x402' | 'mpp'.

Tasks

The canonical route plan includes task routes only when a2a() is installed. A generated route module can still call a task handler without A2A, but it receives a structured 404 capability response.

Task creation accepts a 20–256 character Task-Access-Token header or generates a token and returns it with the task. List, get, cancel, and subscribe operations require the same token.

CLI templates

The CLI supplies two composable TanStack Start shells:

  • tanstack-headless provides the runtime route modules without a storefront.
  • tanstack-ui layers a minimal read-only endpoint table over the same headless route modules.
bunx @lucid-agents/cli my-agent --adapter=tanstack-headless
bunx @lucid-agents/cli my-agent --adapter=tanstack-ui

Exports

export {
  createTanStackRuntime,
  createTanStackHandlers,
} from '@lucid-agents/tanstack';

export type {
  TanStackHandlers,
  TanStackRequestHandler,
  TanStackRouteHandler,
  TanStackRuntime,
} from '@lucid-agents/tanstack';

On this page