> ## Documentation Index
> Fetch the complete documentation index at: https://docs.duvo.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Writing Effective AOPs

> The AOP is where most of an Agent's quality lives. Write clear, testable instructions that produce reliable, predictable Runs.

Most of an Agent's quality lives in its AOP (Agent Operating Procedure). When an Agent underperforms, the fix is almost never a different model — it's a clearer AOP. Duvo also derives your Agent's evaluation criteria from the AOP, so clarity pays off twice: better Runs, and scores you can actually act on.

## Why the AOP Matters

<CardGroup cols={3}>
  <Card title="It is the Agent's behavior" icon="bot">
    The Agent follows it on every Run. If a step can be read two ways, sooner or later it will be.
  </Card>

  <Card title="It is your quality bar" icon="gauge">
    Duvo scores completed and failed Runs against criteria derived from the AOP, and surfaces the results in the [Runs List](/user-guide/running-assignments/jobs-list). Vague instructions produce vague scores you can't act on.
  </Card>

  <Card title="It is your safety boundary" icon="shield">
    Volume caps, value thresholds, approval rules, and hard "never do this" limits all live in the AOP.
  </Card>
</CardGroup>

## Write for a Capable New Team Member

Your Agent reads the AOP the way a person would; it doesn't execute it like code. Write it the way you'd brief a capable colleague on their first day: they know the tools, they don't know your business. Anything a new hire would have to ask about (which spreadsheet, whose approval, what happens to rejects) needs to be written down. Pseudo-code doesn't.

Watch out for words like "promptly", "as appropriate", and "if necessary". Each one is a decision you're quietly handing to the Agent, and it won't make that call the same way twice.

## Use the Canonical Shape: GOAL, STEPS, NOTES

Duvo's own AOP tooling generates and rewrites AOPs in one consistent shape. Writing yours the same way keeps Agent Builder edits clean and makes every Run easier to debug.

* **`# GOAL`** — one sentence describing what the Agent does on a single Case and the expected outcome.
* **`# STEPS`** — a numbered list of imperative actions, one action per step. Inline everything that belongs to a step into that step: decision criteria, data formats, error handling, and escalation.
* **`# NOTES`** *(optional)* — only genuinely cross-cutting concerns, such as timezone or naming conventions. Omit it otherwise.

<Note>
  Skip the separate ERROR HANDLING or ESCALATION sections at the bottom. A rule that sits far from the step it belongs to tends to get missed exactly when it matters. Put it in the step.
</Note>

## The Principles

1. **Lead with the goal and the definition of done.** State the outcome and how the Agent knows it succeeded, before the steps. An Agent that knows what "done" looks like makes better decisions along the way.
2. **Describe one Case, not the batch.** Write the AOP around processing a single item from start to finish. The platform handles iteration: [Queues](/user-guide/assignment-features/case-queue) feed Cases to your Agent one at a time, and [schedules](/user-guide/assignment-features/scheduling-assignments) and [triggers](/user-guide/assignment-features/event-driven-triggers) decide when Runs start. Batch loops ("go through all pending reports") hide per-item failures inside a single Run and break per-Case tracking and retries.
3. **Be specific and unambiguous.** Name the exact Connection, sheet, field, label, and recipient. Replace "the relevant data" with the actual source. Most failures trace back to one ambiguous sentence.
4. **Make decisions concrete.** Every decision point needs an explicit condition and an explicit action for each outcome: "If the total exceeds \$5,000, send it to the finance lead. Otherwise, approve it automatically." If you can't put a number on it, it's a decision for a human — make it an approval step.
5. **Put limits and guardrails in the AOP.** State caps and thresholds directly: "never send more than 20 emails in one Run", or "if an invoice exceeds €10,000, stop and request approval." Don't rely on the model to be cautious on its own. See [Guardrails for High-Risk Automations](/user-guide/security/high-risk-guardrails).
6. **Say when to ask a human — the Agent won't decide to on its own.** The Agent never invents its own approval gates. If the AOP doesn't tell it to pause, it won't, even before something hard to undo. The good news: plain language works. "Get the requester's go-ahead before sending" is enough to create a [Human-in-the-Loop](/user-guide/assignment-features/human-in-the-loop) checkpoint; there's no special syntax to learn.
7. **Close every branch.** Every path through the AOP should end somewhere definite: the output is delivered, the item is escalated to a person, or the work is postponed for a retry. Write down the unhappy paths too — a source system that doesn't respond, a required field that's missing, a lookup with no match. Don't leave those for the Agent to figure out. See [Retries, Failures, and Skipped Steps](/user-guide/reliability/retries-and-failures).
8. **Give context, not just commands.** A short "why" and an example of good versus bad output sharpen the Agent's judgment on the cases you didn't anticipate.

