Emergency Stop is the move a person makes when an agent has to halt now. One action stops the agent, its helpers and any copies it made, across each system it reached. The stop is confirmed back: what halted, what did not, and what was in flight. It differs from Interruption, which pauses one task and keeps its work. This one trades the work for certainty.
When to Use It
Agents act on real systems with real reach
A person may learn of a problem after the agent is acting
Copies or helpers can outlive the window that started them
When Not To
The agent cannot act on anything outside its chat
A pause that keeps the work is what humans need; that is Interruption
The stop cannot reach the agent; then it is a promise, not a control
Three views
The exchange between the human, the agent and the system the agent acts on; who holds each part of it; and the component that implements it.
01 · the interaction
02 · who holds what
01The stopOne action, reachable in seconds, that a person takes without a runbook
02ScopeOne agent, a team of agents, or all agents under this account
03ReachThe stop reaches helpers, copies and scheduled work, not only the chat window
04ConfirmationWhat halted, what did not, and what was mid-action when it did
05RestartA deliberate act by a person, and not automatic
03 · the component · code: experimental
vendor presets are recreations, not vendor assets
THE LIVE PLAYGROUND NEEDS A WIDER SCREEN — IT'S WAITING ON DESKTOP.
THE ANATOMY ABOVE AND THE CODE BELOW ARE THE SAME COMPONENT.
Do / Don't
Do
Reach each place the agent runs: its helpers, its copies and its scheduled jobs.
Don't
Treat closing the chat window as the stop.
A stop that closes the window leaves the agent running on the server. The stop has to reach where the agent is.
Do
Say the stop is requested until each target reports back, then name what halted and what did not.
Don't
Show the agent as stopped the moment the button is pressed.
A press is a request to the systems the agent reached. A person who reads it as done stops watching while a copy keeps writing.
Do
Make the stop one press that gives up the work: no confirm step, and nothing that keeps running to finish its step.
Don't
Put an extra confirm dialog in front of the stop, or let the agent finish what it was doing first.
A hard stop can lose a long run. That is the price, and a soft stop that keeps working does not stop anything.
Do
Name the people who hold the stop, and record each press and each restart with a name and a time.
Don't
Hand the stop to the whole company, or to no one in particular, and restart on a timer.
Too few hands and the stop comes late; a crowd and it gets pressed for noise. A named press and a named restart keep both in view.
Every pair cites a documented tension or principle boundary — no free-floating taste.
Get the Code
Namespaced install (add the registry to components.json once):
/**
* EmergencyStop — headless core.
* Pattern: a person halts one agent, or all of them, in one move, and sees that the halt held.
* Anatomy: Scope · The stop · Reach · Confirmation · Restart
*
* The press and the halt are two facts, kept apart. Pressing the stop records a
* request and hands it to the host's kill switch (onStopRequest). The stop is
* confirmed only when the host has reported back on every target it reached:
* halted, still running, or mid-action. Until then the component says
* "requested", never "stopped".
*
* Lifecycle:
* armed → requested (STOP: one press, no confirm step)
* requested → confirmed (the last awaited REPORT arrives)
* confirmed → requested (STOP_AGAIN on a target that kept running)
* confirmed → restarted (RESTART, a person's act; with targets not halted,
* only after the person says they know)
* Contract events (spec 2026-10-04 §1): execution.stopped with phase "requested"
* on each press, execution.stopped with phase "confirmed" when every awaited
* report is in, and execution.started on restart.
*/
import * as React from 'react';
import type { Actor, InteractionEvent, InteractionEventType } from '@/lib/interaction-contract';
export type { Actor, InteractionEvent, InteractionEventType } from '@/lib/interaction-contract';
export type StopScope = 'one' | 'team' | 'all';
export type StopState = 'armed' | 'requested' | 'confirmed' | 'restarted';
/** What the host's kill switch reports for one target. */
export type StopReport = 'halted' | 'still-running' | 'mid-action';
/** A report, or a mid-action target the person has checked by hand. */
export type TargetOutcome = StopReport | 'checked';
export interface StopTarget {
id: string;
/** What is running: a helper, a copy, a scheduled job, a login. */
label: string;
/** The narrowest scope whose stop reaches this target. Defaults to 'one'. */
reach?: StopScope;
/** Where it runs, shown as a small tag: server, schedule, browser. */
where?: string;
}
/** What the host's kill switch receives on each press. */
export interface StopRequest {
runId: string;
scope: StopScope;
/** The targets this press asks the host to halt. */
targetIds: string[];
/** The named person who pressed. */
by: string;
at: string;
/** True for a second press on a target that kept running. */
again: boolean;
}
export interface StopConfirmation {
phase: 'confirmed';
scope: StopScope;
halted: string[];
stillRunning: string[];
midAction: string[];
checked: string[];
}
export const scopeRank: Record<StopScope, number> = { one: 0, team: 1, all: 2 };
export const scopes: StopScope[] = ['one', 'team', 'all'];
export const scopeLabel: Record<StopScope, string> = {
one: 'This agent',
team: 'Its team',
all: 'All agents on the account',
};
export const reaches = (scope: StopScope, t: StopTarget) => scopeRank[t.reach ?? 'one'] <= scopeRank[scope];
export type Event =
| { type: 'SET_SCOPE'; scope: StopScope }
| { type: 'STOP'; by?: string; at?: string }
/** The host's kill switch answered for one target. */
| { type: 'REPORT'; targetId: string; outcome: StopReport; at?: string }
| { type: 'STOP_AGAIN'; targetId: string; by?: string; at?: string }
| { type: 'MARK_CHECKED'; targetId: string }
| { type: 'ACK'; value: boolean }
| { type: 'RESTART'; by?: string; at?: string };
export interface MachineState {
state: StopState;
runId: string;
/** The named person who holds the stop. Each press and restart is recorded with this name. */
person: string;
scope: StopScope;
targets: StopTarget[];
/** Targets the current request still waits on. Empty once confirmed. */
awaiting: string[];
/** What the host reported per target, or "checked" after the person looked. */
outcomes: Record<string, TargetOutcome>;
/** The first press: who, when, which scope. */
press: StopRequest | null;
/** The person said they know some targets did not halt. */
ack: boolean;
restart: { by: string; at: string } | null;
/** Contract events in order. The Root hands each one to onEvent once. */
events: InteractionEvent[];
}
export interface InitialOptions {
runId: string;
targets: StopTarget[];
scope?: StopScope;
person?: string;
}
export function initialState({ runId, targets, scope = 'one', person = 'You' }: InitialOptions): MachineState {
return { state: 'armed', runId, person, scope, targets, awaiting: [], outcomes: {}, press: null, ack: false, restart: null, events: [] };
}
function emit<P>(s: MachineState, type: InteractionEventType, actor: Actor, at: string, payload: P, correlationId?: string): InteractionEvent[] {
const e: InteractionEvent<P> = {
id: `${s.runId}:stop:${s.events.length + 1}`,
runId: s.runId,
actor,
type,
at,
payload,
...(correlationId ? { correlationId } : {}),
};
return [...s.events, e];
}
export const reachedTargets = (s: MachineState) => s.targets.filter((t) => reaches(s.scope, t));
/** Reached targets whose report says they did not halt, and that the person has not settled. */
export const unresolvedTargets = (s: MachineState) =>
reachedTargets(s).filter((t) => s.outcomes[t.id] === 'still-running' || s.outcomes[t.id] === 'mid-action');
export const haltedTargets = (s: MachineState) =>
reachedTargets(s).filter((t) => s.outcomes[t.id] === 'halted' || s.outcomes[t.id] === 'checked');
function confirmation(s: MachineState): StopConfirmation {
const ids = (o: TargetOutcome) => reachedTargets(s).filter((t) => s.outcomes[t.id] === o).map((t) => t.id);
return {
phase: 'confirmed',
scope: s.scope,
halted: ids('halted'),
stillRunning: ids('still-running'),
midAction: ids('mid-action'),
checked: ids('checked'),
};
}
/** A request settles when nothing is awaited; the confirmation is then recorded as its own event. */
function settle(s: MachineState, at: string): MachineState {
if (s.state !== 'requested' || s.awaiting.length > 0) return s;
const next = { ...s, state: 'confirmed' as const };
// The confirmation answers the latest press.
const press = [...s.events].reverse().find((ev) => (ev.payload as { phase?: string }).phase === 'requested');
return { ...next, events: emit(next, 'execution.stopped', 'system', at, confirmation(next), press?.id) };
}
const now = () => new Date().toISOString();
export function reducer(s: MachineState, e: Event): MachineState {
switch (e.type) {
case 'SET_SCOPE':
return s.state === 'armed' && s.scope !== e.scope ? { ...s, scope: e.scope } : s;
case 'STOP': {
if (s.state !== 'armed') return s;
const at = e.at ?? now();
const targetIds = reachedTargets(s).map((t) => t.id);
const press: StopRequest = { runId: s.runId, scope: s.scope, targetIds, by: e.by ?? s.person, at, again: false };
const next: MachineState = { ...s, state: 'requested', awaiting: targetIds, outcomes: {}, ack: false, press };
const payload = { phase: 'requested', scope: press.scope, targetIds, by: press.by, at, again: false };
return settle({ ...next, events: emit(next, 'execution.stopped', 'human', at, payload) }, at);
}
case 'REPORT': {
if (s.state !== 'requested' && s.state !== 'confirmed') return s;
const target = s.targets.find((t) => t.id === e.targetId);
if (!target || !reaches(s.scope, target)) return s;
const awaited = s.awaiting.includes(e.targetId);
// A late report (nothing awaited) can only change what the person sees, not a settled check.
if (!awaited && (s.outcomes[e.targetId] === e.outcome || s.outcomes[e.targetId] === 'checked')) return s;
const next = {
...s,
awaiting: s.awaiting.filter((id) => id !== e.targetId),
outcomes: { ...s.outcomes, [e.targetId]: e.outcome },
};
return settle(next, e.at ?? now());
}
case 'STOP_AGAIN': {
if (s.state !== 'confirmed' && s.state !== 'requested') return s;
if (s.outcomes[e.targetId] !== 'still-running' || s.awaiting.includes(e.targetId)) return s;
const at = e.at ?? now();
const by = e.by ?? s.person;
const next: MachineState = { ...s, state: 'requested', awaiting: [...s.awaiting, e.targetId], ack: false };
return {
...next,
events: emit(next, 'execution.stopped', 'human', at, { phase: 'requested', scope: s.scope, targetIds: [e.targetId], by, at, again: true }),
};
}
case 'MARK_CHECKED':
if (s.state !== 'confirmed' && s.state !== 'requested') return s;
if (s.outcomes[e.targetId] !== 'mid-action') return s;
return { ...s, outcomes: { ...s.outcomes, [e.targetId]: 'checked' } };
case 'ACK':
return s.state === 'confirmed' && s.ack !== e.value ? { ...s, ack: e.value } : s;
case 'RESTART': {
if (s.state !== 'confirmed') return s;
const left = unresolvedTargets(s);
if (left.length > 0 && !s.ack) return s;
const at = e.at ?? now();
const by = e.by ?? s.person;
const next: MachineState = { ...s, state: 'restarted', restart: { by, at } };
return { ...next, events: emit(next, 'execution.started', 'human', at, { restart: true, by, notHalted: left.map((t) => t.id) }) };
}
}
}
/** The one line the Confirmation part reads out. */
export function confirmationText(s: MachineState, agent = 'the agent'): string {
const reached = reachedTargets(s);
const halted = haltedTargets(s).length;
const outside = s.targets.length - reached.length;
const outsideLine = outside > 0 ? ` ${outside} outside this stop kept running.` : '';
switch (s.state) {
case 'armed':
return '';
case 'requested': {
const answered = reached.length - s.awaiting.length;
return `Stop requested. ${answered} of ${reached.length} answered so far. Waiting to hear from ${s.awaiting.length}.`;
}
case 'confirmed': {
const left = unresolvedTargets(s).length;
return left === 0
? `Stop confirmed. ${halted} of ${reached.length} halted. Nothing in this stop is still running.${outsideLine}`
: `${halted} of ${reached.length} halted. ${left} need${left === 1 ? 's' : ''} you to look.${outsideLine}`;
}
case 'restarted':
return `You restarted ${agent}. Nothing restarts it on a timer.`;
}
}
export function stopLabel(scope: StopScope, agent = 'the agent'): string {
if (scope === 'all') return 'Stop all agents on the account now';
if (scope === 'team') return `Stop ${agent} and its team now`;
return `Stop ${agent} now`;
}
interface EmergencyStopContext extends MachineState {
agent: string;
send: (e: Event) => void;
}
const Ctx = React.createContext<EmergencyStopContext | null>(null);
export function useEmergencyStop(): EmergencyStopContext {
const ctx = React.useContext(Ctx);
if (!ctx) throw new Error('EmergencyStop parts must be used inside <EmergencyStop.Root>');
return ctx;
}
export interface RootProps {
/** One agent run; every contract event carries it. */
runId: string;
/** The agent's name, used in the button and the confirmation. */
agent?: string;
/** Everything the stop could reach: helpers, copies, scheduled jobs, logins. */
targets: StopTarget[];
defaultScope?: StopScope;
/** The named person who holds the stop. Defaults to "You". */
person?: string;
/**
* Called on each press. Send it to your kill switch, then call report(targetId, outcome)
* for every target in request.targetIds as the answers come in.
*/
onStopRequest?: (request: StopRequest, report: (targetId: string, outcome: StopReport) => void) => void;
/** Every contract event, once each. */
onEvent?: (e: InteractionEvent) => void;
children: React.ReactNode;
}
function Root({ runId, agent = 'the agent', targets, defaultScope = 'one', person, onStopRequest, onEvent, children }: RootProps) {
const [machine, send] = React.useReducer(reducer, { runId, targets, scope: defaultScope, person }, initialState);
const report = React.useCallback((targetId: string, outcome: StopReport) => send({ type: 'REPORT', targetId, outcome }), []);
const sent = React.useRef(0);
React.useEffect(() => {
const fresh = machine.events.slice(sent.current);
sent.current = machine.events.length;
for (const e of fresh) {
onEvent?.(e);
const p = e.payload as { phase?: string } & Omit<StopRequest, 'runId'>;
if (e.type === 'execution.stopped' && p.phase === 'requested') {
onStopRequest?.({ runId: e.runId, scope: p.scope, targetIds: p.targetIds, by: p.by, at: p.at, again: p.again }, report);
}
}
}, [machine.events, onEvent, onStopRequest, report]);
const value = React.useMemo(() => ({ ...machine, agent, send }), [machine, agent]);
return (
<Ctx.Provider value={value}>
<div role="group" aria-label="Emergency stop" data-pattern="emergency-stop" data-part="root" data-state={machine.state}>
{children}
</div>
</Ctx.Provider>
);
}
/** One agent, its team, or the account. Locked after the press. */
function Scope({ legend = 'Stop scope' }: { legend?: string }) {
const { scope, state, targets, send } = useEmergencyStop();
const name = React.useId();
return (
<fieldset data-part="scope" disabled={state !== 'armed'}>
<legend>{legend}</legend>
{scopes.map((s) => (
<label key={s} data-checked={scope === s || undefined}>
<input type="radio" name={name} value={s} checked={scope === s} onChange={() => send({ type: 'SET_SCOPE', scope: s })} />
<span data-part="scope-name">{scopeLabel[s]}</span>
<span data-part="scope-count">
Reaches {targets.filter((t) => reaches(s, t)).length} of {targets.length}
</span>
</label>
))}
</fieldset>
);
}
type TriggerProps = Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, 'onClick'>;
/** The stop. One press, no confirm step. Disabled once pressed. */
function Trigger({ children, ...props }: TriggerProps) {
const { state, scope, agent, send } = useEmergencyStop();
return (
<button type="button" data-part="trigger" disabled={state !== 'armed'} onClick={() => send({ type: 'STOP' })} {...props}>
{children ?? stopLabel(scope, agent)}
</button>
);
}
/** "14:02:11 UTC" from an ISO time; anything else as given. */
export const clockTime = (at: string) => (/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/.test(at) && at.endsWith('Z') ? `${at.slice(11, 19)} UTC` : at);
/** Who pressed, when, and which scope. Renders only after the press. */
function PressRecord() {
const { press } = useEmergencyStop();
if (!press) return null;
return (
<p data-part="press-record">
<span data-part="kicker">Press recorded</span> {press.by} · <time dateTime={press.at}>{clockTime(press.at)}</time> · {scopeLabel[press.scope].toLowerCase()}
</p>
);
}
export type ReachTone = 'armed' | 'outside' | 'awaiting' | TargetOutcome;
export const reachChip: Record<ReachTone, string> = {
armed: 'Will stop',
outside: 'Outside this stop',
awaiting: 'Stop requested',
halted: 'Halted',
'still-running': 'Still running',
'mid-action': 'Was mid-action',
checked: 'Checked by you',
};
export function reachTone(s: MachineState, t: StopTarget): ReachTone {
if (!reaches(s.scope, t)) return 'outside';
if (s.state === 'armed') return 'armed';
if (s.awaiting.includes(t.id)) return 'awaiting';
return s.outcomes[t.id] ?? 'awaiting';
}
/** Every target, with what the stop did to it. Stop again and Mark checked sit on the rows that need them. */
function Reach({ label = 'What the stop reaches' }: { label?: string }) {
const machine = useEmergencyStop();
const { targets, state, send } = machine;
const live = state === 'requested' || state === 'confirmed';
return (
<ul data-part="reach" aria-label={label}>
{targets.map((t) => {
const tone = reachTone(machine, t);
return (
<li key={t.id} data-part="target" data-tone={tone}>
<span data-part="target-label">{t.label}</span>
{t.where && <span data-part="target-where">{t.where}</span>}
<span data-part="chip" data-tone={tone}>
{reachChip[tone]}
</span>
{live && tone === 'still-running' && (
<button type="button" data-part="stop-again" aria-label={`Stop again: ${t.label}`} onClick={() => send({ type: 'STOP_AGAIN', targetId: t.id })}>
Stop again
</button>
)}
{live && tone === 'mid-action' && (
<>
<button type="button" data-part="mark-checked" aria-label={`Mark checked: ${t.label}`} onClick={() => send({ type: 'MARK_CHECKED', targetId: t.id })}>
Mark checked
</button>
<span data-part="target-why">It was writing when the stop landed. Check what it left before a restart.</span>
</>
)}
</li>
);
})}
</ul>
);
}
/** Requested, confirmed, or restarted, in one line. Renders after the press. */
function Confirmation({ children }: { children?: (s: MachineState) => React.ReactNode }) {
const machine = useEmergencyStop();
if (machine.state === 'armed') return null;
return (
<div data-part="confirmation" data-state={machine.state}>
<div data-part="tally" aria-hidden="true">
{reachedTargets(machine).map((t) => (
<i key={t.id} data-tone={reachTone(machine, t)} />
))}
</div>
<p role="status" aria-live="polite">
{children ? children(machine) : confirmationText(machine, machine.agent)}
</p>
</div>
);
}
/** A person's act, never a timer. Only once the stop is confirmed. */
function Restart({ children }: { children?: React.ReactNode }) {
const machine = useEmergencyStop();
const { state, ack, restart, agent, send } = machine;
const id = React.useId();
if (state === 'armed') return null;
if (state === 'restarted' && restart) {
return (
<p data-part="restart-record">
<span data-part="kicker">Restart recorded</span> {restart.by} · by hand
</p>
);
}
const left = unresolvedTargets(machine).length;
return (
<div data-part="restart">
{state === 'confirmed' && left > 0 && (
<label htmlFor={id} data-part="ack">
<input id={id} type="checkbox" checked={ack} onChange={(ev) => send({ type: 'ACK', value: ev.target.checked })} />
Restart with {left} part{left === 1 ? '' : 's'} not halted
</label>
)}
<button type="button" data-part="restart-button" disabled={state !== 'confirmed' || (left > 0 && !ack)} onClick={() => send({ type: 'RESTART' })}>
{children ?? `Restart ${agent}`}
</button>
<p data-part="hint">{state === 'requested' ? 'Restart opens once the stop is confirmed.' : 'A restart is your act. Nothing restarts it on a timer.'}</p>
</div>
);
}
export const EmergencyStop = Object.assign(Root, { Scope, Trigger, PressRecord, Reach, Confirmation, Restart });
patterns/emergency-stop/emergency-stop.tsx
/**
* EmergencyStop — styled reference implementation of the headless core.
* The parts sit in the order a person meets them: scope, the stop, what it
* reaches, the confirmation, the restart. Styling lives in tokens.css (.ah-ctl, .ah-stop).
*/
import * as React from 'react';
import {
EmergencyStop as Core,
reachedTargets,
useEmergencyStop,
type StopReport,
type StopRequest,
type StopScope,
type StopTarget,
type InteractionEvent,
} from './emergency-stop-core';
export interface EmergencyStopProps {
/** One agent run; every contract event carries it. */
runId: string;
agent: string;
/** Everything the stop could reach: helpers, copies, scheduled jobs, logins. */
targets: StopTarget[];
defaultScope?: StopScope;
/** The named person who holds the stop. The press is recorded with this name. */
person?: string;
/** Send each press to your kill switch, then call report(targetId, outcome) per target as it answers. */
onStopRequest?: (request: StopRequest, report: (targetId: string, outcome: StopReport) => void) => void;
onEvent?: (e: InteractionEvent) => void;
}
function Body() {
const machine = useEmergencyStop();
const armed = machine.state === 'armed';
return (
<section className="ah-ctl ah-stop" data-state={machine.state}>
<p className="ah-ctl-kicker">Emergency stop</p>
<div className="ah-ctl-part" data-actor="human">
<span className="ah-ctl-label">Scope</span>
<Core.Scope />
</div>
<div className="ah-ctl-part" data-actor="human">
<span className="ah-ctl-label">The stop</span>
<div className="ah-stop-trigger">
<Core.Trigger />
{armed ? (
<p className="ah-ctl-hint">One press, no confirm step. It reaches {reachedTargets(machine).length} running parts.</p>
) : (
<Core.PressRecord />
)}
</div>
</div>
<div className="ah-ctl-part" data-actor="system">
<span className="ah-ctl-label">Reach</span>
<Core.Reach />
</div>
{!armed && (
<div className="ah-ctl-part" data-actor="agent">
<span className="ah-ctl-label">Confirmation</span>
<Core.Confirmation />
</div>
)}
{!armed && (
<div className="ah-ctl-part" data-actor="human">
<span className="ah-ctl-label">Restart</span>
<Core.Restart />
</div>
)}
</section>
);
}
export function EmergencyStop({ runId, agent, targets, defaultScope, person, onStopRequest, onEvent }: EmergencyStopProps) {
return (
<Core runId={runId} agent={agent} targets={targets} defaultScope={defaultScope} person={person} onStopRequest={onStopRequest} onEvent={onEvent}>
<Body />
</Core>
);
}
Give this to your coding agent (shadcn MCP: npx shadcn@latest mcp init --client claude):
Add the @agentsandhumans registry to components.json:
{
"registries": {
"@agentsandhumans": "https://agentsandhumans.ai/api/registry/{name}.json"
}
}
Then install emergency-stop (npx shadcn@latest add @agentsandhumans/emergency-stop) and wire it into the flow where your agent stopping agents fast, in each place they run, and knowing they stopped.
The agent now wakes up when the system changes, with no human prompt. That gap, between trigger and outcome, is the design surface. A human needs to see what fired, what ran, and what it changed.
The phone's owner grants access once by plugging in the board, then has no view of what runs. That is the sharpest version of the reach and approval problem I have seen at the hardware layer.
The interface question flips here. A human is no longer directing one agent but setting rules for thousands. Patterns that assumed one-to-one contact need rethinking at population scale.
The agent went off-brief because a document told it to, and the human saw nothing. That is the strongest case for off-brief-alert and emergency-stop I have seen stated in numbers.
Single-agent review gives a false floor. Agents pass work to each other, and the human needs to see that chain, not the last step alone. That gap is where the stop decision has to land.
No human approved each step. No one knew it went off course. The gap between delegation and disaster is the absence of a person deciding before the agent acts on systems it can damage.
A kill switch written into law is a product requirement in disguise. The bill asks for throttle, suspend and shut down. Someone has to design the screen where a person does that, and prove the stop held. That screen is Emergency Stop.
I read the thread the day it landed. The odds are not the part a product team should hold onto. The part that lands is that the humans closest to these systems point at the Hugging Face breakout and call it a warning shot.
A lab backing its own leaver is new. For designers the line to keep is the second one: there is no plan yet. That is the space where product controls have to do the work.
Ten percent of the staff signing a letter is a design signal. The humans who know the systems best want a brake. Give them one they can press from inside the product.
A hundred million views in a day followed seven posts about AI labs racing toward self-improving AI. That scale of response tells you humans will redirect or stop a product the moment they sense it is moving without them.
A second escape, found by outside researchers, and no formal way inside the lab to look into it. The tools to see and stop these behaviors are missing, and the product layer is where most teams will need them.
The motive is the part product humans should sit with. The agents were reward hacking, chasing the score. They were not told to escape. The escape was the cheapest path to the number, and nothing was watching the path.
The anomaly system fired and rated the alert too low to page anyone. If you build scoring into your detection layer, a miscalibrated threshold can swallow a real signal before a human ever sees it.
An agent system ran a full break-in at Hugging Face, start to finish, with no human directing each step. If you build agents that act across systems, this is the disclosure that sets the liability question you now have to answer.
Reach: a stop that closes the window leaves the agent running on the server. The stop has to reach where the agent is, not where the person is.
Certainty over work: a hard stop can lose a long run. That is the price. A soft stop that keeps working is not a stop.
The right hands: too few humans and the stop is late; a crowd and it is pressed for noise. Name the humans and record the press.
What we are learning from the community
Readers who build with Emergency Stop add what they found: questions, use cases, critiques, other ways to solve it.
An editor reads each one before it shows here. Nothing here changes the pattern's status on its own.
This pattern has no contributions yet. The form below sends the first one.
Oct 4, 2026Component published, experimental: one press records a stop request for the host's kill switch, and the stop reads as confirmed only once each target it reached has reported back. The confirmation names what did not halt; restart is a person's act.
Sep 15, 2026sighting-storyAltman and Amodei gave outsiders a seat and forgot the brakeTwo labs now promise outside reviewers the same screen as insiders. A reviewer who can see a departure but cannot stop the run is a witness, and witnesses are not enough.
Sep 11, 2026Added to the Watching list after the Hugging Face agent breakout and the insider warnings that followed (essay of 2026-09-11).