Four CLI flows. All use direct HTTP over curl-impersonate (cuimp); the claude.ai and Gemini flows replay session cookies copied from the playwriter-connected browser:
research.js— fire a single Haiku prompt at claude.ai and stream the answer.research-from-repo.js— ingest one or more GitHub repos via gitingest.com and feed the combined digest into fable (rewrite.js's concise, no-tools completion mode).gemini-image.js— generate an image on gemini.google.com over cuimp and save it as PNG.gemini-transcribe.js— transcribe an audio file through the Gemini API over cuimp.
- Bun or Node.js ≥18
- Chrome with the playwriter extension active, and the
playwriterCLI on PATH (npm i -g playwriter). - Signed in to the relevant site in that Chrome:
claude.aifor the first and second flows, andgemini.google.comwhen refreshing Gemini cookies (only needed once;GEMINI_COOKIEavoids the browser entirely).
bun refresh-auth.js # capture claude.ai cookies → creds.json
bun research.js "research all improvements for github.com/AnEntrypoint/gm"
bun retrieve.js --last-run # full transcript of the last run
bun retrieve.js --latest | bun retrieve.js <conv-uuid> | bun retrieve.js --list 20Optional env:
CLAUDE_MODEL— defaultclaude-haiku-4-5-20251001THINK_BUDGET— extended thinking tokens, default10000(set0to disable)
Re-run bun refresh-auth.js whenever you see 401/403.
Ingests one or more repos through gitingest.com (same fetch logic as gitingest-batch.mjs, shared via gitingest-lib.mjs) and sends the combined digest straight into fable — rewrite.js's concise + thinking, no-tools completion mode — instead of a manual --file prompt.
bun research-from-repo.js https://github.com/octocat/Hello-World
bun research-from-repo.js https://github.com/octocat/Hello-World https://github.com/octocat/Spoon-Knife --prompt "Compare these two repos"
bun research-from-repo.js https://github.com/octocat/Hello-World --file instructions.txtgitingest-batch.mjs still works standalone (node gitingest-batch.mjs [-o combined.md] <repo-url> ...) for saving raw digests to disk without invoking fable.
Direct HTTP over curl-impersonate (cuimp) — the browser is only needed once, to capture the session cookies:
bun refresh-gemini-auth.js # capture gemini.google.com cookies → gemini-creds.json
bun gemini-image.js "an oil painting of a frog astronaut"
bun gemini-image.js "a cyberpunk city" -o city.png
bun gemini-image.js --check # verify the stored sessionAtomic CLI — prints the absolute output path on stdout (status goes to stderr), so it pipes:
IMG=$(bun gemini-image.js "a red sports car")
open "$IMG"Set GEMINI_COOKIE to skip both the browser and the creds file (e.g. in CI):
GEMINI_COOKIE='__Secure-1PSID=...; __Secure-1PSIDTS=...' bun gemini-image.js "a red sports car"Re-run refresh-gemini-auth.js when the CLI reports stale cookies. Options: --creds <file>, --browser-version <v> (default 145), --curl-impersonate <path>, --proxy <url>, --timeout <ms>, --debug.
The HTTP logic lives in gemini-client.mjs; gemini-client.test.mjs covers frame parsing, image extraction and the full request→download pipeline. gemini-browser.mjs is used only by refresh-gemini-auth.js, to capture cookies; every Gemini request then goes through cuimp.
bun gemini-transcribe.js talk.mp3 -o talk.txt # API key from gemini-creds.json, uploaded over cuimpcreds.json (claude.ai session cookies) and gemini-creds.json (Gemini web session cookies for gemini-image.js, and optionally the API key for gemini-transcribe.js) are gitignored. Never commit them.