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

# Connecting Agents with Queues

> One Agent that does everything gets worse as the workload grows. Split the process into stages connected by Queues, and every item gets its own Run — the thousandth processed as reliably as the first.

One of the most underused building blocks in Duvo is the Queue between two Agents. Most teams start with one Agent that does everything — find the work, process it, deliver the results — and only discover Queues when that Agent becomes impossible to debug. This guide covers when to split a process across Agents connected by a Queue, and what the boundary actually buys you.

For the organizational criteria (different owners, different SLAs, reusable steps), see [Multi-Agent Decomposition](/user-guide/building-assignments/process-decomposition); for the design rules inside a single Queue (settling every Case, postpone vs. fail), see [Designing Work Around Queues and Cases](/best-practices/queues-and-cases). This page focuses on the mechanics and payoff of the Queue connection itself.

## The One-Agent Trap

A single Agent that finds twelve items and processes them in one Run works fine — until it doesn't:

* The Run fails on item 9, and items 1–8 are done but items 9–12 are not. There is no way to retry just the failures.
* One risky step (posting publicly, paying, deleting) forces you to babysit the whole Run, even though most of it is safe read-only work.
* Every improvement to one part of the procedure risks breaking the rest, because it is all one AOP.
* When the Run is slow, you can't tell which part is slow.

Each of these is the same root problem: the process has stages with different failure modes, risk levels, and speeds, but they share one Run.

## The Mental Model: a Queue Is a Contract Between Agents

A Queue is not a to-do list. It is the interface between two Agents:

* The **producer** Agent finds work and creates one Case per item, writing a fixed set of fields into the Case data. Its responsibility ends there.
* The **consumer** Agent has a Case trigger on the Queue. Each new Case starts a Run that claims it, reads those fields as its input, does one item's worth of work, and settles the Case.

The Case data is the contract. If both AOPs name the same fields, the two Agents compose like functions — and each side can be tested, fixed, and improved without touching the other.

## A Real Pipeline

The pipeline below is a real production setup of an e-commerce team that answers customer reviews across a dozen marketplace platforms; the process is three Agents connected by two Queues:

```mermaid theme={"dark"}
flowchart LR
    A[Review Orchestrator<br/>runs on a daily schedule] -->|one Case per platform| Q1[(Queue:<br/>Platform Reviews)]
    Q1 -->|Case trigger,<br/>parallel| B[Platform Collector<br/>read-only browsing]
    B -->|one Case per platform<br/>with reviews found| Q2[(Queue:<br/>Review Responses)]
    Q2 -->|Case trigger,<br/>sequential| C[Review Responder<br/>drafts and posts replies]
```

1. **Review Orchestrator** (scheduled, daily). Reads the list of active platforms from a spreadsheet and creates one Case per platform in the **Platform Reviews** Queue — title "Platform name – date", data: platform name, URL, platform type, and the date to collect. That is its whole job.
2. **Platform Collector** (Case trigger on Platform Reviews, Cases processed in parallel). Claims one Case, logs into that platform in the browser, extracts yesterday's negative reviews, and updates the Case with the structured list — including the reviews it filtered out, so there is an audit trail. If reviews were found, it creates a Case in the **Review Responses** Queue carrying the original fields plus the reviews. This stage is deliberately read-only.
3. **Review Responder** (Case trigger on Review Responses, one Case at a time). Categorizes each review, drafts a localized reply from the matching template in [Files](/user-guide/assignment-features/files), posts it on the platform, and logs the outcome.

<Tip>
  The team's favorite property of this design: the list of platforms lives in the spreadsheet, not in any Agent. Add a row, and tomorrow there is simply one more Case; switch a platform off, and it quietly drops out of the day's work. Nothing else changes — no AOP edits, no rewiring, no risk to the platforms already running.
</Tip>

## What the Queue Boundary Buys You

These are properties of the boundary itself, not of this example — every Queue-connected process gets them, and none are available to a single Agent:

* **Volume doesn't dilute quality.** Every Case is processed by its own Run, with the Agent's full attention — the two-hundredth item is handled exactly like the first. Growth adds Cases, not risk: an Agent looping over an ever-growing list inside a single Run gets slower and sloppier as the batch grows; a Queue does not.
* **Fan-out without batch loops.** One short producer Run can become dozens — or thousands — of independent Cases for the platform to work through. No "go through all pending items" step hiding failures inside a single Run.
* **Sequential or parallel, per stage.** A stage that only reads can safely process many Cases at once; a stage that acts outward — sending, posting, paying — can take them one at a time. Each stage gets the processing mode its work calls for. In one Agent, the riskiest step sets the pace for everything.
* **Failures stay the size of one item.** One blocked item postpones or fails one Case while the rest of the batch proceeds. Recovery means reprocessing that Case — not re-running the whole batch.
* **Stages iterate independently.** Each stage is its own Agent with its own AOP, so an improvement to one stage is drafted, tested, and promoted without touching the others. With one Agent, every tweak to the final step forces you to re-test everything before it.
* **State passes between stages explicitly.** Each stage records what it read, produced, and decided on the Case it is working, and copies forward the fields the next stage needs. A downstream Case starts its own timeline, so include a stable identifier in the Case data — that is what lets you trace one item across the whole pipeline when someone asks why it was handled the way it was.
* **Work only flows where it exists.** When a stage finds nothing to act on for an item, it ends cleanly — no downstream Case is created, and the next stage never wakes up for it.
* **You can see where the process is slow.** A growing Pending backlog on one Queue points at exactly one stage.

