Skip to main content

Unofficial CLI for Google Flow — drive Veo image-to-video generations from the terminal.

Project description

gflow-cli

Unofficial, reverse-engineered Python CLI for Google Flow. Drive Google Flow Veo image-to-video generations from your terminal — without the browser.

CI Release PyPI version Python versions License: MIT Status: alpha Code style: ruff Type checked: pyright Tests: TDD

⚠️ Not affiliated with Google. Reverse-engineered from public Flow web traffic. Endpoints can change at any time. See full DISCLAIMER before use.

📚 Docs: INDEX · Architecture · Authentication · Configuration · Usage · Security · Known issues · Plan · Changelog 🤖 For AI agents: CLAUDE.md · .claude/


Objective

For Google AI Ultra and Pro subscribers who have Flow credits and want to use them efficiently.

Your subscription includes a generous Veo credit allowance, but the Flow web UI was designed for hand-crafted, one-at-a-time video creation — not for the batch workflows that actually justify burning through hundreds of credits a month. The UI is slow (waiting for the React app, dragging assets, clicking through dialogs), the DOM is fragile to automate, and there's no way to script "generate these 50 clips while I'm at lunch."

gflow-cli reverse-engineers Flow's internal REST API on aisandbox-pa.googleapis.com and exposes it as a clean command-line tool. Same Veo model, same quality, same Ultra/Pro billing — without ever opening a browser (after a one-time auth capture).

