Session
Claude Code@.github/workflows/release-cli.yml release seems to be failing
@.github/workflows/release-cli.yml
release seems to be failing
Let me investigate the CLI build setup and check for recent workflow run failures.
All 5 recent runs have failed. Let me check the latest failure details.
Let me also check if earlier runs had different failures.
Found the issues. There are two problems:
1. HOMEBREW_TAP_TOKEN secret is not set (current failure)
The logs show HOMEBREW_TAP_TOKEN: is empty. GitHub Actions would mask it as *** if it were set. The git push fails with:
remote: Invalid username or token. Password authentication is not supported for Git operations.
You need to create a GitHub Personal Access Token (classic) with repo scope for the JustinyAhin/homebrew-threadcast repo and add it as a secret named HOMEBREW_TAP_TOKEN in the threadcast repo settings.
2. Binary name mismatch in Homebrew formula (latent bug)
The tar archives contain files named threadcast-darwin-arm64, threadcast-linux-x64, etc. But the formula does:
def install
bin.install "threadcast" # looks for a file named "threadcast"
end
This will fail at brew install time because there's no file called threadcast inside the archive — it's called threadcast-darwin-arm64 (etc.).
Fix — rename the binary to threadcast before creating the tar.gz:
Now fix issue 1 — set the HOMEBREW_TAP_TOKEN secret. You'll need to:
- Go to github.com/JustinyAhin/threadcast → Settings → Secrets and variables → Actions
- Add a repository secret named
HOMEBREW_TAP_TOKENwith a Personal Access Token (classic) that hasreposcope and access toJustinyAhin/homebrew-threadcast
The binary naming fix is committed locally and ready to push when you're ready.
how to i create the pat?
- Go to github.com → click your profile picture → Settings
- Scroll down the left sidebar → Developer settings
- Personal access tokens → Tokens (classic)
- Click Generate new token → Generate new token (classic)
- Give it a name like
homebrew-tap - Set an expiration (or no expiration)
- Check the
reposcope (full control of private repositories) - Click Generate token
- Copy the token immediately (you won't see it again)
Then add it as a secret:
- Go to github.com/JustinyAhin/threadcast → Settings → Secrets and variables → Actions
- Click New repository secret
- Name:
HOMEBREW_TAP_TOKEN - Value: paste the token
- Click Add secret
why classic instead of fine grained?
You're right, fine-grained is the better choice here. I defaulted to classic out of habit, but fine-grained lets you scope it tighter.
With a fine-grained token:
- Set Resource owner to
JustinyAhin - Repository access → Only select repositories → pick
homebrew-threadcast - Permissions → Repository permissions → Contents: Read and write
- That's it — no other permissions needed
This is more secure since it only grants write access to that one repo instead of all repos under your account.
JustinyAhin/threadcast is private though
that's okay?
Yes, that's fine. The HOMEBREW_TAP_TOKEN is only used to clone and push to homebrew-threadcast. It doesn't need access to threadcast itself.
The workflow already uses ${{ github.token }} (line 77) for downloading release assets from the private threadcast repo — that's provided automatically by GitHub Actions.
so now how can i install the package on my mac?
Once you've set the secret and run the release workflow successfully:
brew tap JustinyAhin/threadcast
brew install threadcast
If you want to install it right now without waiting for the release, you can build locally:
bun run --filter @threadcast/cli build
Then copy the binary from packages/cli/dist/threadcast-darwin-arm64 to somewhere on your PATH:
cp packages/cli/dist/threadcast-darwin-arm64 /usr/local/bin/threadcast
seems to have work?
Release looks good! All 8 assets (4 raw binaries + 4 tar.gz archives) are there and the workflow passed (green checkmark).
You should now be able to install via Homebrew:
brew tap JustinyAhin/threadcast
brew install threadcast
==> Auto-updating Homebrew...
Adjust how often this is run with $HOMEBREW_AUTO_UPDATE_SECS or disable with$HOMEBREW_NO_AUTO_UPDATE=1. Hide these hints with $HOMEBREW_NO_ENV_HINTS=1 (see man brew).
==> Auto-updated Homebrew!
Updated 7 taps (steipete/tap, hashicorp/tap, infisical/get-cli, sst/tap, stripe/stripe-cli, homebrew/core and homebrew/cask).
==> New Formulae
aoe: Terminal session manager for AI coding agents
grafanactl: CLI to interact with Grafana
infisical/get-cli/infisical@0.43.56
rtk: CLI proxy to minimize LLM token consumption
rustledger: Fast, pure Rust implementation of Beancount double-entry accounting
sss-cli: Shamir secret share command-line interface
whodb-cli: Database management CLI with TUI interface, MCP server support, AI, and more
zxing-cpp: Multi-format barcode image processing library written in C++
==> New Casks
brewy: Native app for managing Homebrew packages
iloader: iOS Sideloading Companion
You have 21 outdated formulae and 1 outdated cask installed.
==> Tapping justinyahin/threadcast
Cloning into '/opt/homebrew/Library/Taps/justinyahin/homebrew-threadcast'...
remote: Enumerating objects: 8, done.
remote: Counting objects: 100% (8/8), done.
remote: Compressing objects: 100% (3/3), done.
remote: Total 8 (delta 1), reused 8 (delta 1), pack-reused 0 (from 0)
Receiving objects: 100% (8/8), done.
Resolving deltas: 100% (1/1), done.
Tapped 1 formula (13 files, 8.2KB).
==> Fetching downloads for: threadcast
✘ Formula threadcast (0.0.1)
Error: Failed to download resource "threadcast (0.0.1)"
Download failed: https://github.com/JustinyAhin/threadcast/releases/download/cli-v0.0.1/threadcast-darwin-arm64.tar.gz
The repo is private, so Homebrew can't download the release assets — they require authentication.
You have a few options:
- Make the repo public — simplest fix, Homebrew will just work
- Host binaries elsewhere (S3, Cloudflare R2, etc.) — keep repo private but serve assets from a public URL
- Set
HOMEBREW_GITHUB_API_TOKEN— works for you locally, but anyone else installing would need to do the same
Which approach works for you?
how to do 1?
with r2
Here's what you need to set up:
R2 Setup
- Cloudflare Dashboard → R2 → Create bucket (e.g.
threadcast-releases) - Settings → Public access → enable either the
r2.devsubdomain or a custom domain - R2 → Manage R2 API Tokens → Create API token with Object Read & Write on that bucket
- Copy the Access Key ID, Secret Access Key, and note your account ID
GitHub Secrets
Add these to JustinyAhin/threadcast → Settings → Secrets:
R2_ACCESS_KEY_IDR2_SECRET_ACCESS_KEYR2_ENDPOINT—https://<account-id>.r2.cloudflarestorage.comR2_PUBLIC_URL— your bucket's public URL (e.g.https://pub-xxx.r2.devor your custom domain)
Workflow Changes
Here's what changed:
releasejob — added an "Upload to R2" step that copies the.tar.gzfiles tos3://threadcast-releases/cli/v{version}/update-homebrewjob — downloads checksums from R2 instead of GitHub releases, and the formula URLs now point toR2_PUBLIC_URLinstead of GitHub
Secrets you need to add
| Secret | Value |
|---|---|
R2_ACCESS_KEY_ID |
From R2 API token |
R2_SECRET_ACCESS_KEY |
From R2 API token |
R2_ENDPOINT |
https://<account-id>.r2.cloudflarestorage.com |
R2_PUBLIC_URL |
Your bucket's public URL (e.g. https://pub-xxx.r2.dev) |
The R2 bucket name is hardcoded as threadcast-releases — adjust if you name it differently.
✔︎ JSON API formula.jws.json Downloaded 31.9MB/ 31.9MB
✔︎ JSON API cask.jws.json Downloaded 15.3MB/ 15.3MB
==> Fetching downloads for: threadcast
✘ Formula threadcast (0.0.1)
Error: Failed to download resource "threadcast (0.0.1)"
Download failed: https://github.com/JustinyAhin/threadcast/releases/download/cli-v0.0.1/threadcast-darwin-arm64.tar.gz
The formula in homebrew-threadcast still has the old GitHub URLs — the workflow changes haven't been released yet.
To get it working you need to:
- Create the R2 bucket + secrets (as described above)
- Push the workflow changes
- Run the release workflow again
Or if you want to test it right now before re-running the full release, you can manually upload the existing tarballs and update the formula:
# Download the tarballs from the existing GitHub release
gh release download cli-v0.0.1 --pattern "*.tar.gz" --dir /tmp/tc-release
# Upload to R2 (replace with your actual values)
for f in /tmp/tc-release/threadcast-*.tar.gz; do
aws s3 cp "$f" "s3://threadcast-releases/cli/v0.0.1/$(basename "$f")" \
--endpoint-url "https://<account-id>.r2.cloudflarestorage.com"
done
Then update the formula in homebrew-threadcast to point to your R2 public URL instead of the GitHub release URL.
already did those
Try installing again:
brew untap justinyahin/threadcast && brew tap justinyahin/threadcast && brew install threadcast
cool
just did that
and ran threadcast
and i was already logged in
why?
Auth is stored at ~/.threadcast/config.json. Both the locally-built binary and the Homebrew-installed one read from the same path, so your previous login persisted.
haaa
not good haha
That's actually standard behavior for CLIs — gh, docker, aws all store config in ~/.{name}/. The Homebrew-installed binary is the same program, just installed to a different path.
Were you expecting it to require a fresh login, or is there a specific concern? Happy to change the behavior if needed.