TruvaG3

A Microagents Reference Architecture: Dynamic Capability Discovery and Decentralized Coordination

An introduction to a microagents architecture in which specialized tools and agents dynamically register their capabilities with a shared registry, are addressed by logical names rather than hardcoded URLs, and coordinate without a central conductor — with orchestration inside each agent and decentralized coordination across the system. The concepts are grounded in TruvaG3[1], an open-source reference implementation.

Neelabh Tripathi · May 7, 2026

The wiring problem

Most agent frameworks today follow the same pattern. You build an agent, give it a list of tools, and start a loop. The agent reasons, picks a tool, calls it, reads the result, and repeats. If you want a second agent, you usually wire it into the first as another callable, or you put both inside a higher-level orchestrator that decides whose turn it is.

This pattern works at demo scale. It is harder to defend at production scale[30][31]. Adding a tool requires redeploying the agent. Sharing a tool across agents means duplicating registration code in every agent that needs it. Adding a new agent that other agents should be able to reach means rebuilding the orchestration graph that decides routing. Mentally, the model works like a single program with internal function calls. That is fine for prototypes, but it does not match how distributed systems are usually built.

This article describes a different design, borrowed almost entirely from how production microservices are built: a service registry indexed by capability, peers that find each other at runtime, and direct point-to-point calls. There is no central orchestrator routing between participants. There is, however, a per-agent orchestrator that runs each agent's own reasoning loop. The result is a two-layer coordination model that is easier to reason about than a single global one — and one that follows patterns the infrastructure community has refined over the past decade.

The article describes the architecture in concept-first form. The concrete examples — code paths, execution traces, registry screenshots — come from TruvaG3[1], an open-source reference implementation written in Go. TruvaG3 exists to make these patterns easy to inspect. The source code, the example deployments, the design notes, and the registry-viewer web app[13] are all public, and the entire system runs on a laptop in a local Kubernetes cluster. When the article points to a specific behavior, a numbered citation links to the relevant file or directory in the repository.

How today's frameworks coordinate

Before describing the new approach, it helps to look at what is normal today. Most popular agent frameworks share the same wiring approach: the developer hands the framework a complete list of tools and agents — in code or configuration — before the program runs. The framework does not look outside that list at runtime.

The same point, by framework, in everyday terms:

Tools and agents that run in another process or service are not an exception to this. To use a tool that lives elsewhere, the agent's own code must contain a wrapper that knows the external tool exists and how to reach it. The wrapper is what the framework treats as "the tool"; the framework still requires that wrapper to be present in the source at startup. By default, none of these frameworks reads a shared, live registry to learn what tools or agents are currently available across the deployment, and none lets new tools or agents — deployed elsewhere, after the program has started — become usable to existing callers without a code change.

Tools and peers are wired in source Agent program (compiled binary) Agent loop Tool A Tool B Sub-agent C agent.tools = [tool_a, tool_b, sub_agent_c] All participants are bound into the agent's program before it starts. No outside list is consulted at runtime. A new tool deployed elsewhere cannot be picked up Agent program (running) Agent loop Tool A Tool B Sub-agent C Tools and peers fixed at startup. ✗ NO LINK Tool D deployed later, separate process The running agent has no way to discover it. A code change and redeploy are required to use it.
Figure 1. Build time vs runtime in popular agent frameworks. Left: tools and peers are referenced by name in the agent's source code; once compiled, they are part of the same program. Right: a tool deployed separately after the agent starts is invisible to the running agent — there is no shared registry the agent consults at runtime, so the only way to use the new tool is to add a reference to it in source and redeploy.

The shared pattern across all seven is a central coordinator. Some component inside the framework — a graph runner, a crew, a team manager, an LLM-driven dispatch loop, a workflow object — holds the plan, decides the order of operations, and routes work between participants. The participants themselves are passive: they react to calls, constrained by a list of peers and tools that was fixed when the program started. Whether the order is decided by an LLM, a routing graph, or a turn-selection policy, the list it picks from does not change while the program is running. This is the well-known orchestration pattern from distributed-systems literature, where one process directs the others.

Orchestration is not wrong. It gives you a global view, easy retries, and clean state machines. It also gives you a single point of failure, a single point of scale, and a single component that must change every time you add a participant. In multi-agent systems, the trade-offs are the same ones the microservices community faced a decade ago, when it moved away from centralized orchestrators (workflow engines, enterprise service buses) toward decentralized service-discovery patterns[11].

The microagents architecture

The architectural class this article describes has begun to acquire a name in industry literature: a microagents architecture. The term is used in two related senses, and it is worth distinguishing them up front.

At a workflow level, articulated in a recent CIO article on the agentic enterprise[8], microagents are "specialized AI systems designed to perform narrow, well-defined tasks within a workflow," and macro-agents are components that "coordinate multiple micro agents to complete an end-to-end business process." This framing is about division of labor and governance.

At an architectural level, which is the focus of this article, a microagents architecture is a system with the following properties:

Microsoft's multi-agent reference architecture[6] describes the foundational pattern as a "Dynamic Agent Registry (Service Mesh for Agents)": an orchestrator consults this registry at runtime to discover and route to specialized agents. Alibaba Cloud's recent reference design[7] emphasizes the location-transparency property explicitly: "Agents do not directly hold each other's physical addresses (IP/Port) but query the Agent Registry and use each other's logical names (agentName) to obtain access endpoints. This achieves complete decoupling with location transparency."

