> ## Documentation Index
> Fetch the complete documentation index at: https://amplifysecurity-eng-2210-deterministic-workflows-docs.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Writing an agent

> The AGENT.md format — YAML frontmatter plus a Markdown body — and every field it accepts.

## 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.

```markdown theme={null}
---
name: dependency-auditor
description: Audits third-party dependencies for known-vulnerable versions and unmaintained packages, and reports each one as a finding.
model: anthropic/claude-sonnet-4-6
allowed-tools:
  - shell
  - ripgrep_search
  - web_fetch
  - report_finding
---

You audit third-party dependencies.

## Workflow

1. Locate every manifest and lockfile in the repository.
2. For each direct dependency, determine the resolved version.
3. Flag versions with known advisories, and packages with no release in over two years.
4. Report each one with `report_finding`, citing the manifest path and the resolved version.

## Rules

- Report the resolved version from the lockfile, never the range from the manifest.
- Do not report transitive dependencies unless the advisory is critical.
```

That's the entire contract. No build step, no registration.

## Frontmatter reference

| Key                | Required | Type               | What it does                                                                                                           |
| ------------------ | -------- | ------------------ | ---------------------------------------------------------------------------------------------------------------------- |
| `name`             | Yes      | string             | How the agent is referenced — by workflow steps and by `spawn_agent`. Must be unique.                                  |
| `description`      | Yes      | string, ≤500 chars | What this agent does. **Load-bearing** — see below.                                                                    |
| `model`            | No       | string             | Which model to run. Omit to inherit the default.                                                                       |
| `allowed-tools`    | No       | string\[]          | Restricts the agent to these tools. Omit to inherit.                                                                   |
| `maxIterations`    | No       | positive int       | Budget of reasoning↔tool cycles before the agent is stopped.                                                           |
| `timeout`          | No       | positive int (ms)  | Wall-clock limit for one execution.                                                                                    |
| `produces`         | No       | list               | The kinds of result this agent's step may record. See [contracts](#contracts-what-a-step-produces-and-consumes) below. |
| `consumes`         | No       | list               | The kinds this agent's step reads, and how. See [contracts](#contracts-what-a-step-produces-and-consumes) below.       |
| `mutates-worktree` | No       | boolean            | Declares that this agent edits files in the repository. See below.                                                     |

### Why the description matters

Two audiences read `description`, and neither is your agent itself:

* **You, choosing agents for a workflow** — the [workflow editor](/workflows/create-a-workflow#agents) and
  the [agent library](/agents/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:

```yaml theme={null}
# Good — states the job and the output
description: Audits third-party dependencies for known-vulnerable versions and unmaintained packages, and reports each one as a finding.

# Too vague to be useful to anyone deciding whether to use this agent
description: Dependency helper.
```

### `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](/agents/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](/workflows/create-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:

```yaml theme={null}
produces:
  - kind: amplify:finding
```

`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](#defining-your-own-kind) below.

### `consumes`

The kinds this agent's step reads, and how it wants them delivered:

```yaml theme={null}
consumes:
  - kind: amplify:finding
    mode: each
```

| Field      | Required | What it does                        |
| ---------- | -------- | ----------------------------------- |
| `kind`     | Yes      | The kind this step reads.           |
| `mode`     | No       | `each` or `all`. Defaults to `all`. |
| `group-by` | No       | Only with `mode: each`. See below.  |

**`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](/workflows/running#run-statuses), 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.

<Note>
  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.
</Note>

### `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:

```yaml theme={null}
consumes:
  - kind: amplify:finding
    mode: each
    group-by: [detection_id, properties.filePath]
```

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.

<Note>
  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`.
</Note>

### `mutates-worktree`

Set this to `true` if your agent edits files in the repository:

```yaml theme={null}
mutates-worktree: true
```

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:

```yaml theme={null}
produces:
  - kind: scan-report
    schema:
      fields:
        verdict:
          type: string
          enum: [clean, issues-found]
        total_findings:
          type: integer
```

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.

<Note>
  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.
</Note>

## 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](/workflows/create-a-workflow#agents)
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:

```
~/.amplify/agents/<name>/AGENT.md    # available in every session
./agents/<name>/AGENT.md             # project-local
```

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.

<Tip>
  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.
</Tip>

## Next steps

<CardGroup cols={2}>
  <Card title="Tool reference" icon="wrench" href="/agents/tool-reference">
    Valid `allowed-tools` values and what each does.
  </Card>

  <Card title="The agent library" icon="books" href="/agents/library">
    Built-in agents worth reading as examples.
  </Card>
</CardGroup>
