Skip to content

Add Homebrew tap support#14

Merged
agarcher merged 9 commits intomainfrom
homebrew
Jan 11, 2026
Merged

Add Homebrew tap support#14
agarcher merged 9 commits intomainfrom
homebrew

Conversation

@agarcher
Copy link
Owner

@agarcher agarcher commented Jan 11, 2026

Summary

  • Add Homebrew formula template and automatic tap updates on release
  • Release workflow extracts SHA256 checksums and updates agarcher/homebrew-tap
  • Use deploy key (more secure than PAT) for cross-repo authentication
  • Skip tap updates for pre-release versions (-rc, -beta, -alpha)

Setup required

  1. Create homebrew-tap repo with Formula/ directory
  2. Add deploy key (public) to tap repo with write access
  3. Add deploy key (private) as TAP_DEPLOY_KEY secret to this repo

Installation (after setup)

brew install agarcher/tap/wt

Test plan

  • Create tap repo with initial commit
  • Configure deploy key
  • Tag a release and verify formula is updated in tap
  • Test brew install agarcher/tap/wt

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Homebrew support for macOS (Intel & Apple Silicon) and Linux (x86_64 & ARM64) with platform-specific binaries, checksums, and automatic formula updates on each release
    • New release workflow: make release <major|minor|patch> that bumps version, tags, and publishes releases
  • Documentation

    • README and release docs updated with Homebrew install instructions, release guidance, and renamed project references

✏️ Tip: You can customize this high-level summary in your review settings.

agarcher and others added 2 commits January 11, 2026 11:47
- Add Formula/wt.rb template for Homebrew distribution
- Update release workflow to publish to agarcher/homebrew-tap on release
- Extract and pass SHA256 checksums for all platform binaries
- Skip tap update for pre-release versions (-rc, -beta, -alpha)
- Update README with brew install instructions
- Mark Homebrew support complete in implementation plan

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
More secure approach - deploy key is scoped to single repo only.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@coderabbitai
Copy link

coderabbitai bot commented Jan 11, 2026

📝 Walkthrough

Walkthrough

Adds a VERSION-driven release flow: Makefile target and scripts to bump, tag, and push releases; GitHub Actions now emit tag/version and per-OS/arch checksums and update a Homebrew tap; includes a Homebrew formula template and generator; README, docs, and release guidance updated.

Changes

