A small set of battle-tested reliability guardrails for running an agent that uses cron + browser automation without bricking itself or spamming the timeline.
This kit is opinionated:
- One browser driver at a time (global mutex)
- One tab at a time (single-tab policy)
- Fail closed (if you can’t verify a post, it didn’t happen)
- Smoke test before you touch X (snapshots can lie;
actcan wedge)
Brand note: This is the ops layer behind Anti Hunter (@AntiHunter59823). It’s intentionally generic enough to reuse, but it’s written in the style of “ship receipts, don’t hand-wave.”
Prevents cron jobs and ad-hoc manual runs from colliding.
scripts/browser_mutex.py- acquire with backoff
- stale lock takeover
- release
Reduces wrong-tab actions, stale refs, and “tab not found.”
Detects when the browser control channel is unhealthy before you open X.
Clear error classification + recovery ladder so you don’t thrash.
This repo assumes a working directory called $WORKSPACE.
Set these paths for your environment:
- Mutex lock file:
$WORKSPACE/memory/cron_browser_mutex.json - Mutex helper:
$WORKSPACE/scripts/browser_mutex.py
python3 $WORKSPACE/scripts/browser_mutex.py acquire \
--label manual_<task_name> \
--stale-ms 300000python3 $WORKSPACE/scripts/browser_mutex.py acquire \
--label <cron_job_name> \
--backoff 60,120,240 \
--stale-ms 300000If still locked after backoff: SKIP. Don’t touch the browser.
Immediately after acquiring the mutex:
- list tabs
- close all extra page tabs
- run the entire workflow in exactly one page tab
Use this exact sequence:
- Navigate to:
data:text/html,<html><body><textarea aria-label='t'></textarea></body></html>
- Snapshot (refs=aria)
- Click the textarea
- Type:
ok - Evaluate:
textarea.value === "ok"
If the smoke test fails with a true timeout (error contains "timed out after"):
- do your recovery budget (gateway restart max 1, browser stop/start max 1)
- re-run smoke test
- if still failing: STOP (don’t touch X)
Prefer intent composer:
https://x.com/intent/tweet?in_reply_to=<tweetId>
Preflight gate (required):
- fresh snapshot
- visible “Replying to …” context
- textbox contains intended text
- Reply button enabled
Postflight verification (required):
- capture toast “View” URL if present
- open the posted tweet
- DOM verify it links to the parent
/status/<parentTweetId>
If you can’t verify: do not update state.
Do not claim “posted” unless you have:
- a captured tweet URL, and
- (for replies) threading verified.
Drop this at the top of any cron that touches the browser:
MUTEX
- acquire: python3 $WORKSPACE/scripts/browser_mutex.py acquire --label <job> --backoff 60,120,240 --stale-ms 300000
- if locked after backoff: SKIP
- release always: python3 $WORKSPACE/scripts/browser_mutex.py release
SINGLE TAB
- after lock: list tabs; close extra page tabs
SMOKE TEST
- data: textarea click+type+evaluate == "ok"
HARDENING
- browser.act timeoutMs=60000
- true stall signature: "timed out after"
- recovery budget: gateway restart max 1; browser stop/start max 1
- STOP after budget exhausted
FAIL CLOSED
- require toast View URL capture or reliable fallback
- verify threading for replies
- only then update state
- Mutex helper:
scripts/browser_mutex.py - Single-tab + X rules:
playbooks/browser_mutex_single_tab.md - Stall recovery:
playbooks/stall_runbook.md
MIT (recommended). Replace this section if you want a different license.