Why this pattern exists
Many LLM “multi-agent” stacks are still graphs of direct calls: agents hold references to peers, and a central orchestrator often walks the graph sequentially. That is simple to prototype, but it couples deployability, failure domains, and scaling to a single control plane. Problems that are naturally parallel—independent dimensions per document chunk, reviewer lens, or evidence passage—pay unnecessary latency and operational fragility.
The Agentic Mesh reframes the system: agents remain stateless with respect to one another; streams carry state and linkage. A coordinator fans work out; specialists consume homogeneous tasks in parallel; an aggregator reconciles partial results. The topology stays a DAG; the messaging substrate (Redis Streams in the reference implementation, or other log-like buses) supplies ordering, persistence, and consumer-group mechanics.
Key Takeaways
- Decoupled Architecture: Agents communicate exclusively via persistent message streams, removing direct RPC coupling.
- Natural Parallelism: Workloads fan out to specialized agents that process tasks concurrently, dramatically reducing latency.
- Durable State: The streaming substrate handles ordering, retries, and persistence independent of agent liveness.
Formal picture
Definition (Agentic Mesh): A directed acyclic graph G = (A, S) where A is a set of autonomous agents and S is a set of persistent, ordered message streams, such that: (1) each agent reads only from its designated input stream(s) and writes only to its output stream(s); (2) no agent holds a reference to any other agent; (3) streams persist messages independently of agent liveness.
Structurally, this is closer to “log plus small pure functions” than to RPC-heavy agent chat. The payoff is not a smarter model—it is cleaner boundaries for scale, replay, and replacement of individual roles.
%%{init: {'theme':'base','themeVariables':{'darkMode':false,'background':'#ffffff','mainBkg':'#ffffff','fontSize':'15px','fontFamily':'system-ui, -apple-system, Segoe UI, sans-serif'},'flowchart':{'curve':'basis','padding':14,'nodeSpacing':48,'rankSpacing':52,'htmlLabels':false,'useMaxWidth':true,'diagramPadding':12}}}%%
flowchart TB
PROD[["Producer"]]
INTAKE[("intake stream — tasks")]
COORD[["Coordinator"]]
S0[("parallel slot 0")]
S1[("parallel slot 1")]
SN[("slot …")]
SP0[["Specialist"]]
SP1[["Specialist"]]
SPN[["Specialist"]]
PART[("partials / merge-in")]
AGG[["Aggregator"]]
PROD --> INTAKE --> COORD
COORD --> S0
COORD --> S1
COORD --> SN
S0 --> SP0
S1 --> SP1
SN --> SPN
SP0 --> PART
SP1 --> PART
SPN --> PART
PART --> AGG
classDef agent fill:#eff6ff,stroke:#2453b8,stroke-width:2px,color:#0f172a,rx:8px,ry:8px
classDef stream fill:#fff7ed,stroke:#c56033,stroke-width:2px,color:#0f172a,rx:12px,ry:12px
class PROD,COORD,SP0,SP1,SPN,AGG agent
class INTAKE,S0,S1,SN,PART stream
Properties that matter in production
| Property | What you gain | Typical mechanism |
|---|---|---|
| Decoupling | Swap, scale, or rewrite one agent without touching others. | Agents address only stream names and payloads. |
| Persistence | Survive crashes without losing in-flight work. | Durable logs; pending lists and acknowledgements (for example Redis PEL / XACK). |
| Parallelism | Match latency to the slowest branch, not the sum of branches. | Fan-out streams plus horizontally scaled consumer groups. |
| Idempotency | At-least-once delivery without corrupting downstream state. | Ack after durable side effects; deterministic or merge-safe handlers. |
| Hot-pluggability | Change model, policy, or hosting per role independently. | Shared AgentSpec contract at the boundary. |
Reference topology (document review)
The companion implementation routes document review through doc.review.tasks, per-lens inputs such as doc.review.grammar, outputs doc.suggestions.*, and a terminal doc.review.summary. Solid arrows are publishes (XADD); dotted arrows are consumer-group reads and acks (XREADGROUP / XACK).
%%{init: {'theme':'base','themeVariables':{'darkMode':false,'background':'#ffffff','mainBkg':'#ffffff','fontSize':'14px','fontFamily':'system-ui, -apple-system, Segoe UI, sans-serif'},'flowchart':{'curve':'basis','padding':12,'nodeSpacing':40,'rankSpacing':44,'htmlLabels':false,'useMaxWidth':true,'diagramPadding':12}}}%%
flowchart LR
P[["Producer / Ingestion"]]
T[("doc.review.tasks")]
C[["Coordinator"]]
Gin[("doc.review.grammar")]
Cin[("doc.review.clarity")]
Tin[("doc.review.tone")]
Sin[("doc.review.structure")]
GA[["Grammar"]]
CA[["Clarity"]]
TA[["Tone"]]
SA[["Structure"]]
Gout[("doc.suggestions.grammar")]
Cout[("doc.suggestions.clarity")]
Tout[("doc.suggestions.tone")]
Sout[("doc.suggestions.structure")]
AGG[["Aggregator"]]
SUM[("doc.review.summary")]
P -->|XADD| T
T -.->|XREADGROUP| C
C -.->|XACK tasks| T
C -->|XADD| Gin
C -->|XADD| Cin
C -->|XADD| Tin
C -->|XADD| Sin
Gin -.->|XREADGROUP| GA
Cin -.->|XREADGROUP| CA
Tin -.->|XREADGROUP| TA
Sin -.->|XREADGROUP| SA
GA -->|XADD| Gout
GA -.->|XACK| Gin
CA -->|XADD| Cout
CA -.->|XACK| Cin
TA -->|XADD| Tout
TA -.->|XACK| Tin
SA -->|XADD| Sout
SA -.->|XACK| Sin
Gout -.->|XREADGROUP| AGG
Cout -.->|XREADGROUP| AGG
Tout -.->|XREADGROUP| AGG
Sout -.->|XREADGROUP| AGG
AGG -->|XADD| SUM
classDef agent fill:#eff6ff,stroke:#2453b8,stroke-width:2px,color:#0f172a,rx:8px,ry:8px
classDef stream fill:#fff7ed,stroke:#c56033,stroke-width:2px,color:#0f172a,rx:12px,ry:12px
class P,C,GA,CA,TA,SA,AGG agent
class T,Gin,Cin,Tin,Sin,Gout,Cout,Tout,Sout,SUM stream
XACKs each suggestion stream after merge (omitted as separate edges for clarity).End-to-end sequence
Message-level view of the same pipeline: intake, coordinated fan-out with explicit acknowledgements, parallel specialist work, then merge to summary.
%%{init: {'theme':'base','themeVariables':{'darkMode':false,'background':'#ffffff','mainBkg':'#ffffff','fontSize':'14px','actorBkg':'#eff6ff','actorBorder':'#2453b8','actorTextColor':'#0f172a','signalColor':'#334155','signalTextColor':'#0f172a','labelBoxBkgColor':'#fff7ed','labelBoxBorderColor':'#c56033','labelTextColor':'#0f172a','noteBkgColor':'#f8fafc','noteBorderColor':'#cbd5e1','noteTextColor':'#334155','activationBkgColor':'#dbeafe','activationBorderColor':'#2453b8','sequenceNumberColor':'#ffffff'},'sequence':{'mirrorActors':false,'actorFontSize':14,'messageFontSize':13,'boxMargin':12,'actorMargin':40,'wrap':true,'wrapPadding':10}}}%%
sequenceDiagram
autonumber
box rgba(239, 246, 255, 0.4) "External & Ingestion"
actor Client as Client / Caller
participant Ingest as Ingestion
end
box rgba(255, 247, 237, 0.4) "Event Bus"
participant Bus as Streams Bus
end
box rgba(248, 250, 252, 0.8) "Orchestration"
participant Coord as Coordinator
participant Agg as Aggregator
end
box rgba(238, 242, 255, 0.4) "Parallel Specialists"
participant Gram as Grammar
participant Clar as Clarity
participant Tone as Tone
participant Stru as Structure
end
Client->>+Ingest: Submit document / chunk work
Ingest->>Bus: XADD doc.review.tasks
Bus-->>Coord: XREADGROUP task
Coord->>Coord: Plan parallel lenses
rect rgba(226, 232, 240, 0.4)
Note over Coord, Bus: Fan-out — one XADD per lens
Coord->>Bus: XADD doc.review.grammar
Coord->>Bus: XADD doc.review.clarity
Coord->>Bus: XADD doc.review.tone
Coord->>Bus: XADD doc.review.structure
end
Coord->>Bus: XACK doc.review.tasks
rect rgba(241, 245, 249, 0.5)
Note over Bus, Stru: Specialists — consumer groups
Bus-->>Gram: deliver grammar task
Bus-->>Clar: deliver clarity task
Bus-->>Tone: deliver tone task
Bus-->>Stru: deliver structure task
end
Gram->>Bus: XADD doc.suggestions.grammar
Gram->>Bus: XACK doc.review.grammar
Clar->>Bus: XADD doc.suggestions.clarity
Clar->>Bus: XACK doc.review.clarity
Tone->>Bus: XADD doc.suggestions.tone
Tone->>Bus: XACK doc.review.tone
Stru->>Bus: XADD doc.suggestions.structure
Stru->>Bus: XACK doc.review.structure
rect rgba(255, 247, 237, 0.4)
Note over Bus, Agg: Aggregation & Finalization
Bus-->>Agg: XREADGROUP from suggestion streams
Agg->>Agg: Align by doc id and chunk id
Agg->>Bus: XADD doc.review.summary
Agg->>Bus: XACK each suggestion stream
end
Note over Client, Ingest: Caller retrieves doc.review.summary via API,
webhook, or polling (not a raw bus push).
Conclusion
Use stream-native meshes when work decomposes into independent units with a well-defined merge (QA over evidence passages, multi-lens review, per-tenant or per-region fan-out). Prefer classical orchestration when the workflow is deeply sequential with branching business rules that are easier to express as a single control program—though even then, moving hand-offs onto a log often clarifies failure recovery.
These notes condense the architecture section of the Agentic Mesh research companion. By treating the communication substrate as a first-class citizen, the Agentic Mesh pattern bridges the gap between experimental AI scripts and robust, production-ready distributed systems.