Centralized orchestration Orchestrator graph / crew / runner / team / kernel / workflow Tool Agent Tool Participants are wired in source at construction. The orchestrator routes work between them. Decentralized coordination Capability Registry passive index no central control logic Tool Agent Tool Participants register at runtime. Peers find each other through the registry. No central conductor.
Figure 2. Two architectural approaches in contrast. Left: popular agent frameworks place a central orchestrator at the top, with all participants wired in at construction; the orchestrator routes work between them. Right: a microagents architecture inverts this — participants register themselves into a passive registry at runtime; coordination is decentralized, with peers finding each other through the registry and calling each other directly, with no central component directing the flow.

The contrast with the seven frameworks in the previous section is direct. Each of those binds every participant at construction; a microagents architecture lets participants come and go independently. The registry is the only thing they need to know about each other, and — in this article's variant — the only thing the LLM needs to know about them either.

Agent code holds no peer references Agent program (compiled binary) Agent loop Registry client agent.tools = registry.discover() No peer is named in source. The program only knows how to read the registry. Anything available there can be used immediately. A new tool deployed elsewhere is immediately visible Capability Registry Tool A · Tool B · Sub-agent C · Tool D Agent program Agent loop Tool D deployed later, separate process registers reads ✓ DISCOVERED Tool D registers on startup; the agent sees it on its next registry read. No code change. No redeploy.
Figure 3. Build time vs runtime in a microagents architecture. Left: the agent program ships with no peer references in source — only a registry client. Tools and peers are not bound at compile time. Right: a tool deployed separately registers itself into the shared registry on startup; the agent picks it up on its next read, with no code change and no redeploy.

This article describes one specific reference design for that class — and that design has a working open-source reference implementation in TruvaG3[1], the framework this article is grounded in. Everything that follows can be cloned, deployed locally, and observed in the live registry-viewer UI. The dynamic registry pattern itself has decades of precedent in service-discovery infrastructure, and the LLM-as-registry-consumer extension is also available in other open-source systems[16]. The architectural point here is the role the registry plays at request time: its current contents are what the LLM sees in its planning prompt, so the LLM picks among capabilities that are dynamically present rather than capabilities that were configured ahead of time.

A different approach: the capability registry

The architecture is built around a single primitive: a capability registry. Every participant — whether a simple tool or a full reasoning agent — publishes the capabilities it offers into a shared index, each identified by name. These capability names are runtime facts about the deployment; they are not configuration carried in any caller's code, and no participant references a peer's capability by name in its own source. When a request needs to be planned, the framework hands the registry's current contents to the LLM as the planning context, and the LLM picks which capabilities to invoke. For example, if the LLM chooses financial_analysis for a step, the framework dispatches that step to whichever endpoint the registry currently lists for financial_analysis. Whether that endpoint is a deterministic function or an agent running its own plan-act-observe loop is invisible at the dispatch site. (In the reference implementation, the index is backed by Redis[27], but the choice of backend does not affect the pattern.)

Capability Registry passive index · accepts whoever registers · entries expire on missed heartbeat capabilities:get_current_weather → weather-tool-v2 just registered capabilities:financial_analysis → research-agent heartbeat 5s ago capabilities:convert_currency → currency-tool heartbeat 9s ago register { name, address, capabilities, ttl: 30s } heartbeat (every 15s) heartbeat (every 15s) weather-tool-v2 just booted research-agent running currency-tool running
Figure 4. Self-registration: at boot, each participant pushes its own description to the registry — name, address, capabilities, and TTL — and from then on heartbeats every 15 seconds to refresh that 30-second TTL. The registry never initiates; it accepts whoever registers and evicts whoever stops heartbeating. The set of capabilities the LLM sees in any planning prompt is whatever has registered and is currently heartbeating — nothing was preconfigured anywhere.

There are three core roles in the architecture:

RoleRegisters capabilities?Discovers peers?Has internal orchestrator?
ToolYesNoNo — passive HTTP endpoint
AgentYesYesYes — drives a plan-act-observe loop
Registry——No — a passive index

The difference between Tools and Agents matters. A Tool is a capability provider with no autonomy: it answers calls, returns data, and finishes. An Agent is a provider and a consumer: it answers calls, and while serving them it can find other capabilities in the same registry and call them directly. In a statically-typed language, this difference can be enforced at compile time through interface design. In TruvaG3[1] (written in Go), Tools satisfy a Registry interface (register only); Agents satisfy a Discovery interface that includes Registry (register and discover). Tools cannot call discovery methods, because those methods do not exist on their interface. The framework's design notes[3] document the full contract. The separation becomes a property the type system can check before the code runs.

The registry itself is intentionally simple. It is a key-value index: capabilities map to service IDs, and service IDs map to addresses. Entries expire after a TTL and are kept alive by heartbeats. The registry does not route messages, throttle calls, or apply policy. It is to this architecture what etcd is to Kubernetes — coordination data, not a coordinator.

Self-describing capabilities

A registration carries more than a name. It serves two distinct consumers. The framework reads it for dispatch — a network address and an endpoint per capability. The LLM reads it for planning — a natural-language description of each capability and a structured schema for its inputs and outputs, so it can decide which capability matches a step and what payload to send.

The address resolves to the right form for the deployment. In a Kubernetes cluster, the framework writes a Service DNS name, so calls to the participant load balance across replicas through the cluster's own Service. Outside Kubernetes, it writes a plain host and port. Whichever form ends up in the registry is the form callers use; no agent ever carries a hardcoded URL.

Here is what this looks like in the live registry: the top-level structure of the entry for weather-tool-v2[9], with the Kubernetes metadata sub-object trimmed for display:

