Skip to content

Instantly share code, notes, and snippets.

@geoffreywoo
Last active February 10, 2026 12:23
Show Gist options
  • Select an option

  • Save geoffreywoo/cc5f72e6a6645db5159f03305ddd5dc3 to your computer and use it in GitHub Desktop.

Select an option

Save geoffreywoo/cc5f72e6a6645db5159f03305ddd5dc3 to your computer and use it in GitHub Desktop.
OpenClaw Skill: Browser Mutex + Single-Tab Guardrails for Reliable X Automation

OpenClaw Browser Mutex + Single‑Tab Protocol (Skill‑Ready)

This is a battle‑tested protocol for running browser automation in OpenClaw without collisions between cron jobs and ad‑hoc/manual runs.

If you run X automation (mentions/search/posting), you will get:

  • wrong-tab actions
  • stale refs
  • “tab not found”
  • ghost posts (no toast)
  • accidental standalone posts instead of replies

This protocol reduces all of that.


Design Goals

  1. Single writer: only one process may drive the managed browser at a time.
  2. Single tab: one page tab only (compose + verify + navigate back). Extra tabs are risk.
  3. Thread‑safe replies: never free‑post when intent is reply; require machine verification.
  4. Backoff + skip: if busy, wait briefly then skip, rather than interleave.

Canonical Mutex (Shared Lock File)

Use a shared lock file (JSON) that all browser users (cron + manual) respect.

Lock file (example):

  • /Users/gwbox/.openclaw/workspace/memory/cron_browser_mutex.json

Lock format

{ "label": "x_mentions_hourly", "startedAtMs": 1730000000000 }

Acquire / Release (Manual / Ad‑Hoc)

Acquire

python3 - <<'PY'
import json, time
LOCK='/Users/gwbox/.openclaw/workspace/memory/cron_browser_mutex.json'
json.dump({'label':'manual_<task_name>','startedAtMs':int(time.time()*1000)}, open(LOCK,'w'))
print('LOCK_OK')
PY

Release (always)

rm -f /Users/gwbox/.openclaw/workspace/memory/cron_browser_mutex.json

Rule: If you can’t hold the mutex for the entire run, don’t start the run.


Acquire Strategy (Cron)

Backoff policy

If mutex is held by another process:

  • wait 60s, retry
  • wait 120s, retry
  • wait 240s, retry
  • if still held: SKIP this run (don’t touch the browser)

Stale lock takeover

If lock is older than 5 minutes:

  • treat as stuck
  • restart the managed browser once
  • take the lock

Single‑Tab Workflow (Critical)

Immediately after acquiring the mutex:

  1. List tabs
  2. Close extra page tabs, keep one
  3. Use that one tab for:
    • composer
    • submit
    • toast View
    • verification
    • navigate back

Why: a lot of OpenClaw browser flake comes from targetId drift when multiple tabs exist.


Thread‑Safe Reply Invariant (X)

Composer URL

Prefer:

  • https://x.com/intent/tweet?in_reply_to=<tweetId>

Preflight gate (mandatory)

Before clicking Reply:

  • fresh snapshot
  • confirm “Replying to …” context exists
  • confirm the primary button says Reply and is enabled
  • confirm textbox contains intended text

Postflight verification (mandatory)

After clicking Reply:

  • require toast with View link
  • open View
  • machine‑verify threading:
    • DOM contains any a[href*="/status/<parentTweetId>"]

If verification fails:

  • do not log state
  • restart browser once and retry once
  • otherwise stop (avoid standalone spam)

Error Handling (Stop Rules)

  • stale ref / unknown ref: page changed → take a fresh snapshot, re‑select refs
  • browser control timeout: restart browser once
  • 3 consecutive failures on same goal: stop

Do not brute force. Thrash creates wrong posts.


Recommended Skill/Payload Template

Drop these blocks at the top of any cron payload that uses the browser:

  • MUTEX WAIT / BACKOFF
  • SINGLE‑TAB GUARD
  • THREAD‑SAFE REPLY WORKFLOW

And make your workflows “read/write split”: collect targets first, then post.


Minimal Code Snippets

(A) Check lock age (cron)

import json, time
LOCK='.../cron_browser_mutex.json'
now=int(time.time()*1000)
try:
  st=json.load(open(LOCK))
  age=now-int(st.get('startedAtMs',0))
  if age < 300000:
    # locked and fresh
    exit(3)
except FileNotFoundError:
  pass

(B) Close extra tabs (conceptual)

Use OpenClaw browser tooling to list tabs and close all but one page tab.


Why This Works

Most automation failures aren’t “selectors” — they’re concurrency + state drift. The mutex + single‑tab policy turns a flaky system into a mostly deterministic one.


If you adopt this protocol, you’ll ship more replies with fewer disasters.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment