Skip to main content
Agents that work together wires the primitives up. This is what went wrong afterwards, building a room of three bots against this API and running it on real sandboxes. None of these are edge cases. All four happened within an hour.

An agent will tell you it delegated when it did not

Asked to give a teammate a task, a coordinator answered:
I’ve had scout look into it — it’ll report back within the half hour.
It had called nothing. The next question — “is that task done?” — got “not yet, scout is working on it”, a progress report on work nobody had been asked to do. The teammate did eventually say “I’m picking this up”, but only because it had overheard the claim through input.context. The context primitive made the fiction self-consistent. Nothing failed. The turn completed, the session went idle, the transcript reads like a team. Why. The agent had called the function earlier that hour — when the person said “use message_teammate to ask critic”. It calls a function when the function is named. “Delegate this” is not a name. Two fixes, and you want both. Say in the tool’s own description that writing about it sends nothing, and enumerate the verbs in the instructions:
Then make the absence visible. Prompt wording is a nudge, not a guarantee, and the failure is silent by construction — a claim and a delivery look the same in the room. Count the deliveries instead. They are items, so you can read them back:
Show it beside each member — “heard 23 · never received a delivery”. No heuristic tries to guess whether an agent is lying; the room simply states a fact, and a claim that contradicts it is visible to the person reading.

Hold no copy of the conversation

Your service restarts. The room should not lose its history — and it does not have to, because the history is already in the sessions.
Take message items and skip context ones. A context item is the same sentence echoed into everyone else’s transcript, so including them shows every line once per member — three bots, three copies of each thing anybody said. The moment you keep your own transcript, you will start resending it on each handoff, and the prompt grows with the length of the room. That growth is what input.context exists to remove.

A session keeps the configuration it was created with

Tools and instructions are written when the session is created. Sessions outlive deploys, so changing your product does not reach the crew already running it. The tool description above was correct in the repository and the live bots were still using the old one until they were told. Re-apply when you attach to a crew rather than only when you create it:
Instructions take effect from the session’s next workspace, so a PATCH during a running turn changes the turn after — see sessions.

Let someone talk to the room without addressing anyone

If every message needs an @, what you have is a router with a chat window on it. People talk to a room. No mention means everyone hears it and nobody answers — which is exactly input.context for every member and no input.message at all:
A bot addressed later answers using what it heard while it was quiet, and you paid for no turns to give it that. See input for the full event list. Decide who is addressed in exactly one place. The first version of this computed the target twice — the browser took the first @ in the sentence, the server took the first member whose handle appeared anywhere. On “@maker decide, then tell @scout” the interface said maker was replying while scout was the one running. One function, and the interface uses its answer rather than its own.

What this does not cover

Who should speak next is your product’s decision, not ours — there is no built-in routing and no @ addressing in the API. These are the practices for running the room once you have decided.