aihu — The reactive Web Components framework

aihu aihu

Durable Web Components your AI agent can drive — not disposable UI it generates.

A complete Web Components framework — routing, SSR, auth, data, and deploy — where every component is also an MCP tool.

npx create-aihu my-app --template agent

Deployment

Build for production

bun run build
bun run preview

bun run build compiles all .aihu SFCs through the Rust compiler, bundles with Vite/Rolldown, and validates against the per-package size budgets in .size-limit.json. bun run preview serves the production build locally to verify output before deploying.

`defineAihuConfig`

The app configuration lives in aihu.config.ts:

import { defineAihuConfig } from '@aihu/server'

export default defineAihuConfig({
  build: {
    target: 'universal',
    outDir: 'dist',
    sourcemap: false,
  },
  plugins: [],
})

Build target options: 'client' (browser bundle only), 'server' (server bundle only), 'universal' (both, default).

Cloudflare Workers

Use @aihu/adapter-cloudflare to deploy to Cloudflare Workers or Pages:

// aihu.config.ts
import { defineConfig } from '@aihu/app'
import { cloudflare } from '@aihu/adapter-cloudflare'

export default defineConfig({
  adapter: cloudflare({ name: 'my-worker' }),
})

The adapter:

Adapter options:

Option Type Default Description
name string from package.json Cloudflare Worker name in wrangler.toml
mode 'workers' | 'pages' 'workers' Deployment target
generateWrangler boolean true Write wrangler.toml if absent

Deploy after build:

wrangler deploy --config wrangler.toml

For a manual Worker without the adapter, use @aihu/server's request router directly:

import { createRequestRouter, defineRoute, json } from '@aihu/server'

const router = createRequestRouter({
  routes: [
    defineRoute('/api/hello', () => json({ hello: 'world' })),
  ],
})

// Cloudflare Worker
export default { fetch: router }

Vercel

Use @aihu/adapter-vercel to deploy using the Vercel Build Output API v3:

// aihu.config.ts
import { defineConfig } from '@aihu/app'
import { vercel } from '@aihu/adapter-vercel'

export default defineConfig({
  adapter: vercel(),
})

The adapter:

Adapter options:

Option Type Default Description
runtime 'edge' | 'serverless' 'edge' Vercel function runtime
outputDir string '.vercel/output' Build Output API output directory
nodeVersion string 'nodejs18.x' Node.js version for serverless runtime

Deploy after build:

vercel deploy --prebuilt

Bun server

Run aihu server-side on Bun using @aihu/server's fetch-API router:

import { createRequestRouter, defineRoute, json } from '@aihu/server'
import { createAgentReadinessRoutes } from '@aihu-plugin/agent-readiness'

const ar = createAgentReadinessRoutes({
  name: 'My App',
  endpoint: 'https://myapp.example.com/mcp',
  summary: 'An aihu-powered app.',
})

const router = createRequestRouter({
  routes: [
    defineRoute('/llms.txt', ar.llmsTxt),
    defineRoute('/.well-known/mcp/server-card.json', ar.mcpServerCard),
    defineRoute('/robots.txt', ar.robotsTxt),
    defineRoute('/api/hello', () => json({ hello: 'world' })),
  ],
})

Bun.serve({ fetch: router })

Deno

The same router works on Deno Deploy — aihu uses only Web Standard APIs (Fetch, ReadableStream, URL):

import { createRequestRouter, defineRoute, json } from '@aihu/server'

const router = createRequestRouter({
  routes: [
    defineRoute('/api/hello', () => json({ hello: 'world' })),
  ],
})

Deno.serve(router)

Node.js

aihu output is standard ESM. Any Node.js ≥20.18.0 runtime can serve an aihu application:

npm run build
node dist/server/entry.js

The server entry is generated by the universal build and uses @aihu/server's request router.

On supported Node platforms @aihu/server lazily loads a native Rust addon to render SSR. Edge runtimes (Cloudflare, Vercel Edge, Deno) automatically skip it and use the TypeScript fallback. To force the fallback on Node — e.g. on an unsupported platform or to debug a parity issue — set AIHU_NATIVE_SKIP=1 in the server environment.

`viteRouterIntegration()` at build time

The Vite plugin performs these steps at build time:

  1. scanPages(dir) — discovers all .aihu files under src/pages/.
  2. For each page, reads the .route.json sidecar emitted by the Rust compiler.
  3. Assembles the route manifest into the virtual:aihu-routes module.
  4. Emits dist/routes.json for runtime consumption.

Route manifests are fully static after build — no filesystem scanning at runtime.