diff --git a/CLAUDE.md b/CLAUDE.md index 5e9d239c..cdf8edbe 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -34,7 +34,9 @@ carries the slot name it was bound to; a collaborator carries its registry name `sessionId`, and **no `leader` key** — a collaborator is a named peer, not a primary. An **observer** carries only its own `sessionId`: a pane the daemon could not place as any of the above, authorized to `READ`/`METRICS`, to `REPLY`/`ASK` on its own pane, and to `SEND` only to a target that resolves -as an observer too — never to a lead, a collaborator, or a spawned member, and never a ticket. +as an observer too — never to a lead, a collaborator, or a spawned member, and never a ticket. It +finds such a target in `fleet_list`'s `panes` array, which for an observer is filtered to exactly +what it may send to and reduced to `sessionId`, `label`, `status`, `role` and `deliverable`. Don't infer what you can ask. Only if that call is unavailable, fall back to these — each is one-way, so keep reading until one @@ -180,7 +182,7 @@ you decide. | Message a **peer lead** on this host | `fleet_send{sessionId: , content}` — `fleet_list` → `leads` reports it. Coordination only, **never** a task | | Message a **peer lead** on another daemon or host | `fleet_send{coordId: , content}` — needs a `coordinator:` block; your own coord-id is in `fleet_list`. Coordination only, **never** a task | | Message a **collaborator** on this host | `fleet_send{sessionId: , content}` — `fleet_list` reports a `collaborators` array, and each row carries that peer's `name` and the `sessionId` you send to. It is visible to you, to an architect and to another collaborator, never to a worker. Coordination only, **never** a task | -| Message an **unconfigured pane** — a tab a person opened by hand | `fleet_send{sessionId: , content}` — it needs **no** `fleet.collaborators` entry and no restart, because a pane becomes deliverable the moment its agent connects the bridge MCP. **Neither `fleet_list` nor `ListAgents` lists these**, so read the terminal id by joining `herdr tab list` to `GET /agents` on `tab_id`. Such a pane resolves as an `observer`: it can answer you with `fleet_reply`, and it can `fleet_send` to another observer pane, but never to you. Coordination only, **never** a task | +| Message an **unconfigured pane** — a tab a person opened by hand | `fleet_send{sessionId: , content}` — it needs **no** `fleet.collaborators` entry and no restart, because a pane becomes deliverable the moment its agent connects the bridge MCP. `fleet_list`'s `panes` array reports every such pane with its label and the terminal id to send to — the full row for you, an architect or a collaborator; filtered and reduced for an observer. **`ListAgents` still never lists these**, and joining `herdr tab list` to `GET /agents` on `tab_id` stays the read-only fallback if the array is missing. Such a pane resolves as an `observer`: it can answer you with `fleet_reply`, and it can `fleet_send` to another observer pane, but never to you. Coordination only, **never** a task | | Answer a peer lead that messaged you | `fleet_send{coordId}` — or `{sessionId}` if they are on this host. **Not** `fleet_reply`: it has no peer route and the publish is refused | | Read your own held lead-to-lead mail (no ack) | `fleet_poll{coordId: }` — primary-only; never acks, so `fleet_list`'s `held[]` still shows it after. `fleet_list`'s `held[]` gives only a truncated preview — this is the only way to read the full body | | Collect a held reply | `fleet_poll{target}` · then `fleet_ack{target, msgId}` |