---
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 &bull; 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).*