## Wiring Checklist

<Steps>
  <Step title="Create the Queue" icon="inbox">
    Create a Queue per stage boundary and give it a name that describes the work items in it, not the Agent (see [Queue](/user-guide/assignment-features/case-queue)).
  </Step>

  <Step title="Connect the producer" icon="arrow-right">
    Give the upstream Agent the Queue (Producer) Connection, and write the Case creation into its AOP: one Case per item, with the exact fields listed by name.
  </Step>

  <Step title="Connect the consumer and enable its Case trigger" icon="zap">
    Give the downstream Agent the Queue (Consumer) Connection and enable a [Case trigger](/user-guide/assignment-features/case-queue) on the Queue. An Agent has one Case trigger, and a Queue should have exactly one consuming Agent — two consumers competing for the same Cases is a conflict, not extra capacity.
  </Step>

  <Step title="Choose sequential or parallel processing" icon="gauge">
    Decide how the stage works through its Cases: in parallel for independent, read-only work; one at a time when the stage writes somewhere that must not race, or acts publicly.
  </Step>
</Steps>

## Design Rules for the Boundary

* **Agree on the Case fields before writing either AOP.** Consumers break when producers freestyle the data. List the exact field names in both AOPs, and keep them stable — a field rename is an interface change.
* **One Case = the unit you would want to retry.** A freight team audits thousands of shipments; they create one Case per shipment, not one per weekly invoice file. When an audit is disputed, they reprocess one shipment. Pick the granularity by asking "what would I want to redo in isolation?"
* **Deduplicate in the producer.** The platform does not deduplicate Cases for you. Before creating, the producer checks whether a Case for that item already exists.
* **Carry upstream fields forward.** When a stage creates the next Case, it copies the original fields and adds its own output. Downstream Agents and humans should never have to walk back up the pipeline to find the platform name.
* **Give every item a stable identifier.** Include an ID (order number, review URL, shipment number) in the Case data, and use it in everything the pipeline writes to external systems, so results can be traced back to the originating Case.

<Note>
  Inside each stage, the usual Case discipline applies — claim one Case per Run and settle it explicitly (complete, fail with a reason, postpone, or hand over). See [Queue](/user-guide/assignment-features/case-queue) for the Case lifecycle.
</Note>

## When Not to Use a Queue

* **The process is one coherent flow** a single person would do end-to-end in a few minutes, with no per-item tracking need — keep one Agent. A Queue you don't need is pure overhead.
* **A Run needs to route work onward immediately** — an intake Agent escalating a hard Case to a specialist mid-process. That is [Agent Handover](/user-guide/assignment-features/assignment-handover): the Case moves to the target Agent directly, no intermediate Queue required.
* **The stages always run together and share context** that is expensive to serialize into Case data. If stage B constantly needs "everything stage A saw", the boundary is in the wrong place.

## Signs You Got the Shape Wrong

| Symptom                                               | What it means                                                                             |
| ----------------------------------------------------- | ----------------------------------------------------------------------------------------- |
| A consumer AOP contains "for each item…" loops        | The Case granularity is too coarse — the loop should be Cases                             |
| One Queue's Pending count grows week over week        | The producer outpaces the consumer — switch the stage to parallel processing, or split it |
| Two Agents keep editing the same records              | The boundary splits one responsibility — merge the stages or move the write to one side   |
| Every change to one Agent requires re-testing another | The Case data contract is leaking — stages depend on behavior, not fields                 |

## Related

<CardGroup cols={2}>
  <Card title="Multi-Agent Decomposition" icon="workflow" href="/user-guide/building-assignments/process-decomposition">
    When to split a process across Agents — ownership, SLAs, and reusable steps.
  </Card>

  <Card title="Queue" icon="inbox" href="/user-guide/assignment-features/case-queue">
    Cases, statuses, triggers, and the full Case lifecycle.
  </Card>

  <Card title="Agent Handover" icon="arrow-right-left" href="/user-guide/assignment-features/assignment-handover">
    Route a Case to another Agent immediately, without a stage boundary.
  </Card>

  <Card title="AOP" icon="file-text" href="/user-guide/building-assignments/assignment-sop">
    Write each stage's AOP around processing a single Case.
  </Card>
</CardGroup>
