Quick Start
1
Default — no config, behaviour unchanged
A gateway with no
control block defaults to backend: "off", a no-op brake that is byte-for-byte today’s behaviour.2
Enable the durable file brake
Selecting
backend: "file" instantiates a durable sentinel that survives a restart and is shared across replicas that point at the same path.3
Or configure it in gateway.yaml
4
Drive the brake from Python (works today)
Engage, inspect, and release the durable brake directly — the sentinel behaviour is available today.
How It Works
The operator engages one durable sentinel; every admission seam consults it to refuse new work, while runs already in flight are untouched and finish normally.engage and disengage are idempotent — engaging twice or disengaging a missing sentinel is safe.
Fail-Safe Behaviour
An ambiguous brake holds new work rather than letting it run freely: any sentinel that cannot be read with confidence counts as engaged.Configuration Options
EmergencyStopConfig from praisonaiagents.gateway.
Properties and methods:
enabled→bool—Truewhenbackend != "off".to_estop()→ the concrete brake (NullEmergencyStopfor"off",FileEmergencyStop(path)for"file").to_dict()/from_dict()— YAML/JSON roundtrip;from_dict(None)tolerates a missing block.
GatewayConfig as control and surfaces in GatewayConfig.to_dict() as {"control": {"backend": "off", "path": None}} when defaults hold.
Full field, type, and default reference for
EmergencyStopConfig, EmergencyStopProtocol, NullEmergencyStop, FileEmergencyStop, and EmergencyStopStateWhen to Enable
Match the backend to whether an on-call operator needs an instant, durable hold.Backward Compatibility
off is the default and reproduces today’s behaviour byte-for-byte — no brake is engaged, is_engaged() is always False, and no new dependency is added.
Roadmap (what this ships vs. what comes next)
Kept intentionally minimal per the lightweight-and-powerful mandate: this PR ships the shared core contract + fail-safe policy + config selector only. The heavy bot-side wiring (WS inbound, kanban dispatch, scheduler seams) and the
praisonai gateway pause/resume CLI belong in the wrapper/bot packages and are a natural follow-up that consumes this contract.off/file selector, and the audit-safe state snapshot. Selecting backend: "file" instantiates the durable brake and wires it into GatewayConfig.control; you can already engage it and inspect state() from Python. Consultation at the WebSocket inbound, kanban dispatch, and scheduler seams — plus a praisonai gateway pause/resume CLI — is follow-up work in the bot/wrapper packages.
Best Practices
Always pass reason and actor when engaging
Always pass reason and actor when engaging
engage(reason="cost spike", actor="mervin") records who paused and why in the sentinel, surfaced by state() for /health and audit. An unlabelled hold is hard to explain later.Trust the fail-safe, but alert on it
Trust the fail-safe, but alert on it
An unreadable or corrupt sentinel counts as engaged on purpose — new work stays held. Treat
state().reason == "unreadable-sentinel" as a signal to inspect the file, not as a normal engaged state.Leave it off unless an operator needs the brake
Leave it off unless an operator needs the brake
Single-node dev and deployments without on-call control gain nothing from a durable sentinel. Keep
backend: "off" there for zero cost and unchanged behaviour.Related
Gateway Turn Lock
Serialise turns cluster-wide.
Gateway Admission Control
Concurrency ceiling & backpressure.
Gateway Graceful Drain
Drain toward shutdown — orthogonal to the brake.
Gateway Channel Supervision
Per-channel pause vs. this fleet-wide brake.

