Skip to content
Français

Send instructions during a task

Give a running agent a new instruction and track how it is delivered.

Create a steering controller and pass it to the dispatch. While the task runs, send() submits another instruction and resolves when Outpost can report how it was delivered.

import { reportValue } from "./reporter.ts";
import { createSteering, dispatch } from "@elie-laloum/outpost";
import { coder, repository, sandboxProvider } from "./outpost.config.ts";

const steering = createSteering();
const running = dispatch({
  repository,
  sandboxProvider,
  agent: coder,
  branch: { mode: "named", name: "outpost/auth-refactor" },
  brief: { text: "Refactor the auth module." },
  steering,
});
const delivery = await steering.send("Leave the legacy/ folder untouched.");
reportValue(delivery.mode);
// Example output: injected
const result = await running;

send() resolves when the agent receives the text, not when it has acted on it. The agent reads it as one more user message; the brief still applies.

AgentmodeWhat happens
Built-in harnessinjectedAdded to the next model request, after the current tool results. A model about to finish continues instead.
Claude CodeinjectedWritten to its stream-json input. It joins the running turn, or runs next in the same process if Claude was already answering.
CodexinjectedA steered dispatch runs codex app-server. turn/steer adds the text to the active turn, or starts the next one.
Copilot CLI, Kimi Code, AntigravityresumedOutpost stops the process once its conversation is known, then resumes it with the text in the same sandbox.

With resumed, the action in progress is cut short, but files already changed stay in the workspace. Every sandbox provider carries live input; on Vercel and Daytona each instruction costs one provider command and arrives a moment later.

You send itWhat happensmode
Before the agent startsAppended to the prompt.injected
During the turnDelivered as in the table above.injected / resumed
After the agent answeredOutpost resumes the conversation in a new turn, so the result reflects it.resumed
While no dispatch uses the controllerWaits for the next dispatch that receives the controller.―

An instruction the dispatch cannot deliver, for example because the agent never reported a conversation, is rejected when the dispatch ends. The rejection is an OutpostError with code steering and the text in details.text.

Each built-in subagent run has an id, reported by its subagent event. Pass it as subagent to reach that run only.

import { createSteering, type DispatchOptions } from "@elie-laloum/outpost";

const steering = createSteering();
const request: DispatchOptions = {
  brief: { text: "Review the repository." },
  steering,
  observe(event) {
    if (event.kind !== "subagent" || event.status !== "started") return;
    if (event.name === "inspect")
      void steering.send("Only inspect src/.", { subagent: event.id });
  },
};

API reference: SteeringSendOptions.

An instruction still waiting when its run ends is rejected with code steering and the run id in details.subagent.

A controller serves one dispatch at a time, across all its passes; attaching it to a second concurrent dispatch fails. Once a dispatch ends, the next one can use it. close() rejects pending instructions and every later send().

result.resume() and result.fork() do not inherit it: pass steering again in their options.

In a workflow, return steering from the request of a defineAgentTask() or defineIsolatedTask(). With a fallback agent, steering follows the candidate that runs.

Each delivery emits a steer agent event with text, mode, pass, and subagentId when a subagent received it. The terminal reporter prints it, and the conversation records it as a user message.

A resumed delivery ends the interrupted turn with a stopped event of reason steered; that turn appears in result.turns with interrupted: "steering". A pass still emits one summary, and result.usage includes interrupted turns. A replay reproduces steered runs turn by turn.

  • Instructions live in memory. For questions and answers that must survive a restart, use interactive tasks.
  • A dispatch with steering rejects agents that can neither take live input nor resume a conversation, including replay agents.
  • Codex steering uses the app-server protocol, which Codex marks experimental.
  • Subagents of CLI agents cannot be addressed: an instruction with subagent is rejected as soon as a CLI turn sees it.

API: createSteering · Steering · SteeringSendOptions · SteeringDelivery · DispatchOptions.