Skip to content

Talking to an agent in a room

A station is a place an agent works. It is also, if you turn the bridge on, somebody you can message.

Every adopted station gets a Matrix identity and a room of its own. You send a message, the hub hands it to the harness as a turn, and the agent’s reply comes back as that agent — in a client you already have, on a phone you already carry. The harness itself never learns Matrix exists.

This is the half of AgentPod that is not a console. The console is for operating the ground an agent stands on; the room is for working with the agent.

an identity the station appears as a user, named for its node and station key. The member list shows the readable form.
a room one per station, created when the station is adopted
a space rooms hang under a space named for the machine they run on. A flat roster is fine at thirty agents and unusable at two hundred; clients that read the hierarchy group the list for free.

Rooms are encrypted at creation. Any client that can read an encrypted room can read these; there is nothing extra to turn on.

  • The agent’s replies, posted as the agent, streaming as the turn progresses
  • Voice notes, in both directions — see Voice notes
  • Permission questions, when the agent wants to run a tool and its mode says to ask
  • A card when a turn fails, saying what failed rather than going silent — see When a turn fails
  • Approval gates and questions from a board, if the workspace is linked to a SuperPipeline board — see Working a board
  • Images you send, passed to the agent rather than just their file name

An agent in ask mode parks when it wants to run a tool, and the question is posted where you are:

Permission needed: Write src/main.ts
1. Allow once
2. Allow always
3. Reject
Reply with the number, or the option's name.

Reply 1, or Allow once. Nothing else counts. A reply that is not plainly one of the options approves nothing and shows the list again.

That pedantry is deliberate. Against options named Allow once and Allow always, a bare “yes” does not say which — and approving a tool call you did not mean to approve is the one failure worth being awkward about.

A question stops standing the moment the turn moves on: answered in the console, cancelled, or failed. A room can never approve something that was already decided.

It expires after 30 minutes. A question nobody answers in that time is withdrawn: the agent is told it was not given permission (it is not left waiting for ever), and the room says so. A reply that arrives after a question closed — expired, or answered in the console a moment earlier — is refused in the room. It is never passed to the agent as a message, so a late 1 cannot turn into an instruction. Once you have talked to the agent again, a number is an ordinary message.

Updated apps show what you are allowing. The same message also carries the request in full for apps that understand it: the tool, its command, each file change and the files it touches, with buttons that say what each option does (allow once, always, reject). Such an answer is bound to exactly the request you saw — if the agent asked something else since, it is refused. When the card could not show everything (a very long change, a terminal), nothing in the room can allow it — not a button, and not a typed number either; answer in the console. Whoever answers, by button, by number or in the console, is recorded with the answer, and the card closes wherever it was answered.

A board room carries more than gates and questions. A card waiting on a person (blocked, failing, not authorised) and a SuperToolkit approval request arrive there too — see Boards. Answers to them are never passed to an agent as a message. A decision nobody answers in time is reminded and then escalated in the same room, as a reply to its card — see When nobody answers.

Sending a message spends the agent’s time, so it needs the same authority as dispatching it any other way — and approving a permission question is dispatching by another name, so it needs that authority too.

Who may message which agent is read from a mayDispatch claim the hub signed into your token. It is not a header, not a parameter, and not derived from anything sent alongside. See Dispatch and grants.

A message that arrives while the agent is mid-turn is held and delivered when the turn ends, rather than refused. The room says so as a notice. Refusing would make the room a worse place to talk than a terminal, which is the opposite of the point.

The hub is the push gateway. A client registers a pusher with the homeserver, the homeserver calls the hub for every event that should reach a phone, and the hub turns each call into one push per device.

A message push carries the room, the event id and an unread count — not the message. The device fetches and decrypts the event itself and words the notification locally. A push that carried the text would put an encrypted room’s contents through a service that has no business seeing them.

One addition, and it is counts rather than text: the push for an agent’s answer that ended a turn with tool calls also carries how many steps ran and how many failed, which is what a client’s widget recap reads.

The one exception: the fleet Live Activity

Section titled “The one exception: the fleet Live Activity”

By operator decision of 2026-09-29, the Lock Screen fleet card is pushed by the hub, and those pushes carry agent names, the current step’s title, and a pending decision’s question and option labels in plaintext — readable by Apple in transit.

That is a deliberate widening of the gateway’s otherwise strict line, taken so the card can say something useful rather than “an agent needs you”. It is the only place it applies: message pushes still carry ids only, and nothing else changed.

A gate that offers a choice of versions never offers an approval on the Lock Screen — the card cannot show the versions — only a rejection; you choose in an updated app or on the board.

A permission request or a gate the hub posted is also tagged on the push as time-sensitive, so it reaches a person through Focus — the tag, not the text.

Pushes are configured per deployment and are optional: a hub with no push configuration answers that route with a 404 and still boots. Pushes are not worth taking a control plane down for.

The bridge is off unless the hub is configured for it: a homeserver URL, a server name, and the application-service tokens. Deployment detail lives in the operator guide rather than here, because it is a property of your hub and not of the product.

With the bridge off, everything else in AgentPod works exactly as it does now. Nothing in the console depends on it.