Interrupt AI Agent Coordinators Safely: What Pause, Redirect, and Abort Must Mean

How to interrupt AI agent coordinators without orphaning work: a signal ladder, tool-boundary stops, branch-per-worker git rules, a redirect protocol, a drill.

Interrupt AI agent coordinators: a coordinator fanning out to workers, with pause, redirect, and abort controls marked at the tool boundary
Pause and redirect wait for a tool boundary. Abort waits, then escalates on a timer.

9:40 a.m., Tuesday. A coordinator has sixteen workers grinding through a dependency migration you kicked off at 9:05, and you have just noticed that the plan it wrote targets the wrong major version. You reach for Ctrl+C. What happens next depends on details nobody put in the launch post: which process gets the signal, which workers are on their own machines, and whether any of them is halfway through rewriting a lockfile.

Being able to interrupt AI agent coordinators safely is the difference between a fleet and a runaway. A chatbot’s stop button cancels a stream; nothing was in flight but tokens. A coordinator that delegates to workers on cloud VMs and commits to branches on your behalf is holding half-written files, unreturned shell commands, and workers who have no idea you pressed anything. It needs three separate controls, each with an operational definition you have tested: pause, redirect, abort.

Interrupting an acting agent is a distributed-systems operation, not a keypress. The state is scattered across processes, machines, and git worktrees, and the cleanest cooperative checkpoint is the tool boundary: a tool call has returned and the next has not been issued. Pause and redirect are defined against that moment. Abort attempts the same exit, then escalates when a worker does not cooperate. Vendors will keep saying their coordinator is “always responsive to direction.” Your job is to find out what that means at the tool boundary.

Cursor put steering at the tool boundary on Aug 19, then promised a coordinator that is never blocked on Sep 10

The Aug 19, 2026 Cursor changelog entry, “Cloud Agents and Cursor Harness Improvements,” contains the most operationally honest sentence a harness vendor has shipped this year: “You can now send a message to steer the agent while it’s working without interruption. Follow-ups wait for the next tool call instead of cutting the agent off mid-action” (cursor.com/changelog). The same entry puts subagents on their own virtual machines, each with “an isolated copy of the project with clean context.”

Cursor changelog, Aug 19, 2026: subagents on their own virtual machines, /goal, and the Steering improvements note Screenshot: Cursor changelog, “Cloud Agents and Cursor Harness Improvements” (Aug 19, 2026), captured Sep 13, 2026.

On Sep 10, 2026, the “Introducing Projects” post by Alexi Robbins and Fredrika Lindh (cursor.com/blog/projects) scaled the idea up to a coordinator that “plans the work, delegates it to agents that implement it, and brings the finished work back to you to check.” And the line to interrogate: “Because it delegates rather than executes, it is never blocked and is always responsive to direction.” Add “A Project runs on its own computer in the cloud, so closing your laptop doesn’t stop it,” and the problem has its shape. Direction reaches the coordinator. What reaches the sixteen workers is up to you.

Cursor blog, Sep 10, 2026: “Direct thousands of agents through one coordinator,” never blocked and always responsive to direction Screenshot: Cursor blog, “Introducing Projects” (Sep 10, 2026), captured Sep 13, 2026.

Neither document describes what a stop does to in-flight subagents or their branches, or whether a redirect re-plans everything or only the changed part. Treat those semantics as unknown until a controlled test shows otherwise. That gap is this runbook, for Projects, for a Claude Code session that spawned subagents, for a codex exec job in CI, and for a home-built coordinator on a cron.

Define pause, redirect, and abort as contracts before you need them

Write these into the coordinator’s operating doc and make every harness honor them, whatever its native keybinding.

Control Operator’s meaning Coordinator In-flight workers
Pause “Hold everything; I am about to change my mind.” Hold flag; no new tasks; plan kept Finish the current tool call, checkpoint, wait
Redirect (steer) “Change this part; keep the rest.” Diffs the plan: keep, modify, or drop each task Keep-tasks continue; modify-tasks take the delta at the next boundary; drop-tasks checkpoint and exit
Abort “Stop spending. Preserve evidence.” Broadcast stop, grace window, escalate, sweep Stop at the next boundary; past the window, killed; worktrees never deleted

Two things are deliberately absent: a pause that freezes a process mid-syscall (SIGSTOP can hold file locks and stall sockets without producing a coherent checkpoint), and an abort that deletes anything. Abort ends spending; cleanup is a later, human-reviewed step.

Interrupt AI agent workers at the tool boundary, not mid-write

The signal ladder is where home-built coordinators go wrong, because a terminal makes Ctrl+C feel like a universal stop. It is not.

Ctrl+C sends SIGINT to the foreground process group of your terminal. Workers spawned in that group get it. Workers started with setsid, nohup, a container runtime, or on a remote VM do not. Neither does a stdio MCP server whose parent already exited; a well-behaved one quits on EOF, a sloppy one keeps running with your credentials in its environment. And a cloud-hosted coordinator never hears your laptop at all.

