--- layout: blog title: "Agents That Plan and Delegate" permalink: /blog/17 description: "An agent shouldn't just react tool by tool. It should form intent — plan what it's doing — and direct intent — delegate what it shouldn't do itself. Go Micro now gives every agent both, as plain tools." --- # Agents That Plan and Delegate *June 7, 2026 • By the Go Micro Team* When we [introduced `micro.NewAgent()`](/blog/16), 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](/blog/15) 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](/blog/16): the plan is saved to the same [store](/docs/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](/blog/15) 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 owner@acme.com 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 owner@acme.com 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 owner@acme.com that the launch plan is ready","to":"comms"}) 📨 notify: to=owner@acme.com 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](/blog/15), now driven by the agent itself rather than a router. The full runnable code is in [examples/agent-plan-delegate](https://github.com/micro/go-micro/tree/master/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](/blog/14): 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](/docs/guides/plan-delegate) for the full reference, or the [agent patterns guide](/docs/guides/agent-patterns) for where this fits among the other ways to build with agents. --- *Go Micro is open source. Star us on [GitHub](https://github.com/micro/go-micro), join the [Discord](https://discord.gg/G8Gk5j3uXr), or read the [docs](https://go-micro.dev/docs).*