gflow-cli 0.2.0a1__tar.gz → 0.4.0a2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (113) hide show
  1. {gflow_cli-0.2.0a1 → gflow_cli-0.4.0a2}/.claude/README.md +2 -2
  2. {gflow_cli-0.2.0a1 → gflow_cli-0.4.0a2}/.claude/commands/release.md +5 -5
  3. gflow_cli-0.4.0a2/.env.template +75 -0
  4. {gflow_cli-0.2.0a1 → gflow_cli-0.4.0a2}/.github/workflows/ci.yml +3 -1
  5. {gflow_cli-0.2.0a1 → gflow_cli-0.4.0a2}/.github/workflows/release.yml +2 -0
  6. {gflow_cli-0.2.0a1 → gflow_cli-0.4.0a2}/.gitignore +3 -0
  7. gflow_cli-0.4.0a2/CHANGELOG.md +315 -0
  8. {gflow_cli-0.2.0a1 → gflow_cli-0.4.0a2}/CLAUDE.md +27 -13
  9. {gflow_cli-0.2.0a1 → gflow_cli-0.4.0a2}/CONTRIBUTING.md +19 -18
  10. {gflow_cli-0.2.0a1 → gflow_cli-0.4.0a2}/DISCLAIMER.md +11 -11
  11. {gflow_cli-0.2.0a1 → gflow_cli-0.4.0a2}/KNOWN_ISSUES.md +35 -23
  12. {gflow_cli-0.2.0a1 → gflow_cli-0.4.0a2}/PKG-INFO +86 -63
  13. {gflow_cli-0.2.0a1 → gflow_cli-0.4.0a2}/PLAN.md +125 -52
  14. {gflow_cli-0.2.0a1 → gflow_cli-0.4.0a2}/README.md +84 -62
  15. {gflow_cli-0.2.0a1 → gflow_cli-0.4.0a2}/docs/ARCHITECTURE.md +57 -19
  16. {gflow_cli-0.2.0a1 → gflow_cli-0.4.0a2}/docs/AUTHENTICATION.md +33 -33
  17. gflow_cli-0.4.0a2/docs/CONFIGURATION.md +190 -0
  18. {gflow_cli-0.2.0a1 → gflow_cli-0.4.0a2}/docs/INDEX.md +13 -3
  19. {gflow_cli-0.2.0a1 → gflow_cli-0.4.0a2}/docs/SECURITY.md +19 -17
  20. gflow_cli-0.4.0a2/docs/USAGE.md +397 -0
  21. gflow_cli-0.4.0a2/docs/USER_GUIDE.md +625 -0
  22. gflow_cli-0.4.0a2/docs/superpowers/plans/2026-05-09-image-mvp-orchestration.md +319 -0
  23. gflow_cli-0.4.0a2/docs/superpowers/plans/2026-05-09-image-mvp.md +430 -0
  24. {gflow_cli-0.2.0a1 → gflow_cli-0.4.0a2}/docs/superpowers/plans/2026-05-09-video-mvp-orchestration.md +3 -3
  25. {gflow_cli-0.2.0a1 → gflow_cli-0.4.0a2}/docs/superpowers/plans/2026-05-09-video-mvp.md +116 -116
  26. gflow_cli-0.4.0a2/docs/superpowers/plans/2026-05-10-phase-4-hardening-orchestration.md +358 -0
  27. gflow_cli-0.4.0a2/docs/superpowers/plans/2026-05-10-phase-4-hardening.md +2736 -0
  28. gflow_cli-0.4.0a2/docs/superpowers/specs/2026-05-10-phase-4-hardening-design.md +484 -0
  29. {gflow_cli-0.2.0a1 → gflow_cli-0.4.0a2}/pyproject.toml +7 -5
  30. {gflow_cli-0.2.0a1 → gflow_cli-0.4.0a2}/samples/README.md +6 -4
  31. gflow_cli-0.4.0a2/samples/captured/06_batchGenerateImages.json +103 -0
  32. gflow_cli-0.4.0a2/samples/captured/07_batchGenerateImages_seeded.json +121 -0
  33. {gflow_cli-0.2.0a1 → gflow_cli-0.4.0a2}/scripts/smoke_e2e.py +6 -6
  34. gflow_cli-0.4.0a2/scripts/smoke_image.py +147 -0
  35. {gflow_cli-0.2.0a1 → gflow_cli-0.4.0a2}/skills/README.md +6 -5
  36. gflow_cli-0.4.0a2/skills/gflow-cli/SKILL.md +158 -0
  37. gflow_cli-0.4.0a2/src/gflow_cli/__init__.py +3 -0
  38. gflow_cli-0.4.0a2/src/gflow_cli/__main__.py +6 -0
  39. gflow_cli-0.4.0a2/src/gflow_cli/_cli_helpers.py +185 -0
  40. {gflow_cli-0.2.0a1/src/flow_cli → gflow_cli-0.4.0a2/src/gflow_cli}/api/__init__.py +3 -3
  41. gflow_cli-0.4.0a2/src/gflow_cli/api/_retry.py +138 -0
  42. gflow_cli-0.4.0a2/src/gflow_cli/api/client.py +897 -0
  43. {gflow_cli-0.2.0a1/src/flow_cli → gflow_cli-0.4.0a2/src/gflow_cli}/api/dto.py +96 -1
  44. gflow_cli-0.4.0a2/src/gflow_cli/api/image.py +236 -0
  45. {gflow_cli-0.2.0a1/src/flow_cli → gflow_cli-0.4.0a2/src/gflow_cli}/api/recaptcha.py +2 -2
  46. {gflow_cli-0.2.0a1/src/flow_cli → gflow_cli-0.4.0a2/src/gflow_cli}/api/routes.py +27 -1
  47. {gflow_cli-0.2.0a1/src/flow_cli → gflow_cli-0.4.0a2/src/gflow_cli}/auth.py +14 -10
  48. {gflow_cli-0.2.0a1/src/flow_cli → gflow_cli-0.4.0a2/src/gflow_cli}/cli.py +30 -8
  49. gflow_cli-0.4.0a2/src/gflow_cli/cli_image.py +535 -0
  50. {gflow_cli-0.2.0a1/src/flow_cli → gflow_cli-0.4.0a2/src/gflow_cli}/cli_video.py +77 -59
  51. {gflow_cli-0.2.0a1/src/flow_cli → gflow_cli-0.4.0a2/src/gflow_cli}/config.py +41 -7
  52. gflow_cli-0.4.0a2/src/gflow_cli/errors.py +216 -0
  53. {gflow_cli-0.2.0a1/src/flow_cli → gflow_cli-0.4.0a2/src/gflow_cli}/manifest.py +1 -1
  54. gflow_cli-0.4.0a2/src/gflow_cli/observability.py +160 -0
  55. {gflow_cli-0.2.0a1/src/flow_cli → gflow_cli-0.4.0a2/src/gflow_cli}/paths.py +14 -14
  56. {gflow_cli-0.2.0a1/src/flow_cli → gflow_cli-0.4.0a2/src/gflow_cli}/profile_store.py +7 -7
  57. gflow_cli-0.4.0a2/tasks/lessons.md +195 -0
  58. gflow_cli-0.4.0a2/tests/api/test_client.py +177 -0
  59. {gflow_cli-0.2.0a1 → gflow_cli-0.4.0a2}/tests/api/test_client_generate_video.py +44 -28
  60. gflow_cli-0.4.0a2/tests/api/test_client_image.py +799 -0
  61. gflow_cli-0.4.0a2/tests/api/test_concurrency.py +199 -0
  62. {gflow_cli-0.2.0a1 → gflow_cli-0.4.0a2}/tests/api/test_dto.py +1 -1
  63. gflow_cli-0.4.0a2/tests/api/test_image.py +253 -0
  64. gflow_cli-0.4.0a2/tests/api/test_image_dto.py +122 -0
  65. {gflow_cli-0.2.0a1 → gflow_cli-0.4.0a2}/tests/api/test_recaptcha.py +1 -1
  66. gflow_cli-0.4.0a2/tests/api/test_retry.py +243 -0
  67. gflow_cli-0.4.0a2/tests/api/test_routes.py +93 -0
  68. {gflow_cli-0.2.0a1 → gflow_cli-0.4.0a2}/tests/api/test_video.py +1 -1
  69. gflow_cli-0.4.0a2/tests/cli/__init__.py +0 -0
  70. gflow_cli-0.4.0a2/tests/cli/test_cli_image.py +459 -0
  71. gflow_cli-0.4.0a2/tests/cli/test_error_handling.py +323 -0
  72. gflow_cli-0.4.0a2/tests/cli/test_helpers.py +158 -0
  73. gflow_cli-0.4.0a2/tests/conftest.py +38 -0
  74. gflow_cli-0.4.0a2/tests/features/__init__.py +0 -0
  75. gflow_cli-0.4.0a2/tests/features/auth.feature +28 -0
  76. gflow_cli-0.4.0a2/tests/features/conftest.py +89 -0
  77. gflow_cli-0.4.0a2/tests/features/image.feature +25 -0
  78. gflow_cli-0.4.0a2/tests/features/test_auth_steps.py +186 -0
  79. gflow_cli-0.4.0a2/tests/features/test_image_steps.py +191 -0
  80. gflow_cli-0.4.0a2/tests/features/test_step_collision_guard.py +16 -0
  81. gflow_cli-0.4.0a2/tests/features/test_video_steps.py +253 -0
  82. gflow_cli-0.4.0a2/tests/features/video.feature +27 -0
  83. {gflow_cli-0.2.0a1 → gflow_cli-0.4.0a2}/tests/test_auth.py +6 -6
  84. {gflow_cli-0.2.0a1 → gflow_cli-0.4.0a2}/tests/test_cli_video.py +83 -13
  85. gflow_cli-0.4.0a2/tests/test_config.py +161 -0
  86. gflow_cli-0.4.0a2/tests/test_errors.py +276 -0
  87. {gflow_cli-0.2.0a1 → gflow_cli-0.4.0a2}/tests/test_manifest.py +2 -2
  88. gflow_cli-0.4.0a2/tests/test_observability.py +165 -0
  89. {gflow_cli-0.2.0a1 → gflow_cli-0.4.0a2}/tests/test_paths.py +8 -8
  90. {gflow_cli-0.2.0a1 → gflow_cli-0.4.0a2}/tests/test_profile_store.py +7 -7
  91. {gflow_cli-0.2.0a1 → gflow_cli-0.4.0a2}/tests/test_smoke.py +7 -7
  92. {gflow_cli-0.2.0a1 → gflow_cli-0.4.0a2}/uv.lock +162 -3
  93. gflow_cli-0.2.0a1/.env.template +0 -59
  94. gflow_cli-0.2.0a1/CHANGELOG.md +0 -59
  95. gflow_cli-0.2.0a1/docs/CONFIGURATION.md +0 -182
  96. gflow_cli-0.2.0a1/docs/USAGE.md +0 -262
  97. gflow_cli-0.2.0a1/skills/gflow-cli/SKILL.md +0 -156
  98. gflow_cli-0.2.0a1/src/flow_cli/__init__.py +0 -3
  99. gflow_cli-0.2.0a1/src/flow_cli/__main__.py +0 -6
  100. gflow_cli-0.2.0a1/src/flow_cli/api/client.py +0 -246
  101. gflow_cli-0.2.0a1/tests/api/test_client.py +0 -44
  102. gflow_cli-0.2.0a1/tests/api/test_routes.py +0 -36
  103. gflow_cli-0.2.0a1/tests/test_config.py +0 -104
  104. {gflow_cli-0.2.0a1 → gflow_cli-0.4.0a2}/.gitattributes +0 -0
  105. {gflow_cli-0.2.0a1 → gflow_cli-0.4.0a2}/LICENSE +0 -0
  106. {gflow_cli-0.2.0a1 → gflow_cli-0.4.0a2}/samples/captured/01_upload_image.json +0 -0
  107. {gflow_cli-0.2.0a1 → gflow_cli-0.4.0a2}/samples/captured/02_batchAsyncGenerateVideoText.json +0 -0
  108. {gflow_cli-0.2.0a1 → gflow_cli-0.4.0a2}/samples/captured/03_batchCheckAsyncVideoGenerationStatus.json +0 -0
  109. {gflow_cli-0.2.0a1 → gflow_cli-0.4.0a2}/samples/captured/04_archive_workflow.json +0 -0
  110. {gflow_cli-0.2.0a1 → gflow_cli-0.4.0a2}/samples/captured/05_createProject.json +0 -0
  111. {gflow_cli-0.2.0a1/src/flow_cli → gflow_cli-0.4.0a2/src/gflow_cli}/api/video.py +0 -0
  112. {gflow_cli-0.2.0a1 → gflow_cli-0.4.0a2}/tests/__init__.py +0 -0
  113. {gflow_cli-0.2.0a1 → gflow_cli-0.4.0a2}/tests/api/__init__.py +0 -0
@@ -2,7 +2,7 @@
2
2
 
3
3
  This directory holds **internal maintainer workflows** that are bundled with the repo so any contributor running Claude Code in this checkout gets the same environment.
4
4
 
5
- > Distinct from `skills/flow-cli/SKILL.md` at the repo root, which is the **published** Skill end users install into their own Claude Code to learn how to use `gflow` from agent contexts. `.claude/` is for *us*, the maintainers; `skills/` is for *them*, the users.
5
+ > Distinct from `skills/gflow-cli/SKILL.md` at the repo root, which is the **published** Skill end users install into their own Claude Code to learn how to use `gflow` from agent contexts. `.claude/` is for *us*, the maintainers; `skills/` is for *them*, the users.
6
6
 
7
7
  ## Layout
8
8
 
@@ -31,7 +31,7 @@ Example: `commands/foo.md` → invoked as `/foo`.
31
31
 
32
32
  ## Adding an internal skill
33
33
 
34
- Same shape as the published one in `skills/flow-cli/`:
34
+ Same shape as the published one in `skills/gflow-cli/`:
35
35
 
36
36
  ```markdown
37
37
  ---
@@ -1,10 +1,10 @@
1
1
  ---
2
- description: Cut a new flow-cli release — bump version, update CHANGELOG, tag, push.
2
+ description: Cut a new gflow-cli release — bump version, update CHANGELOG, tag, push.
3
3
  ---
4
4
 
5
- # `/release` — Cut a new flow-cli release
5
+ # `/release` — Cut a new gflow-cli release
6
6
 
7
- You are about to release a new version of `flow-cli`. Follow this sequence verbatim — every step matters.
7
+ You are about to release a new version of `gflow-cli`. Follow this sequence verbatim — every step matters.
8
8
 
9
9
  ## Inputs
10
10
 
@@ -32,7 +32,7 @@ Ask the user (if not already provided):
32
32
  uv run ruff check src tests
33
33
  uv run ruff format --check src tests
34
34
  uv run pyright src
35
- uv run pytest -q --cov=flow_cli --cov-fail-under=80
35
+ uv run pytest -q --cov=gflow_cli --cov-fail-under=80
36
36
  ```
