# peer — Manual

## What it does

Talks to the other navi instances on the local network — machines that announced themselves to the same hive registry. Asking is real work on the other side: a full agent turn runs on the peer's machine, with the peer's own tools, files and services, and returns its answer as text.

The **hive is only a phone book**. It answers "which machines exist"; the question itself travels directly to the peer's API port and the hive is never on the message path. That matters when the hive is down: `list` still works from cache, `ask` still reaches a peer you already know.

## Actions

| Action | What it does |
|---|---|
| `list` | Every machine in the swarm: name, address, online/offline, OS, core count. Our own machine is filtered out. |
| `status` | One peer's live state: uptime, version, port, machine facts, and whether the peer itself can reach the hive. |
| `ask` | A question for a peer. Answered by an agent run on that machine. |

```json
{"action": "list"}
{"action": "status", "peer": "yuki"}
{"action": "ask", "peer": "yuki", "question": "Is the docker stack on this host healthy? Report container names and restart counts."}
```

## `ask` — how to write the question

The peer sees **only your question**. It does not see this conversation, this machine, or anything you already know. So the question must be self-contained:

- Name the machine implicitly ("the services on this host"), never "the server I mentioned".
- Say what you want back: a table, a yes/no with the evidence, the raw command output.
- Ask about **the peer's** machine. Anything you can check locally — your own files, your own services, your own process list — is cheaper and faster done here. Asking a peer about this machine's state is a normal way to waste a minute.
- Keep it under 4000 characters; that is the wire limit.

An ask is not instant: the peer runs a real LLM turn, with a server-side ceiling of `PEER_ASK_TIMEOUT_SEC` (120 s) plus 30 s of client slack. Peers answer **one at a time** — a burst of asks queues behind a semaphore rather than fanning out onto the GPU. When the peer's turn hits its own iteration limit, the answer comes back with a note that it may be incomplete; that is a truncated answer, not a failure.

For a question that may take a while, pass `background: true`: the call detaches immediately, returns a `task_id`, and the answer arrives later as a completion note (collect it with `tasks`). `peer` is one of the settings-configured backgroundable tools; only `ask` is worth detaching.

## Errors, and what they mean

| Error | Cause |
|---|---|
| `swarm_unconfigured` | `HIVE_URL` is empty, or `.swarm-key` is missing — this machine is not in a swarm. Nothing to retry. |
| `hive_unreachable` | The registry did not answer and no cached peer list exists yet. |
| `unknown_peer` | No peer by that name. The error lists the names that are known. |
| `peer_unreachable` | The peer is offline or its port is closed. Try `list` to see whether it is down. |
| `peer_refused` | The peer answered with an HTTP refusal — most often an ask that would loop back to itself. |
| `self_ask` | The name you asked is this very navi. Check locally instead. |

A `list` result headed `(STALE — hive unreachable, last known list)` is the cached book: names and addresses are real, online flags may not be.

## Loop safety

`ask` cannot recurse. Two independent guards:

1. The answering agent run is created with `peer` **excluded from its tools**, so the peer physically cannot ask onward.
2. An ask whose originating instance id matches the receiver's own uuid is refused at the boundary.

That is also why a remote question can be answered but never relayed: a peer cannot forward your ask to a third machine.

## Not to be confused with

- **`spawn_agent`** — a sub-agent runs *here*, in this session's world, under the same navi. A peer is another machine with its own agent, reached over the network.
- **`ssh_exec`** — a raw shell on a remote host. A peer answers a *question* using its own agent and tools; you get judgement, not a command transcript.
