Guides

File-Based Agent Routing

Discover agents from the filesystem and serve them automatically with zero route boilerplate.

Define agents as folders on the filesystem. The framework scans them at build time, generates route handlers, and serves each agent at /.well-known/agents/<name>.

Setup

Wrap your Next.js config with withAgents:

next.config.ts
import { withAgents } from "experimental-agent/next/agents";

export default withAgents({
  // your normal Next.js config
  reactStrictMode: true,
});

If you're using durable workflows, compose with withWorkflow:

next.config.ts
import { withAgents } from "experimental-agent/next/agents";
import { withWorkflow } from "workflow/next";

export default withAgents(withWorkflow({
  reactStrictMode: true,
}));

That's it. Create agent folders and they're served automatically.

Directory Structure

src/agents/
  v0/
    agent.ts                # agent config (optional)
    system/
      1-instructions.md     # system prompt parts
      2-constraints.md
    skills/
      coding.md             # host skills

Each top-level folder inside the agents directory becomes a named agent. The folder name is the agent name.

agent.ts

Optional. When present, must export default an agent instance:

agents/v0/agent.ts
import { agent } from "experimental-agent";
import { vercelSandbox } from "experimental-agent/sandbox";

export default agent("v0", {
  model: "anthropic/claude-sonnet-4-6",
  system: "You are a coding assistant.",
  sandbox: vercelSandbox(),
  skills: [],
});

When agent.ts is absent, the framework creates an agent from the filesystem config alone (system prompts and skills).

system/*.md

Markdown files in the system/ subdirectory form the agent's system prompt. Files are sorted by name and concatenated with double newlines, so use numeric prefixes to control order:

system/
  1-role.md          # "You are a coding assistant."
  2-constraints.md   # "Never delete files without asking."
  3-style.md         # "Be concise. Use code blocks."

Result: "You are a coding assistant.\n\nNever delete files without asking.\n\nBe concise. Use code blocks."

Empty files and non-.md files are ignored.

skills/*.md

Each .md file in the skills/ subdirectory becomes a host skill. The file's absolute path is passed to the agent at runtime:

skills/
  coding.md     # skill instructions for coding tasks
  review.md     # skill instructions for code review

Config-Only Agents

Agents don't need any code. A folder with just system/ and/or skills/ files creates a working agent:

agents/
  helper/
    system/
      1-instructions.md
    skills/
      writing.md

This creates an agent named "helper" that's served at /.well-known/agents/helper.

Merging

When an agent has both an agent.ts and filesystem config, the framework merges them. The agent.ts config is the base and filesystem config is layered on top:

ConfigMerge behavior
System promptFilesystem prompts are appended after the agent.ts prompt
SkillsFilesystem skills are appended after the agent.ts skills
Everything elsemodel, tools, generation, etc. from agent.ts are used as-is

This works correctly with resolvable options. If your agent.ts system prompt is a function, the filesystem prompt is appended to the resolved value at runtime.

agents/v0/agent.ts
import { agent } from "experimental-agent";

export default agent("v0", {
  system: ({ context }) => `You work on project ${context.projectName}.`,
});
agents/v0/system/1-safety.md
Always ask before deleting files.

At runtime, the system prompt resolves to:

["You work on project acme.", "Always ask before deleting files."]

Auto-Detection

The framework auto-detects your project layout:

WhatDetection orderOverride
Agents directorysrc/agents/agents/agentsDir option
App directorysrc/app/ (if it has layout.tsx) → app/
next.config.ts
import { withAgents } from "experimental-agent/next/agents";

export default withAgents({}, {
  agentsDir: "custom/path/to/agents",
});

Generated Files

withAgents writes two files into .well-known/agents/[agent]/[[...path]]/ inside your app directory:

FilePurpose
_registry.tsMaps agent names to their config and dynamic import() calls
route.tsNext.js route handler that resolves agents and delegates to handleRequest

These files are auto-generated on every Next.js startup and gitignored (a .gitignore is created automatically). Don't edit them.

Routing

Each agent is served at /.well-known/agents/<name> with the same API as handleRequest:

POST /.well-known/agents/v0/:sessionId     # send a message
GET  /.well-known/agents/v0/:sessionId     # get session / reconnect stream
GET  /.well-known/agents/v0/openapi.json   # OpenAPI spec

Requesting an unknown agent name returns a 404 with a list of available agents.

Debug Mode

Pass debug: true to log discovered agents at startup:

next.config.ts
import { withAgents } from "experimental-agent/next/agents";

export default withAgents({}, { debug: true });
[withAgents] discovered agents: [ 'v0', 'helper' ]

Multiple Agents

Add more folders to serve more agents:

src/agents/
  v0/
    agent.ts
    system/1-instructions.md
  code-review/
    system/1-instructions.md
    skills/review.md
  docs-writer/
    agent.ts

Each gets its own endpoint:

  • /.well-known/agents/v0
  • /.well-known/agents/code-review
  • /.well-known/agents/docs-writer

Ignored Entries

  • Dot-prefixed folders (.shared/, .utils/) are ignored
  • Files in the agents root directory are ignored (only folders become agents)
  • Non-.md files in system/ are ignored