Ready-to-use GitHub Actions workflows that build, package, and publish CLI tool releases on github.com — compatible with Luca.
Luca is a lightweight tool manager that installs CLI tools directly from GitHub Releases. It follows a distributed model: no central registry, no package index — just a zip file attached to a GitHub Release.
Many open-source projects don't publish pre-built binaries in their GitHub Releases. These workflows solve that by giving developers a copy-paste CI pipeline that builds, bundles, and publishes release assets in the format Luca expects.
Push a tag, get a release with binaries. That's it.
| Workflow | Language | Build tooling | Binary type |
|---|---|---|---|
| publish_release_swift.yml | Swift | swift build, lipo |
Native universal binary |
| publish_release_go.yml | Go | go build with cross-compilation |
Native universal binary |
| publish_release_rust.yml | Rust | cargo build per target triple |
Native universal binary |
| publish_release_dotnet.yml | C# / .NET | dotnet publish with Native AOT |
Native universal binary |
| publish_release_python.yml | Python | PyInstaller --onefile |
Bundled standalone binary |
| publish_release_zig.yml | Zig | zig build per target |
Native universal binary |
- Copy the workflow for your language into your repository at
.github/workflows/ - Replace the placeholders (see table below) with your project's values
- Push a tag:
git tag 1.0.0 git push --tags
- The workflow will build your tool, create a GitHub Release, and upload the assets automatically
Each workflow has a small set of placeholders in the env: block at the top of the file. Replace them before committing.
| Placeholder | Description | Example |
|---|---|---|
[TOOL_NAME] |
Executable product name (as in Package.swift) |
swiftlint |
| Placeholder | Description | Example |
|---|---|---|
[TOOL_NAME] |
Output binary name | mytool |
[GO_VERSION] |
Go version | 1.23 |
[MAIN_PACKAGE] |
Path to main package | . or ./cmd/mytool |
| Placeholder | Description | Example |
|---|---|---|
[TOOL_NAME] |
Binary name (as in Cargo.toml [[bin]]) |
ripgrep |
[RUST_TOOLCHAIN] |
Rust toolchain | stable or 1.82 |
| Placeholder | Description | Example |
|---|---|---|
[TOOL_NAME] |
Output binary name | mytool |
[DOTNET_VERSION] |
.NET SDK version | 9.0.x |
[PROJECT_PATH] |
Path to .csproj file |
src/MyTool/MyTool.csproj |
| Placeholder | Description | Example |
|---|---|---|
[TOOL_NAME] |
Output binary name | mytool |
[PYTHON_VERSION] |
Python version | 3.12 |
[ENTRY_POINT] |
Path to main script | src/main.py |
| Placeholder | Description | Example |
|---|---|---|
[TOOL_NAME] |
Binary name (as in build.zig addExecutable) |
mytool |
[ZIG_VERSION] |
Zig version | 0.13.0 |
Every workflow produces three release assets attached to the GitHub Release:
| Asset | Contents |
|---|---|
<name>-macOS.zip |
macOS universal binary (arm64 + x86_64) |
<name>-Linux.zip |
Linux x86_64 binary |
<name>.artifactbundle.zip |
Swift artifact bundle containing both binaries |
The artifact bundle is a standard format defined by Swift Package Manager. It includes an info.json manifest with platform-specific binary paths, making it usable as a SwiftPM binary target as well.
Each workflow follows the same 4-job pipeline:
build-macos ──┐
├── generate-artifactbundle ── create-release
build-linux ──┘
build-macos— Runs onmacos-15. Builds arm64 and x86_64 binaries, merges them into a universal binary withlipobuild-linux— Runs onubuntu-latest. Builds a statically-linked x86_64 binarygenerate-artifactbundle— Assembles the.artifactbundledirectory structure withinfo.jsoncreate-release— Creates a GitHub Release (idempotent — reuses existing if found) and uploads all three zip assets
All workflows use the built-in GITHUB_TOKEN — no Personal Access Token required. The create-release job declares permissions: contents: write for release creation and asset uploads.
Workflows depend only on official GitHub-maintained actions:
actions/checkout@v4actions/upload-artifact@v4actions/download-artifact@v4- Language setup actions (
actions/setup-go@v5,actions/setup-python@v5,actions/setup-dotnet@v4)
Release creation and asset uploads use direct GitHub REST API calls — no third-party release actions.
- Requires macOS runner for
lipoandswift build --arch - Linux build uses the official
swift:6.0-jammyDocker image insideubuntu-latest - Uses
-Xswiftc -static-stdlibfor statically-linked Linux binaries
- Cross-compilation is done natively via
GOOS/GOARCHenvironment variables CGO_ENABLED=0ensures fully static binaries with no system library dependencies- Build flags include
-trimpath -ldflags="-s -w"to strip debug info and reduce binary size
- Builds per target triple:
aarch64-apple-darwin,x86_64-apple-darwin,x86_64-unknown-linux-gnu - Installs
musl-toolson Linux for static linking support - Uses
lipoon macOS to merge the two Darwin builds into a universal binary
- Defaults to Native AOT (
/p:PublishAot=true) for small, fast, self-contained binaries - If your project doesn't support AOT, switch to
/p:PublishSingleFile=true /p:SelfContained=true - Linux AOT builds require
clangandzlib1g-dev(installed automatically)
- Uses PyInstaller to bundle the Python interpreter and all dependencies into a single executable
- Resulting binaries are larger than compiled languages (~20–50 MB)
- macOS build is not a universal binary — it runs on the runner's native architecture (arm64 on
macos-15) - Automatically installs dependencies from
requirements.txtorpyproject.tomlif present
- Zig has excellent built-in cross-compilation support
- Installs Zig by downloading the official release tarball (no third-party setup action needed)
- Output paths may vary depending on your
build.zigconfiguration — see inline comments in the workflow
These workflows are designed to be copied and modified. Common customisations:
- Remove the Linux job if you only target macOS (update
generate-artifactbundleto remove the Linux variant frominfo.json) - Remove the artifactbundle job if you don't need Swift Package Manager compatibility (have
create-releasedepend directly on the build jobs) - Add more platforms (e.g.
windows-latest) by adding a build job and extending the release/bundle steps - Inject version numbers into your binary (e.g. via
ldflagsin Go,--definein Swift, etc.) - Add code signing for macOS binaries using
codesignafter thelipostep
These workflows are provided under the same license as Luca. See LICENSE for details.