HomeBlog › Last-prompt-wins: cancellation semantics for impatient humans
Blog

Last-prompt-wins: cancellation semantics for impatient humans

Jul 19, 20265 min readBy the Rysh team

In rysh, a new prompt cancels the in-flight one. No queue, no zombie completions — steering. Why impatience is the right design center.

You sent the wrong prompt. Everyone does, forty times a day. The interesting question is what your tools do next.

Most chat UIs have the same answer: you wait. The model is mid-completion, the stop button works when it feels like it, and your correction joins a queue behind the mistake it's correcting. By the time your fix runs, the agent has confidently finished answering your past self — and now you're reading two wrong answers instead of one.

rysh takes a different position, and we gave it a blunt name: last-prompt-wins.

The semantics

Every pane in rysh is a conversation. Type a prompt (Double-Escape flips a pane between shell mode and prompt mode) and it goes to that pane's LLM execution actor. Now type another prompt while the first is still running.

The first one dies. Immediately. The in-flight completion is cancelled, and the new prompt starts fresh. No queue. No "please wait for the current response." The newest instruction is the only instruction.

That's the whole contract, and it holds everywhere prompts flow: pane prompts, and @agent prompts to autonomous agents — which also answer to an explicit brake, @@agent stop, when you want a halt rather than a redirect.

Why the terminal taught us this

Terminal people already have this instinct burned in. Ctrl+C is a right. You don't ask a runaway process for permission to stop it; you don't wait for find / to finish before correcting the path. The shell's model is: the human's newest intent wins, always, instantly.

Chat interfaces quietly revoked that right, and we all adapted by becoming careful — writing longer, more defensive prompts up front because correction is expensive. That's backwards. The empirical loop that actually works with agents is steering: fire a rough prompt, watch the output stream into the pane, and correct mid-flight the moment it drifts. Cheap corrections beat perfect first drafts.

Impatience isn't a character flaw here. It's information. Your newest intent is the highest-value signal in the whole system, and the runtime should treat it that way.

How it works underneath

rysh is built on an actor model (proto.actor over NATS), and last-prompt-wins falls out of it naturally.

Each pane has a child actor dedicated to LLM execution — the LLMPromptExecutionActor. Prompts arrive as messages in its mailbox, processed strictly one at a time (actors process sequentially; there isn't a mutex in sight). The completion itself runs in a goroutine holding a cancellable context.

When a new prompt message lands, the actor cancels the old context, then starts the new completion. The dying goroutine can't corrupt anything on its way out because it never held actor state to begin with — goroutines capture only immutable values: the pane ID, the prompt text, a publisher handle. Cancellation is a context signal, not a knife fight over shared memory.

Sequential mailbox for ordering, cancellable context for interruption. Two boring primitives, one honest guarantee.

What cancellation does — and doesn't — undo

Precision matters here, so let's be exact.

Last-prompt-wins stops the loop: the in-flight completion and whatever tool calls it was about to make. It does not un-run what already ran. If the agent executed a shell command three steps ago, that command happened.

This is why the semantics pair with rysh's approval gates instead of replacing them. Dangerous operations — file writes, edits (shown preview-first, as a coloured diff), non-allowlisted bash, git commit — wait for your explicit approval. A pending approval belonging to a cancelled prompt simply dies with it: the dangerous thing never executes. And a long-running background job you did approve keeps running until you kill it deliberately (bash_session with kill — background work shouldn't die just because you rephrased a question).

So the risk surface splits cleanly: reversible, observable work flows freely and cancels instantly; irreversible work queues behind a human regardless of how many prompts you've fired.

Everything above happens in a pane you can watch — every tool call visible, every cancellation obvious, because the old response just stops and the new one starts. No spinner theater.

The design argument

There's a philosophical fork in agent UX right now. One branch treats the model's in-flight work as precious: queue the human, protect the completion. The other treats the human's current intent as precious: kill the completion, follow the human.

We think the second branch is obviously right for real work, for a reason that has nothing to do with politeness: an agent completing an outdated instruction isn't productive, it's expensive noise. Tokens spent answering a prompt you've already retracted have negative value — you pay for them (rysh runs on Claude with your own API key; those are your tokens) and then you pay again in attention to ignore the result.

Last-prompt-wins is a small feature with a long shadow. It changes how you write prompts (rougher, faster, corrected live), how you supervise agents (steer, don't specify), and how much you trust the system (a tool that obeys your newest intent instantly is a tool you'll hand more work to).

Your past self had worse information than you do right now. Your tools should stop listening to them.


We're recruiting design partners. If your team wants agents that steer like a terminal instead of queueing like a ticket system, come build with us: rysh.ai/design-partner

Related: Judge-decided reset and resume · Approval gates: deciding which operations deserve a human

Try Rysh

Every pane is a shell and an AI agent — install takes one command.

Get started free →