Two bugs, both found by autopsy of the djsim_phonewall run (2026-07-08): 15 calendar prompts queued, 2 generated, then THIRTEEN consecutive "Timed out — no new asset" at a metronomic 3m30s apart. 45 minutes of the driver politely feeding prompts into a Flow that had stopped generating. 1. NO CIRCUIT BREAKER. Each timeout threw, was reported failed, and the loop moved straight on. When Flow goes quiet it does not spontaneously start again. Now: 3 consecutive failures -> clear isRunning, log a loud system message, leave the queue intact for a hand-resume. (The abuse-flag path already had consecutiveRateLimits; failures had nothing.) 2. done_ids() COUNTED 'ratelimited' AS DONE. handleRateLimit() writes that status with the explicit comment "report the task back as pending" — and the server then binned the task forever. Now excluded. 'failed' is still counted: a timeout may have burned credits invisibly, so nothing retries automatically. requeue.py: the deliberate way to retry. --list / --dry / by id or prefix / --failed. Writes a .bak, never re-runs a success. Used it to make the 13 cal79 prompts pending again. Note for whoever reads this next: the LIVE server + queue live in ~/Library/Application Support/flowrinse/, not this repo. HERE is derived from the script's own dir, so running the repo copy silently serves the stale Jul-6 queue. Copy the script over, run it from there. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|---|---|---|
| banks | ||
| .gitignore | ||
| background.js | ||
| content.js | ||
| flowclient.py | ||
| games.monsterrobot.flowrinse.plist | ||
| install.sh | ||
| launch.sh | ||
| local_server_example.py | ||
| manifest.json | ||
| popup.css | ||
| popup.html | ||
| popup.js | ||
| queue.jsonl | ||
| README.md | ||
| requeue.py | ||
Flow Auto-Pilot
A Brave extension + local queue that drains a prompt bank through Google Labs Flow (Nano Banana 2 images, Veo videos) on the webui-only credits you can't reach via API. The extension types prompts into the Flow agent box with trusted CDP input (Flow ignores synthetic DOM events), waits for the media grid to grow, harvests the new asset URLs, and downloads them with the page's session cookies.
Not headless: Brave must be running and logged into the Flow account. But once the tab is open with Auto-start ticked, it runs unattended.
Parts
| File | Role |
|---|---|
manifest.json, background.js, content.js, popup.* |
the Brave MV3 extension |
local_server_example.py |
queue server on :8017 — queue.jsonl in, results.jsonl out |
queue.jsonl |
the prompt bank (one task per line) |
flowclient.py |
enqueue() / wait_for() so a game project can request assets |
launch.sh |
start server + keep Mac awake + open/focus one Flow tab |
install.sh + games.monsterrobot.flowrinse.plist |
self-healing launchd agent |
Run it by hand
./launch.sh https://labs.google/fx/tools/flow/project/<PROJECT_ID>
Server comes up (under caffeinate), Brave focuses the Flow tab, and with
Auto-start ticked the rinse begins. Files land in
~/Downloads/flowrinse/<category>/.
Run it unattended (launchd)
./install.sh
Fires launch.sh at login and every 10 min. Because launch.sh is idempotent
(port check + tab reuse), the repeat runs are no-ops that self-heal a dead
server or a closed tab.
macOS TCC gotcha (same as the vault-backup job): launchd can't execute
scripts inside ~/Documents, so install.sh runs a copy at
~/Library/Application Support/flowrinse/. That copy owns the live
queue.jsonl / results.jsonl / downloads/ once the agent is running.
Re-run ./install.sh after editing launch.sh or local_server_example.py
to resync the copy. First run pops one Automation prompt (allow control of
Brave) — click Allow on the rig's screen.
launchctl kickstart -k gui/$(id -u)/games.monsterrobot.flowrinse # run now
launchctl bootout gui/$(id -u)/games.monsterrobot.flowrinse # stop it
Enqueue from another project
from flowclient import enqueue
enqueue("Sierra EGA record-store back room, 160x168, 16-color",
kind="image", category="morp2_bg")
Or over the wire: POST http://localhost:8017/enqueue with
{"prompt","kind","model","category","dest"}.