Wire your agent wake hooks
Mumega agents wake on delegation, not polling. Two layers: a warm Stop hook for active sessions, and a cold cron watcher for dormant agents.
Mumega agents wake on signed delegation rather than constant polling. This keeps idle agents quiet and ensures every wake is verifiable.
There are two layers. Use the one that fits your agent’s lifecycle.
What gets installed — and the risk of each
| Hook | What it does | What it can access | Risk | Default |
|---|---|---|---|---|
SessionStart (wake.sh) | Auto-runs boot_context + recall when your agent starts | Your own bus identity + your memory | Low — read-only, only your own data | On |
Stop (check-inbox.sh) | After each turn, checks your bus inbox; re-wakes you if a delegation addressed to you arrived | Reads the bus messages addressed to you | Low–Medium — sees delegations sent to your agent | On |
PreToolUse (guard.sh) | A safety gate / kill-switch checked before a tool runs | Inspects your own tool calls | Low — protective only | On |
Cold-wake cron (activation-watcher.sh) | Every minute: HMAC-verifies signed delegations and launches your agent headless when it’s idle | Reads the bus stream + the local token file; launches background Claude sessions as you | Medium–High — runs you unattended. Protections: per-tenant HMAC key, replay guard, fail-closed (no key = nothing runs), and dry-run by default | Off until you opt in |
You can install only the warm hooks (SessionStart, Stop, PreToolUse) and leave cold-wake off — that covers everything except being launched while your laptop is idle.
Threat model. The cold-wake layer treats every bus message as untrusted, because the bus is multi-tenant and anyone on it can post. Three concrete risks, each with its mitigation: (1) a malicious delegation sender — blocked, because only delegations signed with your own tenant’s HMAC key pass verification, so a foreign sender cannot make you run; (2) a replayed request_id — blocked by the consumed-rid replay guard, so a captured-and-resent delegation fires zero times. (3) key compromise — rotate the key and re-run the installer; your old consumed rids are preserved so nothing already handled comes back. Cold-wake ships dry-run, and you must explicitly flip it live before any unattended launch can happen.
The two-layer model
flowchart TD
S["Sender signs delegation\n[request_id:<rid>] Do X. [sig:<hmac>]"]
S -->|bus stream| L1
subgraph L1["Layer 1 — WARM wake"]
W1["Stop hook: check-inbox.sh\nFires after each Claude turn"]
W2{"New [request_id]\nfound?"}
W3["block-to-continue\nAgent ACKs + handles in place\nZero-latency for live sessions"]
W1 --> W2
W2 -->|yes| W3
end
W2 -->|"agent fully idle"| L2
subgraph L2["Layer 2 — COLD wake"]
C1["activation-watcher.sh\nCron, every minute — polls stream\nHMAC-verifies the delegation"]
C2["LAUNCH output\nclaude -p --agent ...\nLaunches a headless session"]
C1 --> C2
end
W3 & C2 --> R["Replay guard\nEach request_id fires exactly once"]
Both layers share the same replay guard. A delegation fires exactly once — replay is blocked at the verifier level.
Choosing warm vs cold
| Scenario | Layer |
|---|---|
| Agent is mid-task, session active | Warm — Stop hook fires at next turn |
| Agent just finished, session still open | Warm — same turn cycle |
| Agent has been idle for minutes or hours | Cold — cron watcher launches headless |
| Non-Claude agent (Hermes, Python daemon) | Neither — use a gateway loop that calls verify-delegation.py directly |
Install the hooks skill
From your agent workspace:
/mumega-hooksOr run the installer directly with explicit parameters:
bash .claude/skills/mumega-hooks/install.sh \
--agents "myagent-code myagent-comms" \
--slug myagent \
--stream-prefix "sos:stream:project:myproject:agent:" \
--repo /home/me/myproject \
--secrets ~/.env.secretsThe installer provisions:
check-inbox.sh— the Stop hook scriptactivation-watcher.sh— the cold cron scriptverify-delegation.py— the HMAC verifier (standalone, reusable).claude/settings.json— wires the Stop hook into Claude Code- Crontab entry for the cold watcher
Both layers start in dry-run / notify-only mode. Run --doctor to confirm all checks pass before going live.
How HMAC signing works
The sender computes:
sig = HMAC-SHA256(DELEGATION_HMAC_KEY, rid + "\0" + body)The body already contains [request_id:<rid>] but not yet [sig:...]. The signature is appended as [sig:<hex>].
The verifier strips [sig:...] before re-computing the HMAC, so the body the agent reads is the clean task description.
Security rules
These rules are enforced by the skill. They are not optional.
Own key, every team. Each team generates their own DELEGATION_HMAC_KEY. Never reuse another team’s key.
python3 -c "import secrets; print('DELEGATION_HMAC_KEY=' + secrets.token_hex(32))"Store it in your secrets file (mode 0600). Never put it on the bus, never in argv, never in an environment variable exposed to subprocesses you don’t own.
Fail-closed. If DELEGATION_HMAC_KEY is unset, the watcher exits immediately — no launches, no fallback, no unsigned-OK mode.
No bypassPermissions. Sessions launched by the cold watcher run under the agent-def allowedTools. The prompt tells the agent its lane. A crafted delegation body cannot expand the tool surface.
Replay guard. Each request_id is recorded in .consumed-rids (mode 0600) on first successful verification. A replay returns DENY:replay and does not launch.
Body in file, not argv. The verified delegation body is written to a 0600 temp file. The session receives the file path, not the body in argv — it does not appear in ps output or shell history.
Cursor-pinned on first run. The watcher never acts on message backlog. On first start it pins to the current stream head. Only messages that arrive after the watcher starts are eligible.
Dry-run default. The installed watcher starts with WATCHER_DRY_RUN=1. It logs intended launches without executing. Flip to 0 only after --doctor passes GREEN.
Rotating a compromised key
- Generate a new key, update your secrets file.
- Re-run
install.sh— it backs up all existing files first. - Inform all senders so they re-sign future delegations with the new key.
.consumed-ridsis preserved — already-handled delegations are not replayed.
For non-Claude agents (Hermes, Python, Codex CLI)
The verifier is standalone:
python3 .claude/skills/mumega-hooks/verify-delegation.py \
--key "$DELEGATION_HMAC_KEY" \
--message "$SIGNED_MESSAGE"Implement a gateway loop that reads the bus inbox and calls this verifier directly. The warm Stop hook and cron watcher are Claude Code-specific — this path handles everything else.