Most agent frameworks ask you to wire everything up in code: register tools in an array, configure a runtime, plug in a queue for background work, and bolt on observability later. eve, the open-source agent framework Vercel announced on June 17, 2026, takes the opposite approach. It is filesystem-first: you describe an agent with files in conventional locations, and eve discovers them, compiles a manifest, and serves a durable backend that runs on Vercel Functions.
If you have built a Next.js app, the mental model will feel familiar — eve has been called "Next.js for agents." A file in tools/ becomes a callable tool. A file in schedules/ becomes a cron job. A file in channels/ becomes a Slack or HTTP entry point. There is almost no registration boilerplate.
In this tutorial you'll build a small but complete research assistant agent from scratch, then layer on tools, a skill, durability, a subagent, and a schedule. By the end you'll understand the whole eve project shape and be ready to deploy.
Prerequisites
Before starting, ensure you have:
- Node.js 20+ installed
- pnpm (or npm) available on your
PATH - Comfort with TypeScript and
async/await - A free Vercel account (only needed for the deploy step)
- A code editor (VS Code recommended)
You do not need any model provider API keys to follow along locally with the scaffold. On Vercel, model strings resolve through AI Gateway using OIDC, so you never manage provider keys directly.
eve is in beta at the time of writing. The folder conventions described here are stable, but exact helper signatures may shift before general availability. Always check the generated README in your scaffold.
What You'll Build
A research assistant agent that can:
- Answer questions using a typed
web_searchtool and asave_notetool. - Load a multi-step "research report" skill only when a deep task calls for it.
- Run as a durable session that survives cold starts and redeploys.
- Delegate focused subtasks to a subagent.
- Post a weekly recap on a schedule.
We'll build it incrementally so each concept stands on its own.
Step 1: Scaffold the Project
The fastest path is the eve CLI. It creates the directory, installs dependencies, initializes Git, and starts the dev server:
npx eve@latest init research-agentWhen it finishes, stop the dev server (so you can edit files cleanly) and open the project:
cd research-agentYou'll see an agent/ directory at the heart of the project. Everything that defines your agent lives under agent/. This is the layout eve discovers automatically:
research-agent/
├─ agent/
│ ├─ agent.ts # runtime config (model, options)
│ ├─ instructions.md # the always-on system prompt
│ ├─ tools/ # one typed tool per file
│ ├─ skills/ # on-demand procedures
│ ├─ subagents/ # child agents for delegation
│ ├─ channels/ # entry points (HTTP, Slack, ...)
│ ├─ schedules/ # cron jobs
│ └─ sandbox/ # isolated compute environment
├─ package.json
└─ README.mdTo add eve to an existing app instead, run npx eve@latest init . in that project, or install the packages manually:
pnpm add eve ai zodStep 2: Define the Agent
A minimal agent is just two files. First, the system prompt in agent/instructions.md. This is the always-on context — keep it short and behavioral:
You are a focused research assistant.
- Use the available tools when they help answer a question.
- When asked for a thorough write-up, load the research report skill.
- Always cite where a fact came from. If you are unsure, say so.Next, the runtime config in agent/agent.ts. The single most important setting is the model:
import { defineAgent } from 'eve';
export default defineAgent({
model: 'anthropic/claude-opus-4.8',
});That model string resolves through AI Gateway, so swapping providers later is a one-line change — for example openai/gpt-5.4-mini for a cheaper, faster default. AI Gateway also handles provider fallbacks, which keeps your agent responsive when a single provider has a bad day.
Start the dev server to confirm everything compiles:
pnpm devStep 3: Add Your First Tool
Tools are typed actions the model can call during a turn. The rule is simple: each file in agent/tools/ is one tool, and the filename becomes the tool name the model sees. No central registry.
Create agent/tools/web_search.ts. The model will see this as a tool named web_search:
import { defineTool } from 'eve/tools';
import { z } from 'zod';
export default defineTool({
description: 'Search the web for recent information about a topic.',
inputSchema: z.object({
query: z.string().min(1).describe('The search query'),
limit: z.number().int().min(1).max(10).default(5),
}),
async execute({ query, limit }) {
// Replace this with a real search provider in production.
const results = Array.from({ length: limit }, (_, i) => ({
title: `Result ${i + 1} for "${query}"`,
url: `https://example.com/${encodeURIComponent(query)}/${i + 1}`,
}));
return { query, results };
},
});A few things to notice:
- The
inputSchemais a Zod schema. eve uses it to validate model arguments and to generate the JSON schema the model sees, so descriptions on each field guide the model toward correct calls. executereceives the validated input as its first argument. Whatever you return is serialized back to the model as the tool result.- There is no
namefield — the filenameweb_search.tsis the name. This is why eve favorssnake_casefilenames.
Add a second tool so the agent can persist findings. Create agent/tools/save_note.ts:
import { defineTool } from 'eve/tools';
import { z } from 'zod';
export default defineTool({
description: 'Save a short research note for later reference.',
inputSchema: z.object({
title: z.string(),
body: z.string(),
}),
async execute({ title, body }, ctx) {
// The second argument is the tool context. It exposes the sandbox,
// logging, and session metadata. Here we write to the agent sandbox.
await ctx.sandbox.writeFile(
`notes/${title.replace(/\s+/g, '-').toLowerCase()}.md`,
`# ${title}\n\n${body}\n`,
);
return { saved: true, title };
},
});The second parameter, ctx, is the tool context. It gives you the agent's sandbox — an isolated, bash-style filesystem each eve agent gets — along with logging and session metadata. Framework tools like bash, read_file, and write_file target this same sandbox, so your authored tools and the built-in ones share one environment.
Step 4: Talk to Your Agent
eve exposes HTTP routes for starting and streaming durable sessions. Start a session with a POST:
curl -X POST http://127.0.0.1:3000/eve/v1/session \
-H 'content-type: application/json' \
-d '{"message":"What is Vercel eve and why does it matter?"}'The response body contains a continuationToken, and the response includes an x-eve-session-id header. Use that session id to attach to the live stream, which emits NDJSON lifecycle events as the agent thinks, calls tools, and produces output:
curl http://127.0.0.1:3000/eve/v1/session/<sessionId>/streamEach user message or external event creates a turn. During a turn the agent can call tools, load skills, read and write sandbox files, delegate to subagents, and stream events back. Because the session id is durable, you can reconnect to the same stream after a disconnect and pick up where you left off.
Step 5: Understand Durability
This is eve's headline feature, and it costs you nothing to enable. Sessions run on top of Vercel Workflows, which persist progress as an event log and deterministically replay it to reconstruct state. The practical result:
- A session survives cold starts — if the function spins down between messages, the next message replays the log and continues.
- A session survives redeploys — you can ship new code while long-running agents are mid-task.
- A session survives long pauses — an agent can wait hours for a human approval or a slow tool result without holding a process open.
On Vercel, the compiled agent runs from Vercel Functions, and because turns are long-running and stream incrementally, eve benefits from Fluid Compute, which is enabled by default for new projects. You write ordinary async tool functions; the durability is handled by the runtime.
Step 6: Add a Skill for Deep Tasks
Tools are small, typed actions. Skills are larger procedures or reference material the model loads on demand — multi-step workflows or domain knowledge that would bloat the always-on prompt if you pasted it into instructions.md.
Create agent/skills/research-report.md:
---
name: research-report
description: Produce a structured, cited research report on a topic.
---
# Research Report Procedure
Follow these steps when the user asks for a thorough report:
1. Call `web_search` two or three times with different angles on the topic.
2. Group the findings into 3 to 5 themes.
3. For each theme, write a short paragraph and cite the source URLs.
4. Call `save_note` with the final report so the user can retrieve it later.
5. End with a one-paragraph executive summary at the top.Because the skill is separate, the model only pulls it into context when a turn actually needs it — keeping the default prompt lean and the agent fast for simple questions. You install community skills into agent/skills/ with the eve skills CLI, but authoring your own is just dropping a Markdown file here.
The split between tools and skills is the most important design idea in eve. Tools = typed actions the model calls. Skills = instructions the model reads. Reach for a skill when you'd otherwise write a long "when the user asks X, do A then B then C" block in your prompt.
Step 7: Delegate with a Subagent
Sometimes a turn needs focused work done in isolation — research a sub-question with a narrower toolset, or run something in parallel without polluting the main conversation. That's a subagent: a child agent with its own fresh conversation history and state.
eve offers two kinds. The built-in agent tool delegates to a copy of the current agent. For a specialist, declare a subagent under agent/subagents/. Create agent/subagents/fact-checker/agent.ts:
import { defineAgent } from 'eve';
export default defineAgent({
model: 'anthropic/claude-opus-4.8',
});Give it its own narrower instructions in agent/subagents/fact-checker/instructions.md:
You are a fact-checker. Given a claim and its sources, verify whether the
sources actually support the claim. Respond with: SUPPORTED, REFUTED, or
UNCLEAR, followed by one sentence of justification. Do not speculate.Now the main agent can delegate a verification subtask to fact-checker, which runs as a separate agent. Unlike a skill — which adds instructions to the running agent — a subagent has its own identity, history, and tool set. Use subagents to parallelize work, sandbox a risky subtask, or give a specialist a tightly scoped job.
Step 8: Run Work on a Schedule
Agents don't only react to messages. A schedule is a cron expression plus a handler; on Vercel it deploys as a Vercel Cron Job. Create agent/schedules/weekly-recap.ts:
import { defineSchedule } from 'eve/schedules';
// Runs every Monday at 09:00 UTC.
export default defineSchedule({
cron: '0 9 * * 1',
async run(ctx) {
await ctx.startSession({
message:
'Summarize the research notes saved in the last 7 days and post a recap.',
});
},
});The handler starts a fresh durable session, exactly as an HTTP request would — so all your tools, skills, and durability apply to scheduled runs too. This is how you turn a reactive assistant into a proactive one that, say, emails a Monday digest or refreshes a cache overnight.
Step 9: Add a Channel
So far you've talked to the agent over raw HTTP. Channels are entry points into the same agent runtime — they start sessions, route platform events into turns, and apply platform-specific auth and formatting. HTTP is built in; platform channels are one CLI command each. To add Slack:
npx eve@latest channels add slackThis writes agent/channels/slack.ts, a small adapter that maps Slack events into agent turns. Slack, Discord, Teams, Telegram, Twilio, GitHub, and Linear ship by default, and defineChannel from eve/channels covers custom ones. The key idea: the same agent serves every surface. You don't rebuild logic per platform — each channel is just a thin adapter file, and channel secrets live in environment variables.
Step 10: Deploy to Vercel
eve is built to run on Vercel with no extra infrastructure. The simplest path is Git-based:
- Push the project to a Git repository connected to Vercel.
- Vercel detects the eve project and builds the compiled agent as Vercel Functions.
- AI Gateway resolves your model strings via OIDC — no provider keys to set.
Prefer the CLI? Install it and deploy directly:
npm i -g vercel
vercel deployOnce deployed, open Agent Runs in the Vercel dashboard. Every eve project gets observability with zero setup: sessions, turns, tool calls, reasoning, timing, and token usage are all visible. If you also want AI SDK spans in an external OpenTelemetry backend, add an agent/instrumentation.ts file.
Testing Your Implementation
Verify each layer locally before deploying:
- Agent boots:
pnpm devstarts without errors and prints the local URL. - Tools register: start a session asking "search for eve framework news" and confirm the stream shows a
web_searchtool call. - Skill loads: ask for "a full research report on X" and confirm the
research-reportskill is pulled in (visible in the lifecycle events). - Durability: kill the dev server mid-session, restart it, and reattach to the stream with the same session id — the session resumes.
- Subagent: ask the agent to "fact-check this claim against its sources" and confirm delegation to
fact-checker.
Troubleshooting
A tool never gets called. Check the description and field .describe() text — the model relies on them to decide when to call a tool. Vague descriptions lead to unused tools.
Model errors about credentials locally. Locally you may need a provider key in your environment; on Vercel, AI Gateway + OIDC handles this. Check the scaffold README for the exact local env var.
Filename vs tool name mismatch. Remember the filename is the tool name. Rename the file, not a name field, and use snake_case.
Schedule never fires locally. Cron schedules deploy as Vercel Cron Jobs — they run on the deployed environment, not necessarily on every local dev run. Trigger the handler manually in dev to test it.
Next Steps
- Replace the mock
web_searchwith a real provider (e.g. a search API or Firecrawl) and wire credentials through Vercel Connect. - Add a
connections/integration for a typed external service so credentials stay out of your prompt and tool code. - Explore the sandbox further — run model-generated code in an ephemeral microVM with the built-in
bashtool. - Compare eve's filesystem-first model with code-first frameworks like the Vercel AI SDK to decide which fits your team.
Conclusion
eve reframes agent development around the filesystem: tools, skills, subagents, channels, and schedules are all just files in conventional folders, and eve compiles them into a durable backend that runs on Vercel Functions. You got a working research assistant with typed tools, an on-demand skill, durable sessions, a specialist subagent, a weekly schedule, and a deploy path — without managing queues, runtimes, or provider keys yourself.
The biggest mental shift is the tools-versus-skills split: typed actions the model calls versus procedures the model reads. Get that right and your agents stay fast on simple turns while remaining capable on deep ones. From here, swap in real integrations, add channels for the surfaces your users actually live on, and let Vercel's durability carry the long-running work.