Back to Go Micro

Agents That Plan and Delegate

internal/website/blog/17.md

5.27.07.7 KB
Original Source

Agents That Plan and Delegate

June 7, 2026 • By the Go Micro Team

When we introduced micro.NewAgent(), an agent was already a service with an LLM inside: scoped tools, persistent memory, and a micro chat router that dispatches across agents. And in Agents for Services we made the case that intelligence should be distributed — agents coordinate "not through code… through understanding."

This post is the next beat. An agent that only reacts, one tool call at a time, isn't really understanding anything — it's improvising. Two things turn reaction into intent: the agent should plan what it's doing before it does it, and delegate what it shouldn't be doing itself. Go Micro now gives every agent both.

True to the rest of the framework, they aren't a new layer. There's no harness, no workflow engine, no agent graph. plan and delegate are two ordinary tools — the LLM calls them exactly like it calls a service endpoint — added automatically to every agent. (If you've followed what everyone from Claude Code to LangChain calls "deep agents," this is the same idea, built the go-micro way: as tools, not as a framework.)

The smallest version

An agent doesn't need any services to plan. Here's a complete program:

go
package main

import (
	"context"
	"fmt"
	"os"

	"go-micro.dev/v5"
)

func main() {
	a := micro.NewAgent("assistant",
		micro.AgentProvider("anthropic"),
		micro.AgentAPIKey(os.Getenv("ANTHROPIC_API_KEY")),
	)

	resp, err := a.Ask(context.Background(),
		"Plan how to launch a product, then carry out what you can.")
	if err != nil {
		panic(err)
	}
	fmt.Println(resp.Reply)
}

Save it in a fresh module and run:

bash
mkdir my-agent && cd my-agent
go mod init my-agent
go get go-micro.dev/v5
# save the code above as main.go
export ANTHROPIC_API_KEY=sk-ant-...
go run main.go

The agent records a plan with the plan tool, then works through it. That's the whole setup.

plan: stating intent

plan is exactly what it sounds like: before multi-step work, the model writes down an ordered list of steps, and updates it as it goes.

json
{
  "steps": [
    {"task": "draft the announcement", "status": "in_progress"},
    {"task": "schedule the email",     "status": "pending"},
    {"task": "publish the blog post",  "status": "pending"}
  ]
}

This builds directly on the memory we already shipped: the plan is saved to the same store every service uses — file-backed by default, Postgres or NATS KV in production — under agent/{name}/plan, and folded back into the system prompt on the next turn. The agent stays oriented across a long task and picks up where it left off after a restart.

You get it for free. To make an agent reliably plan, just say so in its prompt:

go
micro.AgentPrompt("For multi-step requests, call the plan tool first to record your steps, then carry them out.")

delegate: directing intent

The harder move is knowing what not to do yourself.

A single agent managing ten services is a different kind of monolith — it knows a little about everything and a lot about nothing. We argued in Agents for Services that the fix is the same one microservices made for code: distribute it. Give each domain its own agent, and let them hand work to each other over RPC.

That hand-off already existed — an agent is a service, so any agent can call any other agent's Agent.Chat endpoint. delegate simply lets the agent reach for it as part of its own reasoning, instead of you wiring the routing. The model calls delegate with a subtask, and Go Micro resolves it delegate-first:

  1. If the target names a registered agent that owns the relevant services, the subtask goes to it over RPC. The domain expert handles its own services.
  2. Otherwise a focused, short-lived sub-agent is created for just that subtask, with a fresh, isolated context, and torn down when it's done.
json
{
  "task": "Notify [email protected] that the launch plan is ready",
  "to": "comms"
}

One design decision worth calling out: we didn't add a "spawn" or a "fork" primitive. A sub-agent is just an agent — created with New, talked to with Ask, the same two calls you already use. There's no new concept to learn, because there's no new concept: it's the existing RPC model, surfaced as a tool. Ephemeral sub-agents load and persist no history and get no tools of their own — so they can't plan or re-delegate, which keeps delegation from recursing.

Putting it together

Two services (task, notify) and two agents. The conductor owns task; comms owns notify. Ask the conductor to create some tasks and notify someone, and watch intent split across the system:

go
comms := micro.NewAgent("comms",
	micro.AgentServices("notify"),
	micro.AgentPrompt("You handle outbound notifications."),
	micro.AgentProvider("anthropic"),
	micro.AgentAPIKey(key),
)
go comms.Run()

conductor := micro.NewAgent("conductor",
	micro.AgentServices("task"),
	micro.AgentPrompt(
		"For multi-step requests, call the plan tool first. "+
			"For notifications, delegate to the \"comms\" agent (to: \"comms\")."),
	micro.AgentProvider("anthropic"),
	micro.AgentAPIKey(key),
)

resp, _ := conductor.Ask(ctx,
	"Create three launch tasks: Design, Build, and Ship. "+
		"Then make sure [email protected] is notified that the launch plan is ready.")

A typical run:

→ plan({"steps":[{"task":"create Design task","status":"pending"}, ...]})
→ task_TaskService_Add({"title":"Design"})
→ task_TaskService_Add({"title":"Build"})
→ task_TaskService_Add({"title":"Ship"})
→ delegate({"task":"Notify [email protected] that the launch plan is ready","to":"comms"})
  📨 notify: [email protected] message="The launch plan is ready"

The conductor never learned how to send a notification. It learned who does. comms handled it with its own service, in its own context, over RPC — exactly the distributed-intelligence picture from blog 15, now driven by the agent itself rather than a router.

The full runnable code is in examples/agent-plan-delegate. Set any provider key (ANTHROPIC_API_KEY, OPENAI_API_KEY, …) and go run main.go.

Why it's only two tools

It would have been easy to ship a planning engine, a sub-agent scheduler, a delegation graph. We didn't, on purpose. Every one of those is a new abstraction to learn and maintain, and Go Micro's bet has been consistent since we went all in on AI: services are the only abstraction, the LLM calls them as tools, and an agent's own capabilities are no exception.

plan and delegate are two small tools added to mechanisms that already existed — the store, and agent-to-agent RPC. That's the entire feature. It's also why there's nothing to configure: if you've written a micro.NewAgent, you already have them.

Getting started

The fastest way to see it end to end is the runnable example in the repo — it has the module set up and both agents wired:

bash
git clone https://github.com/micro/go-micro
cd go-micro/examples/agent-plan-delegate
export ANTHROPIC_API_KEY=sk-ant-...    # or OPENAI_API_KEY, GEMINI_API_KEY, ...
go run main.go

To start from scratch in your own project, use the smallest-agent snippet above (go mod init + go get go-micro.dev/v5).

Read the Plan & Delegate guide for the full reference, or the agent patterns guide for where this fits among the other ways to build with agents.


Go Micro is open source. Star us on GitHub, join the Discord, or read the docs.