{
  "id": "weather-tool-v2",
  "name": "weather-tool-v2",
  "type": "tool",
  "address": "weather-tool-v2-service.truvag3-examples.svc.cluster.local",
  "port": 80,
  "health": "healthy",
  "last_seen": "2026-05-07T01:50:18Z",
  "capabilities": [
    { "name": "get_current_weather",  "endpoint": "/api/capabilities/get_current_weather"  },
    { "name": "get_weather_forecast", "endpoint": "/api/capabilities/get_weather_forecast" }
  ]
}

The address and port together are what the framework dials. Each capability inside the capabilities array contributes a relative endpoint. Combined, they yield the full URL the executor calls. For get_current_weather in this deployment, that resolves to:

http://weather-tool-v2-service.truvag3-examples.svc.cluster.local:80/api/capabilities/get_current_weather

In a non-Kubernetes deployment, the same record would carry an address like weather-tool.example.com and a port chosen by the deployment — 443 for an HTTPS-fronted production service, 8080 for a self-hosted service without TLS. The registry stores the explicit connection target; how the call is wrapped (HTTP, HTTPS, with or without a reverse proxy or service-mesh sidecar) is a deployment concern, not a registry concern. The agent's source code never sees this URL — the framework reads it from the registry at request time and dials.

The capability description itself comes in three layers, each more precise than the last:

Each capability inside the capabilities array carries those three description layers. Here is get_current_weather in full:

{
  "name": "get_current_weather",
  "description": "Gets current weather conditions for a location including temperature, humidity, and wind.",
  "endpoint": "/api/capabilities/get_current_weather",
  "input_types": ["json"],
  "output_types": ["json"],
  "input_summary": {
    "required": [
      {
        "name": "lat",
        "type": "number",
        "description": "Latitude coordinate (-90 to 90)",
        "example": "40.7128"
      },
      {
        "name": "lon",
        "type": "number",
        "description": "Longitude coordinate (-180 to 180)",
        "example": "-74.0060"
      }
    ]
  }
}

And here is devops_operations, an external capability served by an Agent — devops-chat-agent[15], the same agent featured in the multi-domain execution example later in the article — that runs its own internal plan-act-observe loop behind this endpoint:

{
  "name": "devops_operations",
  "description": "Handles Kubernetes and infrastructure operations end-to-end: from investigation and diagnostics to remediation and verification. Delegate any DevOps task as a natural language request and receive a synthesized response with findings, actions taken, and current state.",
  "endpoint": "/query",
  "input_types": ["json"],
  "output_types": ["json"],
  "input_summary": {
    "required": [
      {
        "name": "query",
        "type": "string",
        "description": "Natural language DevOps or infrastructure question to delegate",
        "example": "Which pods in truvag3-examples are not Ready and what do their logs say?"
      }
    ],
    "optional": [
      {
        "name": "session_id",
        "type": "string",
        "description": "Session ID for conversational context (omit for stateless one-shot queries)",
        "example": "sess_abc123"
      }
    ]
  }
}

The two records are structurally identical. A caller looking up either capability sees the same fields in the same structure — name, description, endpoint, input and output types, and the structured field hints. The fact that one is served by a stateless tool and the other by an agent that runs its own internal plan-act-observe loop is invisible at the registry layer. From the LLM's point of view at planning time, a capability is a capability — it picks by what the capability does, not by what kind of process serves it.

The consequence: a participant's registration is enough, on its own, to know how to reach it and what data its capabilities accept and return. There is no separate API documentation that has to be kept in sync, no client SDK with hardcoded signatures, and no version-pinned schema file. How a multi-step plan actually executes against this data — formatting payloads, dispatching, threading values between steps — belongs to the per-agent orchestrator described later in the article.

What makes the discovery dynamic

The discovery is dynamic in three senses, each of which matters in production. To be precise about the term: discovery here does not mean the agent's code calling a lookup function. The agent's code does not know any capability names. It is the chain by which the registry's current state reaches the LLM at planning time, and from there reaches the address that handles each step.

The mechanics behind the three properties below — a key-value registry, TTL-based liveness, additive registration — are borrowed from service-discovery patterns that have been used in microservice systems for over a decade. What is distinctive in the microagents version of those mechanics is the role they play: the consumer of the registry's contents is not application code with a known target name; it is an LLM choosing from a runtime menu. The plumbing is standard. The mediation is not. This combination is uncommon in agent frameworks, where tools are usually bound to agents at construction time.

t = 0s flight-tool deployed CAPABILITY REGISTRY search_flights flight-tool cheapest_dates flight-tool heartbeat 15s · TTL 30s Agent + LLM resolves to flight-tool healthy Flight planning is now possible. Agent source named no tool. t = 30s hotel-tool deployed alongside CAPABILITY REGISTRY search_flights flight-tool cheapest_dates flight-tool search_hotels hotel-tool hotel_ratings hotel-tool Agent + LLM flight-tool healthy hotel-tool healthy Catalog grew. No agent code changed. Multi-step trip plans are now possible. t = 90s hotel-tool stopped heartbeating CAPABILITY REGISTRY search_flights flight-tool cheapest_dates flight-tool search_hotels hotel-tool hotel_ratings hotel-tool Agent + LLM resolves to flight-tool healthy Hotel capabilities dropped within one TTL window. Liveness is the registration.
Figure 5. How the LLM's planning catalog changes over time, drawn from a live local cluster running flight-tool and hotel-tool. (Two capabilities are shown per tool for clarity; flight-tool publishes four in total and hotel-tool publishes three.) (A) flight-tool deploys and registers; the registry now contains search_flights and cheapest_dates, each mapped to flight-tool — entries that did not exist a moment ago. (B) hotel-tool deploys alongside and contributes new capabilities — search_hotels and hotel_ratings; the catalog grows, and the LLM can now plan a multi-step "find a flight and find a hotel" request, all without any agent code change. (C) hotel-tool stops heartbeating; its entries expire within one TTL window, and the catalog shrinks back to where it was after Panel A. The three panels visualize the three properties described below: a runtime tool list, a live registry, and zero-config additivity.

The same mechanism applies to agents. research-agent-telemetry[10] publishes capabilities like financial_analysis and sentiment_analysis; devops-chat-agent[15] publishes devops_operations. Each agent registers with the same shared registry, exactly the way a tool would. The only structural difference, invisible at the registry layer, is what runs behind those endpoints: a plan-act-observe loop instead of a deterministic function.

t = 0s research-agent-telemetry deployed CAPABILITY REGISTRY financial_analysis research-agent-telemetry sentiment_analysis research-agent-telemetry heartbeat 15s · TTL 30s registers research-agent-telemetry (type: agent) Agent loop plan → act → observe ↻ t = 90s devops-chat-agent deployed alongside CAPABILITY REGISTRY financial_analysis research-agent-telemetry sentiment_analysis research-agent-telemetry devops_operations devops-chat-agent registers devops-chat-agent (type: agent) Agent loop plan → act → observe ↻
Figure 6. How agents publish their capabilities, shown as a time-lapse like the earlier tool figure. (A) At t = 0s, research-agent-telemetry deploys; the registry now lists financial_analysis and sentiment_analysis, both newly added. (B) At t = 90s, devops-chat-agent deploys alongside; the registry now also contains devops_operations. Both agents register the same way a tool would — capability name, endpoint, field hints, and TTL-driven liveness — and the registry treats both kinds of participants identically. From the LLM's planning prompt, all three capabilities look like any other. The structural difference is invisible at the registry layer: behind these endpoints runs a plan-act-observe loop, not a stateless function.

The tool list is runtime data, not code. The agent's source names no tool and no capability. The set of capabilities a request can use is not declared anywhere in the agent's code — it is whatever the registry currently advertises. When a request arrives, the framework reads that current state and presents it to the LLM as the planning context. Only at that moment, when the LLM is shown a fresh menu and asked to plan against the incoming request, does any specific capability enter the picture. The LLM picks from the menu; the framework then dispatches each chosen step to the address the registry currently lists for it. The same chosen capability, picked again in a later request, can land on a different address if the topology has shifted in between.

A live registry, not a static catalog. Every participant sends a heartbeat to the registry every 15 seconds, refreshing a 30-second TTL on its entry. If a participant crashes, shuts down, or loses network connectivity, it drops out of the registry within at most one TTL window. What the LLM sees on its next planning prompt is therefore the set of participants currently running and reachable — nothing more, nothing less. There is no separate health-check system; liveness is the registration.

Zero-config additivity. Deploying a new tool or agent makes its capabilities part of every running agent's planning catalog within one refresh cycle. No agent code changes. No central manifest is updated. No agent needs to be redeployed. The same property holds in reverse: removing a participant is clean — its registrations expire, and the LLM simply stops seeing it as an option. This is the property that separates a live registry from a static dependency graph.

These three properties together — a runtime tool list, TTL-driven liveness, and additive registration — turn a key-value index into something a multi-agent system can be built on. They also make the architecture easy to extend: adding a participant is purely additive, and the system never needs a coordinated redeploy to support a new capability.

Two coordination layers

One way to see the architecture is as a system with two distinct coordination layers, each using a different pattern.

Capability Registry (Redis) passive index · TTL 30s · heartbeat 15s · no logic, no routing capabilities:financial_analysis → research-agent-telemetry capabilities:web_search → web-search-tool capabilities:geocode_location → geocoding-tool capabilities:devops_operations → devops-chat-agent register + discover register + discover register only register only Agent A AIOrchestrator plan → act → observe ↻ Agent B AIOrchestrator plan → act → observe ↻ Tool 1 passive HTTP endpoint no orchestrator Tool 2 passive HTTP endpoint no orchestrator register discover
Figure 7. Tools and Agents are peers in one capability registry. Agents both register and discover; Tools only register. The asymmetry — that Agents carry an internal orchestrator and may call back to other registered peers — sits inside each Agent and is enforced at compile time.

Inside an agent: orchestration

Each Agent has its own per-request orchestrator. When a request arrives, the orchestrator hands the LLM its current capability catalog (kept in sync with the registry) and asks for a plan. The plan it gets back is structured as a directed acyclic graph (DAG)[28][29] — each step names a capability and lists its upstream dependencies, but no step ever loops back to itself. The orchestrator then executes that DAG step by step with parallelism where possible — resolving each capability to a concrete endpoint at execution time, handling retries and parameter resolution, and synthesizing the final response. This is orchestration in the traditional sense: one conductor directing a sequence of steps against a known plan. It is the right pattern for a single agent's reasoning loop, where global state is needed.

Agent (one process) — AIOrchestrator drives the flow PHASE 1 Plan Single LLM call against the live capability catalog. Output: a DAG of steps. PHASE 2 Execute steps For each step: resolve capability → HTTP call → response. Run in DAG order, with parallelism where possible. PHASE 3 Synthesize Assemble step outputs into a final response for the user. iterative re-plan, if needed Tool (in its own process) Agent (in its own process) HTTP HTTP
Figure 8. Inside an agent: orchestration. A single AIOrchestrator[4] inside the agent's process drives three phases — plan against the catalog, execute the resulting DAG, synthesize the response — and can loop from execute back to plan when the LLM decides partway through that further planning is needed. The Execute phase's HTTP calls leave the process and reach peers — tools or other agents — that run in their own processes. One conductor inside one process; dispatched calls cross the boundary.

