For the complete documentation index, see llms.txt. Prefer markdown by appending.mdto documentation URLs or sendingAccept: text/markdown.
Integrate AI Kit
Port complete AI templates into Core Kit while keeping Core authentication, billing, API, database, and application structure intact.
Core Kit already includes a small authenticated streaming chat endpoint. AI Kit adds complete product slices: persisted chat, model selection, attachments, web search, image generation, RAG, text to speech, voice, and a credits example.
Treat the integration as a feature port, not a repository merge. Keep Core Kit as the owner of shared infrastructure, then bring over only the AI capabilities your product needs.
Do not merge the repositories wholesale
Both kits define apps/web, packages/api, packages/auth, packages/db, packages/i18n, packages/shared, packages/storage, and UI packages. Replacing those directories with their AI Kit versions removes Core features such as organizations, billing, admin, email, analytics, and monitoring.
The paths below assume both repositories are cloned next to each other:
Decide ownership
Use Core Kit as the source of truth for the application shell. AI Kit should contribute feature code behind those existing boundaries.
| Concern | Keep from Core Kit | Port from AI Kit |
|---|---|---|
| Authentication | Better Auth config, account flows, organizations, hooks | AI routes that consume c.var.user.id |
| Billing and access | Plans, subscriptions, feature access | Credit costs only if your product needs a separate credit balance |
| API | Existing Hono app, middleware, error handling | AI route files under packages/api/src/modules/ai |
| Database | Existing auth and billing schema | Selected AI schemas such as chat.ts, rag.ts, and image.ts |
| Storage | Existing @workspace/storage package and credentials | AI upload paths and attachment logic |
| UI and i18n | Core packages, theme, layouts, translations | Feature-specific components, routes, and strings |
This ownership rule is the main protection against difficult future updates. A shared package has one owner; imported AI features adapt to it.
Choose a first vertical slice
Start with one template and make it work end to end before adding another.
| Template | AI package | Database schema | Web surface |
|---|---|---|---|
| Chat | packages/ai/core, packages/ai/chat | chat.ts, optional credits | modules/chat, (apps)/chat |
| Image | packages/ai/core, packages/ai/image | image.ts, optional credits | modules/image, (apps)/image |
| RAG | packages/ai/core, packages/ai/rag | rag.ts, pgvector | modules/rag, (apps)/rag |
| Text to speech | packages/ai/core, packages/ai/tts | Optional credits only | modules/tts, (apps)/tts |
| Voice | packages/ai/core, packages/ai/voice | Optional credits only | modules/voice, (apps)/voice |
Chat is the best first integration because it exercises authentication, streaming, persistence, storage, and provider configuration without native dependencies.
Copy the selected AI packages
Copy ../ai/packages/ai/core and the feature package you selected into packages/ai/. Keep their package names, such as @workspace/ai and @workspace/ai-chat, so the source imports continue to resolve.
mkdir -p packages/ai
cp -R ../ai/packages/ai/core packages/ai/core
cp -R ../ai/packages/ai/chat packages/ai/chatDo not copy ../ai/pnpm-lock.yaml. Merge the required entries from AI Kit's pnpm-workspace.yaml into Core Kit's catalogs, then run pnpm install from Core Kit so pnpm resolves one version per dependency.
Copy dependencies from the selected package's package.json rather than installing every provider. For example, the chat package lists its model and web-search providers in ../ai/packages/ai/chat/package.json.
Merge the database schema
Copy only the schema files used by the selected template into packages/db/src/schema/. Do not replace Core Kit's auth.ts, billing.ts, or the existing migration history.
AI Kit groups template tables into PostgreSQL schemas such as chat, rag, and image. The files reference Core Kit's existing user table, so authenticated and anonymous Core users can own AI data without a second identity system.
Merge the exports into the existing index:
export * from "./auth";
export * from "./billing";
export * from "./chat";AI Kit's credit example defines a customer table in customer.ts. Core billing already defines its own customer, so do not copy that file unchanged. Choose one design:
- Rename the AI table and exports to a dedicated
ai_creditor credit-ledger model if credits are separate. - Replace
deductCreditswith plan or entitlement checks if AI usage belongs to a Core subscription. - Remove the credit middleware and UI if the feature is unlimited.
RAG also requires the PostgreSQL vector extension. Use a database image or hosted provider with pgvector, enable CREATE EXTENSION vector, and include that change in the migration review.
Generate a new migration from the combined schema:
pnpm with-env pnpm --filter @workspace/db db:generate
pnpm with-env pnpm --filter @workspace/db db:migrateReview the generated SQL before applying it to an existing production database. It should add the selected AI tables and schemas, not recreate Core auth tables.
Replace the demo AI route with the selected routers
Core Kit already mounts aiRouter at /api/ai in packages/api/src/index.ts. AI Kit uses the same mount point, so preserve Core's Hono app and replace the small packages/api/src/modules/ai/router.ts implementation with the selected nested routers.
For chat, port:
../ai/packages/api/src/modules/ai/chat.ts
../ai/packages/api/src/modules/ai/router.tsThen add the selected workspace packages to packages/api/package.json. Keep Core Kit's existing middleware.ts, and port only the AI-specific deductCredits logic if you kept credits. Core's enforceAuth already resolves the session and sets c.var.user.
Route collision
The Core example exposes POST /api/ai/chat. AI Kit chat exposes its persisted operations below /api/ai/chat/chats, plus model and sharing routes. Remove or rename the example route before registering the AI Kit router.
Keep provider SDKs and provider keys in the server-side AI packages. Browser components should only call the Hono API.
Port the web feature
Copy the selected route group and feature module from AI Kit:
../ai/apps/web/src/app/[locale]/(apps)/chat
../ai/apps/web/src/modules/chatChat also imports shared AI application components from ../ai/apps/web/src/modules/common. Copy the components reached by the feature's imports, but adapt them to Core's existing app layout, navigation, auth client, query provider, theme, and UI package. Do not replace Core's root layout.
Use Core's authenticated dashboard when the AI feature is part of the product. A typical destination is:
apps/web/src/app/[locale]/dashboard/(user)/chat
apps/web/src/modules/ai/chatMoving the files is optional, but keeping AI product features under the dashboard makes Core authorization and navigation boundaries explicit.
Merge the selected app dependencies from ../ai/apps/web/package.json. In particular, persisted chat uses @ai-sdk/react on the client while provider SDKs remain dependencies of the server-side AI package.
Port the AI elements imported by the feature from ../ai/packages/ui/web/src/components/ai-elements and merge the ai translation namespace from ../ai/packages/i18n/src/translations. Add each new @workspace/ai* package to Core's INTERNAL_PACKAGES list in apps/web/next.config.ts so Next.js transpiles workspace source.
Voice also runs @workspace/ai-voice as a separate LiveKit worker. Copying its web screen does not deploy that worker.
Merge environment validation
Copy variable definitions, not .env files. Add only the providers and tools used by your selected feature to:
apps/web/.env.exampleapps/web/env.config.ts- The relevant package
env.tspresets apps/web/turbo.jsonfor variables required by build or dev tasks- Your deployment environment
For a Gateway-backed chat, the minimal provider variable is:
AI_GATEWAY_API_KEY=""Attachments also need the existing Core storage variables. Web search needs the key for the strategy you enable, such as TAVILY_API_KEY, BRAVE_SEARCH_API_KEY, EXA_API_KEY, or FIRECRAWL_API_KEY.
Do not expose provider keys with NEXT_PUBLIC_.
Verify the integrated slice
Run the checks from the Core repository:
pnpm install
pnpm lint
pnpm --filter web buildThen verify the behavior that crosses package boundaries:
- Sign in with a normal Core account and, if enabled, an anonymous account.
- Send a request and confirm the response streams.
- Reload and confirm persisted content still belongs to the same user.
- Try to request another user's chat directly and expect an authorization failure.
- Upload an attachment if the selected feature uses storage.
- Confirm rate limits and plan or credit checks fail before invoking a paid provider.
Production readiness
The template gives you the feature shape. Before charging users, tighten the boundaries that retries and long streams exercise:
- Make usage or credit deductions idempotent with a generation or message ID.
- Pass
c.req.raw.signalinto model calls so cancelled requests stop provider work. - Persist provider usage separately from product credits for reconciliation.
- Add structured AI telemetry without recording prompts or sensitive attachments by default.
- Use resumable streams backed by durable state if conversations must survive navigation, reconnects, or multiple server instances.
- Rate-limit by authenticated user or organization, with an IP fallback for anonymous traffic.
Other client platforms
The server integration is shared. Once the web slice works, add only the client layer required by each platform:
How is this guide?
Last updated on