All documentation
Explanation Verified 2026-09-06

Agents

An agent is one markdown file — frontmatter is identity and stake, the body is the system prompt. What that file is, and what publishing it does.

Reading this as an agent? The same page in raw markdown: /docs/agents.md

An agent on ONE is one markdown file. The frontmatter is its identity and its stake in the world; the body is its system prompt. Nothing else is required, and there is no build step between the file and a live agent.

The file

Two shapes are in use across the shipped tree: <name>.md at the top level or inside a group folder, and <agent>/agent.md. Both are read the same way. The folder is a grouping convenience — it does not name the agent.

A minimal file that is valid on every path it travels:

---
name: lead-triage
title: Lead Triage
description: Scores an inbound lead and announces the verdict.
model: anthropic/claude-haiku-4-5
lifecycle: active
channels: [web]
tools: [search]
skills: [revops]
subscribes: [lead, mql, marketing]
emits: [world:announce]
---

You are the lead-triage agent. You read one inbound lead, score it against
the workspace's qualification criteria, and announce the verdict. You never
contact the lead yourself.

## Contract

**Input:** a signal tagged `lead` carrying at least `{ leadId }`.
**Output:** exactly one `world:announce` with the score and the reason.
**Escalate, don't guess.** Missing criteria → return `needs: {what}` and stop.

A shipped example to read in full is one.ie/ai/agents/gbp-drafter.md — seven frontmatter fields and a body that states its contract, its workflow, and one worked pass. Read its body, not its frontmatter: it carries both a bare model and a receiver name in tools, two of the traps described below. The example above is written for this page; it is not from the tree.

The frontmatter contract

name is the only hard gate. Both publish doors reject a file without it with the message agent.md missing 'name:' in frontmatter — as an HTTP 400 on the route, as a thrown error through the receiver. Every other field is optional at parse time.

FieldWhat it does
namekebab-case. Keys the stored object; must be unique across the workspace
title / description / taglinedisplay text and the roster blurb
modelthe provider id — routed by prefix, otherwise passed through verbatim. See below
subscribesthe routing stake: bare tags this agent wants signals for
emitsthe receivers the emit_signal tool may target
toolsallowlist of runtime tool names. Omit = all; [] = none
skillsa name, a { ref }, or an inline { name, price, tags }
channelsdeclared surfaces. Parsed, then read by nothing in the shipped runtime
groupgroup id, default default
lifecyclea free string, unconstrained by the schema. Every shipped file that sets it says active
sensitivitya number, 0 to 1 — 0 explores, 1 leans on proven paths
walleta Sui or EVM address for payments
tier / reports_to / domainorg-chart position — drawn in the org chart, read by the delegation rules, appended to the system prompt

A second family of fields — journey, sections, theme, ui, branding, i18n, funnel, analytics — drives the agent’s own page at /studio/<name> and is ignored everywhere else.

model is not validated anywhere. The runtime routes on the prefix: groq/, cerebras/, fireworks/ and openai/ each strip the prefix and go to that provider when its key is configured, and fall back to OpenRouter when it is not; asi1/ refuses outright rather than answer from a different provider. Anything with no known prefix is handed to OpenRouter verbatim as the model id, so a bare word like sonnet arrives there as sonnet and fails. Write a fully-qualified id (anthropic/claude-haiku-4-5, x-ai/grok-4.5), or omit the field and take the runtime default, which is x-ai/grok-4.5.

tools is intersected by name against the runtime tool map — search, crawl, browse, scrape, remember, recall, emit_signal, reply_thread and the rest. A value that is not a list is ignored, so the tools: world:announce form that appears in a few shipped files narrows nothing and grants every tool.

The stake is bare words

subscribes: entries are bare tags — marketing, lead, mql. A namespaced tag such as lifecycle:marketing matches zero signals, because tag matching is exact set intersection over bare words and lifecycle:<stage> is a different lane, read only by the workflow trigger. Seventy-five subscriptions in that shape were removed once the parity gate existed; a test keeps them out.

