Use Kestrel's operator controls when work is already running or waiting for human input. Three API calls support that workflow:
operator.inboxoperator.threadoperator.control
The CLI and Kestrel One build their run controls on these calls. Use them when you need to inspect or steer an existing thread instead of starting the task again.
The control loop
read inbox -> open thread -> apply control action -> inspect operator.controlled eventUse that loop when a run is blocked, a child thread needs attention, or the next step needs human direction.
SDK example
import { KestrelClient } from "@kestrel-agents/sdk/runner";
const client = new KestrelClient({
target: {
kind: "remote",
baseUrl: process.env.KESTREL_RUNNER_SERVICE_URL!,
authToken: process.env.KESTREL_RUNNER_SERVICE_TOKEN!,
},
});
const context = {
actor: {
actorId: "user-123",
actorType: "operator",
displayName: "Taylor Example",
tenantId: "acme",
},
tenantId: "acme",
};
const inbox = await client.getOperatorInbox({ sessionId: "reference-session-001" }, context);
const view = await client.getOperatorThread("thread-main", context);
const controlled = await client.controlOperator(
{
action: "retry",
threadId: "thread-main",
message: "Retry after refreshing evidence.",
},
context,
);Common actions
Available operator actions include:
| Action | Use when | Result |
|---|---|---|
retry | the thread should try again with the same general goal | operator.controlled |
steer | the operator wants to inject new direction | operator.controlled |
stop | the run should stop and wait | operator.controlled |
focus_thread | the operator wants to switch attention to a specific branch | operator.controlled |
supersede_child_thread | a child branch is stale and should be replaced | operator.controlled |
resolve_fan_in_checkpoint | a join point needs explicit operator resolution | operator.controlled |
Invalid actions fail deterministically. The protocol tests explicitly verify that an unsupported operator.control action returns runner.error.
Workflow: blocked thread to resolution
The operator workflow is usually:
- read
operator.inboxfor the affected session - open
operator.threadto see blocker, focus, or checkpoint state - decide whether the narrowest safe action is
retry,steer,stop, orfocus_thread - apply the control action
- inspect the resulting
operator.controlledevent before deciding on a second intervention
That sequence is what keeps operator work attached to the same durable thread instead of creating a fresh disconnected run every time the workflow hesitates.
CLI workflow
In the CLI, use these commands:
/stop [message]
/steer <message>
/retry [reason]
/focus <threadId>
/approve [message]
/reject [message]
/reply <message>That CLI flow maps onto the same protocol. The CLI is not inventing local state here. It is a thin operator cockpit over the runner.
Kestrel One workflow
Kestrel One provides the same controls through /api/kchat/control. It can:
- read
operator.inbox - load
operator.thread - submit
operator.control - inspect
task.graph - read or update
project.snapshot - request
project.review
This gives browser users the same run controls as the CLI alongside run details and artifacts.
For task graphs, project snapshots, and reviews, continue to Review and state workflows.
What to inspect before you control a thread
- read the operator inbox for the affected session
- inspect the thread view and the next action or blocker
- confirm whether a child thread or fan-in checkpoint is involved
- pick the narrowest control action that moves the workflow forward
Continue the original work
If a run blocks on evidence, operator control can steer the existing thread instead of creating a disconnected replacement run.