Release orchestration and project scaffolding for npm, PyPI, and Go
Project description
rlsbl
Release orchestration and project scaffolding CLI for npm, PyPI, and Go.
Install
From npm:
npm i -g rlsbl
From PyPI (requires Node.js 18+):
uv tool install rlsbl
Quick start
rlsbl scaffold
rlsbl release minor
Commands
All commands work at the top level -- registries are auto-detected from project files (package.json, pyproject.toml, go.mod). Use --registry <npm|pypi|go> when you need to target a specific registry.
scaffold [--force] [--update]
Scaffolds CI/CD infrastructure and release tooling for all detected registries.
rlsbl scaffold
rlsbl scaffold --registry npm # target npm only
rlsbl scaffold --registry pypi --force # overwrite existing files
rlsbl scaffold --registry go # target Go only
Context-aware behavior when files already exist (without --force):
| File | Behavior |
|---|---|
CLAUDE.md |
Appends rlsbl sections if the marker is not present |
.gitignore |
Merges missing entries from the template |
.github/workflows/ci.yml |
Preserves existing file, prints a note to review manually |
| All others | Skipped |
release [patch|minor|major] [--dry-run] [--quiet]
Bumps version, commits, pushes, and creates a GitHub Release. Defaults to patch.
rlsbl release minor
rlsbl release major --dry-run --registry npm
The version is synced across all detected project files (package.json, pyproject.toml, VERSION) regardless of which registry is primary. Go projects use a plain VERSION file as the version source.
If .rlsbl/hooks/pre-release.sh exists, it runs before any changes are made. A non-zero exit aborts the release. If .rlsbl/hooks/post-release.sh exists, it runs after the release completes (non-fatal). See Release flow for details.
status
Shows project status: package name, version (per registry), git branch, last tag, working tree state, changelog coverage, and CI workflow presence.
rlsbl status
rlsbl status --registry pypi
check <name>
Checks name availability on both npm and PyPI, and warns about confusingly similar names.
rlsbl check my-cool-lib
rlsbl check my-cool-lib --registry npm # npm only
npm checks variant spellings (hyphens, underscores, dots, no separator). PyPI normalizes per PEP 503 and checks common alternatives.
discover [--mine]
Lists all projects in the rlsbl ecosystem by querying GitHub for repositories with the rlsbl topic.
rlsbl discover
rlsbl discover --mine # only your repos
Uses GitHub token if available (higher rate limit). Works unauthenticated for public repos.
Ecosystem tagging
By default, scaffold and release add an "rlsbl" keyword to package.json and/or pyproject.toml, and set the rlsbl topic on the GitHub repository. This makes projects discoverable via rlsbl discover.
To disable tagging:
| Method | Scope |
|---|---|
--no-tag flag |
Single invocation |
{"tag": false} in .rlsbl/config.json |
This project |
{"tag": false} in ~/.rlsbl/config.json |
All your projects |
Precedence: CLI flag > project config > user config > default (enabled).
Global flags: --help, --version.
Release flow
When you run release, the following happens in order:
- Verifies
ghCLI is installed and authenticated - Checks that the git working tree is clean
- Reads the current version from the primary project file
- Computes the new version and confirms the git tag does not already exist
- Validates that
CHANGELOG.mdcontains a## <new-version>section - Runs
.rlsbl/hooks/pre-release.shif present (non-zero exit aborts) - Writes the new version to the primary project file
- Syncs the new version to all other detected project files
- Commits the version bump (uses
safegitif available, otherwisegit) - Pushes the branch to
origin - Creates a GitHub Release tagged
v<new-version>with the changelog entry as notes - The GitHub Release triggers
publish.yml, which publishes to the registry - Runs
.rlsbl/hooks/post-release.shif present (non-fatal -- the release is already complete). TheRLSBL_VERSIONenv var is set to the released version. Useful for local install (go install ./cmd/myapp/), deploy, or notifications. - Spawns a background process that watches CI via
gh run watch. When CI finishes, it prints the result to stderr (so AI agents can read it) and sends a desktop notification (notify-sendon Linux,osascripton macOS). On CI failure, it also prints the GitHub Actions run URL. This happens automatically -- no configuration needed.
What scaffold creates
| File | Source | Purpose |
|---|---|---|
.github/workflows/ci.yml |
Registry-specific | CI workflow (lint, test) |
.github/workflows/publish.yml |
Registry-specific | Publish on GitHub Release (OIDC) |
CHANGELOG.md |
Shared | Version changelog |
LICENSE |
Shared | MIT license (author and year filled in) |
.gitignore |
Shared | Standard ignores for the ecosystem |
CLAUDE.md |
Shared | AI assistant instructions |
.claude/settings.json |
Shared | Claude Code settings |
.rlsbl/hooks/pre-release.sh |
Shared | User-customizable pre-release validation |
.rlsbl/hooks/post-release.sh |
Shared | User-customizable post-release actions |
.git/hooks/pre-push |
Shared | One-liner that calls rlsbl pre-push-check |
Hook files are made executable automatically. The record-gif and pre-push-check functionality is provided as built-in subcommands (rlsbl record-gif, rlsbl pre-push-check) rather than scaffolded scripts.
The scaffolded .gitignore includes a *.local-only pattern. Create a .local-only/ directory or rename files with a .local-only suffix to keep them out of version control -- useful for local-only assets, experiments, and keeping the working tree clean for tools that check git status.
Pre-push hook
The rlsbl pre-push-check subcommand enforces changelog coverage. During scaffold, a one-liner git hook is installed at .git/hooks/pre-push that calls this subcommand. It prevents pushing when CHANGELOG.md lacks an entry for the current version.
How it works:
- Detects project type (
package.json,pyproject.toml, orVERSION) - Extracts the current version
- Checks that
CHANGELOG.mdcontains a heading## <version> - Blocks the push with an error if the entry is missing
To reinstall manually:
echo '#!/bin/sh' > .git/hooks/pre-push && echo 'exec rlsbl pre-push-check "$@"' >> .git/hooks/pre-push && chmod +x .git/hooks/pre-push
First publish
The first version must be published manually before CI can take over:
| Registry | Manual first publish | Then configure |
|---|---|---|
| npm | Add an NPM_TOKEN secret to your GitHub repo (Settings > Secrets > Actions), then push a release |
CI handles subsequent publishes |
| PyPI | Run uv publish |
Set up Trusted Publishing on pypi.org |
| Go | Push to GitHub and create a release -- Go modules are published by the tag itself | No secrets needed; pkg.go.dev indexes automatically |
After configuration, all subsequent releases are handled by CI when rlsbl release creates a GitHub Release. Go projects use GoReleaser in CI (via GitHub Actions) to build cross-platform binaries.
Environment variables
| Variable | Default | Description |
|---|---|---|
RLSBL_PUSH_TIMEOUT |
120 |
Timeout in seconds for git push operations. Increase if your pre-push hooks (e.g. test suites) take longer than 2 minutes. |
RLSBL_VERSION |
-- | Set automatically when running .rlsbl/hooks/post-release.sh. Contains the just-released version string. |
Requirements
- Node 18+
- GitHub CLI (
gh), installed and authenticated - git
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file rlsbl-0.8.2.tar.gz.
File metadata
- Download URL: rlsbl-0.8.2.tar.gz
- Upload date:
- Size: 49.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a8c21450b98cf7daeba1514f911d436dedf6a394a289b2ac7a4807115d174bb3
|
|
| MD5 |
32e015fedfc3b73f67c21c3c9790fc95
|
|
| BLAKE2b-256 |
72f727a702c6e495b9f0071bae9461f2d329781f995eac42766462262501d01a
|
Provenance
The following attestation bundles were made for rlsbl-0.8.2.tar.gz:
Publisher:
publish.yml on smm-h/rlsbl
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
rlsbl-0.8.2.tar.gz -
Subject digest:
a8c21450b98cf7daeba1514f911d436dedf6a394a289b2ac7a4807115d174bb3 - Sigstore transparency entry: 1434367757
- Sigstore integration time:
-
Permalink:
smm-h/rlsbl@6f4179f523b2674979428382042afd7678fde520 -
Branch / Tag:
refs/tags/v0.8.2 - Owner: https://github.com/smm-h
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@6f4179f523b2674979428382042afd7678fde520 -
Trigger Event:
release
-
Statement type:
File details
Details for the file rlsbl-0.8.2-py3-none-any.whl.
File metadata
- Download URL: rlsbl-0.8.2-py3-none-any.whl
- Upload date:
- Size: 46.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2d6d4cc22a642142c5d23bf5a11ef3e58ab5e7f2379d680bff89c0507d9a588e
|
|
| MD5 |
395da2151f6d3c0a6006c61913169fac
|
|
| BLAKE2b-256 |
792ce8dc7223b6bce1e3ba9d4da6b2ff59116e601f43558ac552115698497d29
|
Provenance
The following attestation bundles were made for rlsbl-0.8.2-py3-none-any.whl:
Publisher:
publish.yml on smm-h/rlsbl
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
rlsbl-0.8.2-py3-none-any.whl -
Subject digest:
2d6d4cc22a642142c5d23bf5a11ef3e58ab5e7f2379d680bff89c0507d9a588e - Sigstore transparency entry: 1434367938
- Sigstore integration time:
-
Permalink:
smm-h/rlsbl@6f4179f523b2674979428382042afd7678fde520 -
Branch / Tag:
refs/tags/v0.8.2 - Owner: https://github.com/smm-h
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@6f4179f523b2674979428382042afd7678fde520 -
Trigger Event:
release
-
Statement type: