# Agent-to-Agent Communication

Agents communicate through [bindings](/agentos/docs/bindings). You define a bindings group that lets one agent send work to another, and the agent calls it like any other CLI command.

## Example: code writer + reviewer

This example gives the writer agent a `review` binding. The writer sends the file's full contents (the VMs share no filesystem), and the binding writes them into a separate reviewer VM and sends a review prompt back through the reviewer.

examples/agent-to-agent/server.ts:

```ts
import { agentOS, setup } from "@rivet-dev/agentos";
import { createClient } from "@rivet-dev/agentos/client";
import { z } from "zod";

// The reviewer is its own isolated agent VM.
const reviewer = agentOS({});

// Bridge the writer to the reviewer. The VMs share no filesystem, so the writer
// sends the full file contents; the bridge writes them into the reviewer's VM
// and asks the reviewer to review. Runs on the host.
async function reviewCode(code: string): Promise<string> {
	const client = createClient<typeof registry>({
		endpoint: "http://localhost:6420",
	});
	const reviewerHandle = client.reviewer.getOrCreate("my-project");

	// Write the submitted contents into the reviewer's VM.
	await reviewerHandle.filesystem.writeFile("/home/agentos/review.ts", code);

	// Ask the reviewer to review.
	await reviewerHandle.sessions.open({
		agent: "claude",
		env: { ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY! },
	});
	const result = await reviewerHandle.sessions.prompt({
		content: [
			{
				type: "text",
				text: "Review the code at /home/agentos/review.ts and list any issues.",
			},
		],
	});
	await reviewerHandle.sessions.delete();

	return (
		result.message?.content
			.filter((block) => block.type === "text")
			.map((block) => block.text)
			.join("") ?? ""
	);
}

// The writer agent gets a `review` binding collection. When the writer runs
// `agentos-review submit`, the bridge above executes on the host.
const writer = agentOS({
	bindings: [
		{
			name: "review",
			description: "Send code to the reviewer agent and get back a review.",
			bindings: {
				submit: {
					description:
						"Submit the full contents of a file to the reviewer agent for review. Returns the reviewer's feedback as text.",
					inputSchema: z.object({
						code: z.string().describe("The full source code to review."),
					}),
					execute: async (input: { code: string }) => ({
						review: await reviewCode(input.code),
					}),
				},
			},
		},
	],
});

export const registry = setup({ use: { writer, reviewer } });

registry.start();
```

examples/agent-to-agent/client.ts:

```ts
import { createClient } from "@rivet-dev/agentos/client";
import type { registry } from "./server";

const client = createClient<typeof registry>({
	endpoint: "http://localhost:6420",
});
const writerAgent = client.writer.getOrCreate("my-project");

await writerAgent.sessions.open({
	agent: "claude",
	env: { ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY! },
});

// The writer calls the `review` binding collection, which bridges to the reviewer VM.
await writerAgent.sessions.prompt({
	content: [
		{
			type: "text",
			text: "Write a small REST API, then send it to the review agent for review.",
		},
	],
});
```

The writer agent sees the review binding as a CLI command. Because the VMs share no filesystem, it sends the full file contents, not a path:

```bash
agentos-review submit --code "$(cat api.ts)"
```

The binding writes the contents into the reviewer's VM, prompts the reviewer, and returns the review to the writer as JSON.

## Why bindings?

Bindings are the natural communication layer between agents because:

- **The agent doesn't need to know about other agents.** It just calls a binding. You can swap the implementation without changing the agent's behavior.
- **No credentials in the VM.** The binding executes on the server, so it can access other agents directly without exposing connection details.
- **Composable.** Chain any number of agents by adding more bindings. Each binding is a self-contained bridge to another agent.

## Recommendations

- Each agent has its own isolated VM and filesystem (they share no filesystem). Pass file contents through the binding input, then use `writeFile` in the binding to land them in the other VM.
- Use [Workflows](/agentos/docs/workflows) to make multi-agent pipelines durable across restarts.