<Warning>
  If a step sends, deletes, or pays for anything and you want a person to see it first, say so in that step. For help deciding which actions deserve a gate, see [Designing Human-in-the-Loop Workflows](/user-guide/assignment-features/hitl-design).
</Warning>

Closed branches are the difference between an AOP you can trust and one you have to babysit:

```mermaid theme={"dark"}
flowchart TD
    A[Step runs on one Case] --> B{Did it succeed?}
    B -->|Yes| C[Deliver the output<br/>and mark the Case done]
    B -->|Data missing or ambiguous| D[Escalate to a person<br/>with the reason]
    B -->|System unavailable| E[Postpone the Case<br/>and retry later]
```

## Do and Don't

| Do                                                | Don't                                          |
| ------------------------------------------------- | ---------------------------------------------- |
| State the goal and the definition of done         | Assume the Agent will infer what success means |
| Write the AOP around one Case, end to end         | Write batch loops over "all pending items"     |
| Name exact sources, fields, and recipients        | Say "the relevant data" or "the right people"  |
| Put caps, thresholds, and approvals in the AOP    | Rely on the model to be cautious by default    |
| End every branch in done, escalated, or postponed | Leave edge cases and failures to guesswork     |
| Iterate in a draft revision, validated by evals   | Edit a live Agent's AOP blind                  |

## A Quick Example

**Vague:** "Read incoming invoices and enter them into the system."

**Effective:**

```
# GOAL
Process one incoming invoice: validate it, get approval where needed, and enter it into NetSuite.

# STEPS
1. Extract the supplier, invoice number, date, and total from the invoice PDF.
   - If any of those four fields is missing or unreadable: add the invoice to the
     "Needs review" Google Sheet with the reason, and stop. Do not guess.
2. If the total is over €10,000: request approval from the finance lead before entering it.
3. Create the record in NetSuite and reply to the sender via Gmail confirming receipt.
```

Same task, but now the Agent knows what to read, what counts as done, what to do when the data is bad, and when to ask before acting.

## The AOP Is Not the Only Context

The AOP is the shared process everyone relies on, but it's not the only thing your Agent sees on a Run. Two other layers ride alongside it:

* **[Agent Memory](/user-guide/assignment-features/assignment-memory)** holds personal preferences, like your own approval threshold or how you want output formatted. It applies only to your Runs and never changes the shared AOP.
* **[Learnings](/user-guide/assignment-features/learning-feature)** capture what worked in past Runs and carry it forward automatically.

If [refining your Agent](/user-guide/building-assignments/refining-your-assignment) turns up a rule the whole team needs, put it in the AOP, where it's versioned and everyone can see it — not in a personal note where only your Runs benefit.

<Tip>
  A great AOP fits on a screen or two. If yours keeps growing past that, it's usually a sign the process wants to be more than one Agent — see [Multi-Agent Process Decomposition](/user-guide/building-assignments/process-decomposition).
</Tip>

## Test and Improve, Don't Edit Live

Treat the AOP like code. Change it in a draft revision, validate it on real cases, and promote it only once it holds. **Never edit a production Agent's AOP blind** — it is the fastest way to break an Agent that was working. Once it's live, let the Evaluations guide refinement instead of intuition. See [Test Safely Before Going Live](/user-guide/getting-started/test-safely), [Promote to Production](/user-guide/getting-started/promote-to-production), and [Monitor the First Week](/user-guide/getting-started/monitor-first-week).

## Related

<CardGroup cols={2}>
  <Card title="AOP" icon="book-open" href="/user-guide/building-assignments/assignment-sop">
    What an AOP is, how it differs from the Agent Builder, and how to create one.
  </Card>

  <Card title="Model Selection" icon="cpu" href="/user-guide/advanced/model-selection">
    Match the model to the difficulty of the AOP.
  </Card>

  <Card title="Multi-Agent Process Decomposition" icon="split" href="/user-guide/building-assignments/process-decomposition">
    When one AOP is doing too much, split it.
  </Card>

  <Card title="Tips and Patterns" icon="lightbulb" href="/best-practices/tips-and-patterns">
    The rest of the practical guidance across the docs.
  </Card>
</CardGroup>
