🪤 Dead Man's Switch
A heartbeat watchdog that fires when you go silent — now a full handler toolkit.
"If I don't check in by tomorrow, the package ships itself."
What is it?
The Dead Man's Switch is the oldest trick in the espionage playbook, turned into a command-line toolkit. You arm it with a TTL (time-to-live). You stamp a heartbeat — a proof of life. If the heartbeat goes stale — if you're taken, you're cut off, or your cron just breaks — the switch escalates and fires its payload.
v0.2.0 grows the prop into the whole apparatus around it: a deterministic engine with a grace/warning phase, a tamper-evident event log, signed heartbeats and cancel tokens, proof-of-life challenges with a covert duress flag, Shamir secret sharing for the disarm key, quorum cancel approval, escalation policies, delivery channels with retry, a contact roster, a scenario simulator, handler reporting, and pre-flight checklists.
A natural fit for:
- Novel research — the scene where the captured hero can't touch the file and the countdown is real.
- Automation safety — if a scheduled task stops reporting, get an alert.
- Personal failsafes — a check-in ritual that escalates when it breaks.
Features
- ⏱️ Heartbeat with configurable TTL and grace/warning phase
- 🔫 Six payload types:
print,webhook,email,command,file,notify - 🧾 Tamper-evident event log (SHA-256 hash chain)
- 🔐 Signed heartbeats & cancel tokens (HMAC, replay-protected)
- 🧠 Proof-of-life challenges with a covert duress answer
- 🗝️ Shamir secret sharing to split the disarm key among trusted parties
- 👥 Quorum cancel — M-of-N approvals before a cancel is honored
- 📈 Escalation policies — remind → alert → release on a schedule
- 📡 Delivery channels with retry queue (file + loopback UDP)
- 🧪 Scenario simulator — replay beat patterns on a deterministic clock
- 📋 Handler reporting — status, timeline, post-mortem, runbook, debrief
- ✅ Pre-flight checklists and config auditing
- 🕯️ Digital legacy planner — staged, gated release of assets
- 📦 Zero runtime dependencies, pure Python standard library
Install
pip install deadman-switch
From source:
git clone https://github.com/AnonymoDGH/deadman-switch
cd deadman-switch
pip install -e .
Quickstart
# 1. Arm it — 60 seconds of silence means fire
dms arm --ttl 60 --payload '{"type": "command", "command": "echo released the files"}'
# 2. Prove you're alive
dms heartbeat
# 3. How much slack is left?
dms status
# [+] Alive. Last beat 3s ago, 57s of slack left.
# 4. Block until the switch fires
dms watch
CLI reference
All commands accept --config <path> to point at a different config file.
| Command | What it does |
|---|---|
dms init |
Create a default config and first heartbeat |
dms arm --ttl <s> --payload <json> |
Set TTL / payload, then beat |
dms heartbeat |
Stamp the heartbeat file |
dms status |
Report age and whether the switch is tripped |
dms watch [--interval <s>] |
Block until the payload fires |
dms disarm |
Neuter the payload (safe mode) |
dms report |
Render a live status report |
dms dry-run |
Show what the payload would do, without doing it |
dms audit |
Audit the config for misconfiguration |
dms plan [--window <s>] [--safety <f>] |
Recommend a beat schedule |
dms runbook [--out <file>] |
Render the handler runbook |
dms checklist [pre-arm|pre-travel|pre-release] |
Show a pre-flight checklist |
dms templates [--apply <name>] |
List or apply switch templates |
dms policy [--ttl <s>] |
Show the default escalation policy |
dms simulate --scenario <regular|silence|missed> |
Run a deterministic scenario |
dms split <secret> -n <N> -k <K> [--out-dir <d>] |
Split a secret into shares |
dms combine <share-files...> |
Reconstruct a secret from shares |
dms beacon --key <k> --switch-id <id> --seq <n> --ts <t> |
Emit a signed liveness beacon |
dms export --format <json|markdown|cheat-sheet> |
Export switch state/history |
Payloads
{ "type": "webhook", "url": "https://example.com/hook", "data": "{\"op\":\"release\"}" }
{ "type": "email", "from": "agent@example.com", "to": "control@example.com",
"subject": "SILENCE", "message": "The package is loose.",
"smtp_host": "smtp.example.com", "smtp_user": "u", "smtp_pass": "p" }
{ "type": "command", "command": "python notify.py --urgent" }
{ "type": "file", "path": "release.txt", "message": "..." }
{ "type": "notify", "label": "trusted-contact" }
The handler toolkit (v0.2.0)
The package is organized as small, testable modules you can compose:
| Module | Purpose |
|---|---|
engine |
Deterministic switch state machine (arm/beat/warn/trip/fire) |
state |
The switch lifecycle FSM |
events |
Tamper-evident hash-chained event log |
clock |
Injectable clocks (FixedClock) for deterministic tests |
store |
Atomic on-disk persistence of state + log |
payloads |
The six payload actions + dry_run |
policy |
Escalation policies (remind/alert/release) |
crypto |
PBKDF2 keys, signed heartbeats & cancel tokens |
proof |
Proof-of-life challenges + duress flag |
duress |
Spoken duress code pairs |
recovery |
Shamir secret sharing for the disarm key |
quorum |
M-of-N cancel approval |
beacon |
Signed outbound liveness beacons + watcher |
heartbeat |
Signed heartbeat records + ledger |
channels |
Delivery channels (file, loopback UDP) + retry queue |
contacts |
Trusted contact roster with clearance + rotation |
dispatcher |
Routes alerts to contacts by escalation level |
simulator |
Deterministic scenario replay |
schedule |
Beat schedule planning + cron hints |
metrics |
Heartbeat regularity (jitter, punctuality) |
watchdog |
Multi-switch fleet manager on a shared clock |
handler |
Mission-control orchestrator for one switch |
audit |
Config security linting |
checklists |
Pre-arm / pre-travel / pre-release checklists |
templates |
Preset switch configurations |
scenarios |
Tabletop threat scenarios for training |
report / runbook / debrief / exporter |
Handler documentation |
escrow |
Encrypted payload escrow released on fire |
legacy |
Staged digital-legacy release planner |
inventory |
Registry of all switches (anti-forgotten-switch) |
rotation |
Key/token rotation scheduling |
journal |
Operator journal attached to beats |
formats / timefmt |
Serialization + human-friendly time |
Example: simulate a silence scenario
dms simulate --scenario silence --ttl 60 --duration 300 \
--beat-interval 30 --silence-from 60
# scenario: silence
# final state: fired
# fired: yes
Example: split the disarm key
dms split "my-disarm-key" -n 3 -k 2 --out-dir ./shares
dms combine ./shares/share-1.txt ./shares/share-3.txt
How it works
Tests
pip install pytest
pytest
The suite is fully deterministic: the engine runs on an injected FixedClock,
network tests use loopback UDP, and there are no external services.
License
MIT — a fiction research prop. Use it on systems you own, and keep the fireworks in the novel where they belong.
Release files for deadman-switch 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| deadman_switch-0.2.0.tar.gz | 97.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| deadman_switch-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 182.0 kB
Release files / deadman_switch-0.2.0.tar.gz
| Download URL | deadman_switch-0.2.0.tar.gz |
|---|---|
| Size | 97.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
b61ad0cab0d9335f2d0ccf772c1631cc934062dce3e4cf394c0a963b90744f74
|
|
BLAKE2b-256 checksum How to use checksums |
2b42bae0bb1a5429365a9b9efa730a5ec4860665b969ef85f7874002adf7b4e8
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.3
|
Release files / deadman_switch-0.2.0-py3-none-any.whl
| Download URL | deadman_switch-0.2.0-py3-none-any.whl |
|---|---|
| Size | 84.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
16197b3a103fbf18f81336aa51ca4c5863cf0248196f93aefcdc6c382e1083d7
|
|
BLAKE2b-256 checksum How to use checksums |
5e842f13277ba96aafb1b7033d559f785c97aa4062c8f8adcfb5774b4bee7164
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.3
|