CClawMetryDocs

Guard & governance

Pause, stop, kill#

Four controls, one actuator, and an honest answer per session about whether each one can work.

What each does#

ControlPOSIXWindows
PauseSIGSTOPNtSuspendProcess
ResumeSIGCONTNtResumeProcess
StopSIGINT — the equivalent of Ctrl-CConsole Ctrl+C from a detached helper
KillSIGTERM, escalating to SIGKILL across the treetaskkill /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_<session_id>, and that file is enforced only by the enforcement 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/<agent_key>/pause  -X POST -d '{}' -H 'content-type: application/json'
curl -s localhost:8900/api/agents/<agent_key>/resume -X POST -d '{}' -H 'content-type: application/json'
curl -s localhost:8900/api/agents/<agent_key>/stop   -X POST -d '{}' -H 'content-type: application/json'

Choosing between them#

SituationControl
It is looping but the work is salvageablePause, look at the transcript, then resume or stop
It is going nowhere and you want a clean exitStop — the runtime gets to write its transcript
It is doing something actively harmfulKill
It is spending and you cannot tell yetPause. 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

Cookie preferences