So the coordinator, never the terminal, owns the ladder:

abort issued
  t+0 s    write STOP to the run's control file; coordinator issues no new tasks;
           workers poll the file at every tool boundary and exit cleanly
  t+30 s   SIGTERM to every worker pid still alive (local) / stop call (remote)
  t+40 s   SIGKILL to anything still alive; log pid, task id, branch as "killed dirty"
  t+40 s   orphan sweep: anything tagged with this RUN_ID and still running is a finding

The 30-second grace window is illustrative; set it to the longest tool call your workers legitimately make (a test suite, a build) plus margin. On Linux and macOS, kill -TERM and kill -KILL do the escalation; semantics are in signal(7) on man7.org. On Windows the tree kill is taskkill /PID <pid> /T /F, and a guaranteed tree kill means assigning workers to a job object at spawn (learn.microsoft.com, Job Objects).

Two harness realities belong in the contract. Do not translate an interactive CLI’s Escape or Ctrl+C behavior into coordinator semantics; keybindings and process behavior differ across releases. Test each harness you operate. Non-interactive runs such as codex exec (developers.openai.com/codex/noninteractive) have no keyboard; their pause and abort must come from an external control channel and the ladder. When a vendor manages the loop, as the OpenAI Agents API does (it “manages sessions, orchestration, context compaction, and recovery,” per the Agents API overview, beta Sep 10, 2026), verify that vendor’s current session-stop control and its latency before the run starts.

Make partial commits safe before you ever stop anything

An abort at t+40 s leaves worktrees in whatever state the workers were in. That is fine if, and only if, the git discipline was set up front. Four rules.

One branch per worker, one worktree per worker. The coordinator creates agent/<run-id>/<task-id> from the base commit and gives each worker its own git worktree (git-scm.com). Two workers never share a checkout, so a killed worker’s damage stops at its own directory.

RUN=r$(date +%Y%m%d-%H%M)
git worktree add -b agent/$RUN/t07 ../wt-$RUN-t07 origin/main
RUN_ID=$RUN TASK_ID=t07 run-worker --cwd ../wt-$RUN-t07   # tags travel in the environment

Checkpoint at the boundary, not at the end. Each worker commits wip: <task-id> <step> after every tool call that changed files. Cheap, ugly, and why a boundary stop loses seconds, not the whole task. The coordinator squashes before it opens a PR.

