Skip to content

ci: per-platform PyInstaller build + release workflow (#33)#63

Merged
massive-value merged 5 commits into
mainfrom
ci/33-pyinstaller-build-workflow
May 8, 2026
Merged

ci: per-platform PyInstaller build + release workflow (#33)#63
massive-value merged 5 commits into
mainfrom
ci/33-pyinstaller-build-workflow

Conversation

@massive-value

Copy link
Copy Markdown
Owner

Summary

  • Adds .github/workflows/release-binaries.yml: a four-target PyInstaller matrix (linux-x64, macos-x64, macos-arm64, windows-x64) that runs on v* tags and workflow_dispatch, builds a single-file wbox binary per target, computes its SHA-256, and attaches the four binaries plus a combined SHA256SUMS.txt manifest to the GitHub Release for the tag.
  • Adds scripts/wbox_entry.py: a tiny PyInstaller entry shim that imports and calls wealthbox_tools.cli.main:app. PyInstaller --onefile prefers a script file to a module:function reference, so the shim keeps the build invocation clean and avoids dynamic-import edge cases.
  • The existing publish (PyPI) job in ci.yml is untouched, satisfying the trusted-publisher constraint in CLAUDE.md. Both workflows fire on v* tags and operate independently.

Closes #33.

Manifest contract for #42 / #43

Downstream installer rewrites (#42 install.sh, #43 install.ps1) can rely on this contract being stable across releases:

  • Manifest filename: SHA256SUMS.txt
  • Format: standard sha256sum-compatible — one record per line, <hex-sha256><two-spaces><filename>
  • Sort order: ASCII-sorted by filename (deterministic across runs)
  • Binary filenames:
    • wbox-linux-x64
    • wbox-macos-arm64
    • wbox-macos-x64
    • wbox-windows-x64.exe
  • Asset location: all four binaries plus SHA256SUMS.txt are uploaded to the same GitHub Release for the tag, so installers can fetch <release-url>/<binary> and <release-url>/SHA256SUMS.txt from the same prefix.

The contract is also documented in a header comment block at the top of release-binaries.yml.

Design notes

  • New workflow file vs. extending ci.yml: chose a separate file. The 4-target matrix would clutter ci.yml, the trigger filter (v* tags + workflow_dispatch only — no PRs) is cleaner in isolation, the PyPI publish job stays trivially untouched, and this workflow can be disabled or re-run independently when debugging.
  • Runner labels: macos-13 for Intel x64 and macos-14 for Apple Silicon arm64. These are the conventional GitHub-hosted labels that produce the right native architecture without cross-compile.
  • Per-platform sums sidecar: each matrix job emits a <binary>.sha256 alongside its binary. The manifest-and-release job concatenates these into SHA256SUMS.txt, ASCII-sorts, and verifies with sha256sum -c before upload. The per-binary .sha256 files are not uploaded as release assets — SHA256SUMS.txt is the single source of truth for installers.
  • Permissions: matrix build jobs run with contents: read; only the manifest-and-release job is granted contents: write (needed for gh release upload).
  • Release creation: the upload step creates the release if missing (idempotent), then uploads with --clobber so re-runs don't fail.
  • workflow_dispatch gating: the upload step is gated on if: startsWith(github.ref, 'refs/tags/'). On a manual dispatch (no tag), the build + checksum + manifest-verify still run end-to-end, so the user can validate the whole pipeline without cutting a real release. A SHA256SUMS artifact is also uploaded for inspection.
  • Smoke test: each binary runs --version before checksumming, so a broken build fails fast.

Test plan

  • User triggers workflow_dispatch on a fork; all four matrix jobs succeed and produce a binary + sidecar sum
  • manifest-and-release job concatenates the four sidecars into SHA256SUMS.txt and the sha256sum -c verification passes
  • On a real v* tag push, the four binaries + SHA256SUMS.txt appear as assets on the GitHub Release
  • ci.yml publish job still runs and publishes to PyPI on the same tag (unchanged behaviour)

🤖 Generated with Claude Code

Adds .github/workflows/release-binaries.yml — a four-target matrix
(linux-x64, macos-x64, macos-arm64, windows-x64) that runs PyInstaller
on v* tags and attaches the binaries plus a SHA-256 manifest to the
GitHub Release.

Manifest contract (locked for downstream consumers #42, #43):
- Filename: SHA256SUMS.txt
- Format: standard sha256sum-compatible
- Binary names: wbox-<platform>[.exe]

The existing publish (PyPI) job in ci.yml is unchanged.

Closes #33

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 79def36bc3

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +84 to +88
pyinstaller \
--onefile \
--name "${{ matrix.binary }}" \
--noconfirm \
scripts/wbox_entry.py

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Bundle package data into PyInstaller binaries

For the released binaries, commands such as wbox skills install and wbox skills upgrade load wealthbox_tools/skills/wealthbox-crm via importlib.resources, but this PyInstaller invocation only includes the Python entry script/modules. PyInstaller’s documented options require adding non-code assets explicitly (--add-data) or collecting package data (--collect-data, “Collect all data from the specified package or module”), so the --version smoke test can pass while the binary omits the skill template and later fails when users run those commands. Please add the bundled skill data to both PyInstaller invocations and smoke-test a resource-backed command.

Useful? React with 👍 / 👎.

)

Codex auto-review P2: --version smoke test passes even if the binary
omits skills/wealthbox-crm, so users only discover the missing template
when running `wbox skills install` or `wbox skills upgrade`. Both load
wealthbox_tools/skills/wealthbox-crm via importlib.resources, which
PyInstaller does not bundle by default for non-Python assets.

Add --collect-data wealthbox_tools to both PyInstaller invocations
(Unix and Windows) so the entire skills/ tree is captured. Extend the
smoke test to invoke `skills install --platform claude-code-user
--no-bootstrap`, which exercises the bundled resource and fails the
build if --collect-data didn't pull the template in.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 03606819b3

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread .github/workflows/release-binaries.yml Outdated
target: linux-x64
binary: wbox-linux-x64
shell: bash
- os: macos-13 # Intel runner (x86_64)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Use a supported Intel macOS runner

This x64 build now targets macos-13, but GitHub’s Actions macOS 13 deprecation notice says the macos-13 label was retired in December 2025 and recommends labels such as macos-15-intel for x86_64 workloads. On current tag releases this matrix leg will never be scheduled, so the required build job fails and manifest-and-release cannot publish any binaries.

Useful? React with 👍 / 👎.

GitHub Actions retired the macos-13 label in December 2025 and recommends
macos-15-intel for x86_64 workloads going forward. With macos-13 the x64
matrix leg would never schedule on a real v* tag, failing the required
build job and blocking manifest-and-release from publishing any binaries.

Critical Codex P1 — fixed in PR rather than deferred to an issue because
this PR's entire purpose is producing release binaries; without a working
x64 macOS leg the workflow has zero release value.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: cd8d0c9faf

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +88 to +89
--collect-data wealthbox_tools \
scripts/wbox_entry.py

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Copy package metadata into the frozen binary

For these PyInstaller builds, the smoke test invokes --version, which calls importlib.metadata.version("wealthbox-cli") in src/wealthbox_tools/cli/main.py; PyInstaller’s docs state that distribution metadata is not collected by default and must be added with --copy-metadata/copy_metadata, while --collect-data wealthbox_tools only collects package data. As a result, every matrix binary can build successfully but then fail immediately at ./dist/${{ matrix.binary }} --version with PackageNotFoundError, preventing release assets from being published; add --copy-metadata wealthbox-cli to both PyInstaller invocations.

Useful? React with 👍 / 👎.

…es (PR #63)

PyInstaller's --collect-data only collects package data files; it does NOT
copy distribution metadata. Five modules call importlib.metadata.version
("wealthbox-cli") (cli/main.py, cli/doctor.py, cli/skills.py,
cli/_skill_bootstrap.py, firm/archive.py), so without --copy-metadata the
smoke-test step's `--version` invocation would raise PackageNotFoundError
on every matrix job, blocking manifest-and-release from publishing.

Codex P1 (3rd pass on PR #63). Like the macos-13 fix, this is the
exception case: workflow's whole purpose is producing release binaries,
so a dead smoke test means zero release value.

After this, the next signal worth acting on is workflow_dispatch on a
fork — Codex's static analysis has hit its limit; only running the
workflow exercises the full PyInstaller bundling chain.
…x context (PR #63)

GitHub Actions evaluates a step's `shell:` field before matrix expansion,
so `shell: ${{ matrix.shell }}` produces a workflow-syntax parse error
("Unrecognized named-value: 'matrix'") that blocks every trigger,
including workflow_dispatch. Three earlier push-events failed silently
for this reason.

Removing the matrix.shell references and the now-unused `shell:` keys
on matrix entries. The build steps that explicitly need pwsh (Windows
backtick line continuations) keep their hardcoded `shell: pwsh`; the
install/smoke-test steps fall back to GitHub's per-OS default (bash on
Linux/macOS, pwsh on Windows), which is exactly what matrix.shell was
specifying anyway.
@massive-value massive-value merged commit 133a96a into main May 8, 2026
10 checks passed
@massive-value massive-value deleted the ci/33-pyinstaller-build-workflow branch May 8, 2026 17:55
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.

PyInstaller per-platform build workflow

1 participant