Between participants: decentralized coordination

Between participants, no such conductor exists. Each Agent runs its own orchestrator independently. When one Agent needs a capability that another participant exposes, it asks the registry, gets an address, and calls the endpoint directly over HTTP. The receiving participant — Tool or Agent — handles the call on its own terms. Nothing in the middle routes, sequences, or coordinates. This is decentralized coordination: peers acting on a shared protocol (the capability contract) rather than being directed by a controller.

Capability Registry passive index · register and discover Agent A AIOrchestrator plan → act → observe ↻ Tool B passive endpoint no orchestrator Agent C AIOrchestrator plan → act → observe ↻ Tool D passive endpoint no orchestrator register / discover user query HTTP HTTP HTTP (Agent → Agent)
Figure 9. Between participants: decentralized coordination. Agent A receives the user query (the inbound blue arrow on the left) and becomes the request initiator. From there, each participant runs independently. The dashed lines up to the registry carry registration and discovery; the blue arrows between participants carry the actual HTTP calls. There is no process in the middle that coordinates the calls — peers act on the shared protocol, the capability contract, and call each other directly.

The microservices analogy is direct. A microservice has step-by-step business logic on the inside (orchestration) and interacts with peers through service discovery and direct calls (decentralized coordination). The architecture applies the same pattern to multi-agent systems: orchestration inside each agent, decentralized coordination between agents and tools. In the reference implementation, the per-agent orchestrator and its outbound HTTP dispatch live in the orchestration/ package[4]; the registry and discovery interfaces that participants use to find each other live in core/[2].

Two executions, examined

The clearest way to understand an architecture is to look at real runs. Below are two captured executions from the reference implementation — one showing orchestration inside an agent, the other showing one agent calling another.

Switzerland trip planning: orchestration with tools

The first run is in response to a single query:

"Find out the top 3 destinations for tourists in Switzerland, by popularity, and give me their weather right now and a good place to stay at each of those locations."

The agent that received this query — travel-chat-agent[12] — is one Agent, the kind described in this article. The query is interesting because the agent cannot plan the full response up front: it does not know the three top destinations until it has performed the web search. Its orchestrator therefore runs the request in three phases, returning to plan twice as new information becomes available — directly exercising the loop-back arrow shown in the orchestration diagram earlier in the article.

Execution DAG for the Switzerland query, captured from the registry viewer. The diagram is laid out vertically and shows three distinct phases. Top: a Planning node feeds a single web-search-tool call. Then a 'Phase 1 → 2' transition node, followed by a Tier Select node, followed by a Phase Plan node, which branches into three parallel geocoding-tool calls. Then a 'Phase 2 → 3' transition node, followed by another Tier Select and Phase Plan, which branches into six parallel calls — three weather-tool-v2 calls and three hotel-tool calls. All ten tool steps converge into a Synthesis (Stream) node at the bottom. The phase boundaries are visually distinct.
Figure 10. Three-phase execution captured from the registry-viewer UI[13]. Phase 1 plans a single web search; the LLM cannot plan further until it knows the destinations. Phase 2 — generated after Phase 1's results return — plans three parallel geocoding calls (one per destination: Zurich, Zermatt, Interlaken). Phase 3 — generated after Phase 2's coordinates return — plans six parallel calls (weather and hotel for each destination). Total wall time: 29 seconds. Maximum parallelism: six.

What this run demonstrates about the microagents architecture in action:

A multi-domain query: agents and tools as peers

The Switzerland run shows the inside of one agent. To see the other coordination layer in practice — and to make the article's central claim visible in a single plan — here is a second captured execution. The query crosses three unrelated domains:

"Can you analyze the status of the local Kubernetes cluster? Also, let me know the current weather at NYC, and the stock price of Tesla."

