Replies: 2 comments 1 reply
Option A deep-dive: full adoption planAssuming we proceed with Option A (full alignment with complyctl/org-infra + source-build Formulae), here is the detailed plan covering all four repos, Critical issue: Cask-to-Formula migration for existing usersHomebrew resolves
This is the single biggest UX risk in this migration and drives most of the sequencing below. Scope: 4 repos with near-identical release pipelines
All 4 use the same custom Per-repo changes (repeated 4x with minor variations)A. Release workflow (
|
| Cohort | Without migration help | With migration help (uf doctor) |
|---|---|---|
| Existing Cask users (most users) | brew upgrade silently does nothing or warns; old Cask orphaned; possible symlink conflict on next brew install |
uf doctor detects Cask, prints/runs brew uninstall --cask X && brew install <tap>/X |
| Existing Formula users (unbound-force only, Linux users) | brew upgrade works but now compiles from source (slower first time, needs Go) |
Same, with expectation-setting message |
| New users | brew install <tap>/X -> source build (slow first time, Homebrew auto-installs Go) |
Docs explain build-from-source; uf setup handles everything |
Recommended migration mechanics:
- Ship Formulae in a coordinated release across all 4 repos (dewey first -- it's a dependency of unbound-force).
- Add a one-time migration helper to
uf doctor/uf setupthat detects casks and offers to migrate. - Publish release notes + update
docs/INSTALLATION.mdwith the manual path:brew uninstall --cask unbound-force dewey gaze replicator 2>/dev/null brew install unbound-force/tap/unbound-force # uf setup handles dewey, gaze, replicator
- Post an org-level "Announcements" discussion.
- After ~2 release cycles, confirm old Cask files can be permanently removed from the tap (they may already be deleted at cutover, depending on decision below).
Suggested sequencing
This spans 4 repos, changes signatures/tests, and touches CI + release -- it warrants Speckit (cross-repo, >=3 stories per AGENTS.md).
| Phase | Scope | Risk | Description |
|---|---|---|---|
| 0. Spec + design | unbound-force (this repo) | None | Speckit spec covering org-infra release adoption + cask-to-formula migration + uf setup/doctor changes. Resolve ollama/dewey dep and migration UX in design. |
| 1. Swap preflight + GoReleaser | All 4 repos | Low | Replace hand-rolled preflight + GoReleaser jobs with reusable_release_preflight.yml + reusable_release_goreleaser.yml. Keep sign-macos temporarily. Ship one release cycle to verify. |
| 2. Formula cutover | dewey first, then gaze/replicator/unbound-force | Medium | Add source-build Formulae. Remove sign-macos jobs. Remove Casks from tap. Secret cleanup. GitHub App creation. |
3. uf setup/doctor migration |
unbound-force | Low | Migration detection helper + tests + docs. Can ship alongside or just after Phase 2. |
| 4. (Optional) Reusable Homebrew workflow | org-infra | Low | If both complyctl and unbound-force use the same Homebrew publishing pattern, propose extracting as reusable_release_homebrew.yml in org-infra. |
Open questions to resolve before spec
-
Migration aggressiveness: Should
uf doctor/uf setupautomatically runbrew uninstall --cask && brew install(with confirmation prompt), or just print the commands? Auto is friendlier but touches user's installed software. -
Casks: delete or transition? Clean cut (delete Casks on cutover day) vs. keep Casks for one release cycle with a deprecation notice in the Cask description. Clean cut is simpler but harder on existing users who don't read release notes.
-
dewey -> ollama dependency: Drop the Homebrew-level
depends_onfor ollama and rely onuf setup's explicitinstallOllama()instead? A Formula depending on a Cask (ollama-app) is fragile across platforms. The cleaner path may be no Homebrew dep +uf setupguarantees ollama. -
GoReleaser
brews:vs. inline heredoc: complyctl PR #742 uses an inline heredoc Formula template in the workflow (not GoReleaser'sbrews:). Match that exactly for org consistency and future reusable-workflow extraction? Or use GoReleaser's built-in Formula generation? -
Unsigned darwin binaries on Releases page: GoReleaser still uploads unsigned darwin tarballs to GitHub Releases (for direct download). OK with Gatekeeper
xattrprompt for manual-download users, given Homebrew users build from source? -
replicator arm64-only: Expand replicator's GoReleaser to build darwin/amd64 too (now cheap without signing), or leave as-is since source-build Formula covers all archs anyway?
-
Spec tier: Confirm Speckit (cross-repo umbrella) vs. one OpenSpec per repo. I lean Speckit given the coordinated tap changes and dependency ordering.
|
@jflowers & @hbraswelrh The discussion looks neat. Option A was actually the one I was suggesting in our messages to separate |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Context
The
complytime/org-infrarepository provides 30+ reusable GitHub Actions workflows for CI, security scanning, dependency management, and releasing. Several unbound-force repos already consume these workflows for CI (linting, vulnerability scanning, dependency review, CRAP analysis, scheduled scans). However, the release workflow remains fully custom in each repo.This discussion proposes adopting org-infra's release infrastructure across unbound-force repos, informed by how
complytime/complyctlconsumes it — and in particular by complyctl PR #742, which is actively adding Homebrew formula publishing to complyctl's release pipeline.Current State
What unbound-force already delegates to org-infra (5 of 7 workflows)
ci_checks.ymlreusable_ci.yml(MegaLinter + commitlint)ci_security.ymlreusable_vuln_scan.yml+reusable_security.ymlci_dependencies.ymlreusable_deps_reviewer.yml+reusable_dependabot_reviewer.ymlci_scheduled.ymlreusable_scheduled.ymlci_crapload.ymlreusable_crapload_analysis.ymlci_local.ymlrelease.ymlAll org-infra references are pinned to commit
0c784711...(v0.7.1).The unbound-force release pipeline today
The current
release.ymlis a 3-job, 399-line pipeline:preflightsort -V), CI check verification, unreleased commit check, tag creation, macOS signing secret detectionreleasesign-macosxcrun notarytool, checksum patching, Homebrew tap pushThis requires 8 secrets:
GITHUB_TOKEN,MACOS_SIGN_P12,MACOS_SIGN_PASSWORD,MACOS_SIGN_IDENTITY,MACOS_NOTARY_KEY,MACOS_NOTARY_KEY_ID,MACOS_NOTARY_ISSUER_ID,HOMEBREW_TAP_TOKEN.How complyctl does it (current + PR #742)
complyctl's release workflow is much simpler — two reusable workflow calls plus a new local Homebrew job:
Key design decision in PR #742: source-build Formula (Homebrew runs
go buildon the user's machine) instead of a pre-built binary Cask. This eliminates macOS signing entirely — no Apple Developer certificate, noxattrworkaround, no notarization.Comparison: unbound-force vs. complyctl release approach
reusable_release_preflight.ymlreusable_release_goreleaser.ymlHOMEBREW_TAP_TOKEN)actions/create-github-app-token)Options
Option A: Full alignment with complyctl pattern
Replace all three jobs with org-infra reusable workflows + source-build Formula.
Changes:
reusable_release_preflight.ymlreusable_release_goreleaser.ymlhomebrewjob (complyctl PR #742 pattern)homebrew_casksandbrewssections from.goreleaser.yaml(handle in workflow)actions/create-github-app-token(replaceHOMEBREW_TAP_TOKENPAT)Result: ~399 lines → ~80 lines. 0 macOS secrets. No macOS runner costs.
Trade-off: Users who download binaries directly from GitHub Releases (not via Homebrew) will get unsigned darwin binaries — macOS Gatekeeper will prompt them to
xattr -dr com.apple.quarantineon first run. Users who install viabrew installare unaffected.Option B: Adopt org-infra for preflight + GoReleaser, keep macOS signing
Delegate the first two jobs to org-infra but keep the sign-macos job custom.
Changes:
reusable_release_preflight.yml(add small local step forMACOS_SIGN_P12detection)reusable_release_goreleaser.yml(add follow-up job for cask/formula artifact upload)actions/create-github-app-tokenfor tap pushResult: ~399 lines → ~250 lines. Still 5+ macOS secrets. Still needs macOS runner.
Trade-off: Preserves signed binary Cask experience but keeps maintenance burden. Diverges from complytime org pattern.
Option C: Hybrid — source-build Formula + unsigned pre-built binaries
GoReleaser still produces darwin binaries on GitHub Releases (for users who want direct download), but Homebrew distribution switches to source-build Formula.
Changes:
1-2. Same as Option A (reusable preflight + GoReleaser)
3. Add simple
homebrewjob (complyctl pattern)4. Remove sign-macos job entirely
5. Remove
homebrew_caskssection from.goreleaser.yaml, keepbrewsasskip_upload: trueor removeResult: ~399 lines → ~100 lines. 0 macOS secrets. Darwin binaries still in Releases (unsigned).
Trade-off: Darwin binaries exist on Releases for manual download but aren't signed. Homebrew users get source-build (no signing needed). Middle ground.
Recommendation
Option A (full alignment) is the recommended target state, with phased adoption:
Phase 1 — Swap preflight + GoReleaser (low risk, immediate value)
reusable_release_preflight.ymlreusable_release_goreleaser.ymlPhase 2 — Switch to source-build Formula (after complyctl PR #742 merges)
homebrewjobactions/create-github-app-tokenPhase 3 — Evaluate reusable Homebrew workflow in org-infra
reusable_release_homebrew.ymlin org-infraRationale
Open Questions
Is the signed Cask experience important enough to justify the maintenance burden? Are there users who specifically need notarized macOS binaries (e.g., enterprise environments with strict Gatekeeper policies)?
GitHub App for unbound-force org: Do we already have one, or do we need to create one for the
actions/create-github-app-tokenpattern? The complyctl PR usesAPP_ID+PRIVATE_KEYsecrets scoped tohomebrew-tap.Other repos: Should replicator, dewey, or gaze adopt the same release workflow pattern? If so, the case for extracting a reusable Homebrew workflow into org-infra gets stronger.
Coordination with complytime: Should we coordinate with the complyctl PR #742 author about extracting the Homebrew publishing step into org-infra as a reusable workflow once the pattern is proven?
Timing: Should Phase 2 block on complyctl PR #742 merging (to learn from any issues they hit), or can we move independently?
References
All reactions