Skip to content

Homebrew tap, Python 3.12 floor, and install/CI hardening#26

Merged
alexkroman merged 12 commits into
mainfrom
claude/installation-paths-ci-Uhfly
Jun 6, 2026
Merged

Homebrew tap, Python 3.12 floor, and install/CI hardening#26
alexkroman merged 12 commits into
mainfrom
claude/installation-paths-ci-Uhfly

Conversation

@alexkroman

Copy link
Copy Markdown
Collaborator

Supersedes #25 (closed). Reworks the install story, adds a Homebrew tap, raises the supported-Python floor to match what CI tests, and hardens the workflows.

Install docs

  • README leads with pipx (recommended) + the curl | sh bootstrap; drops the standalone pip install --user "git+…" line, which increasingly fails under PEP 668 (install.sh still falls back to pip --user automatically when pipx is absent).
  • Adds a Homebrew install section.

Homebrew tap

  • Formula/aai.rb — a Language::Python::Virtualenv formula building aai from the v0.1.0 tag tarball with a pinned 48-package runtime closure. Declares ffmpeg, portaudio, openssl@3, python@3.13 (+ build-time rust/pkgconf) so brew install aai yields a working CLI; the Linux-only keyring deps (jeepney, secretstorage) are scoped to on_linux.
  • scripts/generate_brew_resources.py — offline resource generator from uv.lock (the plan's sanctioned fallback for brew update-python-resources).

⚠️ Release-gated: the formula's source sha256 is a placeholder until the v0.1.0 tag is cut. CI runs brew style (offline) on every PR; the stricter brew audit --strict --online and a real brew install/brew test build need the release and are intentionally deferred.

Python 3.12 floor

  • requires-python = ">=3.12", classifiers, and the mypy/pyright/ruff target-versions all bumped (CI only tests 3.12, so the old 3.11 floor over-claimed support). 3.13 stays supported (the formula ships python@3.13).
  • install.sh gate + messages and the doctor check moved to 3.12.
  • PEP 695 modernizations the py312 target now requires: def f[T](…) in auth/flow.py/output.py, type alias in streaming/macos.py.

CI hardening (ci.yml)

  • check job runs a 3.12 / 3.13 matrix (UV_PYTHON-pinned) so the shipped 3.13 runtime is actually tested.
  • New brew style job lints the formula on every PR.
  • pull_request trigger gains synchronize (PR checks re-run on each push); push scoped to main to avoid double-runs; concurrency cancels superseded non-main runs; timeout-minutes: 15 on every job.
  • A stable lint + typecheck + tests gate job re-publishes that context for branch protection (the matrix would otherwise suffix it (py3.12)/(py3.13) and leave the required check unsatisfiable).

Follow-ups (out of scope)

  • Cut the v0.1.0 release to fill the formula sha256 and enable the online audit/build.
  • Optionally point branch protection at the single lint + typecheck + tests gate so future matrix changes can't re-break the required check.

https://claude.ai/code/session_01Y6P9zAX4orQUNAJDc4zLdq


Generated by Claude Code

claude added 12 commits June 6, 2026 03:06
pipx is the recommended way to install a Python CLI, and the bare
`pip install --user "git+..."` command increasingly fails under PEP 668
externally-managed environments (Debian 12+, Ubuntu 23.04+, Homebrew).
install.sh still falls back to pip --user automatically when pipx is
absent, so pipx-less users remain covered by the curl|sh path.

https://claude.ai/code/session_01Y6P9zAX4orQUNAJDc4zLdq
Declare `depends_on "ffmpeg"` in the formula skeleton so `brew install
aai` yields a working CLI without a separate `brew install ffmpeg`.
ffmpeg is a runtime executable that transcribe/stream shell out to for
decoding non-WAV/URL audio (not a build/link dep of any Python package),
so it belongs alongside portaudio in the runtime depends_on list.

https://claude.ai/code/session_01Y6P9zAX4orQUNAJDc4zLdq
…l docs

Implements the in-repo Homebrew tap (Formula/aai.rb) from the tap plan:
a Language::Python::Virtualenv formula that builds aai from the v0.1.0
GitHub tag tarball and installs its 51-package runtime closure from
pinned resource stanzas. Native deps (portaudio, ffmpeg, openssl@3,
python@3.13, rust/pkgconf for builds) are declared via depends_on so
brew install yields a fully working CLI.

The resources were generated offline from uv.lock via the new
scripts/generate_brew_resources.py (plan Appendix A) since brew isn't
available in this environment; the two Linux-only keyring deps
(jeepney, secretstorage) are scoped to on_linux and the Windows-only
pywin32-ctypes is dropped. README documents the brew tap install path.

Pending before the tap goes live: cut the v0.1.0 release/tag on main to
fill the placeholder source sha256, then brew style/audit/install/test
on macOS to validate the build (neither possible in this Linux env).

https://claude.ai/code/session_01Y6P9zAX4orQUNAJDc4zLdq
CI only exercises Python 3.12, so the previous 3.11 floor (and the stale
3.10-3.13 note) over-claimed support. Bump the minimum to 3.12 across the
board: pyproject requires-python + classifiers, mypy/pyright/ruff target
versions, the install.sh runtime gate and its tests, the doctor check,
the README badge/prose, and AGENTS.md. 3.13 stays supported (the Homebrew
formula pins python@3.13 and audioop-lts backfills audioop there).

https://claude.ai/code/session_01Y6P9zAX4orQUNAJDc4zLdq
Two changes from a quality pass:
- Regenerate Formula/aai.rb against the post-3.12 uv.lock. Bumping
  requires-python to >=3.12 dropped three Python <=3.11 backports from
  the runtime closure (backports-tarfile, importlib-metadata, zipp), but
  the formula still carried them as phantom resources. Now 48 resources,
  matching the lock.
- Consolidate the per-line out.append() calls in the resource generator
  into one resource-block string (byte-identical output).

https://claude.ai/code/session_01Y6P9zAX4orQUNAJDc4zLdq
Add a lint-formula job that runs brew style on Formula/aai.rb via the
SHA-pinned Homebrew/actions/setup-homebrew action, so the formula gets
real Homebrew linting on every PR instead of only a ruby -c syntax check.

Scoped to brew style (offline) deliberately: the stricter
brew audit --strict --online and a brew install/test build need the real
source sha256, which stays a placeholder until the v0.1.0 tag is cut, so
those belong in a release-time job (tap plan Task 4/6).

https://claude.ai/code/session_01Y6P9zAX4orQUNAJDc4zLdq
The 3.12 bump set ruff target-version=py312, which activated PEP 695
modernization lints across the tree (I'd only linted changed files):
- UP047: use def f[T](...) generics in auth/flow.py and output.py
- UP040: use the 'type' keyword for the alias in streaming/macos.py

The new brew style job also flagged two real formula offenses:
- DependencyOrder: sort the runtime depends_on (ffmpeg before openssl@3/portaudio)
- ComponentsOrder: move the on_linux block above the resource stanzas

https://claude.ai/code/session_01Y6P9zAX4orQUNAJDc4zLdq
CI previously tested only 3.12 while the Homebrew formula ships
python@3.13 and the classifiers claim 3.13 — an untested shipped runtime.
Matrix the check job over [3.12, 3.13] (fail-fast off) and pin UV_PYTHON
to the matrix version so check.sh's uv run/build actually exercise each
interpreter. Verified the full suite passes on both locally.

https://claude.ai/code/session_01Y6P9zAX4orQUNAJDc4zLdq
…aths-ci-Uhfly

# Conflicts:
#	aai_cli/output.py
Add 'synchronize' to the pull_request trigger types so a PR's checks
re-run on every new commit, instead of going stale at the run from when
the PR was opened/reopened.

https://claude.ai/code/session_01Y6P9zAX4orQUNAJDc4zLdq
- Scope push to main: PRs are now covered by the pull_request trigger
  (incl. synchronize), so pushing a PR commit no longer fires both a push
  and a pull_request run for the same SHA.
- Add a concurrency group that cancels superseded PR/branch runs on a new
  push, while never cancelling a main run.
- Add timeout-minutes: 15 to every job so a hung step fails fast instead
  of burning toward GitHub's 6-hour default.

Trade-off: branches without an open PR no longer auto-run CI; they run
once a PR is opened (which also fixes fork-PR coverage).

https://claude.ai/code/session_01Y6P9zAX4orQUNAJDc4zLdq
…ection

The py3.12/py3.13 matrix renamed the check contexts to '... (py3.12)' and
'... (py3.13)', so the branch-protection rule requiring the un-suffixed
'lint + typecheck + tests' could never be satisfied and blocked the PR.

Add a check-result gate job that re-publishes that exact name, green only
when every matrix cell passed (if: always() + explicit result check, so a
failed/skipped/cancelled matrix can't satisfy it). Pointing branch
protection at this one stable name also makes future matrix changes safe.

https://claude.ai/code/session_01Y6P9zAX4orQUNAJDc4zLdq
@alexkroman alexkroman merged commit 7baf760 into main Jun 6, 2026
19 checks passed
@alexkroman alexkroman deleted the claude/installation-paths-ci-Uhfly branch June 6, 2026 20:09
alexkroman pushed a commit that referenced this pull request Jun 6, 2026
The Python floor moved to 3.12 (PR #26), so ruff's UP047 now requires the
inline generic syntax instead of a module-level TypeVar.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants