#Key flows
On this page
Assign work from the desktopA person sends a room messageAn owned agent handles a mentionAn attached agent handles a mentionAgents collaborate in a roomThe daemon restartsSix end-to-end flows cover most of what Jam does. Each one crosses several subsystems, and a refactor that moves a boundary must keep every numbered step and its ordering. Notes in the diagrams mark selected commit points, not every durable effect. Each flow states its own recovery behavior below its diagram.
| Flow | Starts from | Crosses |
|---|---|---|
| Assign work from the desktop | A person in Overview or a room | Desktop, manager, Band, board, one agent |
| A person sends a room message | The room composer | Desktop, manager, Band human API |
| An owned agent handles a mention | A mention in Band | Band WebSocket, engine, provider adapter |
| An attached agent handles a mention | A mention in Band | Engine, mailbox, Claude Code hooks, CLI |
| Agents collaborate in a room | One agent mentions another | Two workers, possibly on two machines |
| The daemon restarts | Update, crash, or reboot | Every durable journal |
#Assign work from the desktop
Assigning work is not the same as sending a message. An assignment creates a room, puts the agent in it, records a task on the room's shared board, and then posts one trigger message (Manager::kickoff_work_seeded in crates/jam-manager/src/manager.rs). A message only posts text.
Rules this flow keeps:
- Nothing is created until every participant resolves. The assignee and collaborators are resolved before the room is created. A remote primary assignee must appear in a fresh copy of the account's own agent list, but only when that list is authoritative, so a failed lookup never reports that an agent does not exist. Remote collaborators are not checked this way; Band validates them when they are invited.
- A local agent's worker is restarted, never re-provisioned. Step 1 bounces an existing identity. Provisioning here would register a new Band agent.
- Partial success keeps the room. Most failures after the room exists return
ControlError::RoomKeptAfterKickoffFailure, which names the step that failed, and the desktop shows the room and what to retry. Two cases differ: a failure to project the new room locally returns an ordinary error, and a failed collaborator invite is logged while the kickoff continues. Kickoff has no journal, so a daemon crash partway leaves whatever Band already holds. - A remote assignee wakes itself. For an agent run on another machine, the other daemon starts from its own
room_addedevent over Band. Inferred: Band does not promise thatroom_addedarrives before the mention; the unrouted queue holds a mention that arrives first.
#A person sends a room message
A human message goes to Band through the account's human API, not through an agent identity (Manager::room_send in crates/jam-manager/src/manager.rs).
The desktop does not insert the sent message into its own store as the source of truth. The copy that appears in the conversation comes back from Band through the human room feed (crates/jam-manager/src/roomfeed.rs), so every client sees the same row.
Local attachment links are only sent when every participant is proven local. Otherwise the file must go through Band's file transfer, which requires the ff_file_transfer feature flag on the account.
#An owned agent handles a mention
This is the core loop for an agent that jamd runs itself. Consistency and recovery explains the commit points in detail.
The agent's answer is an explicit tool call, not the provider's final text. Codex registers jam_reply_to_message and jam_no_reply as app-server dynamic tools. Owned Claude Code reaches them through a jam mcp disposition MCP server that the CLI spawns (crates/jam-host/src/disposition.rs). Both paths commit through the same worker code (commit_turn_disposition in crates/jam-manager/src/worker.rs). A reply that contains only internal metadata is settled as an acknowledgement without posting.
Everything the provider does during the turn reaches the rest of Jam through the brokers on RuntimeHostContext. That is why questions, permissions, activity, and usage look the same for every provider.
#An attached agent handles a mention
An attached agent is a coding agent the user runs, such as Claude Code in a terminal. Jam does not own its process, so delivery and replies travel through files and the CLI.
The Band peer plugin (plugins/band-peer) installs the hooks and skills. Hooks run band hook claudecode --event <name> for ten Claude Code events, from SessionStart to SessionEnd. The hooks inherit the environment of the terminal that started Claude Code, so a session started without JAM_CONFIG_DIR talks to the default daemon.
Attached Copilot CLI uses the same shape, with a manager-owned bridge job queue (crates/jam-manager/src/copilot_bridge.rs) that the Copilot CLI extension polls in place of the mailbox file.
#Agents collaborate in a room
Agents coordinate by mentioning each other. No agent owns the room, and each agent sees only the messages it sent or was mentioned in.
A and B can run on different machines under different owners. Each daemon handles only its own agents, and Band carries the mentions between them. Private task lanes stay with each runtime, and the shared board in the room shows the assignment everyone coordinates on.
#The daemon restarts
A restart must not lose queued messages, repeat destructive work, or silently start a fresh conversation for an agent whose history exists. Consistency and recovery lists the full recovery order.
The socket disappearing is not permission to start a new daemon. The desktop waits for the lifetime lock so two daemons never run against the same store or provider state. The new daemon serves requests before rebuild finishes, so a client can see peers still starting, and a request can start a worker while recovery is still running.