The agent file
agents/<name>/agent.md is the only required file an agent has. Frontmatter
for the machine, body for the model — and the body is the prompt, so write it
as instructions to a colleague rather than as documentation about one.
---
name: competitor-watcher
description: Watches competitor sites and drafts a weekly digest.
model: default
effort: high
tools:
- web
- files
- [[price-tracker]]
secrets: [SLACK_WEBHOOK_TOKEN]
---
You watch our competitors and produce a weekly digest.
Check each site listed in [[competitors]]. Note pricing changes, new features
and new posts. Write the digest to outputs/digest.md.
Identity
| field | |
|---|---|
name |
kebab-case, unique in the account. The agent’s identity — the folder must match |
description |
what it does and when to use it. Other agents read this when consulting; people read it in the dashboard |
Only name and the body are required. Every other field widens or narrows
what the agent can reach, and the default is narrow.
Which model, and how hard it thinks
| field | values | |
|---|---|---|
model |
fast | default | max, an alias (opus), or a full id |
a tier, so agents don’t rot when models are renamed. Synonyms land on their tier: small/cheap → fast, large/best → max |
effort |
low | medium | high | xhigh | max |
how long it thinks before answering. Unset leaves the model’s own default |
The two are orthogonal — the model is which brain, effort is how long it
thinks — and fast + max is a real pairing: the cheap model, told to take
its time. The same word means different things on each key: model: max is
the most capable model, effort: max is think-hardest.
Match the tier to the work, not to the importance of the desk. A step that
orders findings other steps produced is a fast step even when its output is
the point of the week; a step that weighs two arguments and picks one is not.
What it may do
| field | |
|---|---|
tools |
the one grant list — built-in groups, exact SDK names, and your own tools |
disallowedTools |
subtract from what it would otherwise have |
skills |
an allowlist. Absent inherits every skill in scope; [] withholds all of them |
agents |
colleagues it may consult mid-run |
scripts |
programs in scripts/, each becoming a callable tool |
apis |
an HTTP API declared inline, as one tool |
mcpServers |
an MCP server declared inline |
secrets |
vault entries its tools may use — names only, never values |
permissionMode |
plan makes the run read-only, whatever else was granted |
The built-in groups are one word each, so you can hold them in your head:
| group | |
|---|---|
read |
Read, Glob, Grep — inspect but never modify |
files |
Read, Write, Edit, Glob, Grep |
bash |
Bash |
web |
WebSearch (server-side, billed per call) + WebFetch |
fetch |
WebFetch only — the local half |
search |
search_files(query) over knowledge, memory, state and storage at every scope |
history |
recall_runs() and read_run(id) — the workspace’s last thirty finished runs |
Anything in tools: that no built-in claims is one of your own tools,
resolved against the workspace’s tools/ and then the account library. A
[[link]] makes that explicit and is the only way to grant a tool whose name
a built-in would otherwise shadow:
tools:
- read # the built-in group
- [[search]] # your tools/search.md, not the platform's search group
{bash: ask} is accepted for per-call approval in Claude Code; platform runs
disable ask-mode and log that they did.
Consulting colleagues
agents:
- [[fact-checker]]
Each name becomes a consult_<name>(question) tool. The colleague’s persona
answers one self-contained question as a toolless call, inline, with the
spend landing on the consulting step. Depth is one — consultants cannot
consult further. It is deliberately weak: a consult asks a specialist what
they think; it does not hand over the task.
Where it runs
| field | |
|---|---|
size |
small | large (default) | heavy — the sandbox reservation |
runtime |
language runtimes and packages the agent’s own scripts need |
size is a price, not just a limit. Memory is a hard ceiling because it is
not compressible: a step over it is killed, which on a single-node host
protects every other tenant. CPU is not capped — a step bursts to whatever is
free and bills at its class rate. Reference figures: 1Gi, 2Gi, 8Gi. Pick
small for an agent that mostly waits on an API, heavy for one that renders
a browser or holds real data.
runtime:
python: "3.12" # optional pin
packages: [pandas] # pip
node: true
npm: [cheerio]
An agent’s own runtime and the runtimes of the tools it grants merge into one environment per step, so a tool carries its own dependencies and the agent does not repeat them.
Its own model credential
provider:
name: groq
token: ${GROQ_API_KEY}
models: { fast: llama-3.3-70b-versatile }
A name resolves to the endpoint, its wire format and where the key goes;
base_url:, format: (anthropic | openai) and auth: (bearer |
x-api-key) spell the same thing out for an endpoint no preset covers.
params: passes anything else the provider accepts — temperature, seed,
response_format — merged into the request verbatim, with a null value
removing a field rather than setting it. See Providers.
Running on a clock
schedule (5-field cron, or @hourly/@daily/@weekly/@monthly) with an
optional IANA timezone runs the agent on its own. Absent, it runs on demand
— the dashboard, foldrun run, or an API call. For anything involving more
than one agent, put the schedule on a flow instead.
Everything beside the file
agents/reporter/
├── agent.md # required
├── skills/ # one capability per folder
├── knowledge/ # given to it; it may read, never write
├── memory/ # what it learned; it writes here
└── scripts/ # code it can call as a tool
memory/ writes are the only writes an agent may make outside outputs/
without an explicit files grant. knowledge/ is denied outright — through
the file tools and through bash.
Where files live, from the agent’s point of view
An agent’s working directory is its own folder, and every path is relative to it. Two spellings reach the workspace root and both are fine:
| place | relative | with the prefix |
|---|---|---|
| a deliverable for a person | ../../storage/report.md |
workspace/storage/report.md |
| what the next run needs | ../../state/history.md |
workspace/state/history.md |
| this step’s scratch | outputs/draft.md |
— |
| the account library (read-only) | — | account/knowledge/prices.md |
There is no /tmp for an agent, and no absolute path is inside its
workspace. A directory a tool made outside the workspace — a repository it
cloned, say — is reached only through that tool’s own read or find action.
A path outside the workspace is refused with a message naming the path the
agent probably meant; the run page and the agent’s Activity page count those
refusals per step, because each one is a wasted turn and a prompt that names
the exact path brings the count to zero.
Handing work to a later step
A step is handed the replies of every earlier group. When the reply is a
report a person should also read, or a list a later step must get exactly,
write it to workspace/storage/ as well — a tool that takes an out= path
and tees its own output there is the reliable way, because a model asked to
copy a long report by hand shortens it. Reply with one line saying what you
concluded; the file is the record.
AGENTS.md — context above the agent
Two scopes, both optional, both inherited: <account>/AGENTS.md for everyone,
<workspace>/AGENTS.md for one workspace. Frontmatter there sets defaults —
provider:, runtime:, timezone:, notify:, budget: (a monthly cap in
USD), foldrun_version: — and the body is context every agent works under.
Nearest wins, but a key replaces the whole value rather than merging into
it: an agent’s notify: replaces the account’s, it does not add to it.
Checking it
foldrun check validates all of this offline, before any model is called —
a tool, skill or colleague that names nothing, a step that names a missing
agent, a broken script path. Run it the way you would run a typecheck.