Skip to main content

The format

An agent is a Markdown document with two parts:
  1. YAML frontmatter — the machine-readable declaration: name, model, tool permissions, budgets.
  2. A Markdown body — the agent’s instructions. This becomes its system prompt.
That’s the entire contract. No build step, no registration.

Frontmatter reference

Why the description matters

Two audiences read description, and neither is your agent itself:
  • You, choosing agents for a workflow — the workflow editor and the agent library show it as the one-line summary of what an agent does.
  • Other agents, deciding whether to delegate to it — an agent choosing a sub-agent to spawn sees only its name and description, so those two lines are the entire interface it has to go on.
Write it as an external, precise statement of the job and its output — not a note to yourself:

allowed-tools restricts, it doesn’t grant

Listing a tool doesn’t create capability that doesn’t exist — it narrows the agent to a subset of what the harness already offers. See the tool reference for valid names. Restricting tools is a real design technique, not just hygiene. An agent that shouldn’t modify code should not be given shell, and a verifier that must stay honest should not be given the ability to report findings. Console’s own policy-fix-verifier works this way: it is deliberately read-only so its verdict can’t be self-serving.

Budgets: maxIterations and timeout

Both are ceilings, not targets. Leave them unset unless the agent is an outlier.
  • Raise maxIterations for agents that legitimately need many tool calls — a broad scan across a large repository.
  • Raise timeout for orchestrators, whose wall clock includes every child they spawn. Set it above the worst-case sum of the children’s durations.

Contracts: what a step produces and consumes

When you chain agents into a workflow, Console needs to know which step’s output feeds which step’s input, so it can run steps that don’t depend on each other together, wait for the ones that do, and skip a step that has nothing to work on. You declare that with produces and consumes.

produces

The kinds of result this agent’s step may record:
produces is a may, never a promise — an agent that looked thoroughly and found nothing has still done its job, and nothing checks that a declared kind was actually emitted. A kind is either one of Console’s own (prefixed amplify:, like amplify:finding or amplify:patch) or one you define yourself. See defining your own kind below.

consumes

The kinds this agent’s step reads, and how it wants them delivered:
mode: all (the default) runs your agent once, with everything matching that kind from earlier in the chain — including an empty set. Use this for a step whose job is to summarize or report on the whole run: “no issues found” is itself a result worth producing, so it needs to run even when there’s nothing to say. mode: each runs a separate copy of your agent per item (or per group, if you set group-by). Zero items means the step doesn’t run at all — it’s recorded as skipped, not as having run and found nothing. Use this when your agent’s job only makes sense one item at a time, like generating a fix for a single bug.
A step can only consume a kind that an earlier step in the same workflow actually produces. Console checks this when you save the workflow, not when it runs.

group-by

For a mode: each step, group-by controls what counts as “one item.” By default every result is its own item; naming fields under group-by batches results that share the same values into a single item instead. patch-generator, Console’s built-in patching agent, is the canonical example — one patch should fix every match of the same underlying issue in the same file, not one patch per individual match:
Names in group-by come from the kind you’re consuming — never from anything about how Console stores it:
  • A field the kind itself declares, including one nested inside another declared field, like properties.filePath above.
  • A documented attribute of that kind. amplify:finding additionally exposes detection_id and severity this way.
  • id — every item is its own group, overriding any default grouping. amplify:finding already groups by detection and file when you set no group-by of your own, so write group-by: [id] explicitly if you want one child per finding instead.
An empty group-by: [] isn’t allowed: grouping by nothing means everything is one group, which is what mode: all already means. Console rejects it and suggests [id] if that’s what you meant.
A result your grouping can’t place — a finding with no detection behind it, say — is left out of that step, with the reason recorded on the step. It still reaches any other step consuming the same kind with mode: all.

mutates-worktree

Set this to true if your agent edits files in the repository:
This states a fact, not a scheduling request. Console uses it to make sure two steps that both edit the checkout never run at the same time and clobber each other’s changes. Leave it unset (the default) for an agent that only reads.

Defining your own kind

If produces names a kind that doesn’t already exist in your organization, attach a schema: block and Console registers it the moment you save the agent — no separate setup step:
Each field has a type (string, number, integer, boolean, object, or array) and can be marked required. A string field can restrict its values with enum; an object field declares its own nested fields; an array field declares the shape of its items. Saving the identical schema again is a no-op. Changing an already-registered kind’s shape is not allowed — Console rejects the save rather than reinterpreting artifacts you’ve already recorded under the old shape. If a kind’s shape needs to change, give it a new name.
Names starting with amplify: are reserved for Console’s own kinds. You can consume amplify:finding or amplify:patch in your own agents, but you can’t register a schema: under that prefix.

Writing one in the web console

Open Agents and create an agent. The editor is a Markdown editor with:
  • Frontmatter linting — malformed YAML is flagged as you type.
  • A model picker — selecting a model rewrites the model: line in place, so what you see in the frontmatter is always what will run.
  • Folders — organize agents as the list grows.
Your organization’s agents appear in the workflow agent picker next to the built-in ones.

Writing one in the CLI

The CLI loads agent definitions from the filesystem, so an agent is just a file:
Override those locations with AMPLIFY_AGENTS_DIR. Definitions load at startup, so restart the CLI after adding one.

Shadowing a built-in agent

Give your agent the same name as one Console ships and yours takes precedence. This is the supported way to change built-in behavior — a workflow step referencing that name keeps working and picks up your version.
Start by copying the built-in agent you want to change, editing the body, and keeping the name. You inherit a working structure and only change what you meant to.

Next steps

Tool reference

Valid allowed-tools values and what each does.

The agent library

Built-in agents worth reading as examples.