Now you can:

  • Burn credits efficientlyfor img in ./inputs/*.png; do gflow i2v "$img" "$prompt" -o "out/$(basename "$img" .png).mp4"; done
  • Build pipelines — wire Veo into your AI video production stack, content automation, or batch experiments
  • Stay in the terminal — no Chromium, no waiting for the UI to load, no clicking through 4 dialogs per clip
  • Parallelise — drive multiple accounts side-by-side with --profile (planned v0.4)

This project is the same pattern as edge-tts — an unofficial Python client over Microsoft's Azure TTS service used by the Edge browser.


Disclaimer

gflow-cli is not affiliated with, endorsed by, or sponsored by Google. It calls a private API surface (aisandbox-pa.googleapis.com) that Google can change or restrict at any time. By using this tool you accept that:

  • You must already have a valid Google AI Ultra or Pro subscription with Flow access.
  • All generations bill against your own Google account, subject to Google's terms.
  • Endpoints, request shapes, and auth flows may break without notice.
  • The maintainer will respond promptly to any takedown request from Google.

Read the full DISCLAIMER before deploying this in any production setting.


Project status

v0.3.0a1 — alpha. Video (T2V/I2V/batch) and image (T2I/I2I/upload) commands are functional end-to-end against a live Google AI Ultra/Pro Flow account.

Milestone Status
Repo scaffold, CI, license, README, disclaimer ✅ done
Auth login flow (one-time browser capture) ✅ done
Video: t2v / i2v / batch (Veo 3.1) ✅ done (v0.2.0a1)
Image generation (T2I/I2I, 1–4 per call, 5 ratios, 3 models) ✅ done (v0.3.0a1)
End-to-end smoke test against live Flow ✅ done
First public alpha release on PyPI ✅ done (v0.2.0a1)
Provider abstraction for official Veo 3.1 API ⏳ planned
Concurrency / per-account pool ⏳ planned (v0.4)

Prerequisites

Requirement Why
Python 3.11+ Modern type hints, asyncio improvements
uv ≥ 0.4 Dependency + virtualenv management; also enables uvx runs
Playwright Chromium Used once for auth login and as the HTTP transport (cookie jar). No UI automation.
Google AI Ultra or Pro account with Flow access Otherwise the API returns 403. Try in labs.google/fx/tools/flow first.
~500 MB disk Chromium browser + Python deps

Tested on Windows 11 + macOS 14 + Ubuntu 24.04. Linux + WSL work but auth login needs a display server (X / Wayland) for the one-time browser capture; a saved profile transfers freely between machines.


Install

Try it without installing (zero-config, recommended for first run)

uvx --from gflow-cli gflow --help

uvx (from uv) downloads and runs the package in a throwaway environment. No global install, no virtualenv to manage. Perfect for occasional batch runs or trying it before committing.

Install as a user tool

uv tool install gflow-cli
gflow --help

This installs gflow (and flow if no conflict) on your PATH system-wide, isolated from your project venvs. Update with uv tool upgrade gflow-cli.

From source (current — pre-release)

git clone git@github.com:ffroliva/gflow-cli.git
cd gflow-cli
uv sync                          # creates .venv, installs runtime + dev deps
uv run playwright install chromium   # one-time browser download (~150 MB)
uv run gflow --help

Install Playwright Chromium (one-time, any install method)

uvx --from gflow-cli playwright install chromium
# or after `uv tool install`:
uv tool run --from gflow-cli playwright install chromium

Quick start

# 1. Sign in once — opens a Chromium window, persists session locally
gflow auth login

# 2. Verify
gflow auth status

# 3a. Generate an image from a text prompt (lands at $FLOW_CLI_OUTPUT_DIR/images/<date>/)
gflow image t2i "a hot air balloon over Tokyo at sunrise"

# 3b. Generate a clip end-to-end
gflow video i2v ./input.png "Slow cinematic push-in, soft golden light" -o out.mp4

The image lands at $FLOW_CLI_OUTPUT_DIR/images/<YYYY-MM-DD>/<media_name>_1.png (defaults to ./out/ when the env var is unset). See docs/USAGE.md § gflow image t2i for --model, --aspect, -n/--count, --seed, and --out flags.

Same call from Python:

import asyncio
from pathlib import Path
from flow_cli.api.client import FlowApiClient
from flow_cli.paths import profile_dir

async def make_clip() -> None:
    async with FlowApiClient(profile_dir=profile_dir("default")) as client:
        project = await client.create_project(title="gflow-cli demo")
        asset = await client.upload_image(Path("input.png"), project.project_id)
        op = await client.generate_video(
            project_id=project.project_id,
            prompt="Slow cinematic push-in, soft golden light",
            start_asset=asset,
            aspect="9:16",
        )
        # Poll op.workflow_id with client.poll_video_status(...)
        # then client.download_video(...) to disk.

asyncio.run(make_clip())

Commands

gflow auth login                                         # one-time browser sign-in
gflow auth status                                        # show current session

gflow image upload <path>                                # upload PNG/JPEG → asset UUID
gflow image t2i "<prompt>" [--model] [--aspect] [-n]     # text-to-image (1–4 per call)
gflow image i2i "<prompt>" --ref PATH_OR_UUID [...]      # image-to-image (1–4 per call)

gflow video t2v "<prompt>" -o out.mp4                    # text-to-video (Veo 3.1)
gflow video i2v <image> "<prompt>" -o out.mp4            # image-to-video (Veo 3.1)
gflow video batch <manifest.tsv>                         # TSV-driven batch

Each command supports --profile <name> for managing multiple Google accounts side-by-side.


Stack

Layer Tech Why
Package + deps uv + hatchling Fast install, lockfile, builds wheels
CLI framework click Mature, declarative, composable subcommands
Console UI rich Pretty progress bars, colour, tables
HTTP transport playwright (page.request) Auto-attaches Google session cookies — no OAuth scraping
Async stdlib asyncio Concurrency primitive for parallel generations
Type checking pyright (strict on src/flow_cli) Catches errors before runtime
Linting / format ruff Single tool, fast
Testing pytest + pytest-asyncio Standard, async-aware
CI/CD GitHub Actions Free, matrix builds, OIDC trusted publishing

No FastAPI, no Django, no SQLAlchemy. This is a CLI + library — keeping the runtime surface tight and uvx-friendly.


Architecture

┌─────────────────┐
│  gflow CLI      │ ← Click + Rich
└────────┬────────┘
         │
┌────────▼────────┐
│  Provider       │ ← protocol (Provider in flow_cli/providers/base.py)
│  abstraction    │
└────────┬────────┘
         │
   ┌─────┴─────┬───────────────┐
   │           │               │
┌──▼──┐    ┌────────┐       ┌───────┐
│Flow │    │Official│       │ Mock  │
│(now)│    │ Veo    │       │(tests)│
│     │    │(planned│       │       │
│     │    │ post-  │       │       │
│     │    │ v0.3)  │       │       │
└──┬──┘    └────────┘       └───────┘
   │
   │   POST /v1/flow/uploadImage
   │   POST /v1/video:batchAsyncGenerateVideoText
   │   POST /v1/video:batchCheckAsyncVideoGenerationStatus
   │   PATCH /v1/flowWorkflows/{id}
   ▼
aisandbox-pa.googleapis.com  (Google's private Flow API)

The Provider interface keeps backends interchangeable. v0.1 ships FlowProvider. v0.3+ will add OfficialVeoProvider (uses googleapis/python-genai against generativelanguage.googleapis.com) — same code path, swap with --provider official.

Auth strategy

gflow-cli doesn't reverse-engineer Google's OAuth flow. Instead it piggybacks on Playwright's persistent context: gflow auth login opens a Chromium window, you sign in normally, and the resulting cookie jar is saved to a per-OS user-data dir via platformdirs:

  • Windows: %LOCALAPPDATA%\gflow-cli\profile_default\
  • macOS: ~/Library/Application Support/gflow-cli/profile_default/
  • Linux: ~/.local/share/gflow-cli/profile_default/

Subsequent commands launch a headless Playwright context using that profile and call REST endpoints via Playwright's HTTP client — which auto-attaches the cookies. No tokens to refresh manually, no SSO scraping. Auth is the only browser interaction, and it's a one-time event.


Use as a Claude Code (or other agent) skill

gflow-cli ships an installable Claude Code Skill at skills/gflow-cli/SKILL.md.

Install for Claude Code:

# Clone the repo, then symlink the skill into your Claude skills dir:
ln -s "$(pwd)/skills/gflow-cli" ~/.claude/skills/gflow-cli

Use in any other agent (Cursor, Codex, Gemini CLI, Aider, ...): the SKILL.md is plain Markdown — point your agent's context at it as a reference doc. The CLI is the same regardless of caller.

When the skill is loaded, an agent sees:

  • When to invoke gflow-cli (the user wants to generate a Veo video, has Flow access, etc.)
  • The full command surface
  • How to handle auth (kick off gflow auth login once, then headless)
  • Common error modes and fixes

Development & TDD workflow

gflow-cli is test-driven. Every public function in Provider implementations starts as a red test that locks the contract before any production code is written. CI rejects any PR that lowers test coverage.

# Setup
uv sync --extra dev
uv run playwright install chromium

# Quality checks (CI runs all three)
uv run ruff check src tests
uv run ruff format --check src tests
uv run pyright src

# Tests
uv run pytest -q                    # all tests
uv run pytest -q --cov=flow_cli     # with coverage
uv run pytest tests/test_providers.py -q   # one file
uv run pytest -k "i2v" -q                  # by keyword

TDD discipline

  1. Red — write a failing test that captures the new behaviour.
  2. Green — write the minimum production code to make it pass.
  3. Refactor — clean up, keep tests green.
  4. Commit — small, atomic, with a descriptive message.

Each Provider method has a corresponding test file under tests/. New routes start as pytest.raises(NotImplementedError) markers, then move to behavioural tests with mocked HTTP, then to live integration tests behind a @pytest.mark.live opt-in. See CONTRIBUTING.md for full workflow.


Releases

gflow-cli follows Semantic Versioning 2.0.0 — breaking changes bump MAJOR, new features bump MINOR, fixes bump PATCH.

Cadence

  • Alpha (0.x.y): rapid iteration. APIs may change between minor versions.
  • 1.0.0: stable surface. Breaking changes require MAJOR bump and migration notes.
  • Patch releases ship as needed for bug fixes.

How releases work

  1. Update CHANGELOG.md with the version's changes (Keep-a-Changelog format).
  2. Bump version in pyproject.toml.
  3. Tag the commit:
    git tag v0.2.0
    git push origin v0.2.0
    
  4. The release.yml GitHub Action runs:
    • Builds the wheel + sdist with uv build
    • Publishes to PyPI via Trusted Publishing — no API tokens stored
    • Creates a GitHub Release with the changelog excerpt + built artifacts attached

Pre-release tags (v*.*.*-rc*, v*.*.*-alpha*, v*.*.*-beta*) auto-flag as pre-releases on GitHub. Install with pip install --pre gflow-cli or uvx --from "gflow-cli==0.2.0a1" gflow.


License

MIT License © 2026 Flavio Oliva (ffroliva).

The full text is in LICENSE. In short:

  • ✅ Commercial use, modification, distribution, private use — all allowed.
  • ❗ No warranty — provided as-is.
  • ❗ Must include the original license + copyright in any copy/derivative.

Note that the Google service this tool talks to has its own terms (Google Labs Additional Terms, Google AI Ultra/Pro subscription terms, etc.). The MIT license here covers gflow-cli's code only — it does not grant any rights to Flow itself or to Veo model output. See DISCLAIMER.


Acknowledgements


Stats

GitHub stars GitHub forks GitHub watchers GitHub issues GitHub pull requests GitHub last commit GitHub repo size PyPI downloads PyPI total downloads

If gflow-cli saves you time, please ⭐ the repo — it's the cheapest way to support the project.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

gflow_cli-0.3.0a1.tar.gz (195.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

gflow_cli-0.3.0a1-py3-none-any.whl (47.9 kB view details)

Uploaded Python 3

File details

Details for the file gflow_cli-0.3.0a1.tar.gz.

File metadata

  • Download URL: gflow_cli-0.3.0a1.tar.gz
  • Upload date:
  • Size: 195.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for gflow_cli-0.3.0a1.tar.gz
Algorithm Hash digest
SHA256 13a1a4fd745dd59eeaa2330052457e040e043901da791058f587952c3dfb597c
MD5 ef556cc07f66bee63421c4a7334362a4
BLAKE2b-256 2cdaa8a920103cde8db1f6e6fc265051f61457b0cf02667279dd1d071751c683

See more details on using hashes here.

Provenance

The following attestation bundles were made for gflow_cli-0.3.0a1.tar.gz:

Publisher: release.yml on ffroliva/gflow-cli

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file gflow_cli-0.3.0a1-py3-none-any.whl.

File metadata

  • Download URL: gflow_cli-0.3.0a1-py3-none-any.whl
  • Upload date:
  • Size: 47.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for gflow_cli-0.3.0a1-py3-none-any.whl
Algorithm Hash digest
SHA256 c82af2dda8694a7040173db1145282c2bcf320d3a3a3de81ea8682a6d56b3fd6
MD5 a0fe154538c871398ce057baeb151e98
BLAKE2b-256 cd1fbfc56a01f139bee3153b9676494688c4a282d3a3f4b7ff7aed62524e8c9e

See more details on using hashes here.

Provenance

The following attestation bundles were made for gflow_cli-0.3.0a1-py3-none-any.whl:

Publisher: release.yml on ffroliva/gflow-cli

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page