No direct pushes to the integration branch. Branch protection with required reviews and status checks on main (docs.github.com), and worker credentials that can push only to agent/*. A coordinator “always responsive to direction” is still one bad plan away from forty PRs; protection keeps that from becoming forty merges.

Stash is not a checkpoint. git stash is per-worktree, unnamed by default, and invisible to the coordinator. Workers do not stash. A stash left behind by a killed worker is work you will discover in March.

With those rules in place, the three controls cost very different amounts of orphaned work. The chart is a model with one point: the expensive control is the hard kill; the cheap one is a boundary stop with checkpoints.

Illustrative chart: orphaned worker-minutes under hard kill, boundary stop, and steer Illustrative model: sixteen workers, 4.5 minutes of uncommitted work each, four tasks invalidated by the redirect, two minutes to relaunch a worker. Not measured.

Hunt orphaned workers before the meter does

Orphans are workers still running after the coordinator thinks they are gone. They burn tokens with no consumer, and fan-out multiplies that spend before anyone notices. The metering side lives in metering subagent fan-out; the hunting side is two habits.

Tag every worker at spawn with RUN_ID and TASK_ID in its environment and write a manifest line: pid or remote id, host, branch, start time. The manifest is the authoritative list of who exists; the coordinator’s memory is not. Then sweep the recorded process ids, never process names:

jq -r --arg run "$RUN" 'select(.run_id == $run and .pid) | .pid' run-manifest.jsonl |
while read -r pid; do
  kill -0 "$pid" 2>/dev/null && echo "alive: $pid"
done
for wt in ../wt-$RUN-*; do [ -n "$(git -C "$wt" status --porcelain)" ] && echo "dirty: $wt"; done

A remote worker the platform lists and your manifest does not is an orphan by definition. A worker that answers no heartbeat for two boundaries is a stall, which has its own signal in stall flags and keepalive, and a stalled worker during an abort is a drill failure.

The redirect protocol: what the coordinator re-plans, and what it must keep

Steering is the control vendors are proudest of and the one that fails quietly. A redirect that makes the coordinator throw away its plan and re-plan from the objective is a replan storm: it re-issues tasks that were fine, spawns duplicates of workers still running, and doubles the bill in the name of responsiveness. The protocol has four moves.

  1. Classify every in-flight task against the new instruction: keep, modify, or drop. Keep means the instruction touches neither the task’s files nor its acceptance criteria. Modify means the task survives with a changed constraint. Drop means its premise is gone.
  2. Keep-tasks are never touched. No restart, no re-prompt. Their workers do not know a redirect happened.
  3. Modify-tasks stop at the next boundary, checkpoint, and get the delta, never the whole new objective. A worker rewriting a lockfile for version 4 needs “target version 5, keep everything else.”
  4. Drop-tasks checkpoint, tag their branch abandoned/<run>/<task>, and exit. The branch stays until a human deletes it. Half-finished work is evidence, and evidence is what you replay when the redirect turns out to be the mistake (fleet replay covers how).

Only then does the coordinator plan new tasks, and only for the gap the redirect opened.

State diagram of pause, redirect, and abort for an agent coordinator, with what in-flight workers do on each transition Cooperative transitions leave Running at a tool boundary. Abort enters Draining, then may force a timed kill.

A coordinator that cannot produce that table before acting has an abort with a friendlier name; when not to use a fleet coordinator covers the work that should stay single-agent.

The tabletop drill: interrupt AI agent fleets once, on purpose

Run this once, on a throwaway copy of a real repo, with the real coordinator and the real number of workers. Two hours, one operator, one observer with a stopwatch. I have never regretted a kill switch. I have regretted, more than once, assuming one worked.

Setup. Sixteen workers, enough tasks that all of them are mid-task at minute five, a RUN_ID on everything, branch protection on, the manifest open in a second terminal.

Pause, at minute five. Measure time-to-quiet: seconds from the control to zero tool calls across the manifest. Count dirty worktrees. Resume, and confirm every worker picked up where it checkpointed.

Redirect, at minute eight. Change one constraint that invalidates roughly a quarter of the tasks. Demand the keep/modify/drop table before anything moves. Count duplicate workers and keep-task workers that restarted anyway.

Abort, at minute twelve. Stopwatch from the control until the orphan sweep returns empty. If the coordinator is cloud-hosted, close the laptop lid and run the sweep again from another machine.

Score it:

Measure Pass Investigate Fail
Time-to-quiet after pause ≤ longest legitimate tool call ≤ 2× that longer, or never
Dirty worktrees after pause 0 wip: commit ≤ 1 boundary old changes with no wip: commit
Duplicate workers after redirect 0 0, but a keep-task restarted ≥ 1
Direct pushes to main 0 n/a ≥ 1
Orphans alive at t+60 s after abort 0 0 locally, ≥ 1 remote ≥ 1 locally
Tokens spent after abort ≈ one tool call per worker ≤ 5 min of fleet burn more, or unknown

“Unknown” in the tokens row is a fail: a fleet whose spend you cannot see per run is running on a bill you will read next month (the operating bill versus the token bill makes that case). The thresholds are yours to tune; the rows are not.

What breaks when you interrupt a coordinator, and the signal that tells you

The signal reached the coordinator and nobody else. Signal: the coordinator says “stopped” while the manifest still shows tool calls, or work keeps landing on branches after you closed the lid. Cause: workers in their own sessions, containers, or VMs, or a hosted coordinator that outlives your laptop by design. Fix: control file plus ladder, never a bare Ctrl+C; for a hosted coordinator, find the stop call and test it.

The replan storm. Signal: the task count jumps after a redirect; two workers hold the same task id; the meter spikes. Cause: re-planning from the objective instead of diffing. Fix: require the keep/modify/drop table as an artifact; refuse redirects that cannot produce one.

The ghost MCP server. Signal: a process from the run outlives the run, often holding a token. Cause: stdio servers that ignore EOF, spawned outside the process group. Fix: sweep by RUN_ID; treat any survivor as a security event, not wasted compute.

Approval fatigue turns abort into “approve everything.” Signal: the operator stops reading stop prompts and clicks through. Cause: a control that asks a question at every step. Fix: abort is one action, never a queue of confirmations; the hygiene for every other queue is in human-in-the-loop queues that don’t become rubber stamps.

The operating layer owns the stop, not the prompt

A coordinator that delegates instead of executing is genuinely harder to block, and Cursor is right to say so. Its stop button is also, from the operator’s side, a promise about workers it does not run in-process. Honoring that promise takes a control file, a signal ladder, a manifest, a git convention, and a drill, none of which are prompt engineering. They are operating-layer infrastructure: the layer that keeps the fleet visible, its transcripts replayable, and one person one place to press stop.

That is the desk-level argument of the multi-agent command center and the discipline argument of agentic ops. A smarter coordinator raises the ceiling on what the fleet can do in an hour. A tested abort is what lets you leave the room.

FAQ: interrupting AI agents and coordinators

How do you stop an AI agent mid-task without corrupting its work?

Stop it at a tool boundary, the moment after a tool call returns and before the next is issued. Interactive harnesses expose this as a single interrupt keypress; coordinators need a control file that workers check at every boundary, plus a signal ladder for workers that never check.

What happens to subagents when you kill the coordinator?

Subagents may die with the coordinator when they share its process or managed job. Detached workers, containers, or cloud VMs may keep running, spending, and holding worktrees because a terminal signal never reaches them. Record every worker in a run manifest at spawn and sweep that manifest after every abort.

Sources