Dispatch + MAF + OTel: A Complete Multi-Agent Stack
Three components, one coherent story. Claude Cowork's redesigned desktop is build-time amplification — N parallel sessions in one window, auto-worktrees, phone-paired control. Microsoft Agent Framework is runtime orchestration — agents handing off to agents under structured middleware. OpenTelemetry is the substrate underneath both, so the same trace ID can span your build session and your shipped product. This is the architecture I run, the rationale for each pillar, the topology that scales it across machines, and the order to build it in.
Companion read
This article assumes you already know the orchestration methodology — the five-layer build-session blueprint at /articles/five-layer-build-blueprint/. That piece names the patterns (memory tiers, gate alphabet, status files, parallel-stream discipline). This piece is the technical architecture that runs underneath those patterns.
Want to stand the whole thing up yourself? Skip to the end — there's a public reference repo with paste-ready prompts, infra scripts, and stage-by-stage build instructions.
Why these three together
The gap most multi-agent setups fall into: build-time tooling and run-time tooling are different worlds. You orchestrate parallel agents in your IDE with one mental model, then your shipped product orchestrates agents in production with a different mental model. Your build-time observability dies at the IDE boundary; your runtime observability starts at deploy and never includes the build context that produced it.
Picking these three forces a single coherent story:
| Layer | What it owns | Lifetime |
|---|---|---|
| Dispatch (Cowork desktop) | The operator's seat. Parallel build sessions, auto-worktrees, phone control for ack-from-anywhere. | Build-time only. Sessions die when you close them. |
| MAF (Microsoft Agent Framework) | The runtime agent substrate. AIAgent.RunAsync, three-layer middleware, A2A handoff primitives, durable agent state. |
Runtime. Lives as long as your product runs. |
| OTel (OpenTelemetry) | The observability spine. Span emission everywhere, GenAI semantic conventions, swappable visualizers (Jaeger, Aspire, Tempo, Datadog…). | Both. Same spec, same collector, same trace IDs. |
The composition is non-obvious. Most teams pick one or two of these. The genuinely valuable combination is all three, where OTel is the bridge.
The three-pillar architecture
Diagram 1 — Dispatch amplifies the operator at build time. MAF coordinates agents at runtime. OTel observes both.
Pillar 1 — Dispatch (Cowork desktop)
Dispatch is the operator-amplification layer. It is not a programming framework; it does not run in production. Its job is to make the human running the build session faster, less error-prone, and reachable from a phone.
What it gives you
- Parallel sessions in a sidebar. One Claude Code window, N work-streams. Each session is a real Claude Code instance, not a chat tab — full file-system access, terminal, editor.
- Auto-worktree per session. Two sessions on the same repo do not share a working tree. Session A can be rewriting auth while session B refactors the database. Zero merge conflicts mid-flight.
- Phone pairing (Dispatch proper). A QR code pairs your phone with the desktop. Your phone becomes a messaging interface; the desktop does the work. You can ack a
[DESIGN-READY]from anywhere. - Integrated terminal + editor. Tighter loop than CLI-only. Useful for the orchestrator's own pre-merge reviews.
What it doesn't give you
- Anything in production. Cowork sessions die when the desktop closes. They are not a runtime.
- An agent framework. Cowork sessions build things that use agent frameworks — they don't replace them.
- A standard observability layer of their own. They emit OTel spans like everything else.
When to use it
Always, for any non-trivial AI-assisted build. The gain over CLI-only Claude Code is meaningful even on a single-session project: faster onboarding, fewer copy-paste errors, ambient awareness of multiple lines of work. The gain over CLI-only is dramatic once you have two or more parallel work-streams.
Pillar 2 — MAF (Microsoft Agent Framework)
MAF is the runtime substrate. When your shipped product needs an agent to call a tool, hand off to another agent, or run a multi-turn conversation under structured middleware, MAF is what runs that. It's an IChatClient interface, an AIAgent abstraction, and a middleware pipeline that wraps every turn.
The three middleware layers
MAF's spine is a three-layer pipeline that wraps every agent turn:
- Agent Run. Outer span. Owns the whole turn — input validation, post-output policy checks (anti-shaming, structural assertions), final response shape.
- Function Calling. Inner span. Validates and routes tool/function invocations. Where Anti-Drift assertions live: did the agent's output reference data that actually exists in the input?
- Chat Client. Innermost span. The actual LLM call. Owns GenAI OTel attributes (
gen_ai.agent.name,gen_ai.request.model,gen_ai.usage.input_tokens, etc.).
Each layer is OTel-instrumented automatically. A single agent turn produces three nested spans without you wiring them by hand.
Agent-to-agent (A2A) primitives
For multi-agent workflows, MAF gives you the building blocks:
- AgentCoordinator — registers a
Dictionary<string, AIAgent>; routesAgentHandoffMessages by destination name; callsdestinationAgent.RunAsync(serializedPayload). No custom message bus, no pub-sub broker. - AgentHandoffMessage — a typed contract: source, destination, payload, context (trace ID, encounter ID, tags). Serialized to JSON between agents.
- SharedContextStore — per-workflow scoped state, isolated by
WorkflowId. Two concurrent workflows share zero state. Backed byConcurrentDictionary<Guid, ConcurrentDictionary<string, object?>>. - ILearningLoopPort — observation persistence interface. Records feedback outcomes plus the threshold snapshots active when the agent fired. Sets you up to feed observations back into model tuning later.
This is enough for most multi-agent workflows. You can ship a coordinator + three agents without writing a single line of plumbing outside MAF's native APIs.
When to use it
Whenever your shipped product runs LLM-backed work. Even a single-agent product benefits — the middleware pipeline gives you policy enforcement and observability for free. For multi-agent workflows, the alternative is hand-rolling the same primitives, which is a year-long project that doesn't compose with anyone else's tooling.
Pillar 3 — OpenTelemetry
OTel is the substrate that bridges the two layers above. Same spec, same collector, same trace IDs — applied consistently to both the build-time Cowork sessions and the runtime MAF agents.
What you get from picking the standard
- Span-based workflow tracing. Every meaningful operation emits a span. Spans nest into a waterfall. Multiple workflows run concurrently with no manual correlation.
- GenAI semantic conventions.
gen_ai.agent.name,gen_ai.request.model,gen_ai.usage.input_tokens,gen_ai.usage.output_tokens. Standardized; portable across providers. - Swappable visualizers. Jaeger, Aspire Dashboard, Grafana Tempo, Datadog APM, Honeycomb, Lightstep. Pick one; switch later. The wire format is identical.
- Cross-language portability. Your .NET MAF agent and your Python lens script can emit spans into the same trace via the same OTLP endpoint.
Custom attributes that pay back
Beyond GenAI conventions, set domain attributes on every span: tempo.encounter_id, tempo.directive_id, tempo.bench.name, etc. Operators search by these in the visualizer; engineers grep these in incident review.
Why it's the bridge
Two reasons. First: a Cowork session emitting OTel spans during a build can hand off the trace ID into an A2A workflow that runs at runtime. The build-time decision and the runtime execution share a parent trace. Second: the operator running the desktop already understands the visualizer; when production fires, they don't need a different mental model.
The 3-PC topology
One PC works fine for a single-stream build. Two work for parallel work-streams. Three is where the architecture really clicks, because PC 3 becomes the always-on observability and Routines runner — and the operator's phone, via Dispatch, becomes a remote control for any of them.
Diagram 2 — All PCs sync to GitHub. PC 1 + PC 2 export OTel traces to the collector on PC 3. The phone pairs with PC 3 via Dispatch for ack-from-anywhere.
Anti-patterns
- Don't fragment one project across PCs by branch. One project per PC at a time. Cross-PC coordination via origin + Routines + OTel — never via shared filesystems.
- Don't make PC 3 your primary IDE. It's plumbing. Long-running collectors and Routine runners need stability; constant edit-build cycles undermine that.
- Don't use Dispatch for planning. Phone is for ack and read. Plan at the keyboard.
The unified observability story
This is the payoff. Because OTel spans everything — Cowork build sessions, MAF agent runs, A2A handoffs, downstream services — a single trace ID can carry across boundaries that traditionally split into separate dashboards.
Diagram 3 — One trace ID. Top half: a Cowork session that built and shipped Stream C. Bottom half: a runtime wipe-detection workflow using the code that session shipped, with MAF middleware spans nested inside the agent run.
Two practical implications:
- When you debug a runtime issue, you can trace back to the build-time decision that introduced it. The commit, the test run, the design ack — all in the same trace history if you propagated the IDs.
- The same operator instinct works in both directions. The visualizer you used to debug an LLM drift in production is the same one you use to debug a slow build session.
End-to-end example: a wipe-detection workflow
Concrete shape of how the three pillars compose for one operator action. Names are from a spatial-temporal raid-analysis platform; the pattern generalizes.
- Build time. Operator opens Cowork desktop on PC 1, spins up a stream session for "percolation core." Auto-worktree on
phase2/stream-c-percolation. Pastes the kickoff prompt. The session reads memory + plan + status file, writes a design note, posts[DESIGN-READY]. Orchestrator session in another sidebar tab reviews, posts[DESIGN-ACK]. Builder session writes code, runs tests, pushes[COMPLETE]. Every step emits OTel spans tagged with the workflow ID. - Merge. Orchestrator pulls, runs full suite + smoke trace, merges to main. Cowork sidebar shows the merge in real time. The
[MERGED]signal propagates to the dashboard issue via a Routine. - Runtime. Real raid happens. WoW writes a combat log line. The shipped Tempo.Host (running on operator's machine) tails the log. Parser emits an event. FightStateBuilder updates state. WipeDetector emits a WipeSignal. AgentCoordinator hands off to InterpretationAgent. Three middleware layers fire (Agent Run / Function Calling / Chat Client), each emitting an OTel span. Anti-Drift validates output. NoShamingPolicy validates output. Directive emerges. NotificationService renders it on screen.
- Observability. Operator opens Jaeger on PC 3. Sees the full trace: build-time spans from when this code was written, runtime spans from this morning's wipe. Same trace family, propagated via the workflow context.
- Feedback. Operator clicks Used / Dismissed / Wrong cause. FeedbackStore persists. ILearningLoopPort records the threshold snapshot for later. Routine on PC 3 picks up the feedback rows in tonight's digest.
None of these steps require code that's specific to the composition. Each pillar handles its own layer; OTel does the threading.
What to build first (priority order)
Don't try to stand up all three at once. The order matters because each unlocks the value of the next:
| Order | Build | Why now |
|---|---|---|
| 1 | OTel collector on whichever machine will be PC 3. | Foundational. Without it, the other two layers emit telemetry that goes nowhere. Jaeger + the existing OTLP wire format gets you 90% of the value in 30 minutes. |
| 2 | MAF middleware skeleton in your shipped product, even if it's just one agent. | Once you have OTel and one MAF agent emitting spans, you have a working observability story. Add agents and middleware policies as the product grows. |
| 3 | Cowork desktop on PC 1 (your seat), with one or two parallel sessions to start. | The amplification kicks in immediately, even at one session. Add more sessions and add PC 2 only when a single PC's parallel-session count starts to feel heavy. |
| 4 | Routines for status-digest and merge-ready checks. | Only meaningful once you have parallel work-streams running often enough that polling status files becomes annoying. Premature otherwise. |
| 5 | Dispatch phone-pairing. | Last. Mobile ack is genuinely useful but only if you're sometimes away from the keyboard while builds are in flight. Solo developers at one desk get little from this. |
Build all vs. some — how to decide
Not every project needs the full stack. The scaling threshold for each pillar is roughly:
- OTel: always. Even a one-script project benefits from spans you can grep through. The cost is near-zero.
- MAF: when you ship LLM-backed code that runs in production. Local developer scripts can use simpler wrappers; production-bound multi-turn or multi-agent work needs the middleware.
- Cowork desktop: when you have at least one project where two work-streams could profitably run in parallel. Solo greenfield projects with one stream can stay on CLI Claude Code.
- 3-PC topology: when a single PC's parallel-session count exceeds 4–5 and the heavy-compute sessions start blocking the orchestrator. Most users land on 2 PCs first; PC 3 emerges later.
- Routines: when status-file polling becomes a fixed cost in your day. If you're checking statuses fewer than 3 times per active build day, polling by hand is fine.
- Dispatch phone-pairing: when you're regularly away from the keyboard while builds are in flight. Specific to your work patterns.
Stand it up yourself
The complete reference repo — paste-ready prompts, infra scripts, stage-by-stage build instructions, ADR templates — lives at github.com/steppe-integrations/multi-agent-build-blueprint. Public. Open the README and follow the stage docs in order. Each stage tells you why, when, and how to build it, plus when it's safe to skip.
Derek Ciula is an enterprise architect, technical mentor, and AI integration specialist. Steppe Integrations helps teams build durable AI-assisted engineering workflows. The architecture in this article runs in production on a spatial-temporal raid-analysis platform and a community-survival multiplayer game; both ship with their full observability spine intact.