Appearance
Project layout
The Agent SDK builds an agent by walking the filesystem under agent/. Each folder has a defined purpose. The path a file lands in determines how the Agent SDK loads it.
Folder structure
For the capabilities below, identity usually comes from the path. A/B experiments can override their file-derived name.
| Path | Resolves to |
|---|---|
agent/tools/approve_pr.ts | tool approve_pr |
agent/mcp-connections/linear.ts | MCP connection linear |
agent/skills/pr-review.md | skill pr-review |
agent/subagents/reviewer/ | subagent reviewer |
agent/channels/drive.ts | channel drive, routes under /v1/channels/drive |
agent/ab.ts | A/B experiment ab unless name overrides it |
agent/ab/concise.ts | A/B experiment concise unless name overrides it |
The root agent takes its name from package.json name, falling back to the directory name. When serving multiple agents, the slug is the directory name and must match [A-Za-z0-9][A-Za-z0-9_-]* (and not the reserved v1, playground, or docs segments).
Full project layout
A full project looks like this.
text
my-agent/
├── package.json
├── agent/
│ ├── agent.ts # runtime config (model, runtime, cloud/local)
│ ├── instructions.md # always-on system prompt (required)
│ ├── tools/
│ │ └── approve_pr.ts # one typed tool per file
│ ├── skills/
│ │ └── pr-review.md # on-demand procedures (SKILL.md convention)
│ ├── mcp-connections/
│ │ └── linear.ts # tools from external MCP servers
│ ├── subagents/
│ │ └── reviewer/ # child agents (agent.ts + instructions.md)
│ ├── channels/
│ │ ├── webhook.ts # custom HTTP surfaces
│ │ ├── slack.ts # the Slack channel pack
│ │ └── github.ts # the GitHub webhook channel pack
│ ├── hooks/
│ │ └── audit.ts # observe the runtime event stream
│ ├── otel.ts # optional OpenTelemetry export
│ ├── ab.ts # optional live A/B experiment
│ ├── ab/
│ │ └── concise.ts # optional: more experiments
│ ├── schedules/
│ │ └── heartbeat.md # cron-driven runs
│ ├── sandbox/workspace/ # files seeded into each session's workspace
│ └── lib/ # shared code (import-only, never discovered)
└── evals/
├── evals.config.ts # required when evals exist (maxConcurrency)
└── readiness.eval.ts # filesystem evalsEvals live in evals/ at the project root, a sibling of agent/, never inside it. agent/evals/ is silently ignored. See Evals.
Folder reference
Each path maps to a capability and a reference page.
| Path | What it is | Reference |
|---|---|---|
agent/agent.ts | defineAgent({ model?, runtime?, cloud?, local? }); the model defaults to grok-4.5 with effort=high, fast=true | Agent config |
agent/instructions.md | Always-on system prompt, required on the root agent (.ts and directory forms exist) | Instructions |
agent/tools/<name>.ts | One typed tool; filename = tool name. execution: "server" (in-process, default) or "agent" (a script that runs where the agent runs) | Tools |
agent/skills/* | SKILL.md-convention procedures, loaded on demand | Skills |
agent/mcp-connections/<name>.ts | MCP servers, available to the model, to server tools (ctx.host.mcp), and to channel/schedule handlers (args.host.mcp) | MCP connections |
agent/subagents/<id>/ | Child agent directory; description required | Subagents |
agent/channels/*.ts | HTTP surfaces beyond the built-in session API; slack.ts and github.ts use the platform packs | Channels |
agent/hooks/*.ts | Observe-only event subscribers, never fatal | Hooks |
agent/otel.ts | defineOtel OTLP export (traces, metrics, optional logs) | OpenTelemetry |
agent/ab.ts, agent/ab/*.ts | defineAB experiments with sticky variants and live metrics | Live A/B metrics |
agent/ab.config.ts | defineABConfig shared A/B settings | Live A/B metrics |
agent/storage.ts | defineStorage backend for the durable host.kv / host.files APIs | Storage |
agent/artifacts.ts | defineArtifacts kinds, the tag_artifact opt-in, and retention | Artifacts |
agent/schedules/* | Cron-driven runs (UTC, 5-field; never auto-fire under --dev) | Schedules |
agent/sandbox/workspace/** | Seed files copied into each local session workspace | Sessions |
agent/playground/ | Custom playground tool chips for the Vite dev playground | Playground |
agent/lib/ | Import-only shared code, never discovered | None |
evals/evals.config.ts | Shared eval settings (e.g. maxConcurrency); required when evals exist | Evals |
evals/**/*.eval.ts | Filesystem evals; case id = path under evals/ | Evals |
agent/lib/ is the only place for shared code. Everything else under agent/ is discovery surface. A stray .ts file in one of these folders is treated as a definition.
Why didn't the Agent SDK discover my file?
Run agent-sdk validate --dir . and agent-sdk info --dir .. validate prints diagnostics, and serve refuses to start on error-severity ones. Warnings, such as cloud runtime combined with local-only capabilities, print but don't block. info lists the discovered surface, so a missing tool or channel shows up immediately. From there, check the folder reference: the file is usually in the wrong directory or has the wrong extension.
bash
agent-sdk validate --dir . # diagnostics; non-zero exit on errors
agent-sdk info --dir . # human-readable surface
agent-sdk info --dir . --json # machine-readable manifest (same shape as GET /v1/info)What's next
Continue with these pages:
- Agent config: the runtime config at the root
- Tools: add typed actions under
agent/tools/ - Live A/B metrics: compare variants from
agent/ab.tsoragent/ab/ - Concepts: why the filesystem is the interface