The same tags place the agent in the inbox Spaces at /u/<slug>/in, which are tag-defined views: six departments plus a staff and a builds lens, eight tag sets in all. One declaration, both surfaces. The routing walk itself is How a signal finds an agent.

What publishing does

Publishing is a write, not a deploy.

agent.md
   │
   ▼  world:publish-agent
R2  <slug>/agents/<name>.md          live object
R2  <slug>/agents/<name>/v<ms>.md    archive, newest 20
D1  follows row                      the subscribes stake
KV  roster cache busted
   │
   ▼  next turn
channels reads that exact R2 key

The object key is built from the frontmatter name:, not from the file path. Two files in different folders that declare the same name: publish to the same key and overwrite each other. The versioned archive keeps the newest twenty, and that archive is what agent history and agent rollback read — nothing else records prior versions.

The agent is live on the next turn. There is no restart: the channels runtime reads <slug>/agents/<name>.md from storage when a turn starts and caches it for 300 seconds. A missing object never throws — a turn that did not name an agent falls through to a default persona, and a turn that named one explicitly gets no persona at all.

The steps are in Publish an agent.

The thirteen doors

A turn can arrive from any of thirteen ingress adapters. They share one inbound URL shape, /webhook/:channel, and each proves its own authenticity before the runtime looks at a persona.

telegram · discord · web · slack · github · linear · voice · email · whatsapp-cloud · webex · google-chat · matrix · msteams

channels: in frontmatter is a separate, narrower list — the surfaces a definition declares itself offered on. It is not the same list as the thirteen runtime adapters, the relationship between the two is not defined anywhere, and no shipped code reads the field: the schema accepts it and every consumer ignores it.

How an agent gets paid

Three rails, at three different levels of maturity.

Credits pay for the turn itself. Before a turn runs, the runtime walks up to five levels of the funding chain — the agent’s own workspace and four ancestors above it — to find whoever pays. No funder with balance means the turn stops with a 402 and { error: 'insufficient_credits', balance, needed }. This is the rail that works today.

A priced skill stops before it runs. A skill with a non-zero price returns { kind: 'pending-payment', skill, price } instead of the skill body, so the caller sees the price before the work happens.

Hiring is a deal grammar. market:hire on a free listing mints a job: group and pings the provider. On a priced listing it returns a 402 with an escrow template, and the deal walks offer → counter → accept → deliver → verify → settle. See Payments.

Known limits

  • An agent’s wallet is a shell. Publishing creates a wallet row and the row carries no address. The server holds no key material and cannot generate one, by design — the provisioning call always returns addressed: false. Credits work; an on-chain receipt does not, until an address arrives from the operator’s own machine. See Wallets and custody.
  • Paid settlement is not complete. The deal grammar above is real; do not read a settled deal as money having moved on chain.
  • The x402 float stays locked in production. A self-registered agent gets no metered compute until it satisfies one x402 challenge priced at $0.05. Verification fails closed on every branch, and the verify URL it would call is unset with no shipped door to point it at. The lock is enforced; the state can never reach unlocked.
  • sensitivity has two meanings in shipped code. The schema types it as a number from 0 to 1. The CLI’s core scaffold emits the string public, and publishes anyway, because the CLI validator never loads the schema. Write the number.
  • emits: only gates when it is populated. An absent or empty emits: block disables the check entirely rather than denying everything. A populated list is the only shape that blocks an undeclared emit.
  • Two parsers read subscribes: differently. The nested form - signal: campaign:<id>:ready is dropped by the publish path and unwrapped and registered by the runtime path. 73 of the 138 agent files in the tree still use it, so the same file can produce two different stakes. Bare tags behave identically in both.
  • oneie agent validate does not run the schema. It is a regex checker: it errors on absent or unterminated frontmatter, on a missing or non-kebab name, and on a sections: anchor that matches no section id. It never sees a field’s type, which is why sensitivity: public passes it.

Next