Cohort / File(s) Summary
Release Scripts
scripts/release.sh, scripts/generate-formula.sh
New: release.sh bumps VERSION, commits, tags, and pushes; generate-formula.sh renders homebrew-formula.tmpl from env vars (VERSION + per-OS/arch SHAs`) and validates required variables.
Homebrew Formula Template
scripts/homebrew-formula.tmpl
New Homebrew formula template with per-arch URL/SHA placeholders, install/completions, caveats, and a version test.
CI/CD Workflow
.github/workflows/release.yml
release job now exposes outputs tag, version, and sha_* per platform; adds an "Extract checksums" step; adds top-level update-homebrew job that clones the tap, generates the formula, commits, and pushes on non-prerelease releases.
Makefile & Build
Makefile
Added release target delegating to scripts/release.sh; VERSION now prefers a VERSION file; added catch-all pattern and help text for release.
Version File
VERSION
New file initialized to 0.0.0.
Docs & Guidance
README.md, IMPLEMENTATION_PLAN.md, .claude/commands/release.md, docs/RELEASE_TEST_PLAN.md
README updated for wt naming and release flow; implementation plan marks Homebrew CI complete; added interactive release guidance and a release test plan.

Sequence Diagram(s)

sequenceDiagram
    actor Developer
    participant Makefile
    participant ReleaseScript as scripts/release.sh
    participant Git
    participant GH_Actions as "GitHub Actions (release)"
    participant FormulaGen as scripts/generate-formula.sh
    participant HomebrewTap as "Homebrew Tap Repo"

    Developer->>Makefile: make release <major|minor|patch> "notes"
    Makefile->>ReleaseScript: ./scripts/release.sh <bump> "notes"
    ReleaseScript->>ReleaseScript: read/parse VERSION, compute new version
    ReleaseScript->>Git: commit VERSION, tag v<NEW_VERSION>, push
    Git->>GH_Actions: trigger release workflow
    GH_Actions->>GH_Actions: build binaries, produce checksums.txt
    GH_Actions->>GH_Actions: extract per-OS/arch SHAs (outputs)
    GH_Actions->>FormulaGen: run with VERSION + SHAs
    FormulaGen->>GH_Actions: emit formula file
    GH_Actions->>HomebrewTap: clone tap, commit formula, push
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐇 I nudged the VERSION, gave it a hop,

tags and checksums gathered in a crop,
templates stitched and scripts set true,
make a release — bottles brew anew,
nibble the bytes and hop for you! 🥕

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title accurately describes the main change: adding Homebrew tap support and automatic updates on release, which is clearly reflected in the workflow changes, formula template, and release automation.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In @.github/workflows/release.yml:
- Around line 178-183: The workflow and the Formula file are inconsistent:
update Formula/wt.rb to use the same placeholders (VERSION_PLACEHOLDER,
SHA_DARWIN_AMD64_PLACEHOLDER, SHA_DARWIN_ARM64_PLACEHOLDER,
SHA_LINUX_AMD64_PLACEHOLDER, SHA_LINUX_ARM64_PLACEHOLDER) instead of the
hardcoded "0.1.0" and fixed SHAs so the sed replacements in
.github/workflows/release.yml actually apply; alternatively, if wt.rb is
intended to be final, change the workflow to inject the concrete version/SHAs
rather than using placeholders—choose one source of truth (preferably a template
wt.rb with placeholders) and align the placeholders between wt.rb and the
release workflow.
🧹 Nitpick comments (3)
.github/workflows/release.yml (3)

67-74: Consider more robust checksum extraction.

The current implementation uses cut -d' ' -f1 which assumes a single space delimiter. However, sha256sum outputs two spaces between the hash and filename. While cut will work (treating consecutive delimiters as one field), using awk would be more explicit and robust.

♻️ More robust checksum extraction
       - name: Extract checksums
         id: checksums
         run: |
           cd dist
-          echo "SHA_DARWIN_AMD64=$(grep wt-darwin-amd64.tar.gz checksums.txt | cut -d' ' -f1)" >> $GITHUB_OUTPUT
-          echo "SHA_DARWIN_ARM64=$(grep wt-darwin-arm64.tar.gz checksums.txt | cut -d' ' -f1)" >> $GITHUB_OUTPUT
-          echo "SHA_LINUX_AMD64=$(grep wt-linux-amd64.tar.gz checksums.txt | cut -d' ' -f1)" >> $GITHUB_OUTPUT
-          echo "SHA_LINUX_ARM64=$(grep wt-linux-arm64.tar.gz checksums.txt | cut -d' ' -f1)" >> $GITHUB_OUTPUT
+          echo "SHA_DARWIN_AMD64=$(grep wt-darwin-amd64.tar.gz checksums.txt | awk '{print $1}')" >> $GITHUB_OUTPUT
+          echo "SHA_DARWIN_ARM64=$(grep wt-darwin-arm64.tar.gz checksums.txt | awk '{print $1}')" >> $GITHUB_OUTPUT
+          echo "SHA_LINUX_AMD64=$(grep wt-linux-amd64.tar.gz checksums.txt | awk '{print $1}')" >> $GITHUB_OUTPUT
+          echo "SHA_LINUX_ARM64=$(grep wt-linux-arm64.tar.gz checksums.txt | awk '{print $1}')" >> $GITHUB_OUTPUT

103-176: Consider eliminating formula duplication.

The formula template is defined in two places:

  1. Formula/wt.rb in the main repository (lines 1-61)
  2. Inline heredoc in this workflow (lines 114-176)

This creates a maintenance burden where changes must be synchronized manually. The workflow could instead read from Formula/wt.rb and replace placeholders.

♻️ Use Formula/wt.rb as the single source of truth

First, update Formula/wt.rb to use the placeholder format:

-  version "0.1.0"
+  version "VERSION_PLACEHOLDER"

And update the SHA256 lines to match the workflow placeholders (they already do).

Then modify the workflow to use the file:

       - name: Update formula
         env:
           VERSION: ${{ needs.release.outputs.version }}
           SHA_DARWIN_AMD64: ${{ needs.release.outputs.sha_darwin_amd64 }}
           SHA_DARWIN_ARM64: ${{ needs.release.outputs.sha_darwin_arm64 }}
           SHA_LINUX_AMD64: ${{ needs.release.outputs.sha_linux_amd64 }}
           SHA_LINUX_AMD64: ${{ needs.release.outputs.sha_linux_arm64 }}
         run: |
           # Strip the 'v' prefix from version for formula
           FORMULA_VERSION="${VERSION#v}"
 
-          cat > homebrew-tap/Formula/wt.rb << 'EOF'
-          # typed: false
-          ...
-          EOF
+          # Checkout the main repo to get Formula/wt.rb
+          git clone --depth 1 --branch ${VERSION} https://github.com/agarcher/wt.git wt-source
+          cp wt-source/Formula/wt.rb homebrew-tap/Formula/wt.rb
 
           # Replace placeholders with actual values
           sed -i "s/VERSION_PLACEHOLDER/${FORMULA_VERSION}/g" homebrew-tap/Formula/wt.rb
           ...

This ensures the formula template is maintained in one place.


185-192: Add idempotency handling for formula updates.

If the workflow runs multiple times for the same version (e.g., manual re-run), the git commit will fail if there are no changes. This could cause the job to fail unnecessarily.

♻️ Handle no-changes scenario gracefully
       - name: Commit and push
         run: |
           cd homebrew-tap
           git config user.name "github-actions[bot]"
           git config user.email "github-actions[bot]@users.noreply.github.com"
           git add Formula/wt.rb
-          git commit -m "Update wt to ${{ needs.release.outputs.version }}"
-          git push
+          if git diff --staged --quiet; then
+            echo "No changes to formula, skipping commit"
+          else
+            git commit -m "Update wt to ${{ needs.release.outputs.version }}"
+            git push
+          fi
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7606402 and c4a3b0d.

📒 Files selected for processing (4)
  • .github/workflows/release.yml
  • Formula/wt.rb
  • IMPLEMENTATION_PLAN.md
  • README.md
🔇 Additional comments (11)
README.md (1)

32-36: LGTM! Documentation correctly reflects the new Homebrew formula.

The heading and installation command updates are consistent with the new Formula/wt.rb implementation and accurately reflect the transition from placeholder to active Homebrew support.

IMPLEMENTATION_PLAN.md (3)

12-12: LGTM! Status update accurately reflects the completed Homebrew integration.


310-337: LGTM! Comprehensive and secure Homebrew tap setup documentation.

The setup instructions are thorough and follow best practices:

  • Uses deploy keys (repo-scoped) rather than PATs (user-scoped)
  • Ed25519 key type is modern and secure
  • Clear step-by-step instructions for tap creation and secret configuration
  • Correctly documents auto-update behavior for non-prerelease versions

379-379: LGTM! Implementation order correctly marked as complete.

Formula/wt.rb (5)

10-32: LGTM! OS/architecture source blocks are correctly structured.

The formula properly:

  • Covers all four target platforms (macOS/Linux × amd64/arm64)
  • Uses correct Homebrew DSL (on_macos, on_linux, on_intel, on_arm)
  • References the correct archive names matching release.yml build output
  • Uses placeholders that align with the workflow's sed replacement patterns

43-56: LGTM! Post-install caveats provide clear shell integration guidance.

The instructions are well-formatted and consistent with the documentation in README.md.


7-7: This formula file is not used by the release workflow.

The release.yml workflow does not update the version in Formula/wt.rb. Instead, it generates a completely new Formula/wt.rb in the homebrew-tap repository using its own embedded template with VERSION_PLACEHOLDER, which it then replaces via sed. The "0.1.0" version in the main repo's Formula/wt.rb will not be replaced by any workflow step and should either be removed or clearly marked as a template.

Likely an incorrect or invalid review comment.


34-41: Install method correctly implements binary selection and completion generation.

The method properly:

  1. Derives the binary name matching release artifacts (wt-{darwin|linux}-{amd64|arm64})
  2. Installs with correct renaming to wt
  3. Generates completions—the wt binary includes a completion subcommand supporting bash, zsh, fish, and powershell, which integrates properly with Homebrew's generate_completions_from_executable helper

58-60: The Homebrew test is broken and will fail.

The test calls wt --version expecting a global flag, but the code only implements a version subcommand. Running wt --version will fail with an unknown flag error. Change the test to use shell_output("#{bin}/wt version") instead, or configure the Go code to support the --version flag via rootCmd.Version = Version in the root command setup.

⛔ Skipped due to learnings
Learnt from: CR
Repo: agarcher/worktree PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-11T16:15:07.592Z
Learning: Applies to Makefile : Set version at build time via LDFLAGS: -X github.com/agarcher/wt/internal/commands.Version=$(VERSION)
.github/workflows/release.yml (2)

15-20: LGTM! Job outputs are correctly structured.

The outputs properly expose the version and per-platform SHA256 values for use in the downstream update-homebrew job.


88-102: LGTM! Secure SSH-based tap repository access.

The job properly:

  • Filters out prerelease versions
  • Uses deploy key for cross-repo access (more secure and scoped than PAT)
  • Configures SSH agent correctly
  • Clones via SSH URL

The TAP_DEPLOY_KEY secret is documented in the setup instructions.

agarcher and others added 3 commits January 11, 2026 13:25
- Add VERSION file (starting at 0.0.0) as single source of truth
- Add scripts/homebrew-formula.tmpl as single formula template
- Add scripts/generate-formula.sh to generate formula from template
- Add scripts/release.sh for automated releases (bump, commit, tag, push)
- Update Makefile with positional args: make release patch "notes"
- Update release workflow to use generate-formula.sh
- Remove duplicate Formula/wt.rb

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Automates release process by analyzing commits since last tag,
generating release notes, and prompting for approval before running.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In @.github/workflows/release.yml:
- Around line 15-20: Strip the leading "v" from the VERSION output and quote
$GITHUB_OUTPUT when writing workflow outputs: update the step that emits
outputs.version (steps.version.outputs.VERSION) to set/version without a leading
"v" (e.g., trim the leading "v" before using it in LDFLAGS so the binary reports
"1.2.3" not "v1.2.3"), and ensure any echo to $GITHUB_OUTPUT is quoted (use
"$GITHUB_OUTPUT") for shell safety in the steps that set outputs.version and the
checksum outputs (sha_darwin_amd64, sha_darwin_arm64, sha_linux_amd64,
sha_linux_arm64).

In @README.md:
- Around line 265-274: Update the release docs to state that CI reads the
version from the pushed git tag (e.g., tag "vX.Y.Z") and distinguish that from
the VERSION file content ("X.Y.Z"); explicitly document whether tags must
include the "v" prefix and how the make release commands produce tags. Either
require tag format "vX.Y.Z" in the README release section or note that the
GitHub Actions workflow strips a leading "v" before embedding the version and
updating the Homebrew formula; if choosing the latter, update the workflow to
strip the "v" prefix consistently so built binaries and the Homebrew formula use
"X.Y.Z".

In @scripts/homebrew-formula.tmpl:
- Around line 4-32: Update the Homebrew formula to use the correct GitHub repo
slug by replacing "agarcher/wt" with "agarcher/worktree" in homepage and all url
entries; change any test that runs the binary to call the subcommand "wt
version" (not the flag "--version") and strip the leading "wt version " prefix
from the output before comparing to version.to_s; and replace any CPU
architecture checks that use Hardware::CPU.arch == :arm64 (or similar) with
Hardware::CPU.intel? to correctly branch between Intel and Apple Silicon when
selecting the amd64 vs arm64 tarball URLs.
🧹 Nitpick comments (3)
scripts/generate-formula.sh (1)

4-16: Fix doc/behavior mismatch (output-file) and validate template exists.

Currently the script advertises [output-file] but doesn’t use $1; also it will emit a confusing sed error if the template path is wrong.

Proposed diff
 # Generate Homebrew formula from template
-# Usage: generate-formula.sh [output-file]
+# Usage: generate-formula.sh  # writes formula to stdout
@@
 TEMPLATE="${SCRIPT_DIR}/homebrew-formula.tmpl"
+
+if [[ ! -f "$TEMPLATE" ]]; then
+    echo "Error: template not found: $TEMPLATE" >&2
+    exit 1
+fi

Also applies to: 25-31

scripts/release.sh (1)

29-96: Add guardrails: validate semver + git state before committing/tagging/pushing.

Right now malformed VERSION (or being on the wrong branch / dirty tree / tag already exists) will fail mid-flight or, worse, create an unintended commit/tag.

Proposed diff
 cd "$REPO_ROOT"
+
+# Safety checks
+if [[ "$(git branch --show-current)" != "main" ]]; then
+    echo "Error: releases must be cut from branch 'main'" >&2
+    exit 1
+fi
+if ! git diff --quiet || ! git diff --cached --quiet; then
+    echo "Error: working tree is not clean" >&2
+    exit 1
+fi
@@
 CURRENT_VERSION=$(cat "$VERSION_FILE" | tr -d '[:space:]')
+if [[ ! "$CURRENT_VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
+    echo "Error: VERSION must be MAJOR.MINOR.PATCH, got: $CURRENT_VERSION" >&2
+    exit 1
+fi
@@
 NEW_VERSION="${MAJOR}.${MINOR}.${PATCH}"
+if git rev-parse -q --verify "refs/tags/v${NEW_VERSION}" >/dev/null; then
+    echo "Error: tag v${NEW_VERSION} already exists" >&2
+    exit 1
+fi
.github/workflows/release.yml (1)

88-125: Harden update-homebrew: ensure known_hosts + don’t fail on “no changes”.

This job will be more reliable if it (a) guarantees github.com is in known_hosts before git clone, and (b) skips commit/push cleanly when rerun with identical content.

Proposed diff
   update-homebrew:
@@
       - name: Clone tap repository
-        run: git clone git@github.com:agarcher/homebrew-tap.git homebrew-tap
+        run: |
+          mkdir -p ~/.ssh
+          ssh-keyscan -H github.com >> ~/.ssh/known_hosts
+          git clone git@github.com:agarcher/homebrew-tap.git homebrew-tap
@@
       - name: Generate and update formula
         env:
           VERSION: ${{ needs.release.outputs.version }}
@@
         run: |
-          # Strip the 'v' prefix from version for formula
-          export VERSION="${VERSION#v}"
           ./scripts/generate-formula.sh > homebrew-tap/Formula/wt.rb
@@
       - name: Commit and push
         run: |
           cd homebrew-tap
@@
           git add Formula/wt.rb
-          git commit -m "Update wt to ${{ needs.release.outputs.version }}"
-          git push
+          if git diff --cached --quiet; then
+            echo "No formula changes."
+            exit 0
+          fi
+          git commit -m "Update wt to v${{ needs.release.outputs.version }}"
+          git push
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c4a3b0d and a57c539.

📒 Files selected for processing (8)
  • .claude/commands/release.md
  • .github/workflows/release.yml
  • Makefile
  • README.md
  • VERSION
  • scripts/generate-formula.sh
  • scripts/homebrew-formula.tmpl
  • scripts/release.sh
✅ Files skipped from review due to trivial changes (2)
  • .claude/commands/release.md
  • VERSION
🧰 Additional context used
📓 Path-based instructions (1)
Makefile

📄 CodeRabbit inference engine (CLAUDE.md)

Makefile: Build for current platform outputs to build/wt using make build
Set version at build time via LDFLAGS: -X github.com/agarcher/wt/internal/commands.Version=$(VERSION)

Files:

  • Makefile
🧠 Learnings (4)
📚 Learning: 2026-01-11T16:15:07.592Z
Learnt from: CR
Repo: agarcher/worktree PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-11T16:15:07.592Z
Learning: Applies to Makefile : Set version at build time via LDFLAGS: -X github.com/agarcher/wt/internal/commands.Version=$(VERSION)

Applied to files:

  • Makefile
📚 Learning: 2026-01-11T16:15:07.592Z
Learnt from: CR
Repo: agarcher/worktree PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-11T16:15:07.592Z
Learning: Applies to Makefile : Build for current platform outputs to build/wt using `make build`

Applied to files:

  • Makefile
📚 Learning: 2026-01-11T16:15:07.592Z
Learnt from: CR
Repo: agarcher/worktree PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-11T16:15:07.592Z
Learning: Applies to internal/hooks/**/*.go : Pass standardized hook environment variables: WT_NAME, WT_PATH, WT_BRANCH, WT_REPO_ROOT, WT_WORKTREE_DIR

Applied to files:

  • Makefile
📚 Learning: 2026-01-11T16:15:07.592Z
Learnt from: CR
Repo: agarcher/worktree PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-11T16:15:07.592Z
Learning: Run linting with `make lint` to execute go vet and golangci-lint

Applied to files:

  • Makefile
🪛 actionlint (1.7.10)
.github/workflows/release.yml

69-69: shellcheck reported issue in this script: SC2086:info:2:89: Double quote to prevent globbing and word splitting

(shellcheck)


69-69: shellcheck reported issue in this script: SC2086:info:3:89: Double quote to prevent globbing and word splitting

(shellcheck)


69-69: shellcheck reported issue in this script: SC2086:info:4:87: Double quote to prevent globbing and word splitting

(shellcheck)


69-69: shellcheck reported issue in this script: SC2086:info:5:87: Double quote to prevent globbing and word splitting

(shellcheck)


69-69: shellcheck reported issue in this script: SC2129:style:2:1: Consider using { cmd1; cmd2; } >> file instead of individual redirects

(shellcheck)

🪛 checkmake (0.2.2)
Makefile

[warning] 1-1: Missing required phony target "all"

(minphony)

🔇 Additional comments (5)
README.md (1)

32-36: No action required. The repository and Homebrew references are correctly configured.

The README correctly references github.com/agarcher/worktree (the repository location) while the Homebrew formula, workflow, and Go module all correctly use github.com/agarcher/wt (the Go module path defined in go.mod). These are separate, complementary identifiers—not inconsistent naming. The formula properly references releases from the correct module path, and brew install agarcher/tap/wt will work as intended.

Likely an incorrect or invalid review comment.

Makefile (4)

1-1: LGTM: Correctly added release to .PHONY.

The release target is properly declared as phony since it doesn't produce a file. The static analysis warning about missing "all" is a false positive—the all target is defined on line 14.


3-4: LGTM: VERSION fallback chain correctly implemented.

The priority order (VERSION file → git describe → "dev") aligns with the PR objectives to use the VERSION file as the single source of truth, with appropriate fallbacks for development scenarios.


60-69: LGTM: Positional argument handling correctly implemented.

The release target properly delegates to scripts/release.sh with arguments forwarded via $(filter-out $@,$(MAKECMDGOALS)). The catch-all pattern rule (%: @:) is necessary to prevent Make from treating positional arguments (e.g., patch, "Fix bug") as unknown targets—this is a standard Make idiom for this use case.


81-81: LGTM: Help documentation is clear and accurate.

The help text correctly documents the release target usage with appropriate examples.

Formula template:
- Fix repo slug: agarcher/wt -> agarcher/worktree
- Fix CPU detection: use Hardware::CPU.intel? instead of arch check
- Fix test: use `wt version` subcommand instead of --version flag

Release workflow:
- Strip v prefix at source (VERSION without v, TAG with v)
- Quote $GITHUB_OUTPUT for shell safety
- Use grep -F and awk for safer checksum extraction

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In @.github/workflows/release.yml:
- Around line 104-107: Update the GitHub Actions step that uses the webfactory
SSH agent by changing the referenced action version from
"webfactory/ssh-agent@v0.9.0" to "webfactory/ssh-agent@v0.9.1" in the Set up SSH
key step so the workflow uses the latest stable release.
🧹 Nitpick comments (1)
.github/workflows/release.yml (1)

121-128: Add --allow-empty or check for changes before committing.

If the formula file hasn't changed (e.g., re-running the workflow for the same version), git commit will fail with "nothing to commit", causing the job to fail.

♻️ Proposed fix to handle no-change scenario
       - name: Commit and push
         run: |
           cd homebrew-tap
           git config user.name "github-actions[bot]"
           git config user.email "github-actions[bot]@users.noreply.github.com"
           git add Formula/wt.rb
-          git commit -m "Update wt to ${{ needs.release.outputs.tag }}"
-          git push
+          if git diff --cached --quiet; then
+            echo "No changes to commit"
+          else
+            git commit -m "Update wt to ${{ needs.release.outputs.tag }}"
+            git push
+          fi
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a57c539 and e3f4799.

📒 Files selected for processing (2)
  • .github/workflows/release.yml
  • scripts/homebrew-formula.tmpl
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2026-01-11T16:15:07.592Z
Learnt from: CR
Repo: agarcher/worktree PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-11T16:15:07.592Z
Learning: Applies to Makefile : Set version at build time via LDFLAGS: -X github.com/agarcher/wt/internal/commands.Version=$(VERSION)

Applied to files:

  • .github/workflows/release.yml
  • scripts/homebrew-formula.tmpl
🔇 Additional comments (9)
scripts/homebrew-formula.tmpl (5)

1-8: LGTM on formula metadata.

The formula header with pragmas, description, homepage, version placeholder, and license is correctly structured for Homebrew.


10-32: Platform blocks look correct.

The on_macos/on_linux with nested on_intel/on_arm blocks properly handle the four platform combinations. The URL and SHA placeholders align with the workflow's build outputs.


34-40: Install method correctly maps CPU architecture.

The use of Hardware::CPU.intel? and OS.kernel_name.downcase is idiomatic Homebrew. The binary naming convention (wt-darwin-amd64, etc.) matches what the release workflow builds. Completion generation from executable is the standard approach.


42-55: Caveats provide clear shell integration instructions.

The heredoc covers zsh, bash, and fish with appropriate config file paths. This aligns with the wt init subcommand pattern.


57-59: Test block validates version output.

The test uses assert_match version.to_s against the wt version output, which will verify the installed binary reports the expected version.

.github/workflows/release.yml (4)

15-21: Outputs properly expose release artifacts.

The job outputs cleanly expose the tag, version, and all four platform checksums for downstream jobs. The naming is consistent and matches the checksum extraction step.


44-47: Version extraction is correct.

The parameter expansion ${GITHUB_REF#refs/tags/} correctly extracts the tag, and ${tag#v} strips the leading 'v'. Quoting "$GITHUB_OUTPUT" is proper shell practice.


71-80: Checksum extraction is robust.

Using grep -F for literal string matching and awk '{print $1}' is safer than regex patterns. The grouped output with { } >> "$GITHUB_OUTPUT" is clean.


94-99: Job structure and prerelease skip logic looks good.

The needs: release dependency ensures checksums are available, and the if condition correctly excludes prereleases using the same pattern as the release step.

Comment on lines +104 to +107
- name: Set up SSH key
uses: webfactory/ssh-agent@v0.9.0
with:
ssh-private-key: ${{ secrets.TAP_DEPLOY_KEY }}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check latest release of webfactory/ssh-agent using GitHub API
gh api repos/webfactory/ssh-agent/releases/latest --jq '.tag_name, .name, .published_at' 2>/dev/null || echo "API call failed or gh CLI not available"

Repository: agarcher/worktree

Length of output: 95


🌐 Web query:

webfactory ssh-agent v0.9.0 security vulnerabilities CVE

💡 Result:

Short answer: There are no publicly recorded CVEs that affect webfactory/ssh-agent v0.9.0. [1][2]

Notes / context:

  • The project's release notes show v0.9.0 (Node 20 update) and the repo issues but no CVE/security advisory for that tag. [1][3]
  • Security scanners/advisors for the action report no known vulnerabilities (but flag other non-CVE concerns like maintenance/score issues). [2]
  • There are unrelated CVEs involving other "ssh-agent" projects (e.g., Jenkins SSH Agent plugin CVE-2018-1999036 and older OpenSSH issues) — these are different projects and do not indicate a CVE for webfactory/ssh-agent v0.9.0. [4][5]

If you want, I can:

  • watch NVD/OSV for future CVE entries for webfactory/ssh-agent and notify you, or
  • run a deeper dependency/security scan (Snyk/OSV/GitHub Dependabot) on the v0.9.0 source.

Update webfactory/ssh-agent to v0.9.1 (the latest stable release).

The action version is currently pinned to v0.9.0, but v0.9.1 is available as the latest stable release. While no known security vulnerabilities exist for v0.9.0, updating to the latest version is recommended for access to bug fixes and improvements.

Update the version from v0.9.0 to v0.9.1.

🤖 Prompt for AI Agents
In @.github/workflows/release.yml around lines 104 - 107, Update the GitHub
Actions step that uses the webfactory SSH agent by changing the referenced
action version from "webfactory/ssh-agent@v0.9.0" to
"webfactory/ssh-agent@v0.9.1" in the Set up SSH key step so the workflow uses
the latest stable release.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In @README.md:
- Around line 26-29: Update the README so the directory name after cloning
matches the clone command: replace the incorrect `cd worktree` with `cd wt` (or
alternatively change the clone command to `git clone
https://github.com/agarcher/wt.git worktree` if you intend to keep `worktree`),
ensuring the commands remain consistent (`git clone ...`, then `cd <directory>`,
then `make build` / `make install`).
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e3f4799 and 70d12e4.

📒 Files selected for processing (2)
  • README.md
  • scripts/homebrew-formula.tmpl
🔇 Additional comments (9)
scripts/homebrew-formula.tmpl (5)

1-8: LGTM!

Standard Homebrew formula header with proper frozen string literal and typed annotations. The metadata is correctly structured with appropriate placeholders for version substitution.


10-32: LGTM!

The platform-specific blocks correctly use Homebrew's DSL for conditional downloads. The URL patterns and SHA256 placeholders are properly structured for all supported architectures (darwin/linux × amd64/arm64).


42-55: LGTM!

The caveats provide clear shell integration instructions for all three supported shells, consistent with the README documentation.


57-59: LGTM!

Standard Homebrew test block that verifies the binary runs and outputs the expected version string.


34-40: The install method is correct and complete.

The wt completion subcommand exists and properly supports bash, zsh, fish, and powershell. The use of generate_completions_from_executable appropriately handles shell completion installation for all supported shells.

README.md (4)

3-4: LGTM!

Badge URLs correctly updated to the new repository name.


32-35: LGTM!

The Homebrew section correctly shows the tap installation command. The format agarcher/tap/wt is the proper shorthand for formulas from agarcher/homebrew-tap.


40-40: LGTM!

Releases page link correctly updated.


265-273: LGTM!

Clear documentation of the new release workflow. The release target exists in the Makefile and scripts/release.sh properly implements the documented workflow, accepting patch, minor, or major arguments with release notes. Examples correctly demonstrate proper usage with semver bump types and commit messages.

Aligns GitHub repo URL with existing Go module path.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
README.md (1)

265-273: Consider adding release prerequisites and troubleshooting guidance.

The new release workflow is clearly documented with good examples. To make the documentation more robust, consider adding:

  • Prerequisites (e.g., clean working directory, being on the main branch)
  • What to do if the push fails or needs to be undone
  • Whether the commit message argument is required or optional

Example addition:

### Releasing

Version is tracked in `VERSION` file. To release:

**Prerequisites**: Ensure you're on the main branch with a clean working directory.

```bash
make release patch "Fix bug in cleanup"
make release minor "Add new feature"
make release major "Breaking change"

This bumps VERSION, commits, tags, and pushes. GitHub Actions then builds binaries and updates the Homebrew tap.

Note: If the push fails, you may need to delete the local tag (git tag -d vX.Y.Z) before retrying.


</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used**: defaults

**Review profile**: CHILL

**Plan**: Pro

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 70d12e4b632f34fda99d0165cc09d2c2cf9260f3 and 2d6e1f38d552369e3d1af4b69a268b24e2de0fed.

</details>

<details>
<summary>📒 Files selected for processing (2)</summary>

* `README.md`
* `scripts/homebrew-formula.tmpl`

</details>

<details>
<summary>🚧 Files skipped from review as they are similar to previous changes (1)</summary>

* scripts/homebrew-formula.tmpl

</details>

<details>
<summary>🔇 Additional comments (5)</summary><blockquote>

<details>
<summary>README.md (5)</summary><blockquote>

`3-4`: **LGTM! Badge references updated correctly.**

The CI and Release badge URLs are correctly updated to reflect the repository rename from `worktree` to `wt`.

---

`26-27`: **LGTM! Source installation instructions updated.**

The git clone URL and directory name are correctly updated to match the new repository name.

---

`32-32`: **LGTM! Homebrew support is now available.**

The section title correctly indicates that Homebrew installation is no longer "coming soon" and is available for macOS/Linux.

---

`35-35`: **LGTM! Homebrew installation command updated.**

The brew install command correctly references the new package name `agarcher/tap/wt`.

---

`40-40`: **LGTM! Download link updated.**

The releases page URL correctly points to the renamed repository.

</blockquote></details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->

agarcher and others added 2 commits January 11, 2026 17:54
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Verify on main branch
- Fetch and verify up to date with origin/main
- Verify working directory is clean

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In @docs/RELEASE_TEST_PLAN.md:
- Around line 54-61: In the "Phase 3: Real Release" section (heading "Phase 3:
Real Release"), replace the bare URL "https://github.com/agarcher/wt/actions"
with a markdown link such as [GitHub
Actions](https://github.com/agarcher/wt/actions) so the link is formatted per
linting standards.
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2d6e1f3 and a10a445.

📒 Files selected for processing (2)
  • docs/RELEASE_TEST_PLAN.md
  • scripts/release.sh
🚧 Files skipped from review as they are similar to previous changes (1)
  • scripts/release.sh
🧰 Additional context used
🪛 markdownlint-cli2 (0.18.1)
docs/RELEASE_TEST_PLAN.md

61-61: Bare URL used

(MD034, no-bare-urls)

🔇 Additional comments (4)
docs/RELEASE_TEST_PLAN.md (4)

63-76: Excellent rollback documentation.

The cleanup section provides comprehensive rollback steps covering tag deletion, release deletion, and VERSION file reset. This is essential for handling failed releases cleanly.


1-76: Well-structured and comprehensive test plan.

This release test plan follows a logical three-phase approach: local testing without side effects, prerequisite verification, and real release execution. The progressive structure from safe testing to actual release, combined with detailed rollback procedures, provides a solid framework for validating the release automation workflow.


5-14: No issues found. The referenced script scripts/generate-formula.sh exists in the repository and the test plan documentation is correct.


16-24: Verify VERSION file exists and contains expected content.

This test expects a VERSION file at the repository root containing the initial version "0.0.0". Ensure this file exists in the codebase with the expected content before running the test.

@agarcher agarcher merged commit 661338b into main Jan 11, 2026
5 checks passed
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.

1 participant