37
37
 
38
38
  4. **Bump version** in `pyproject.toml`:
@@ -83,4 +83,4 @@ Ask the user (if not already provided):
83
83
  ## See also
84
84
 
85
85
  - [README § Releases](../../README.md#releases) — full release policy & cadence
86
- - [PLAN § Phase 5](../../PLAN.md#phase-5--public-alpha-release) — first-release exit criteria
86
+ - [PLAN § Phase 5](../../PLAN.md#phase-5--public-alpha-release-on-pypi) — first-release exit criteria
@@ -0,0 +1,75 @@
1
+ # gflow-cli — example environment variables.
2
+ # Copy to `.env` in the directory where you invoke `gflow` and uncomment what
3
+ # you want to override. ($GFLOW_CLI_HOME is NOT a .env search path — only the
4
+ # current working directory is loaded.)
5
+ # All variables are OPTIONAL — defaults work out of the box for most users.
6
+ # Lines below are commented to show the SHIPPED DEFAULT — uncomment to override.
7
+
8
+ # -----------------------------------------------------------------------------
9
+ # Auth & profiles
10
+ # -----------------------------------------------------------------------------
11
+
12
+ # Root directory for Playwright persistent contexts (signed-in Google sessions).
13
+ # Default (via `platformdirs`):
14
+ # Windows: %LOCALAPPDATA%\gflow-cli (e.g. C:\Users\<you>\AppData\Local\gflow-cli)
15
+ # macOS: ~/Library/Application Support/gflow-cli
16
+ # Linux: $XDG_DATA_HOME/gflow-cli (typically ~/.local/share/gflow-cli)
17
+ # GFLOW_CLI_HOME=
18
+
19
+ # Default profile name. When unset, the resolution chain auto-picks (see
20
+ # docs/CONFIGURATION.md § GFLOW_CLI_PROFILE). Override per-call with
21
+ # `--profile <name>`.
22
+ # GFLOW_CLI_PROFILE=default
23
+
24
+ # -----------------------------------------------------------------------------
25
+ # Output paths
26
+ # -----------------------------------------------------------------------------
27
+
28
+ # Where downloaded assets land. Subfolders are created per kind/date:
29
+ # <output_dir>/images/<YYYY-MM-DD>/<job_id>_<index>.png
30
+ # <output_dir>/videos/<YYYY-MM-DD>/<job_id>.mp4
31
+ #
32
+ # Default (via `platformdirs`):
33
+ # Windows: %USERPROFILE%\Downloads\gflow-cli
34
+ # macOS: ~/Downloads/gflow-cli
35
+ # Linux: $XDG_DOWNLOAD_DIR/gflow-cli (falls back to ~/Downloads/gflow-cli)
36
+ # GFLOW_CLI_OUTPUT_DIR=
37
+
38
+ # -----------------------------------------------------------------------------
39
+ # Provider selection
40
+ # -----------------------------------------------------------------------------
41
+
42
+ # Backend to use for generations.
43
+ # flow - reverse-engineered Flow REST API (default, requires Ultra/Pro)
44
+ # official - official Veo SDK (planned for v0.5+, requires Gemini API key)
45
+ # GFLOW_CLI_PROVIDER=flow
46
+
47
+ # Gemini API key — only required when GFLOW_CLI_PROVIDER=official.
48
+ # Get one at https://aistudio.google.com/apikey
49
+ # GFLOW_CLI_GEMINI_API_KEY=
50
+
51
+ # -----------------------------------------------------------------------------
52
+ # Runtime tuning
53
+ # -----------------------------------------------------------------------------
54
+
55
+ # Per-request HTTP timeout (seconds). Veo videos can take 60-180s each.
56
+ # GFLOW_CLI_TIMEOUT_SECONDS=600
57
+
58
+ # Logging level — DEBUG | INFO | WARNING | ERROR
59
+ # GFLOW_CLI_LOG_LEVEL=INFO
60
+
61
+ # Log format — auto | text | json
62
+ # auto = text on TTY, json when piped (default)
63
+ # GFLOW_CLI_LOG_FORMAT=auto
64
+
65
+ # Per-worker Playwright Page-pool size for batch runs (1-16). FlowApiClient
66
+ # opens N Pages inside one shared persistent BrowserContext; `gflow video batch`
67
+ # fans out via asyncio.gather. ~30-60 MiB memory per Page on Chromium headless;
68
+ # don't exceed 8 without measuring. Shipped in v0.4.0a2.
69
+ # GFLOW_CLI_CONCURRENCY=1
70
+
71
+ # Run Playwright in headless mode for non-`auth login` commands (true|false).
72
+ # Default: true. Set to false if reCAPTCHA Enterprise refuses to mint tokens
73
+ # (Google's bot-detection sometimes refuses headless Chromium but accepts a
74
+ # visible window). The session is still reused from the persistent profile.
75
+ # GFLOW_CLI_HEADLESS=true
@@ -10,7 +10,9 @@ jobs:
10
10
  runs-on: ubuntu-latest
11
11
  strategy:
12
12
  matrix:
13
- python-version: ["3.11", "3.12"]
13
+ python-version: ["3.11", "3.12", "3.13"]
14
+ env:
15
+ FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
14
16
  steps:
15
17
  - uses: actions/checkout@v4
16
18
 
@@ -15,6 +15,8 @@ jobs:
15
15
  environment:
16
16
  name: pypi
17
17
  url: https://pypi.org/p/gflow-cli
18
+ env:
19
+ FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
18
20
  steps:
19
21
  - uses: actions/checkout@v4
20
22
  with:
@@ -51,3 +51,6 @@ samples/*.captured.json # sandbox-recorded API exchanges may contain PII
51
51
  # Claude Code worktrees and lock files
52
52
  .claude/worktrees/
53
53
  .claude/scheduled_tasks.lock
54
+
55
+ # Doc-council scratch dir (bundles + raw reviews + consensus matrix)
56
+ .doc-council/
@@ -0,0 +1,315 @@
1
+ # Changelog
2
+
3
+ All notable changes to `gflow-cli` will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [Unreleased]
9
+
10
+ ## [0.4.0a2] — 2026-05-11
11
+
12
+ > **Documentation polish.** Same release surface as v0.4.0a1; this tag fixes
13
+ > a doc-council pass: four broken Python snippets in the README, a shell
14
+ > exit-code branching example that silently dropped failures, a stale anchor
15
+ > link in `AUTHENTICATION.md`, three USER_GUIDE journeys the target audience
16
+ > needs (credit budgeting, pipeline wiring, error recovery), and a sweep of
17
+ > "planned v0.3 / v0.4" callouts across 9 files that had been overtaken by
18
+ > the Phase 4 release. No code changes. No tests changed.
19
+
20
+ ### Fixed (docs)
21
+
22
+ - **`README.md` Python quick-start snippet rewritten** — the prior block had
23
+ four real bugs (`from gflow_cli.paths import profile_dir` → import error,
24
+ `upload_image(path, project_id)` args reversed, `generate_video(prompt=,
25
+ start_asset=, aspect=)` wrong kwargs, `poll_video_status` method does not
26
+ exist). Snippet now uses the same invocation pattern as
27
+ `gflow_cli.cli_video._run_i2v` and would actually run.
28
+ - **`docs/USAGE.md` exit-code branching example** — `if ! cmd; then case $?`
29
+ always saw `0` because the `if` consumed the exit code; rewritten to
30
+ capture `rc=$?` first. Exit code `2` re-labelled "Bad CLI usage" (auth is
31
+ exit `3`).
32
+ - **`docs/AUTHENTICATION.md` anchor link** to the Phase 4 PLAN heading
33
+ fixed (was `#phase-4--hardening--post-v030a1`, did not exist).
34
+ - **`CHANGELOG.md` footer** — added `[0.4.0a1]:` and `[0.4.0a2]:` compare
35
+ links; reset `[Unreleased]` to compare from v0.4.0a2.
36
+ - **`docs/USER_GUIDE.md` Journey 2** endpoint name `flowMedia:batchGenerateVeoVideo`
37
+ → real route `/v1/video:batchAsyncGenerateVideoText`.
38
+ - **`docs/USER_GUIDE.md` Journey 5.2** invalid placeholder UUID
39
+ (`media-uuid-abc-...`) → canonical hex shape.
40
+ - **`docs/USER_GUIDE.md` Journey 7.1** `echo $?` placement — previously
41
+ captured the exit code of an intermediate command, not the failing batch.
42
+ - **`docs/USER_GUIDE.md` Journey 7.3** softened the "Flow doesn't re-bill"
43
+ claim — billing is a private-API contract we cannot assert.
44
+ - **`KNOWN_ISSUES.md` same-profile examples** swapped `gflow image batch`
45
+ (does not exist) → `gflow video batch`.
46
+
47
+ ### Added (docs)
48
+
49
+ - **`docs/USER_GUIDE.md` Journey on credit budgeting** — rule-of-thumb credit
50
+ cost per `video t2v` / `video i2v` / `image t2i` / `image i2i` call, links
51
+ to Flow's credit-balance UI, batch-cost math example.
52
+ - **`docs/USER_GUIDE.md` Journey on wiring outputs into a pipeline** —
53
+ deterministic output-dir layout, `find` (POSIX) + `Get-ChildItem`
54
+ (PowerShell) recipes, `ffmpeg` consumer example.
55
+ - **`docs/USER_GUIDE.md` Journey on `ContentPolicyError` / `RateLimitError`
56
+ recovery** — what each error means, how long to wait, prompt-rewrite
57
+ pattern, when retry is futile.
58
+ - **`README.md` doc-nav** now links `docs/USER_GUIDE.md` (was missing).
59
+ - **`README.md` Stack table** lists `tenacity` and `structlog` (were
60
+ shipped in v0.4.0a1 but not in the stack overview).
61
+
62
+ ### Changed (docs)
63
+
64
+ - **`CHANGELOG.md` [0.4.0a1] section reordered** — `Added — Phase 4
65
+ hardening` now appears before `Breaking`. The hardening release was
66
+ user-visible value; the env-var rename was a one-line update for most
67
+ users.
68
+ - **Per-class exit codes 3–7** promoted from a bullet to its own "Migration
69
+ notes" subsection in the [0.4.0a1] block.
70
+ - **Version-time-warp sweep across 9 files** — every `(planned v0.3)`,
71
+ `(planned v0.4)`, `v0.3+ will add`, `v0.4 will add`, and `current scaffold
72
+ ignores this` line either describes shipped behaviour or points at v0.5+.
73
+ Files touched: `README.md`, `CHANGELOG.md`, `CLAUDE.md`, `PLAN.md`,
74
+ `KNOWN_ISSUES.md`, `CONFIGURATION.md`, `AUTHENTICATION.md`,
75
+ `ARCHITECTURE.md`, `DISCLAIMER.md`, `SECURITY.md`, `CONTRIBUTING.md`,
76
+ `.env.template`.
77
+ - **`docs/ARCHITECTURE.md` Concurrency section** describes the shipped
78
+ `asyncio.Queue` Page pool, not the target-DDD `Semaphore` model.
79
+ - **`docs/ARCHITECTURE.md` Observability section** describes the shipped
80
+ `error_raised` / `error_unhandled` event names, not the target-DDD
81
+ dot-path names.
82
+ - **`docs/ARCHITECTURE.md` DDD error class names** annotated as target —
83
+ shipped Phase 4 names (`AuthExpiredError`, `RateLimitError`,
84
+ `ContentPolicyError`, `NetworkError`, `WireFormatError`) listed alongside.
85
+ - **`docs/CONFIGURATION.md` `GFLOW_CLI_CONCURRENCY`** describes shipped
86
+ behaviour (per-worker Page pool, `asyncio.gather` fan-out).
87
+
88
+ ## [0.4.0a1] — 2026-05-11
89
+
90
+ > **Phase 4 hardening release.** Concurrency, retry/backoff, typed errors,
91
+ > and structured logs ship — your existing scripts keep running (the
92
+ > `FLOW_CLI_*` env-var shim is in place until v0.5.0). The user-visible
93
+ > contract that changed: shell scripts can now branch on stable per-class
94
+ > exit codes (3–7) for auth / rate-limit / content-policy / network /
95
+ > wire-format failures.
96
+
97
+ ### Added — Phase 4 hardening
98
+
99
+ - **Per-worker Playwright Page pool.** `FlowApiClient.__aenter__` opens
100
+ `Settings.concurrency` Pages inside a single persistent BrowserContext.
101
+ Operations check out a Page via `asyncio.Queue` (FIFO, bounded by
102
+ `maxsize=N`). `GFLOW_CLI_CONCURRENCY=N` (1–16) now actually parallelizes.
103
+ - **`gflow video batch` fans out via `asyncio.gather`** over manifest
104
+ entries — was sequential pre-v0.4.0a1.
105
+ - **`tenacity`-based retry layer** (3 attempts, exponential jittered
106
+ backoff 1s±25% → 2s±25% → 4s±25%) on 5xx / 429 / `playwright.async_api.Error`
107
+ / `TimeoutError`. `Retry-After` honoured, **capped at 60 s**. `reraise=True`
108
+ so the original exception's `__cause__` chain is preserved. reCAPTCHA
109
+ token re-minted **inside the retry loop, every attempt**, on the worker's
110
+ own Page.
111
+ - **RFC 9457 Problem Details exception hierarchy:**
112
+ `GFlowError → FlowApiError → {AuthExpiredError, RateLimitError,
113
+ ContentPolicyError, NetworkError, WireFormatError}`. `except FlowApiError`
114
+ catches the typed subclasses (back-compat). Each carries
115
+ `problem_type` URI, `title`, `status`, `detail`, `instance`
116
+ (`gflow:error:<correlation_id>`), `remediation_hint`, and `route`.
117
+ `to_problem_details()` serializes to the RFC 9457 JSON shape.
118
+ - **Per-class exit codes**: 3 (auth) / 4 (rate-limit) / 5 (content-policy) /
119
+ 6 (network) / 7 (wire-format). Exit 1 = unhandled. Exit 130 = SIGINT.
120
+ - **`WireFormatError` discovery payload** — `route_name`, `http_status`,
121
+ `content_type`, `top_level_keys`, `body_prefix_redacted` so log mining
122
+ can propose new error subclasses for unexpected response shapes.
123
+ - **`structlog` bootstrap** with TTY auto-detection (text on TTY, JSON when
124
+ piped). `show_locals=False` mandatory on the exception renderer so frame
125
+ locals (which may contain auth tokens) NEVER reach the log stream.
126
+ `correlation_id` + `cli_version` bound via `contextvars` at the process
127
+ boundary.
128
+ - **`error_raised` and `error_unhandled` events.** `error_raised` for caught
129
+ `GFlowError`s — carries Problem Details. `error_unhandled` for anything
130
+ else — privacy-safe: hashes message + stack with SHA-256, never logs raw
131
+ payload.
132
+ - **12 `pytest-bdd` scenarios** across `auth.feature`, `video.feature`,
133
+ `image.feature` — all use a mocked `FlowApiClient`. A
134
+ `_forbid_live_playwright` autouse tripwire fails any scenario that
135
+ accidentally tries to start a real browser.
136
+
137
+ ### Migration notes — stable exit codes
138
+
139
+ Shell scripts that previously branched on exit code `1` for any failure
140
+ can now distinguish the failure class. The mapping is locked by an
141
+ ordering-invariant test in `tests/test_errors.py`:
142
+
143
+ | Exit | Error class | Meaning | Retry? |
144
+ |------|-----------------------|--------------------------------------|----------------|
145
+ | 0 | — | Success | — |
146
+ | 1 | (unhandled) | Bug. Filed via `error_unhandled` | No |
147
+ | 2 | (Click) | Bad CLI usage / missing arg | Fix the call |
148
+ | 3 | `AuthExpiredError` | Session cookies invalidated | After re-login |
149
+ | 4 | `RateLimitError` | Flow returned 429 | Yes, with wait |
150
+ | 5 | `ContentPolicyError` | Prompt blocked upstream | After rewrite |
151
+ | 6 | `NetworkError` | DNS / TLS / 5xx after retry | Yes |
152
+ | 7 | `WireFormatError` | Response shape changed (Flow update) | File a bug |
153
+ | 130 | (SIGINT) | User Ctrl-C | — |
154
+
155
+ See [`docs/USAGE.md § Exit codes`](docs/USAGE.md#exit-codes) for a
156
+ shell-script template that branches on these codes.
157
+
158
+ ### Breaking — package + env-var rename
159
+
160
+ - **Python package renamed: `flow_cli` → `gflow_cli`.** All imports must
161
+ change: `from gflow_cli...` (was `from flow_cli...`). The PyPI distribution
162
+ name (`gflow-cli`), the CLI binary (`gflow`), and the user data directory
163
+ (`gflow-cli/` under `platformdirs`) are unchanged.
164
+ - **Env var prefix renamed: `FLOW_CLI_*` → `GFLOW_CLI_*`.** Affected vars:
165
+ `GFLOW_CLI_HOME`, `GFLOW_CLI_OUTPUT_DIR`, `GFLOW_CLI_PROFILE`,
166
+ `GFLOW_CLI_HEADLESS`, `GFLOW_CLI_LOG_LEVEL`, `GFLOW_CLI_LOG_FORMAT`,
167
+ `GFLOW_CLI_PROVIDER`, `GFLOW_CLI_TIMEOUT_SECONDS`, `GFLOW_CLI_CONCURRENCY`,
168
+ `GFLOW_CLI_GEMINI_API_KEY`.
169
+ - **Backwards-compat shim.** Legacy `FLOW_CLI_*` env vars continue to work
170
+ in v0.4.x; on first encounter the process emits a single
171
+ `DeprecationWarning` to stderr summarising the promoted keys. The shim
172
+ will be removed in v0.5.0 — update your `.env` files and shell exports.
173
+
174
+ ### Changed
175
+
176
+ - `FlowApiError` re-parented under `GFlowError`. Legacy positional
177
+ constructor `FlowApiError(status, body, *, route)` preserved (auto-detected
178
+ via `isinstance(args[0], int) and not isinstance(args[0], bool)`).
179
+ - `_resolve_profile` and `_make_provider_dir` deduped — relocated from
180
+ `cli_image.py` + `cli_video.py` to `gflow_cli._cli_helpers`. AST-based
181
+ drift guard in `tests/cli/test_helpers.py` prevents regression.
182
+ - All `logging.*` callsites in `src/` migrated to `structlog`. The
183
+ remaining `print()` in `auth.py` swapped to Rich `console.print()`.
184
+
185
+ ### Internal
186
+
187
+ - New module: `gflow_cli.errors` (RFC 9457 hierarchy + `EXIT_CODE_MAP`).
188
+ - New module: `gflow_cli.observability` (structlog bootstrap + event
189
+ emitters; `show_locals=False` via
190
+ `ExceptionRenderer(ExceptionDictTransformer(show_locals=False))`).
191
+ - New module: `gflow_cli.api._retry` (tenacity `AsyncRetrying` +
192
+ `Retry-After` parser, capped at 60 s).
193
+ - New module: `gflow_cli._cli_helpers` (shared CLI-boundary handlers +
194
+ profile/provider helpers).
195
+
196
+ ## [0.3.0a1] — 2026-05-10
197
+
198
+ ### Added
199
+ - **`gflow image upload PATH`** — upload a single local image (PNG/JPEG) into a
200
+ fresh Flow project and print the asset UUID + dimensions Flow inferred. The
201
+ UUID is reusable as a starting frame for `gflow image i2i --ref` and
202
+ `gflow video i2v`.
203
+ - **`gflow image t2i PROMPT`** — text-to-image generation (1–4 images per call)
204
+ via Google Flow's Imagen / Nano Banana models.
205
+ Flags: `--model {nano2|nano-pro|image4}`, `--aspect {9:16|16:9|1:1|4:3|3:4}`,
206
+ `-n/--count` (1–4), `--seed` (single-image only), `--out DIR`, `--profile`.
207
+ Files land date-partitioned under `$GFLOW_CLI_OUTPUT_DIR/images/<YYYY-MM-DD>/`
208
+ by default; `--out DIR` writes flat as `<DIR>/<media_name>_<n>.png`.
209
+ - **`gflow image i2i PROMPT --ref PATH_OR_UUID`** — image-to-image generation
210
+ with one or more reference images. Each `--ref` is classified at the CLI
211
+ boundary: case-insensitive 8-4-4-4-12 hex UUIDs are passed through verbatim
212
+ (no upload), anything else is canonicalized (symlinks resolved at validation
213
+ time) and uploaded before use. `--ref` is repeatable; UUIDs and paths can mix
214
+ freely on the same call. Same flag set as `t2i` otherwise.
215
+ - **Multi-image fan-out** — `t2i` / `i2i` with `-n {2..4}` mint a single shared
216
+ `batch_id` and issue N parallel POSTs (one per shot, each with its own random
217
+ seed). Same-batch images share the prompt + refs; per-shot variation comes
218
+ from independent seeds.
219
+ - **Three image models** wired behind CLI aliases:
220
+ `nano2` → `NARWHAL` (Nano Banana 2; default, fast/balanced),
221
+ `nano-pro` → `GEM_PIX_2` (Nano Banana Pro; higher quality),
222
+ `image4` → `IMAGEN_3_5` (Imagen 4; photoreal-leaning).
223
+ - **Five aspect ratios** for image generation: `9:16`, `16:9`, `1:1`, `4:3`,
224
+ `3:4` (default `9:16`, matching the Flow web UI).
225
+ - `download_image()` on `FlowApiClient` — direct download of a generated
226
+ image's signed `fifeUrl` to disk. Streams to a temp file and atomically
227
+ renames on success; enforces an SSRF host allowlist (only Google-controlled
228
+ CDNs accepted).
229
+ - `scripts/smoke_image.py` — live single-image E2E smoke script (image
230
+ counterpart of `scripts/smoke_e2e.py` for video). Run after
231
+ `gflow auth login` to exercise the full happy path: project create →
232
+ `batchGenerateImages` → fifeUrl download.
233
+
234
+ ### Changed
235
+ - `FlowApiClient.upload_image` now validates **PNG/JPEG/WebP/GIF magic
236
+ bytes** and rejects files larger than **20 MB** before issuing the upload
237
+ request. Existing callers (`gflow video i2v`, `gflow video batch`) inherit
238
+ the stricter validation; previously-undocumented use of `upload_image` for
239
+ non-image payloads no longer works (was never officially supported).
240
+ - Project renamed `flow-cli` → `gflow-cli` across all docs and source. The
241
+ PyPI package and GitHub repo were already at the new name in v0.2.0a1;
242
+ this commit completes the in-source rename. Local clones may want to
243
+ rename their working directory to match `gh clone https://github.com/ffroliva/gflow-cli`
244
+ behavior.
245
+
246
+ ### Security
247
+ - DEBUG-level body logs now redact reCAPTCHA Enterprise tokens and other
248
+ bearer-style fields before emission, eliminating a token-leak vector when
249
+ users share verbose logs while filing bug reports.
250
+ - `download_image()` enforces an **SSRF host allowlist** on the signed
251
+ `fifeUrl` returned by Flow — only Google-controlled image CDNs
252
+ (`*.googleusercontent.com`, etc.) are followed; any other host raises
253
+ before the GET is issued. Defends against a Flow-side bug or compromise
254
+ redirecting downloads to an attacker-controlled origin.
255
+ - `project_id` allowlist regex `^[A-Za-z0-9-]{1,128}$` on
256
+ `batch_generate_images_url` — closes percent-encoded slash (`%2F`),
257
+ Unicode-lookalike (U+FF0F / U+2215 / U+29F8), and CRLF/NUL injection
258
+ bypasses that the previous denylist guard let through.
259
+
260
+ ### CI
261
+ - Test matrix now includes Python 3.13 alongside 3.11 and 3.12.
262
+
263
+ ## [0.2.0a1] — 2026-05-09
264
+
265
+ ### Added
266
+ - **`gflow video t2v`** — generate a video from a text prompt via Veo 3.1.
267
+ Flags: `--aspect 9:16|16:9|1:1`, `--seed`, `--output`, `--profile`, `--poll-interval`.
268
+ - **`gflow video i2v`** — generate a video from a start image + text prompt (Veo 3.1 I2V).
269
+ - **`gflow video batch`** — run a TSV manifest of video generations against one shared project.
270
+ - `gflow_cli.api` package — low-level REST client (`FlowApiClient`) + value objects
271
+ (`GenerateVideoRequest`, `VideoOperation`, `VideoStatus`) for video generation.
272
+ - `gflow_cli.api.recaptcha` — reCAPTCHA Enterprise token minting via Playwright `page.evaluate`.
273
+ `TokenMinter` caches the discovered site key per session; `mint(action)` is called immediately
274
+ before each generation request.
275
+ - `gflow_cli.manifest` — TSV manifest parser for `gflow video batch`. Supports optional
276
+ `start_image`, `end_image`, `aspect`, `output_path` columns; skips `# `-prefixed comments.
277
+ - `GFLOW_CLI_HEADLESS` env var (`bool`, default `true`). Set to `false` if reCAPTCHA refuses
278
+ to mint tokens in headless mode (Google bot detection fallback).
279
+ - `scripts/smoke_e2e.py` — one-shot live T2V smoke test; run after `gflow auth login` to
280
+ verify the full happy path (create project → generate_video → poll → download).
281
+ - **`CLAUDE.md`** at repo root — project memory hub for AI coding agents
282
+ (Claude Code reads natively; Cursor/Codex/Gemini/Aider can read as reference).
283
+ - **`.claude/`** directory — repo-local Claude Code surface for maintainers.
284
+ - `.claude/README.md` — what goes here, how to extend.
285
+ - `.claude/commands/release.md` — `/release` slash command that automates
286
+ version bump + CHANGELOG migration + tag + push, with quality gates.
287
+ - `gflow_cli.profile_store` — profile inventory + default-profile persistence
288
+ in `$GFLOW_CLI_HOME/config.toml`. Five-step resolution chain (CLI flag > env >
289
+ config > auto-select > raise) with named exceptions
290
+ (`NoProfilesError`, `NoDefaultProfileError`).
291
+ - New auth subcommands: bare `gflow auth`, `gflow auth list`, `gflow auth use <name>`,
292
+ `gflow auth logout [--profile NAME] [-y]`. First login auto-sets default profile.
293
+ - `KNOWN_ISSUES.md` at repo root — open/mitigated/resolved issues with workarounds.
294
+ - `docs/` tree (INDEX, AUTHENTICATION, CONFIGURATION, ARCHITECTURE, USAGE, SECURITY).
295
+ - `.env.template` documenting every supported env var.
296
+ - GitHub Actions CI: ruff, pyright, pytest on Python 3.11 and 3.12.
297
+ - GitHub Actions release workflow: tag-triggered PyPI publish via Trusted Publishing.
298
+ - MIT license, comprehensive README, [`DISCLAIMER.md`](DISCLAIMER.md), [`CONTRIBUTING.md`](CONTRIBUTING.md).
299
+ - [`skills/gflow-cli/SKILL.md`](skills/gflow-cli/SKILL.md) — installable Claude Code Skill.
300
+
301
+ ### Removed
302
+ - `gflow_cli.providers.FlowProvider` and `gflow_cli.models` — superseded by `gflow_cli.api`.
303
+ - Legacy CLI stubs: `gflow upload`, `gflow generate`, `gflow status`, `gflow download`,
304
+ `gflow i2v`. Replaced by the wired `gflow video` subgroup.
305
+
306
+ ## [0.1.0] — _unreleased_
307
+
308
+ First skeleton. Not functional end-to-end yet.
309
+
310
+ [Unreleased]: https://github.com/ffroliva/gflow-cli/compare/v0.4.0a2...HEAD
311
+ [0.4.0a2]: https://github.com/ffroliva/gflow-cli/compare/v0.4.0a1...v0.4.0a2
312
+ [0.4.0a1]: https://github.com/ffroliva/gflow-cli/compare/v0.3.0a1...v0.4.0a1
313
+ [0.3.0a1]: https://github.com/ffroliva/gflow-cli/releases/tag/v0.3.0a1
314
+ [0.2.0a1]: https://github.com/ffroliva/gflow-cli/releases/tag/v0.2.0a1
315
+ [0.1.0]: https://github.com/ffroliva/gflow-cli/releases/tag/v0.1.0
@@ -4,7 +4,7 @@
4
4
 
5
5
  ## What this project is
6
6
 
7
- `flow-cli` is an unofficial Python CLI that drives [Google Flow](https://labs.google/fx/tools/flow) (Veo image-to-video, Imagen text-to-image) from the terminal by reverse-engineering Flow's private REST API at `aisandbox-pa.googleapis.com`. Built for Google AI Ultra/Pro subscribers who want to spend their Flow credits via batch automation rather than the web UI.
7
+ `gflow-cli` is an unofficial Python CLI that drives [Google Flow](https://labs.google/fx/tools/flow) (Veo image-to-video, Imagen text-to-image) from the terminal by reverse-engineering Flow's private REST API at `aisandbox-pa.googleapis.com`. Built for Google AI Ultra/Pro subscribers who want to spend their Flow credits via batch automation rather than the web UI.
8
8
 
9
9
  **Same pattern as `edge-tts`:** a community SDK over a private cloud API.
10
10
 
@@ -17,11 +17,23 @@
17
17
 
18
18
  ## Active phase
19
19
 
20
- **Phase 1Foundation** (refactor scaffold into layered structure, wire `pydantic-settings`, `structlog`, command/query bus). See [PLAN § Phase 1](PLAN.md#phase-1--foundation-target-12-days). Subset already landed: profile-store + `gflow auth` UX (commit `d821f39`).
20
+ **Phase 4Hardening DONE (v0.4.0a2).** Per-worker Page pool, tenacity
21
+ retry/backoff with reCAPTCHA re-mint, RFC 9457 Problem Details error
22
+ taxonomy with per-class exit codes 3–7, structlog observability with
23
+ `error_raised` / `error_unhandled` events, and 12 pytest-bdd scenarios all
24
+ shipped. Documentation polish landed in v0.4.0a2. Next phase TBD — likely
25
+ Phase 5 public alpha on PyPI followed by Phase 6 operations history
26
+ (see `PLAN.md`).
21
27
 
22
28
  ## Architecture (skim)
23
29
 
24
- Layered Clean / Hexagonal see **[docs/ARCHITECTURE.md](docs/ARCHITECTURE.md)** for the full diagram and rationale.
30
+ > Note: the layered diagram below describes the **target** architecture
31
+ > (deferred per [PLAN.md ADR #2](PLAN.md#5-decision-log-adrs-in-miniature)).
32
+ > The current package layout is the simpler
33
+ > `src/gflow_cli/{api/, cli.py, cli_image.py, cli_video.py, _cli_helpers.py,
34
+ > auth.py, config.py, errors.py, observability.py, paths.py,
35
+ > profile_store.py}`. See
36
+ > [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) for the full target shape.
25
37
 
26
38
  ```text
27
39
  interfaces/ → application/ → domain/ ← infrastructure/
@@ -37,19 +49,19 @@ Dependency rule: **`domain/` depends on nothing**. `application/` depends on `do
37
49
 
38
50
  - **Never commit secrets.** `.gitignore` excludes `auth/`, `profile_*/`, `*.cookies.json`, `storage_state.json`, `secrets.json`, `.env`, `.env.local`, `.env.*.local`. If you see one of these staged, abort and tell the user.
39
51
  - **Never add `Co-Authored-By: Claude` (or any AI co-author) to commit messages.** Author attribution is the human user's only.
40
- - **Sessions belong outside the repo.** Default location is `$LOCALAPPDATA/flow-cli/profile_*` (Windows) or `~/.local/share/flow-cli/profile_*` (POSIX) via [`platformdirs`](https://github.com/platformdirs/platformdirs). Never store sessions in `/tmp`, `%TEMP%`, or anywhere the OS auto-reaps.
41
- - **No `print()` in `src/`** — use `structlog` (or `logging` until structlog lands in Phase 1).
42
- - **Domain layer is pure** — `src/flow_cli/domain/*` must not import `application/`, `infrastructure/`, or `interfaces/`. No I/O, no frameworks.
52
+ - **Sessions belong outside the repo.** Default location is `$LOCALAPPDATA/gflow-cli/profile_*` (Windows) or `~/.local/share/gflow-cli/profile_*` (POSIX) via [`platformdirs`](https://github.com/platformdirs/platformdirs). Never store sessions in `/tmp`, `%TEMP%`, or anywhere the OS auto-reaps.
53
+ - **No raw `print()` and no `import logging` in `src/`** — use `structlog` for structured events, or Rich `console.print(...)` for user-facing output.
54
+ - **Domain layer is pure** — `src/gflow_cli/domain/*` must not import `application/`, `infrastructure/`, or `interfaces/`. No I/O, no frameworks.
43
55
  - **Frozen dataclasses for value objects.** Aggregates may have controlled mutation methods, but VOs (AspectRatio, Prompt, JobId, ...) are immutable.
44
56
  - **Async all the way down.** Handlers and providers are `async def`. CLI is the only place that calls `asyncio.run(...)`.
45
57
  - **TDD is non-negotiable.** Red → Green → Refactor → Commit. Coverage floor: **80% overall**, **90% on `domain/` and `application/`**. See [CONTRIBUTING.md](CONTRIBUTING.md).
46
58
 
47
59
  ## Coding conventions
48
60
 
49
- - **Python 3.11+**, strict typing (`pyright --strict` on `src/flow_cli/`), `from __future__ import annotations` at the top of every module.
61
+ - **Python 3.11+**, strict typing (`pyright --strict` on `src/gflow_cli/`), `from __future__ import annotations` at the top of every module.
50
62
  - **`@dataclass(frozen=True)`** for value objects and DTOs. `Protocol` for ports.
51
63
  - **`pathlib.Path`** everywhere — never raw strings for filesystem paths.
52
- - **Click + Rich** for the CLI, **httpx + Playwright** for I/O, **pytest + pytest-bdd** for tests.
64
+ - **Click + Rich** for the CLI, **Playwright `page.request`** as the HTTP transport (auto-attaches Google session cookies), **`tenacity`** for retry/backoff, **`structlog`** for structured logs, **`pytest + pytest-bdd`** for tests.
53
65
  - **Conventional Commits** for messages (`feat:`, `fix:`, `docs:`, `test:`, `chore:`, `refactor:`, etc.). See examples in `git log`.
54
66
  - **Short files, single responsibility.** ~200-400 lines typical, 800 max. Split into `package/<topic>.py` if growing.
55
67
 
@@ -61,7 +73,7 @@ Run all four BEFORE asking to commit:
61
73
  uv run ruff check src tests # lint
62
74
  uv run ruff format --check src tests # formatting
63
75
  uv run pyright src # types
64
- uv run pytest -q --cov=flow_cli # tests + coverage
76
+ uv run pytest -q --cov=gflow_cli # tests + coverage
65
77
  ```
66
78
 
67
79
  CI runs the same four on every push (see `.github/workflows/ci.yml`).
@@ -71,10 +83,10 @@ CI runs the same four on every push (see `.github/workflows/ci.yml`).
71
83
  | I need to… | Read this |
72
84
  |---|---|
73
85
  | Understand the architecture | [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) |
74
- | Add a CLI command | [docs/USAGE.md](docs/USAGE.md) + existing patterns in `src/flow_cli/cli.py` |
75
- | Add a Provider route | [PLAN.md § 4 Feature specs](PLAN.md#4-feature-specs) + existing stubs in `src/flow_cli/providers/flow.py` + capture data in `samples/captured_requests.json` |
86
+ | Add a CLI command | [docs/USAGE.md](docs/USAGE.md) + existing patterns in `src/gflow_cli/cli.py` |
87
+ | Add an API route | [PLAN.md § 4 Phase status](PLAN.md#4-phase-status) + existing client in `src/gflow_cli/api/client.py` + capture data under `samples/captured/` |
76
88
  | Touch auth | [docs/AUTHENTICATION.md](docs/AUTHENTICATION.md) |
77
- | Add a config knob | [docs/CONFIGURATION.md](docs/CONFIGURATION.md) + `.env.template` + (later) `src/flow_cli/shared/config.py` |
89
+ | Add a config knob | [docs/CONFIGURATION.md](docs/CONFIGURATION.md) + `.env.template` + (later) `src/gflow_cli/shared/config.py` |
78
90
  | Write a test | [CONTRIBUTING.md § TDD](CONTRIBUTING.md#test-driven-development-mandatory) + existing patterns in `tests/` |
79
91
  | Cut a release | [README § Releases](README.md#releases) — bump version in `pyproject.toml`, update CHANGELOG, `git tag vX.Y.Z`, push |
80
92
  | Track a known issue | [KNOWN_ISSUES.md](KNOWN_ISSUES.md) |
@@ -97,7 +109,7 @@ uv run gflow auth login --profile experiments # named profile
97
109
  2. `uv run pytest tests/<area>/test_<thing>.py` — verify it fails for the right reason.
98
110
  3. Implement the minimum production code to pass.
99
111
  4. Refactor.
100
- 5. `uv run pytest -q --cov=flow_cli` — verify nothing else broke and coverage didn't regress.
112
+ 5. `uv run pytest -q --cov=gflow_cli` — verify nothing else broke and coverage didn't regress.
101
113
 
102
114
  ### Update a doc
103
115
 
@@ -121,6 +133,8 @@ uv run gflow auth login --profile experiments # named profile
121
133
  - **Question scope creep.** If the user asks for X and you're tempted to also fix Y, ask first.
122
134
  - **Plan before implementing** for anything > 1 file or > 50 LoC. Write the plan into PLAN.md or a comment, then execute.
123
135
  - **Show your work.** When you change something non-obvious, leave a one-line comment with the WHY (not the WHAT — the diff already shows the what).
136
+ - **Fix bugs autonomously.** Given a bug report, reproduce it, trace the root cause, fix it, and verify — no hand-holding needed. Point at logs/errors/failing tests, then resolve them.
137
+ - **Learn from corrections.** After any user correction, append the pattern to `tasks/lessons.md` (create if absent) as a rule that prevents the same mistake. Review it at session start for relevant context.
124
138
 
125
139
  ## See also
126
140