internal/docs/AGENT_DESIGN.md
Service = capability. Agent = intelligence. An agent IS a service — it has a real RPC server, a proto-defined Agent.Chat endpoint, and registers in the registry like everything else.
micro.New("task") // creates a service
micro.NewAgent("task-mgr") // creates an agent (which is also a service)
Same package. Same level. Same communication (RPC). Different responsibilities.
type Agent interface {
Name() string
Init(...AgentOption)
Options() AgentOptions
Ask(ctx context.Context, message string) (*Response, error)
Run() error
Stop() error
String() string
}
Ask is the programmatic API. Send a message, get a response.
Run starts a real RPC server, registers the Agent.Chat endpoint in the registry, and blocks.
service Agent {
rpc Chat(ChatRequest) returns (ChatResponse) {}
}
message ChatRequest {
string message = 1;
}
message ChatResponse {
string reply = 1;
string agent = 2;
repeated ToolCall tool_calls = 3;
}
The agent is callable by any go-micro client:
micro call task-mgr Agent.Chat '{"message": "What tasks are overdue?"}'
type AgentOptions struct {
Name string
Services []string // which services this agent manages
Prompt string // system prompt — identity, domain knowledge, boundaries
Provider string // LLM provider (anthropic, openai, etc.)
Model string // LLM model (optional)
APIKey string
Registry registry.Registry // discover services and other agents
Client client.Client // call service endpoints and other agents
Store store.Store // agent memory (persists across restarts)
HistoryLimit int // max conversation turns to retain
}
Functional options:
agent := micro.NewAgent("task-mgr",
micro.AgentServices("task"),
micro.AgentPrompt("You manage tasks. You understand deadlines and priorities."),
micro.AgentProvider("anthropic"),
)
An agent only sees the endpoints of its assigned services (plus excludes its own endpoints so it doesn't call itself).
Agents persist conversation history in the store. Memory survives restarts.
agent/{name}/history — conversation history
Agents register as real services via server.NewServer with metadata:
server.Metadata(map[string]string{
"type": "agent",
"services": "task,project",
})
The server has a real address, real transport, real endpoints. micro agent list discovers agents by checking server metadata for type=agent.
micro chat is a router. It discovers agents from the registry and dispatches to them via RPC.
client.Call(agentName, "Agent.Chat", ...)route_to_agent toolAgents call each other via standard RPC. An agent is a service — it has an Agent.Chat endpoint. Any agent can call any other agent the same way it calls a service.
// From inside an agent's logic, call another agent:
client.Call("comms-mgr", "Agent.Chat", &ChatRequest{Message: "Notify Alice"})
No special protocol. No broker topics. Just RPC.
agent := micro.NewAgent("task-mgr",
micro.AgentServices("task"),
micro.AgentPrompt("You manage tasks."),
micro.AgentProvider("anthropic"),
)
agent.Run()
agent := micro.NewAgent("project-mgr",
micro.AgentServices("task", "project", "milestone"),
micro.AgentPrompt("You manage the project system."),
micro.AgentProvider("anthropic"),
)
agent.Run()
agent := micro.NewAgent("support", ...)
agent.Init()
resp, _ := agent.Ask(ctx, "What tickets are open?")
func main() {
svc := micro.New("task")
svc.Handle(new(TaskHandler))
agent := micro.NewAgent("task-mgr",
micro.AgentServices("task"),
micro.AgentPrompt("You manage tasks."),
micro.AgentProvider("anthropic"),
)
go svc.Run()
agent.Run()
}
micro agent list # list registered agents
micro agent describe task-mgr # show agent details
micro chat # routes to agents automatically
micro call task-mgr Agent.Chat '{"message": "..."}' # direct RPC
micro run --prompt creates services AND an agent:
micro run --prompt "task management system"
Generated:
task/ ← service
project/ ← service
agent/ ← agent (manages task, project)
The agent reads MICRO_AI_PROVIDER and MICRO_AI_API_KEY from the environment.
micro call, the API, or MCPmicro run, micro deploy, micro build work the same way