Detect the project's language and build system, generate a cross-platform release workflow, ensure a changelog exists, and update the README with download instructions.
Detect build system
Identify the language by checking for:
- Rust —
Cargo.toml(usecargo build --release --target <triple>) - Go —
go.mod(useGOOS/GOARCHenv vars withgo build) - Node.js —
package.jsonwith a build script (usepkg,nexe, or platform-specific bundling) - Python —
pyproject.tomlorsetup.py(usepyinstallerornuitka) - C/C++ —
CMakeLists.txtorMakefile(use cross-compilation toolchains)
Read the project name and current version from the manifest file. If none is found, ask the user.
Generate the workflow
Create .github/workflows/release.yml triggered on version tags:
on:
push:
tags:
- 'v*.*.*'
Use a matrix strategy for cross-platform builds. Default targets:
| Target | Runner | Archive |
|---|---|---|
| x86_64 Linux | ubuntu-latest |
.tar.gz |
| aarch64 Linux | ubuntu-latest |
.tar.gz |
| x86_64 macOS | macos-latest |
.tar.gz |
| aarch64 macOS | macos-latest |
.tar.gz |
| x86_64 Windows | windows-latest |
.zip |
Use target triples matching the detected language (e.g., x86_64-unknown-linux-gnu for Rust, GOOS=linux GOARCH=amd64 for Go).
The workflow needs three jobs:
- build — Matrix job. Compile for each target, archive the binary as
<project>-<tag>-<target>.<ext>, upload as artifact.- Use
tar -czffor.tar.gzandCompress-Archive(Windows) orzipfor.zip. - For Linux aarch64 cross-compilation, include appropriate setup (e.g.,
crossfor Rust, cross-compile packages for C/C++).
- Use
- release-notes — Extract the tagged version's section from
CHANGELOG.md. Fall back togit log --onelinebetween the previous and current tag ifCHANGELOG.mdis missing. - release — Depends on build and release-notes. Create a GitHub Release with
softprops/action-gh-releaseorgh release create, attach all artifacts, use extracted notes as body.
Set permissions: contents: write on the workflow.
Name archives: <project>-v<version>-<target>.tar.gz (or .zip for Windows).
Ensure CHANGELOG.md
If absent, create CHANGELOG.md following Keep a Changelog format:
# Changelog
## [Unreleased]
## [0.1.0] - YYYY-MM-DD
### Added
- Initial release.
Ask the user to confirm the version number.
Update README.md
Add or update an Installation section. Do not hardcode per-asset download URLs or version-stamped archive filenames — they change on every release and force a README edit each time. Instead, link to the releases page (GitHub lists all assets there automatically) and describe the supported platforms generically:
## Installation
Download the build for your platform from the
[latest release](https://github.com/<owner>/<repo>/releases/latest),
then extract the archive and put the binary on your `PATH`.
Prebuilt binaries are available for:
- **Linux** — x86_64, arm64 (`.tar.gz`)
- **macOS** — Apple Silicon, Intel (`.tar.gz`)
- **Windows** — x86_64 (`.zip`)
If you want a copy-paste install command, prefer one that resolves the latest tag at runtime rather than pinning a version — for example gh release download --pattern '<project>-*-x86_64-linux.tar.gz', or a script that queries /releases/latest. This keeps the README stable across version bumps.
Edge cases
- If
.github/workflows/release.ymlalready exists, show a diff preview and ask before overwriting. - If no tags exist, instruct the user:
git tag v0.1.0 && git push origin v0.1.0. - For Rust, suggest
rustup target add <triple>or usingcross. For Go, useGOOS/GOARCHdirectly — no extra tooling needed. - If the build system is unsupported or ambiguous, ask the user for the build commands.
- Ensure the workflow uses
permissions: contents: writeso the release job can create releases and upload assets.