--- title: Pause, stop, kill description: What ClawMetry's process controls do — POSIX signals, the Windows native equivalents, pid-reuse guarding, and why an OpenClaw pause needs the enforcement proxy. keywords: pause AI agent, kill agent process, agent stop signal, Windows agent control, SIGSTOP agent eyebrow: Guard & governance --- # Pause, stop, kill Four controls, one actuator, and an honest answer per session about whether each one can work. ## What each does | Control | POSIX | Windows | |---|---|---| | **Pause** | `SIGSTOP` | `NtSuspendProcess` | | **Resume** | `SIGCONT` | `NtResumeProcess` | | **Stop** | `SIGINT` — the equivalent of Ctrl-C | Console Ctrl+C from a detached helper | | **Kill** | `SIGTERM`, escalating to `SIGKILL` across the tree | `taskkill /T`, escalating to `TerminateProcess` | Kill walks the process **tree**, not just the parent. An agent that has spawned a shell that has spawned a build is not stopped by signalling the top of it. ## Pid-reuse guarding Every action re-verifies the target before signalling. Process ids are reused, and a stale pid from thirty seconds ago can belong to something entirely different by the time a policy fires. This is the kind of bug that is invisible until the day it kills your database. The actuator checks identity, not just liveness. ## One actuator for both paths A hand-pressed pause and a policy-driven pause go through the same code, so they do exactly the same thing to the process — including `resume`, which used to bypass it. There is therefore one place where "what happens to the process" is defined and one place to audit. ## Capability is answered per session `runtime_control_support(runtime, session_id, cwd)` is the single verdict the Guard tab, the daemon and the actuator all read. Nothing re-derives it. Three axes vary independently: ### The OS Windows gets native equivalents, not a signal emulation. Two consequences: - **A Windows Ctrl+C cannot be addressed to one process.** It reaches the whole console. The UI says so rather than implying a precision it does not have. - Win32 calls declare their `argtypes` and `restype` explicitly. The default `c_int` return type truncates a 64-bit handle, and every call against a truncated handle fails **silently** — which looks exactly like a control that does nothing. ### The runtime, per session A **Cursor CLI** session is a real process tree and is controllable. A **Cursor editor** conversation shares the one IDE process and is not — killing it would kill the editor. The resolver answers per session. It does not refuse a whole runtime because one of its surfaces is uncontrollable. ### OpenClaw pause OpenClaw has **no pause primitive**. ClawMetry's pause for an OpenClaw session writes a flag file at `~/.clawmetry/hitl/pause_`, and that file is enforced **only** by the [enforcement proxy](/docs/guard/proxy/). With no proxy running, a "pause" on an OpenClaw session changes nothing. ClawMetry probes the proxy's status and reports `advisory_only` rather than claiming the agent was held. If pausing OpenClaw agents matters to you, run the proxy: ```bash clawmetry proxy start ``` ## The rule **A control that cannot work says why, next to a disabled button.** Never ship one that quietly does nothing. A greyed-out Pause with "OpenClaw has no pause primitive; start the enforcement proxy to make this advisory hold" is useful. A Pause button that appears to work and does not is worse than no button at all, because someone will rely on it during an incident. ## Using them From the Guard tab: select a session, press the control. From the API: ```bash curl -s localhost:8900/api/guard/control -X POST \ -H 'content-type: application/json' \ -d '{"session_id": "…", "action": "pause"}' ``` Accepted actions: `pause`, `resume`, `stop`, `kill`. Anything else is refused rather than passed through to a signal helper. `resume` is control-only. There is no policy that resumes a process — that is a human decision. These endpoints are **origin-checked**, because they signal real processes. They are not entitlement-gated: you pressed the button. There is also a per-agent form: ```bash curl -s localhost:8900/api/agents//pause -X POST -d '{}' -H 'content-type: application/json' curl -s localhost:8900/api/agents//resume -X POST -d '{}' -H 'content-type: application/json' curl -s localhost:8900/api/agents//stop -X POST -d '{}' -H 'content-type: application/json' ``` ## Choosing between them | Situation | Control | |---|---| | It is looping but the work is salvageable | **Pause**, look at the transcript, then resume or stop | | It is going nowhere and you want a clean exit | **Stop** — the runtime gets to write its transcript | | It is doing something actively harmful | **Kill** | | It is spending and you cannot tell yet | **Pause**. It is the only reversible one. | Prefer `stop` to `kill` where you can: a runtime that receives an interrupt usually flushes its session file, and a killed one may not — which means the evidence of what it was doing is exactly what you lose. ## Emergency stop For "everything, now": ```bash curl -s localhost:8900/api/emergency-stop -X POST -d '{}' -H 'content-type: application/json' curl -s localhost:8900/api/emergency-stop/clear -X POST -d '{}' -H 'content-type: application/json' ``` → [Alerts](/docs/dashboard/alerts/)