travel-chat-agent reads the registry's current contents — a catalog of capabilities, not a typed list of tools and agents — and plans a four-step response. The LLM doesn't know (and doesn't need to know) which capabilities are served by tools and which by agents:

Outer execution DAG: travel-chat-agent's four-step plan invokes one agent capability (devops_operations) and three tool capabilities (geocode_location, stock_quote, get_current_weather) from the same catalog, with no special handling for the agent step.
Figure 11. The outer trace, captured from travel-chat-agent's perspective in the registry-viewer UI[13]. Four capability invocations in one plan, drawn from the same catalog. One of them — devops_operations — happens to be served by an agent; the other three by tools. From the dispatch site there is no visible difference between them.

Behind the devops_operations step is a complete second execution. devops-chat-agent receives the request, plans its own response against its own catalog, and runs three tool calls — get_cluster_status and two scoped get_pods calls against devops-tool — then synthesizes a single answer and returns it to travel-chat-agent.

Inner execution DAG: devops-chat-agent receives the call and runs its own plan-act-observe loop, calling three tool capabilities before synthesizing a response.
Figure 12. The inner trace, captured from devops-chat-agent's perspective in the same UI. The orchestration pattern shown earlier in the article — plan, execute, synthesize — runs entirely inside this agent's process. The structured response of this whole DAG is what gets returned through Figure 11's devops_operations step.

What this run demonstrates, in concrete form:

What this unlocks

Two architectural properties fall out of this design — properties that are hard to get when participants are wired statically.

Tools and Agents compose interchangeably. Because the call site does not distinguish between them, a deployment can swap a tool for an agent that exposes the same capability without callers changing. A capability that begins as a deterministic tool (a small service with an HTTP handler) can later be replaced by a reasoning-driven agent that performs its own internal work before responding — under the same capability name. Callers continue to look it up by name and continue to receive structured responses against the same schema. The promotion is a deployment change, not an architectural one.

Adding a participant requires no central change. Drop a new participant into the deployment. It registers itself, advertises its capabilities, and is immediately discoverable. No orchestrator graph needs editing, no routing table needs updating, no central deployment needs redeploying. Within the registry's normal propagation window, the new participant is visible to every existing caller — and can be invoked by them without any change to their own code or configuration. This is the operational property that service-discovery infrastructure gives to ordinary microservices, carried over to the microagents domain.

Some practical consequences (illustrated against a Kubernetes deployment, since that's the most common production setup):

The trade-offs you should know

An honest description should also name what you give up.

No global execution view, by default. Without a central conductor, no single component knows the full state of all in-flight work. Operations and debugging rely on the same distributed-tracing infrastructure that microservice systems use — trace IDs propagated through calls, spans collected per participant, and end-to-end views reassembled from a trace store. This is well-understood and works well in practice, but the absence of a built-in global view is real: there is no point inside the architecture from which to ask "what is happening everywhere right now?"

Cross-participant sequencing is harder. If you need an explicit, system-wide workflow that spans multiple agents and tools — sequenced from a single source of truth, with explicit failure handling and compensations — the decentralized pattern does not give it to you for free. You will need to reintroduce orchestration at the inter-agent layer in whatever form suits the use case: a coordinating agent that drives the others, an external workflow engine, or an event-driven saga with explicit orchestration. The decentralized model handles "each agent can serve and call peers" well; it does not handle "this multi-step process must run in this exact order, with these compensations on failure" — that is a different problem requiring a different approach, and decentralized coordination is not always the right answer.

The registry is a shared dependency. Agents and tools can keep serving in-flight requests without the registry, but new discoveries cannot resolve while it is down. The architecture moves the single point of failure from a central orchestrator process to a passive data store — a trade-off common to most service-discovery designs.

Run it yourself

The reference implementation, TruvaG3[1], is open source. Step-by-step setup instructions for the local-Kubernetes deployment — Redis, the registry-viewer web app, and the bundled example tools and agents[5] — are in the project's Getting Started guide[14]. The full deployment runs on a laptop in a kind cluster.

Both captured executions in "Two executions, examined" come from this same setup. Once the bundled examples[5] are deployed, the two user queries shown there can be run verbatim against your own travel-chat-agent, and the registry-viewer's Execution DAG tab will produce screenshots and trace JSON files equivalent to Figures 10–12 and references [24]–[26]. All the agents and tools involved — travel-chat-agent, devops-chat-agent, and the half-dozen tools they invoke — are part of the bundled examples; no additional setup is needed. Nothing in this article is theoretical.

Conclusion

At the scale of an enterprise agentic platform — many teams, many tools and agents, many independent release cadences — the architecture described in this article is a pattern well-matched to that scale. Dynamic capability discovery, uniform peers, a passive registry, orchestration inside each agent, and decentralized coordination between participants: this combination lets specialized teams own their own participants, ship them on their own schedules, and have their work composed into every other team's agents without coordinated releases or central registration steps. The runtime mechanics ride on infrastructure most organizations already operate — service discovery, load balancing, observability, rolling releases — not on a proprietary orchestration product whose failure modes, scaling characteristics, and cost ceilings become operational concerns of their own.

The mechanics themselves are not new. They borrow from decades of service-discovery practice in distributed systems[11], and the LLM-as-registry-consumer extension is also available in other open-source systems[16]. What this article contributes is a vendor-neutral architecture treatment paired with a Go reference implementation that runs on a laptop — an architecture doc with a clone-and-run companion.

References

  1. TruvaG3 — repository. Open-source reference implementation of the architecture described in this article. https://github.com/truvaagents/truva-g3
  2. TruvaG3 — core/ package. Framework interfaces (Registry, Discovery, Component, AIClient) and base implementations (BaseTool, BaseAgent), plus the Redis-backed service-discovery layer that participants use to find each other. https://github.com/truvaagents/truva-g3/tree/main/core
  3. TruvaG3 — FRAMEWORK_DESIGN_PRINCIPLES.md. The Tool/Agent boundary contract and the rationale behind the typed-interface separation. https://github.com/truvaagents/truva-g3/blob/main/FRAMEWORK_DESIGN_PRINCIPLES.md
  4. TruvaG3 — orchestration/README.md. The orchestration module's user-facing README. Section 4, "AI Orchestration in Detail", walks through how the AIOrchestrator processes an AI-driven request — interpreting the user query, discovering capabilities in the catalog, building the execution plan, and synthesizing the response. The corresponding source code lives under the same directory. https://github.com/truvaagents/truva-g3/blob/main/orchestration/README.md
  5. TruvaG3 — examples/ directory. Sample tools, agents, and end-to-end deployments, including the chat agents used in the walkthrough. https://github.com/truvaagents/truva-g3/tree/main/examples
  6. Microsoft. Multi-Agent Reference Architecture. The phrase "Dynamic Agent Registry (Service Mesh for Agents)" quoted in this article appears under the Patterns section as item #2 in the list of foundational patterns. URL: https://microsoft.github.io/multi-agent-reference-architecture/docs/reference-architecture/Reference-Architecture.html
  7. Alibaba Cloud. Configuration-Driven Dynamic Agent Architecture Network: Achieving Efficient Orchestration, Dynamic Updates, and Intelligent Governance. The location-transparency quote — "Agents do not directly hold each other's physical addresses (IP/Port) but query the Agent Registry and use each other's logical names (agentName) to obtain access endpoints. This achieves complete decoupling with location transparency." — appears under Core Design at the Architectural Level: Peer Collaboration and Decoupling, in the subsection on A2A Protocol design principles. URL: https://www.alibabacloud.com/blog/configuration-driven-dynamic-agent-architecture-network-achieving-efficient-orchestration-dynamic-updates-and-intelligent-governance_602564
  8. Tadepalli, R. Micro and macro agents: The emerging architecture of the agentic enterprise. CIO, April 14, 2026. Defines micro agents as "specialized AI systems designed to perform narrow, well-defined tasks within a workflow" (under the section The rise of micro agents) and macro agents as components that "coordinate multiple micro agents to complete an end-to-end business process" (under The emergence of macro agents). URL: https://www.cio.com/article/4157977/micro-and-macro-agents-the-emerging-architecture-of-the-agentic-enterprise.html
  9. TruvaG3 — examples/weather-tool-v2/. Source code for the Tool whose registration produces the get_current_weather capability shown in this article. https://github.com/truvaagents/truva-g3/tree/main/examples/weather-tool-v2
  10. TruvaG3 — examples/agent-with-telemetry/. Source code for the Agent that registers as research-agent-telemetry, used as an example agent in this article. https://github.com/truvaagents/truva-g3/tree/main/examples/agent-with-telemetry
  11. Lewis, J. & Fowler, M. Microservices. martinfowler.com, 25 March 2014. The seminal article in which the microservices community articulated the migration away from centralized integration infrastructure. ESB products, the authors note, "often include sophisticated facilities for message routing, choreography, transformation, and applying business rules"; "the microservice community favours an alternative approach: smart endpoints and dumb pipes." Services in the new pattern are "choreographed using simple RESTish protocols rather than complex protocols such as WS-Choreography or BPEL or orchestration by a central tool." URL: https://martinfowler.com/articles/microservices.html
  12. TruvaG3 — examples/travel-chat-agent/. Source code for the Agent that registers as travel-chat-agent — the agent whose Switzerland-query execution is the basis for the trace walkthrough in this article. https://github.com/truvaagents/truva-g3/tree/main/examples/travel-chat-agent
  13. TruvaG3 — examples/registry-viewer-app/. Source code for the registry-viewer web app that captured the Switzerland-query DAG screenshot shown in this article. The same UI shows registered services, their capabilities, and live execution DAGs at http://registry.localhost/ when the bundled local-Kubernetes setup is running. https://github.com/truvaagents/truva-g3/tree/main/examples/registry-viewer-app
  14. TruvaG3 — GETTING_STARTED.md. Step-by-step setup guide for the local-Kubernetes deployment of TruvaG3, covering the kind cluster, Redis, the registry-viewer web app, and the bundled example tools and agents. https://github.com/truvaagents/truva-g3/blob/main/GETTING_STARTED.md
  15. TruvaG3 — examples/devops-chat-agent/. Source code for the Agent that registers as devops-chat-agent and exposes devops_operations as its public capability shown in this article. https://github.com/truvaagents/truva-g3/tree/main/examples/devops-chat-agent
  16. Nacos — A2A Agent Registry. Open-source service-discovery platform extended with an A2A agent-registry feature (generally available since Nacos 3.1.0, September 2025), implementing the same pattern described in this article. Integrated with multi-agent frameworks including AgentScope, Spring AI Alibaba, and the Dify A2A plugin. URL: https://nacos.io/en/docs/latest/manual/user/ai/agent-registry/
  17. LangGraph — Overview. Official LangGraph documentation showing the construction-time wiring pattern: StateGraph(...), add_node(), add_edge(), then graph.compile() — the graph is named and fixed at definition time. URL: https://docs.langchain.com/oss/python/langgraph/overview
  18. Microsoft Agent Framework — Overview. The successor to AutoGen and Semantic Kernel (GA April 2026, .NET and Python). Official quickstart shows tools attached at construction (tools: [...]) and graph-based Workflows for multi-agent coordination. URL: https://learn.microsoft.com/en-us/agent-framework/overview/
  19. OpenAI Agents SDK — Quickstart. Official quickstart showing Agent(name=..., handoffs=[history_tutor_agent, math_tutor_agent]) — both tools and inter-agent handoffs are named at agent declaration. URL: https://openai.github.io/openai-agents-python/quickstart/
  20. Google ADK — Quickstart. Official Google ADK quickstart showing the construction-time wiring pattern: Agent(name=..., model=..., tools=[google_search]) — tools are passed to the agent constructor as a fixed list. Multi-agent setups extend this with sub_agents=[...]. URL: https://adk.dev/get-started/quickstart/
  21. CrewAI — Quickstart. Official CrewAI quickstart showing the crew construction pattern: Crew(agents=self.agents, tasks=self.tasks, process=Process.sequential, ...) — agents and tasks are passed to the constructor as fixed lists. URL: https://docs.crewai.com/en/quickstart
  22. LlamaIndex — Understanding agents. Official LlamaIndex documentation showing FunctionAgent(tools=[multiply, add], llm=llm, ...) — agents are built with an explicit tool list at construction time. URL: https://developers.llamaindex.ai/python/framework/understanding/agent/
  23. Pydantic AI — Tools. Official Pydantic AI tools documentation showing both tools=[roll_dice, get_player_name] as a constructor argument and the @agent.tool / @agent.tool_plain decorators — both bind tools to the agent at construction time. URL: https://pydantic.dev/docs/ai/tools-toolsets/tools/
  24. TruvaG3 — execution trace JSON for the Switzerland run. The full plan, step-by-step results, LLM interactions, and DAG metadata for the three-phase Switzerland execution shown in Figure 10. Captured from the registry-viewer UI's Execution DAG tab. URL: https://github.com/truvaagents/truva-g3/blob/main/www/blogs/dag-switzerland-full-execution.json
  25. TruvaG3 — execution trace JSON for the multi-domain outer run. The full plan, step-by-step results, LLM interactions, and DAG metadata for travel-chat-agent's four-step plan shown in Figure 11. The user-profile RAG context (memorized via the agentic-memory tool) is shown with its identifying values redacted to neutral placeholders. URL: https://github.com/truvaagents/truva-g3/blob/main/www/blogs/dag-agent-to-agent-execution-agent1.json
  26. TruvaG3 — execution trace JSON for the multi-domain inner run. The full plan, step-by-step results, LLM interactions, and DAG metadata for devops-chat-agent's three-step plan shown in Figure 12 (the inner trace returned through Figure 11's devops_operations step). URL: https://github.com/truvaagents/truva-g3/blob/main/www/blogs/dag-agent-to-agent-execution-agent2.json
  27. TruvaG3 — AUTO_DISCOVERY_GUIDE.md. The framework's operations guide for the auto-discovery subsystem. Its "Extending: Pluggable Backends" section documents how to swap Redis for alternatives: "The framework ships with a Redis/Valkey-backed registry as the default, but the registry is pluggable behind the core.Discovery interface. You can swap in etcd, Consul, an in-memory mock for tests, or anything else that satisfies the contract." URL: https://github.com/truvaagents/truva-g3/blob/main/docs/operations/AUTO_DISCOVERY_GUIDE.md
  28. Wikipedia, "Directed acyclic graph." Comprehensive open-access reference with multiple diagrams (DAG examples, topological ordering, PERT charts, citation networks), plain-language definition, and an applications section covering job scheduling, version control, compilation order, causal models, and dependency tracking — the same patterns used in the article's execution plans. URL: https://en.wikipedia.org/wiki/Directed_acyclic_graph
  29. Sedgewick, R., & Wayne, K. Algorithms, 4th Edition booksite, Section 4.2 — Directed Graphs. Princeton University. Freely accessible companion to the textbook. Defines directed acyclic graphs (DAGs), states the topological-order equivalence, and lists real-world applications including job scheduling, build/compilation order, and dependency resolution — the same shape the article uses for the orchestrator's plan steps. URL: https://algs4.cs.princeton.edu/42digraph/
  30. Anthropic. How we built our multi-agent research system, June 13, 2025. First-hand engineering account from the team that built and operates Anthropic's Research feature — a multi-agent system serving production traffic at Claude's scale. Cited in this article in §"The wiring problem" as primary-source evidence for the orchestrator-coordination half of the production-scale claim — the "higher-level orchestrator that decides whose turn it is" pattern named in the preceding paragraph. The post's "Synchronous execution creates bottlenecks" subsection documents a specific operational consequence of that wiring: "Currently, our lead agents execute subagents synchronously, waiting for each set of subagents to complete before proceeding. This simplifies coordination, but creates bottlenecks in the information flow between agents. For instance, the lead agent can't steer subagents, subagents can't coordinate, and the entire system can be blocked while waiting for a single subagent to finish searching." URL: https://www.anthropic.com/engineering/multi-agent-research-system
  31. Fourney, A. et al. Magentic-One: A Generalist Multi-Agent System for Solving Complex Tasks. Microsoft Research, November 2024 (arXiv:2411.04468). First-hand engineering account from the Microsoft Research team that built Magentic-One. Cited in this article alongside Anthropic [30] in §"The wiring problem" as primary-source evidence for the static-composition half of the production-scale claim — the "list of tools" / fixed-roster shape named in the preceding paragraph. In §6.2 "Limitations," under the "Fixed team membership" bullet, the authors explicitly name fixed agent composition as an operational limit — and, in the final sentence, sketch the fix that is essentially this article's thesis: "Magentic-One's composition is fixed to a common set of five agents: Orchestrator, WebSurfer, FileSurfer, Coder, and ComputerTerminal. When agents are not needed, they simply serve as a distraction to the Orchestrator, and this may lower performance. Conversely, when extra expertise might be needed, it is simply unavailable. We can easily imagine an alternative approach where agents are added or removed dynamically, based on the task need." URL: https://arxiv.org/abs/2411.04468
  32. Davis, G. Multi-agent workflows often fail. Here's how to engineer ones that don't. GitHub Blog, February 24, 2026. GitHub Blog post on engineering reliable multi-agent workflows, drawing on GitHub's experience with agentic developer tooling. Cited in this article in §"Self-describing capabilities" as evidence for the load-bearing role of structured field schemas in agent-to-agent communication. The post's central thesis, stated up front: "Most multi-agent workflow failures come down to missing structure, not model capability." It elaborates on the specific failure pattern: "Multi-agent workflows often fail early because agents exchange messy language or inconsistent JSON. Field names change, data types don't match, formatting shifts, and nothing enforces consistency." URL: https://github.blog/ai-and-ml/generative-ai/multi-agent-workflows-often-fail-heres-how-to-engineer-ones-that-dont/

Cite as: Tripathi, N. (2026). A Microagents Reference Architecture: Dynamic Capability Discovery and Decentralized Coordination. https://truvag3.dev/blogs/microagents-architecture