Plane docs
Concepts

Enqueue and steer

When a message enters the prompt, and why the careful one is the default.

await client.sessions.send({ id, message: "one more thing" })                  // enqueue
await client.sessions.send({ id, message: "stop — wrong account", mode: "steer" })

mode decides when a message enters a prompt, and defaults to enqueue. To an idle session the two are identical, so it only matters while session.status is running.

enqueue — the default

The message is not folded into the turn that is running when it arrives. The loop finishes every turn the previous message asked for, and the queued messages then start one new turn together, each as its own user turn in sequence order.

Several messages waiting behind a turn are one conversation; answering each in its own turn would reply twice to one thought.

An approval the session is waiting on is untouched, so a parked session stays parked and the message arrives with the turn that answering it starts.

steer

Folded into the running turn at its next step boundary — the only safe seam, and a free one, because the prompt is rebuilt from the log at every step. It arrives labelled, so the model knows it landed mid-thought, and it supersedes every pending approval.

Why the default is the careful one

A message spliced between a tool call and the reasoning about to use its result can produce an answer that reads complete and is not. That is a thing to opt into rather than to get by accident. It is also the conservative choice for a client that retries.

Both survive a restart: the horizon is recorded in the log rather than held in memory, so a process that dies mid-turn resumes with the steer already read and the enqueue still waiting.

Sub-agents

plane_message_subagent takes the same mode with the same default when an agent talks to a child it spawned. The other direction is deliberately not configurable: a child's report is an answer its parent may be blocked on, so holding it until the parent's turn ends would deadlock "spawn three and keep working".

Sending exactly once

await client.sessions.send({ id, message, idempotencyKey: requestId })

The key is deduplicated inside the append itself, under the lock that already serialises a session's writes — so the check and the write are one decision rather than a read followed by a hopeful insert. A duplicate returns the original event and runs no second turn. The key is unique per session.

On this page