# Vercel Functions

Run a durable nanocode agent in Vercel Functions, with its journal kept as steps of a Workflow run, so a turn finishes after the Function that started it dies.

## Overview

`App.create` from `nanocode-ts/vercel` builds an agent on [durable-harness](https://github.com/vercel-labs/durable-harness). Each session is a Workflow run. Every SQL batch that the SDK commits is a step of that run, and each drive replays the batches into an in-memory `node:sqlite` database before it serves the SDK.

The agent exposes route handlers for prompts, events, plans, and hands. A Function that dies mid-turn is replaced by the Workflow queue, and the new Function finishes the turn from the log.

```ts title="lib/agent.ts"
import { App } from 'nanocode-ts/vercel'

// One Claude harness with one model, journaled to the session's Workflow run
export const nanocode = App.create({
  harnesses: [{ id: 'claude', label: 'Claude', models: [haiku] }],
  defaultSelection: { provider: 'claude', model: 'claude-haiku-5-5', thinking: 'low' },
})
```

## Walkthrough

The steps below build a Next.js app with one chat route, run it locally on the file World, and deploy it. They follow [nanocodexyz/durable-vercel](https://github.com/nanocodexyz/durable-vercel).

### Install the Packages

nanocode-ts is not on npm. Install its release tarball, which holds the compiled module and JavaScript, so the install builds no Rust.

```bash
# 1. The app framework and the durable kernel
npm install next react react-dom durable-harness @vercel/functions @vercel/oidc
# 2. nanocode-ts from a release tarball
npm install https://github.com/nanocodexyz/nanocode-ts/releases/download/build-a46c1c3/nanocode-ts-a46c1c3.tgz
```

### Define the Models

Each harness lists the models that a session may start with. A session's harness and model are fixed when it starts, and the route rejects any other selection.

```ts title="lib/settings.ts"
import { models } from 'nanocode-ts/models'

// Take the model's efforts and default from the package's catalog
const entry = models.harnesses
  .find((harness) => harness.id === 'claude')!
  .models.find((model) => model.id === 'claude-haiku-5-5')!

export const haiku = { id: entry.id, label: 'Haiku 5.5', name: entry.name, efforts: entry.efforts, effort: entry.effort }
```

### Create the Agent

`App.create` takes the harnesses, the default selection, and optional host tools, plans, and hands. With `durability: "on"`, the default, a write returns as soon as it runs locally and its batch commits in the background, in order.

```ts title="lib/agent.ts"
import { upgradeWebSocket } from '@vercel/functions'
import { App } from 'nanocode-ts/vercel'
import { haiku } from './settings'

export const nanocode = App.create({
  harnesses: [{ id: 'claude', label: 'Claude', models: [haiku] }],
  defaultSelection: { provider: 'claude', model: 'claude-haiku-5-5', thinking: 'low' },
  // Let nc hand dial the Function over a WebSocket
  hands: { upgrade: upgradeWebSocket },
  durability: 'on',
})
```

### Add the Route

The agent's `GET` and `POST` handlers serve prompts and the event stream. Give the route the longest duration the plan allows, since one drive runs a turn until it ends or the Function stops.

```ts title="app/api/chat/route.ts"
import { nanocode } from '@/lib/agent'

// A drive runs for up to five minutes before the queue takes over
export const maxDuration = 300
export const { GET, POST } = nanocode
```

### Wrap the Config

`withDurableHarness` adds the Workflow routes. Name the file that creates the agent, so the build does not scan every source file.

```ts title="next.config.ts"
import type { NextConfig } from 'next'
import { withDurableHarness } from 'durable-harness/next'

// The Workflow routes for the agent in lib/agent.ts
export default withDurableHarness({} satisfies NextConfig, { agents: ['lib/agent.ts'] })
```

### Run and Deploy

Locally, the Workflow World keeps its log in files, and model requests go to the Vercel AI Gateway with the OIDC token that `vercel env pull` writes. On Vercel, the deployment's own OIDC token signs them.

```bash
# 1. Link the project and pull its OIDC token for the AI Gateway
vercel link && vercel env pull
# 2. Run locally, then deploy
npm run dev
vercel deploy --prod
```

## Recipes

### Add a Host Tool

A host tool is a durable-harness `HostTool`. Each call runs as a Workflow step keyed by the call ID, with the tool's own `replay` rule, and `io.stepId` names the step. A `replay: "never"` tool, such as a payment, waits for every earlier write before it runs, and a crash during it reaches the model as an unknown outcome.

```ts title="lib/agent.ts"
import type { HostTool } from 'durable-harness'

// A payment must never run twice, so the kernel never replays it
const charge: HostTool<{ amount: number }> = {
  name: 'charge',
  description: 'Charge the customer a number of dollars.',
  inputSchema: { type: 'object', properties: { amount: { type: 'number' } }, required: ['amount'] },
  replay: 'never',
  // The step ID stays the same if the step runs again, so it keys the payment
  execute: async ({ amount }, io) => payments.charge({ amount, idempotencyKey: io.stepId }),
}

export const nanocode = App.create({ harnesses, defaultSelection, tools: [charge] })
```

### Use a Visitor's Plan

With `plans`, a visitor signs in with a ChatGPT or Claude plan, and the session's model requests use it. The credential stays sealed in the project's Redis.

```ts title="app/api/plans/[[...path]]/route.ts"
import { nanocode } from '@/lib/agent'

// The sign-in API for the visitor's ChatGPT and Claude plans
export const { GET, POST, DELETE } = nanocode.plans!
```

### Crash a Turn

With `chaos: true`, the agent's `chaos` handler arms a crash: the next tool call kills its Function 1.5 s in. The demo's `npm run drill` does the same in two local processes and checks that the ledger holds one charge.

```bash
# Kill a turn mid-charge, recover it, and check the ledger
npm run drill claude,codex on,strict charge
```

## More

- [durable-vercel](https://github.com/nanocodexyz/durable-vercel): The full app, its drill, and its measurements.

- [Durable Nanocode on Vercel](/experiments/durable-nanocode#on-vercel): How the Workflow run becomes the journal.

- [nanocode-ts](/docs/guides/nanocode-ts): The module and its adapters.

- [Durability](/docs/guides/durability): Replay rules and unknown outcomes.
