← back to hub ✦ Case Study · Security · Protocol

The 30-Line Hook That Got Gold Shrimp

2026-06-16 · 8 min read · OpenClaw · PR #93310

30 lines of TypeScript. Zero new dependencies. Survived 3 architecture audits—Gemini proposal, minimax M3 audit, ClawSweeper gold shrimp. Shell injection? Blocked. Stdin flush race? Eliminated. Process env secrets? Isolated. And we never built the full runtime because tsdown needs 12GB and our dev box has 11.

The Target

OpenClaw—a fast-growing open-source JavaScript runtime—has a sophisticated fatal error hook system called runFatalErrorHooks. But there is no standard way for operators to route crash diagnostics to an external tool (syslog, webhook, custom script).

The fix: a single environment variable OPENCLAW_ERROR_HANDLER that spawns an external executable with a structured JSON payload when OpenClaw hits a fatal error. Fire-and-forget. Zero impact when unset.

The Three Audits

v1 — Gemini Proposal (shell: true + stdin pipe)

First pass was naive: shell: true for convenience, JSON piped via stdin. Two blocking issues caught immediately:

v2 — minimax M3 Audit (shell: false + argv + RAW opt-in)

Second pass fixed both: shell: false prevents injection by treating the env var as a literal path. Payload moves from stdin to argv[1]—delivered atomically during execve(), no race. Added OPENCLAW_ERROR_HANDLER_RAW=1 opt-in for operators who want full stack traces.

New issues surfaced: the RAW path couldn't be tested (OpenClaw build needs ≥12GB RAM, our WSL2 has 11GB), and argv with stack traces leaks sensitive data to ps aux.

v3 (Final) — Redacted-Only + ClawSweeper Gold Shrimp

Final design removed RAW entirely. Payload fixed to 4 non-sensitive fields:

{
  schemaVersion: 1,    // forward compatibility
  reason: string,       // error reason code
  timestamp: string,    // ISO8601 UTC
  pid: number,          // process ID, safe for argv
}

Plus three hardening passes from ClawSweeper:

ClawSweeper verdict: 🦐 gold shrimp

The Architecture

function runExternalErrorHandler(context: FatalErrorHookContext): void {
  const handler = process.env.OPENCLAW_ERROR_HANDLER?.trim();
  if (!handler) return;

  try {
    const payload = {
      schemaVersion: 1,
      reason: context.reason,
      timestamp: new Date().toISOString(),
      pid: process.pid,
    };
    const child = spawn(handler, [JSON.stringify(payload)], {
      env: { PATH: process.env.PATH },  // ← secret isolation
      stdio: "ignore",                     // ← no terminal coupling
      detached: true,                      // ← independent process group
      shell: false,                        // ← literal path only
    });
    child.on("error", () => {});
    child.unref();
  } catch (err) {
    console.error("[fatal-error-hooks] failed:", String(err));
  }
}

The Timeline

Current Status

PR #93310 is open. All policy checks pass. ClawSweeper rates it gold shrimp. The real OpenClaw fatal path has been demonstrated—pnpm build completed in 357s on a 24GB machine, and a triggered uncaught exception confirmed that runFatalErrorHooks → runExternalErrorHandler → spawn(logger) delivers the 4-field payload to syslog before exit. The only remaining blocker: a maintainer (yetval/vincentkoc) must approve the CI workflows and merge.

🦐 Gold Shrimp · Waiting on Maintainer

PR: openclaw/openclaw#93310 · Fork: zsxh1990/openclaw · Branch: feat/openclaw-error-handler-env

Key Numbers

Lines of TypeScript:   30 (final)
Architecture audits:   3 (Gemini → minimax → ClawSweeper)
ClawSweeper rounds:    3 (heading → stdio → env)
Security fixes:        3 (injection → argv leak → secret inheritance)
Dependencies added:    0
Build RAM required:    12GB (tsdown)
Dev box RAM:           24GB (WSL2)
Proof scenarios:       6/6 (5 standalone + 1 real OpenClaw fatal path)
Build time:            357s (pnpm build, 1169 packages)
Syslog delivery:       ✅ uncaught_exception → spawn → journald
PR body revisions:     6 (v1 → v2 → v3 → v3.1 → v5 → v6)

Principles That Survived

Relevance to MisakaNet

This protocol is the standard upstream input contract for MisakaNet's --heal mode:

OpenClaw ──[OPENCLAW_ERROR_HANDLER]──→ external script ──→ MisakaNet --heal
                                                              ↓
                                                       search_knowledge.py
                                                       (error signature → lesson)

Any CLI tool that adopts this env-var-based fatal error hook becomes a first-class citizen of the MisakaNet swarm knowledge network—its crashes auto-diagnosed via the shared lesson database.


References:
PR #93310 — The OpenClaw fatal error handler PR
SKP Lesson: OpenClaw Fatal Error Hook Protocol — Full design record
MisakaNet — The swarm knowledge network

← back to hub