Architecture · 2026-05-06

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.

Cowork Dispatch Microsoft Agent Framework OpenTelemetry 3-PC scaling

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:

LayerWhat it ownsLifetime
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

Three-pillar architecture Vertical stack of three layers: Dispatch on top (operator amplification, build-time), MAF in the middle (runtime agent substrate), OpenTelemetry across the bottom (observability substrate spanning both). Dispatch — Cowork desktop build-time · operator amplification • Parallel sessions in a sidebar — N builders in one window • Auto-worktree per session — zero git ceremony • Phone-paired control via Dispatch — ack from anywhere builds + ships MAF — Microsoft Agent Framework runtime · agent-to-agent substrate • Three-layer middleware: Agent Run / Function Calling / Chat Client • AgentCoordinator routes via AIAgent.RunAsync — no custom message bus • Per-workflow shared context (SharedContextStore) • Anti-Drift + No-Shaming policies as Function Calling middleware emits spans OpenTelemetry — observability spine substrate · spans both build-time and runtime • GenAI semantic conventions · swappable viewers · same trace IDs across both layers build-time runtime

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

What it doesn't give you

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:

  1. Agent Run. Outer span. Owns the whole turn — input validation, post-output policy checks (anti-shaming, structural assertions), final response shape.
  2. 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?
  3. 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:

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

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.

3-PC topology Three PCs (orchestrator, overflow, persistent), a shared GitHub remote at the top, a phone connected via Dispatch on the right, and OTel exports flowing from PC1 and PC2 into PC3's shared collector. GitHub remote source of truth PC 1 — Orchestrator primary builders • Cowork desktop • 3–4 sessions in sidebar • Plan + gate-review + merge authority your seat PC 2 — Overflow heavy compute • Cowork desktop • 1–2 long-running sessions • Bench replays / variance generation / large tests async workhorse PC 3 — Persistent always-on backplane • Shared OTel collector (Jaeger/Aspire/Tempo) • Routines runner • Phone-paired (Dispatch) plumbing, not seat git push/pull OTel: spans → :4317 phone Dispatch (QR)

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

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.

Unified observability waterfall Vertical span waterfall under one trace ID. Build-time spans (Cowork session) on top, runtime spans (MAF agent workflow) below. Custom attributes shown next to each span. Time axis at the bottom. trace_id: c62d572627c75a38ba551df67ee89ba0 one trace, two layers, six services BUILD-TIME cowork.session.run · sidebar=stream-c git.commit · sha=b241bc8 dotnet.test · 153 pass git.push · branch=phase2/c handoff.context · trace_id propagated to runtime RUNTIME tempo.pipeline.run · encounter=Belo'ren log.parse percolation.analyze a2a.handoff agent_run · InterpretationAgent function_call · anti_drift chat_client · gpt-4o-mini notification.show · directive_id=8819951a t=0 t=4.2s build session →→→ runtime workflow

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:

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.

  1. 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.
  2. 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.
  3. 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.
  4. 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.
  5. 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:

OrderBuildWhy 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:

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.