| name | integrating-glirastes-nextjs |
| description | Integrating the Glirastes SDK into a Next.js App Router project — chat route handler, VercelAiChat widget, co-located ai-tool.ts files, codegen pipeline. Use when adding AI chat to a Next.js app where Next.js itself is the backend. |
| version | 1.0.0 |
| tags | ["glirastes","nextjs","ai","app-router"] |
| triggers | ["integrate glirastes","integrate glirastes nextjs","add glirastes to next","add chat to next.js","createAiChatHandler","VercelAiChat","chat route nextjs","ai chat next.js"] |
Integrating Glirastes into Next.js
Scope: Next.js is the only backend in this project. If a separate NestJS / Express backend exists, use integrating-glirastes-nestjs instead — putting the chat route on the real backend avoids duplicate auth and an extra HTTP hop per tool call.
Companion skills:
Stack detection
Confirm before applying:
next.config.{ts,js,mjs} exists at the project root → Next.js ✅
- No
nest-cli.json or sibling backend workspace
package.json shows React 19+, Next.js 15+
If a NestJS backend lives in the same workspace (e.g. apps/api/), stop and use the NestJS skill — the chat route belongs there.
Step 1 — Install
npm install glirastes @ai-sdk/openai
npm install @ai-sdk/react react-markdown
npm install wavesurfer.js
@ai-sdk/openai is the OpenAI provider. Swap for @ai-sdk/anthropic, @ai-sdk/mistral, etc. — Glirastes accepts any AI SDK v6 provider.
Step 2 — Environment variables
Add to .env.local:
OPENAI_API_KEY=sk-...
# Optional — unlocks Glirastes platform features (PII Shield, intent routing, telemetry)
# GLIRASTES_API_KEY=glir_...
API keys must stay server-side. Next.js Route Handlers run on the server, so this is safe — never reference OPENAI_API_KEY from a client component.
Step 3 — File structure convention
Co-locate ai-tool.ts next to the route it wraps. The codegen scanner discovers tools by this convention:
src/app/api/
├── chat/route.ts # createAiChatHandler with the registry
├── tasks/
│ ├── route.ts # The actual API handler
│ └── ai-tool.ts # AI-callable wrapper (defineEndpointTool)
├── tasks/[id]/
│ ├── route.ts
│ └── ai-tool.ts
└── users/search/
├── route.ts
└── ai-tool.ts
src/components/
├── tasks/ai-ui-tool.ts # UI tool definitions (defineUiTool)
└── layout/ai-ui-tool.ts
src/generated/ai-tools/
├── endpoint.generated.ts # AUTO — produced by `glirastes generate-tools`
├── ui.generated.ts
├── modules.generated.ts
└── action-ids.generated.ts
Ignore the src/generated/ai-tools/ directory in your editor — it's regenerated by the CLI on every predev / prebuild.
Step 4 — Bootstrap your first tool
Use the CLI scaffolder. Pass an existing route file:
npx glirastes scaffold --route src/app/api/tasks/route.ts
The scaffolder analyzes the route (HTTP methods, path params, body fields, search params) and emits a starter src/app/api/tasks/ai-tool.ts:
import { z } from 'zod';
import { defineEndpointTool } from 'glirastes';
export const aiTool = defineEndpointTool({
id: 'tasks.list',
toolName: 'list_tasks',
module: 'task_query',
description: 'list tasks. TODO: write a clear description for the AI.',
method: 'GET',
path: '/api/tasks',
inputSchema: z.object({
status: z.enum(['open', 'done']).optional(),
}),
});
Edit description (the LLM reads this to decide when to call the tool), refine the schema, optionally add a uiPattern. For the full tool authoring API, see maintaining-glirastes-tools.
Step 5 — Wire the chat route handler
Two paths depending on tool count:
Few tools (≤5) — manual import
import { openai } from '@ai-sdk/openai';
import { endpointToolsToRegistry } from 'glirastes/server';
import { createAiChatHandler } from 'glirastes/server/nextjs';
import { aiTool as listTasks } from '../tasks/ai-tool';
export const POST = createAiChatHandler({
tools: endpointToolsToRegistry([listTasks]),
model: openai('gpt-4o-mini'),
systemPrompt: 'You are a helpful assistant for our app.',
});
OK as a starting point. The moment you go past a handful of tools, switch to the codegen pipeline below — manual maintenance of the import list breaks down fast.
Production: codegen pipeline (required for non-trivial apps)
In Glirastes 0.3.x the canonical Next.js setup is to wire the codegen as a build hook. Add to package.json:
{
"scripts": {
"predev": "glirastes generate-tools --quiet",
"prebuild": "glirastes generate-tools --quiet",
"ai:scaffold": "glirastes scaffold",
"ai:coverage": "glirastes coverage",
"ai:coverage:ci": "glirastes coverage --ci",
"ai:validate": "glirastes validate-tools",
"ai:validate:ci": "glirastes validate-tools --ci"
}
}
The predev and prebuild hooks regenerate the registry on every dev server start and CI build, so the generated files stay in sync with your *.ai-tool.ts source-of-truth. Without these hooks the chat route imports would point at stale generated output.
Coming in 0.4.0: buildToolRegistry based on import.meta.glob / require.context will let you skip the codegen step and the build hook entirely. Until then, the codegen pipeline is the supported pattern for any non-trivial Next.js app.
Then import the generated registry instead of individual tools:
import { openai } from '@ai-sdk/openai';
import { createAiChatHandler } from 'glirastes/server/nextjs';
import { endpointToolRegistry } from '@/generated/ai-tools/endpoint.generated';
import { uiToolRegistry } from '@/generated/ai-tools/ui.generated';
export const POST = createAiChatHandler({
tools: { ...endpointToolRegistry, ...uiToolRegistry },
model: openai('gpt-4o-mini'),
systemPrompt: 'You are a helpful assistant for our app.',
});
The registries are typed as ToolRegistry (Record<string, Tool>) — pass them straight to createAiChatHandler({ tools }).
Step 6 — Mount the chat widget
Client-side component, then drop into the root layout:
'use client';
import { VercelAiChat } from 'glirastes/react/vercel';
export function ChatWidget() {
return <VercelAiChat endpoint="/api/chat" />;
}
import { ChatWidget } from '@/components/chat/ChatWidget';
import 'glirastes/react/styles.css';
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html>
<body>
{children}
<ChatWidget />
</body>
</html>
);
}
For UI customization (props on VercelAiChat, theming, mentions, voice input, custom approval cards), see building-glirastes-chat-ui.
Step 7 — Verify
Run the codegen + production build first — surfaces most issues:
npm run ai:validate
npm run ai:coverage
npm run build
Build output should list /api/chat as a dynamic route (ƒ /api/chat). Then:
npm run dev
Open the app, click the floating chat trigger (bottom-right by default), send a message that should fire your tool ("show me my open tasks"). The tool result must show up; uiPattern actions fire automatically (e.g. filter-and-navigate rewrites the URL).
Step 8 — Hook up frontend UI actions (optional)
If your tools declare uiPattern: { type: 'open-dialog' | 'open-detail' | 'refresh' | 'toast' }, the SDK derives an action ID and fires it through the UiActionBus. Register handlers anywhere a relevant component mounts:
'use client';
import { useAiClientAction } from 'glirastes/react';
import { useRouter } from 'next/navigation';
export function TaskList() {
const router = useRouter();
useAiClientAction('task-details.open', (payload) => {
router.push(`/tasks/${payload?.taskId}`);
});
}
Action IDs are derived from uiPattern:
uiPattern.type | Action ID |
|---|
open-detail, entity: 'task' | task-details.open |
open-dialog, dialog: 'create-task' | task-create-dialog.open |
refresh, target: 'tasks' | tasks.refresh |
toast | dispatched directly via your toast lib (sonner/react-hot-toast) |
glirastes coverage reports any UI action ID declared in tools but not handled in .tsx files (and vice versa).
CLI quick reference
| Command | Purpose | Common flags |
|---|
glirastes scaffold --route <file> | Create ai-tool.ts next to a route.ts | --dry-run, --force |
glirastes generate-tools | Scan all *.ai-tool.ts files, emit src/generated/ai-tools/*.generated.ts | --quiet (predev/prebuild) |
glirastes generate-endpoint-tools | Endpoint registry only | --quiet |
glirastes generate-ui-tools | UI tool registry + action IDs | --quiet |
glirastes generate-modules | Module/intent registry | --meta @/lib/ai/module-meta |
glirastes generate-auto | Auto-detect repo layout, run the right generator | — |
glirastes validate-tools | Validate naming, duplicates, missing approvals | --ci, --fix, --quiet |
glirastes coverage | Report routes without ai-tool.ts, orphan handlers | --ci, --quiet |
glirastes test | Scaffold an AI behavior test file | — |
glirastes generate-skills | Export current tool registry as Claude Code / Codex skills (for agents to call your tools) | --app-name, --base-url, --auth bearer |
glirastes generate-mcp-server | Export current tool registry as a standalone MCP server project | --app-name, --base-url |
glirastes generate <openapi.yaml> | Generate endpoint tools from an OpenAPI spec | --out <file> |
glirastes check-upgrade | Analyze release notes for breaking changes against your code | --from-version <ver> |
glirastes sync | Upload tool schemas to the Glirastes platform (Pro) | --api-key (or GLIRASTES_API_KEY env) |
For the full deep-dive, see maintaining-glirastes-tools.
Common pitfalls
| Symptom | Cause | Fix |
|---|
Cannot resolve '@ai-sdk/react' at build | Optional peer not installed | npm install @ai-sdk/react react-markdown |
Cannot resolve 'wavesurfer.js/dist/plugins/record.esm.js' | Voice input components reachable in bundle without peer | Either install wavesurfer.js or set showMic={false} on <VercelAiChat /> |
| Chat widget unstyled | styles.css not imported | Add import 'glirastes/react/styles.css' to root layout |
| Tool never fires | path mismatches the actual route | Endpoint tool's path must match the URL the route handler serves exactly |
OPENAI_API_KEY is not configured | Env var missing | .env.local + restart dev server (Next caches env at startup) |
endpointToolRegistry is undefined | Codegen script never ran | npm run predev or run glirastes generate-tools once manually |
| LLM ignores a tool | Description missing or vague | Rewrite to "WHEN to call: ... WHAT it returns: ..." in the description |
UI action task-details.open fires but nothing happens | No useAiClientAction registered | Add handler in a mounted component; verify with glirastes coverage |
| OpenAPI spec generation fails | Spec not validated | Run glirastes validate <openapi.yaml> first |
What this skill does NOT cover
- NestJS adapter — see integrating-glirastes-nestjs
- Tool authoring deep-dive (UI patterns, output schemas, approvals,
module/sharedWith, classification metadata) — see maintaining-glirastes-tools
- Chat UI customization (theming, mentions, voice input, approval cards, action bus, ChatWindow portal) — see building-glirastes-chat-ui
- LangGraph transport — replace
createAiChatHandler + VercelAiChat with the LangGraph variants from glirastes/server/nextjs and glirastes/react/langgraph
- Glirastes platform features (PII Shield via
createPiiShield, intent routing via createLancer, guardrails, usage telemetry) — opt in via GLIRASTES_API_KEY env var; the SDK falls back to free-tier behaviour without it