Orchestration
Agent-to-Agent Communication
Use host tools to let agents communicate with each other.
Agents communicate through host tools. You define a toolkit that lets one agent send work to another, and the agent calls it like any other CLI command.
Example: code writer + reviewer
This example creates a writer agent with a review tool. When the writer calls the tool, it reads the file from the writer’s VM, writes it to a separate reviewer VM, and sends a review prompt.
import { agentOs } from "rivetkit/agent-os";
import { setup } from "rivetkit";
import common from "@rivet-dev/agent-os-common";
import pi from "@rivet-dev/agent-os-pi";
import { toolKit, hostTool } from "@rivet-dev/agent-os-core";
import { createClient } from "rivetkit/client";
import { z } from "zod";
// Tool that bridges the writer to the reviewer
const reviewToolkit = toolKit({
name: "review",
description: "Send code to the reviewer agent",
tools: {
submit: hostTool({
description: "Submit a file for code review",
inputSchema: z.object({
path: z.string().describe("Path to the file to review"),
}),
execute: async (input) => {
const client = createClient<typeof registry>("http://localhost:6420");
const writerHandle = client.writer.getOrCreate(["my-project"]);
const reviewerHandle = client.reviewer.getOrCreate(["my-project"]);
// Read file from writer, write to reviewer
const content = await writerHandle.readFile(input.path);
await reviewerHandle.writeFile(input.path, content);
// Ask the reviewer to review
const session = await reviewerHandle.createSession("pi", {
env: { ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY! },
});
const response = await reviewerHandle.sendPrompt(
session.sessionId,
`Review the code at ${input.path} and list any issues.`,
);
await reviewerHandle.closeSession(session.sessionId);
return { review: response };
},
}),
},
});
// Writer has the review toolkit, reviewer is plain
const writer = agentOs({
options: { software: [common, pi], toolKits: [reviewToolkit] },
});
const reviewer = agentOs({
options: { software: [common, pi] },
});
export const registry = setup({ use: { writer, reviewer } });
registry.start();
import { createClient } from "rivetkit/client";
import type { registry } from "./server";
const client = createClient<typeof registry>("http://localhost:6420");
const writerAgent = client.writer.getOrCreate(["my-project"]);
const session = await writerAgent.createSession("pi", {
env: { ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY! },
});
// The writer will call `agentos-review submit --path /home/user/api.ts`
// when it's ready for a review
await writerAgent.sendPrompt(
session.sessionId,
"Write a REST API at /home/user/api.ts, then submit it for review.",
);
The writer agent sees the review tool as a CLI command:
agentos-review submit --path /home/user/api.ts
When the writer calls this, the host tool reads the file from the writer’s VM, writes it to the reviewer’s VM, and sends a prompt to the reviewer. The review result is returned to the writer as JSON.
Why host tools?
Host tools are the natural communication layer between agents because:
- The agent doesn’t need to know about other agents. It just calls a tool. You can swap the implementation without changing the agent’s behavior.
- No credentials in the VM. The host tool executes on the server, so it can access other agents directly without exposing connection details.
- Composable. Chain any number of agents by adding more tools. Each tool is a self-contained bridge to another agent.