Start with a normal Nuxt app. Agentuity adds service clients, local development support, and deploy validation around Nitro server routes and build output.
Create a Starter
npm create agentuity -- --name my-nuxt-app --framework nuxt
cd my-nuxt-appThe starter runs nuxi init, adds @agentuity/cli, a deploy script, and an optional AI example. It uses Nuxt's server/api/ convention for server routes, the same shape documented by Nuxt's own server directory guide.
If you choose the AI example, the key files are:
| File | Purpose |
|---|---|
server/api/translate.post.ts | Nitro route that handles POST /api/translate |
app/app.vue | UI that calls the API route with $fetch |
nuxt.config.ts | Nuxt configuration in the normal Nuxt shape |
Import an Existing App
For an existing Nuxt app, add the CLI and import the project:
npm install -D @agentuity/cli
npx agentuity project import --validate-only
npx agentuity project importnpm install -D installs the CLI as a project-local dev dependency, not a global install. Use npx to run that local CLI. For Bun, pnpm, and Yarn equivalents, see Local versus global CLI.
agentuity project import registers the app and writes the local project metadata that agentuity deploy expects. Run it once before the first deploy for existing apps.
See Add Agentuity to an existing app for validation, import, the Invalid project folder deploy case, and first deploy.
What Agentuity adds
| Area | Nuxt keeps | Agentuity adds |
|---|---|---|
| routing | Nitro handlers in server/api/ | service clients imported in server-only files |
| local dev | nuxt dev | agentuity dev supplies service credentials |
| build | Nitro output under .output/ | agentuity build runs the build and packages launch metadata |
| deploy | the Nitro server entry | agentuity deploy ships the packaged app |
Add a Service Client and AI Gateway Call
Use standalone service clients directly from Nitro routes. Files under server/api/ are automatically prefixed with /api, and the .post.ts suffix limits this example to POST requests.
The route below uses AIGatewayClient for the model call. The project SDK key authenticates the request, and the model ID is app configuration or request input.
npm install @agentuity/aigateway @agentuity/keyvalue arktypeimport { AIGatewayClient } from '@agentuity/aigateway';
import { KeyValueClient } from '@agentuity/keyvalue';
import { type } from 'arktype';
import { defineEventHandler, getCookie, readBody, setCookie, setResponseStatus } from 'h3';
const DEFAULT_MODEL = 'openai/gpt-5.4-mini';
const HISTORY_NAMESPACE = 'translation-history';
const SESSION_COOKIE = 'agentuity_session';
const SESSION_TTL_SECONDS = 60 * 60 * 24 * 30;
interface HistoryEntry {
readonly model: string;
readonly sessionId: string;
readonly text: string;
readonly timestamp: string;
readonly toLanguage: string;
readonly translation: string;
}
interface HistoryState {
readonly history: readonly HistoryEntry[];
readonly translationCount: number;
}
// Validate the request body at the boundary before using any values
const requestSchema = type({
text: 'string',
toLanguage: 'string',
'model?': 'string',
});
const kv = new KeyValueClient();
const gateway = new AIGatewayClient();
export default defineEventHandler(async (event) => {
const rawBody: unknown = await readBody(event);
const parsed = requestSchema(rawBody);
if (parsed instanceof type.errors) {
setResponseStatus(event, 400);
return { error: 'text and toLanguage are required' };
}
const input = parsed;
const model = input.model ?? DEFAULT_MODEL;
// Read or create a session cookie so history is scoped per browser session
const sessionId = getCookie(event, SESSION_COOKIE) ?? crypto.randomUUID();
setCookie(event, SESSION_COOKIE, sessionId, {
httpOnly: true,
maxAge: SESSION_TTL_SECONDS,
path: '/',
sameSite: 'lax',
// set secure when running in production
secure: process.env.NODE_ENV === 'production',
});
const result = await gateway.completeText({
model,
messages: [
{
role: 'user',
content: `Translate to ${input.toLanguage}:\n\n${input.text}`,
},
],
});
if (!result.hasText) {
setResponseStatus(event, 502);
return { error: 'model returned no text' };
}
const translation = result.text;
// Append to the per-session history stored in KV, keeping the last 5 entries
const previous = await kv.get<HistoryState>(HISTORY_NAMESPACE, sessionId);
const history = [
...(previous.exists ? previous.data.history : []),
{
model,
sessionId,
text: input.text,
timestamp: new Date().toISOString(),
toLanguage: input.toLanguage,
translation,
},
].slice(-5);
const translationCount = (previous.exists ? previous.data.translationCount : 0) + 1;
await kv.set(HISTORY_NAMESPACE, sessionId, { history, translationCount }, { ttl: SESSION_TTL_SECONDS });
return {
translation,
history,
model,
translationCount,
};
});KeyValueClient reads AGENTUITY_SDK_KEY from the environment. Run with agentuity dev for local development so the linked project key is available to Nitro routes.
Use the model id exactly as it appears in the AI Gateway model catalog. Use a provider SDK directly only when the endpoint depends on provider-specific APIs.
Call from the Frontend
Call the Nitro route from app/app.vue using Nuxt's built-in $fetch:
<script setup lang="ts">
const text = ref('Welcome to Agentuity');
const toLanguage = ref('Spanish');
const translation = ref('');
const history = ref<Array<{ text: string; translation: string; toLanguage: string }>>([]);
async function translate(): Promise<void> {
const result = await $fetch<{
translation: string;
history: typeof history.value;
}>('/api/translate', {
method: 'POST',
body: { text: text.value, toLanguage: toLanguage.value },
});
translation.value = result.translation;
history.value = result.history;
}
</script>
<template>
<div>
<textarea v-model="text" />
<select v-model="toLanguage">
<option>Spanish</option>
<option>French</option>
<option>German</option>
</select>
<button @click="translate()">Translate</button>
<p v-if="translation">{{ translation }}</p>
</div>
</template>Run Locally
Run through Agentuity. When the linked project key is available, the CLI supplies AGENTUITY_SDK_KEY to the Nuxt process:
agentuity devSmoke-test the Nitro route directly:
curl http://localhost:3000/api/translate \
-H "content-type: application/json" \
-d '{"text":"Hello","toLanguage":"Spanish"}'Deployed Environment Variables
Configure the variables your deployed app needs. Direct AIGatewayClient calls use AGENTUITY_SDK_KEY; the model ID in this example is normal app configuration or request input.
| Variable | Used by |
|---|---|
AGENTUITY_SDK_KEY | Agentuity service clients and @agentuity/aigateway |
DATABASE_URL | database Nitro routes |
AWS_* | object storage Nitro routes; see Object Storage for exact variables |
Validate Before Deploy
Run the framework build when you want Nuxt-only feedback, then run the Agentuity build. agentuity build runs the framework build during packaging and writes .agentuity/launch.json.
npm run build
npx agentuity buildNuxt is detected as its own framework (nuxt, nuxt3, nuxt-edge, or nuxt-nightly in dependencies). The build adapter packages the Nitro output. Verify the metadata points at the right paths:
cat .agentuity/launch.jsonThe Nitro build produces two output directories:
| Path | Contents |
|---|---|
.output/server | Nitro server bundle, entry is server/index.mjs |
.output/public | Static assets for CDN or edge delivery |
launch.json must reference the server/index.mjs entry inside .output/server. If it points at a static _serve.js helper, the packaged output is not serving Nitro routes.
Deploy only after the framework build, Agentuity build, and a local packaged validation of / and one Nitro route pass:
agentuity deploy --confirmCommon Gotchas
| Symptom | Check |
|---|---|
| Route exists locally but returns 404 after deploy | Confirm the file is under server/api/, not server/routes/; only server/api/ gets the /api prefix |
$fetch('/api/...') works locally but 404s after deploy | Inspect .agentuity/launch.json: processes[0].command must run .output/server/index.mjs |
| Service client returns auth errors | Run with agentuity dev or set AGENTUITY_SDK_KEY in the environment |
| Model call returns an auth error | Verify AGENTUITY_SDK_KEY is available to the Nitro process. See AI Gateway |
| Server credentials leak to the browser | Keep KeyValueClient and AIGatewayClient instantiation in server/api/ or other server-only files; Nitro does not bundle server files into the client |
| Cookie flags rejected by browser | secure: true requires HTTPS; for local testing use secure: process.env.NODE_ENV !== 'development' |
Framework Docs
- Nuxt
server/directory: confirmserver/apirouting, HTTP method suffixes, and h3 helpers - Nuxt deployment: Nitro output targets and how to match build output to your runtime
Next Steps
- Key-Value Storage: store short-lived state from Nitro routes
- AI Gateway: route provider SDK calls through Agentuity
- App Configuration: configure
agentuity.json, env vars, and scripts - Build Configuration: inspect launch metadata and packaging output