diff --git a/CLAUDE.md b/CLAUDE.md index d30b94b5..0e95fd75 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -178,6 +178,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 cannot `fleet_send` back. 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}` | diff --git a/docs/MCP-Contract.md b/docs/MCP-Contract.md index dd21413f..2510a3c5 100644 --- a/docs/MCP-Contract.md +++ b/docs/MCP-Contract.md @@ -182,6 +182,12 @@ Two consequences a lead feels directly: is fine; the message simply waits, and then restarts the member when it next goes idle. - **A spawned member is not deliverable until it has mounted the MCP.** Until then a send waits on that gate for about 60 seconds and then fails without ever reaching the pane. +- **The same gate is what makes an unconfigured pane deliverable.** `contextExtractor` runs on + every MCP request, `initialize` included, and `markTrackedCallerPresent` enrols a spawned member + *or* an observer into `MemberPresence`; `deliverableTo` then tests presence before the lead and + collaborator maps. So mounting the server is the enrolment, and a tab a person opened by hand can + be sent to with no config and no restart. It answers with `fleet_reply` — it cannot `fleet_send`, + because `Authz` keeps `SEND` to a primary, an architect or a collaborator. `UNKNOWN` is deliberately neither injectable nor a pickup. A pane whose status cannot be read is not a pane that is safe to write to — see fleetd #176 for what happens when a gate treats an