@oorabona/release-it-preset
v1.2.0
Published
Release tooling for solo and small-team JS maintainers: human-curated changelogs, OIDC zero-config publishing, recovery presets, monorepo support, pre-release diagnostics.
Maintainers
Readme
@oorabona/release-it-preset
Shared release-it configuration and scripts for automated versioning, changelog generation, and package publishing.
Why this preset?
Most release workflows fall into one of three traps: too much manual work (plain release-it, you assemble everything), too much ceremony (changesets, great for 5+ maintainers, heavy for one), or too much automation with too little control (semantic-release, hands-off by design and format).
@oorabona/release-it-preset occupies the productive middle ground for solo and small-team JavaScript package maintainers who want:
- Human-readable changelogs. Keep a Changelog format (Added/Changed/Deprecated/Removed/Fixed/Security) generated automatically from conventional commits — no manual entry writing, no machine-format diffs.
[YANKED]markers in version headings are preserved transparently; apply them manually post-release per the Keep a Changelog spec. - OIDC publishing without CI plumbing. Import the reusable
publish.ymlworkflow in three lines. OIDC trusted publishing with npm provenance ships on day one, noNPM_TOKENsecret required. - Diagnostic confidence before release. Run
release-it-preset doctorto surface every misconfiguration — git auth, npm auth, changelog hygiene, branch requirements — before anything breaks in CI. - Recovery presets for the real world. Dedicated
republishandretry-publishconfigs handle the scenarios other tools pretend don't happen.
Pick this preset if you maintain one or a few npm packages, write Keep a Changelog, deploy from GitHub Actions, and want pre-built OIDC publishing without adopting changesets or semantic-release's philosophy.
Do not pick this preset if you have a large monorepo with cross-package dependency management needs (use changesets) or if you want zero human involvement in versioning decisions (use semantic-release).
Ecosystem positioning
| Tool | Strength | When to prefer it |
|---|---|---|
| @oorabona/release-it-preset (this) | Keep a Changelog discipline + OIDC workflows + doctor CLI + recovery presets | Solo / small-team JS maintainer, human-curated changelogs, GitHub Actions CI |
| release-it (plain) | Maximum flexibility, smallest opinion footprint | You want to assemble each piece yourself |
| changesets | PR-driven versioning, fixed/linked package versions | 5+ maintainer monorepo, every change deserves explicit intent |
| semantic-release | Fully-automated, zero human intervention | Branch-driven release pipelines, no human review of changelogs |
| release-please | GitHub Release PR pattern, 20+ language strategies | Polyglot repos, GitHub-native PR-driven workflow |
| @release-it-plugins/workspaces | Multi-package iteration + cross-pkg dep sync | Monorepo with bulk publish — composes with this preset (see Composing with @release-it-plugins/workspaces) |
Table of Contents
- Why this preset?
- Ecosystem positioning
- Features
- Installation
- Quick Start
- Available Configurations
- CLI Usage
- Scripts
- Environment Variables
- Configuration Modes
- Borrowing Scripts & Workflows
- Release Workflow
- GitHub Actions Workflows
- Exit codes
- Best Practices
- Troubleshooting
- Public API
- Contributing
Features
- 📦 Multiple release configurations for different scenarios
- 📝 Automatic changelog generation using Keep a Changelog format
- 🤖 Conventional commits parsing and categorization
- 🏷️ Git tagging with optional GitHub release automation
- 🚀 npm publishing with provenance (opt-in, ideal for CI)
- 🔄 Republish and retry mechanisms for failed releases
- ⚡ Hotfix release support
- 🎯 Environment variable configuration
- 🔍 Zero-config auto-detection mode
- 🏢 Monorepo support with parent directory config references
- ⚙️ Passthrough mode for custom config files
Installation
pnpm add -D @oorabona/release-it-preset release-itInstall patterns
| Use case | Command | Notes |
|---|---|---|
| Try without installing | pnpm dlx @oorabona/release-it-preset doctor | Fetch + run, no install. Use for evaluating the preset on an existing repo. |
| One-shot npx | npx -y @oorabona/release-it-preset doctor | Same idea, npm-flavored |
| Adopt as devDep (recommended) | pnpm add -D @oorabona/release-it-preset release-it | Pins via lockfile, idiomatic for projects |
| CI usage | pnpm install --frozen-lockfile && pnpm exec release-it-preset retry-publish --ci | Lockfile-deterministic, no prompts |
| Diagnostic on any repo | pnpm dlx @oorabona/release-it-preset doctor | Works against the cwd's git/package.json/CHANGELOG; great for quick health checks |
Global install is not recommended — pin per-project for reproducibility. The preset is small (<20KB unpacked); CI overhead is negligible.
The peer requirement is release-it ^19.0.0 || ^20.0.0. CI runs against the upper bound (v20.x) on every commit; v19 was smoke-tested manually before the constraint was widened. v20 is recommended for the OIDC trusted publishing handshake (npm ≥ 11.5.1, Node ≥ 24); v19 is supported for composing with @release-it-plugins/workspaces (its peer maxes at v19 today).
Quick Start
Option 1: Using the CLI (Recommended)
Add scripts to your package.json:
{
"scripts": {
"release": "release-it-preset default",
"release:hotfix": "release-it-preset hotfix"
}
}Then run:
pnpm releaseOption 2: Using extends
Create .release-it.json in your project:
{
"extends": "@oorabona/release-it-preset/config/default"
}Add scripts to your package.json:
{
"scripts": {
"release": "release-it"
}
}Initialize CHANGELOG.md
Create a CHANGELOG.md file with Keep a Changelog format:
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
### Added
- Initial releaseGitHub Actions
Quick Start: Reusable Workflows
Import pre-configured workflows into your repository:
PR Validation:
name: PR Checks
on:
pull_request:
types: [opened, synchronize, reopened]
permissions:
contents: read
pull-requests: write
jobs:
validate:
uses: oorabona/release-it-preset/.github/workflows/reusable-verify.yml@main
with:
base-ref: origin/${{ github.base_ref }}
head-ref: ${{ github.sha }}
run-tests: true
secrets: inheritPublish on Tag:
name: Publish
on:
push:
tags: ['v*']
permissions:
contents: write
id-token: write
jobs:
publish:
uses: oorabona/release-it-preset/.github/workflows/publish.yml@main
secrets:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}📖 Full Reusable Workflows Documentation | 📚 CI/CD Integration Examples
Available Configurations
default - Standard Release
Full-featured release with changelog, git operations, and optional GitHub/npm publishing.
CLI:
pnpm release-it-preset defaultExtends:
{
"extends": "@oorabona/release-it-preset/config/default"
}Features:
- ✅ Version bumping (interactive)
- ✅ Automatic changelog population from conventional commits
- ✅ Git commit, tag, and push
- ☑️ GitHub release creation (set
GITHUB_RELEASE=true) - ☑️ npm publishing with provenance (set
NPM_PUBLISH=true)
hotfix - Emergency Hotfix
For urgent patches that need quick changelog generation from git log (GitHub/npm remain opt-in).
CLI:
pnpm release-it-preset hotfixExtends:
{
"extends": "@oorabona/release-it-preset/config/hotfix"
}Features:
- ✅ Forced patch version increment
- ✅ Automatic changelog from recent commits
- ✅ Pre-bump unreleased section population
- ☑️ GitHub release with extracted notes (set
GITHUB_RELEASE=true) - ☑️ npm publishing with provenance (set
NPM_PUBLISH=true)
changelog-only - Changelog Preparation
Updates changelog without performing a release (useful in CI or pre-release).
CLI:
pnpm release-it-preset changelog-only --ciExtends:
{
"extends": "@oorabona/release-it-preset/config/changelog-only"
}Features:
- ✅ Populates [Unreleased] section
- ❌ No version bump
- ❌ No git operations
- ❌ No publishing
manual-changelog - Manual Changelog Release
For releases where you've manually edited the [Unreleased] section in CHANGELOG.md. Skips automatic changelog generation while keeping GitHub/npm steps opt-in.
Workflow:
# 1. Generate initial changelog
pnpm release-it-preset update
# 2. Manually edit CHANGELOG.md [Unreleased] section
# 3. Release without regenerating changelog
pnpm release-it-preset manual-changelogExtends:
{
"extends": "@oorabona/release-it-preset/config/manual-changelog"
}Features:
- ✅ Version bumping (interactive)
- ✅ Preserves manual [Unreleased] edits
- ✅ Moves [Unreleased] to versioned section
- ✅ Git commit, tag, and push
- ☑️ GitHub release creation (set
GITHUB_RELEASE=true) - ☑️ npm publishing with provenance (set
NPM_PUBLISH=true) - ❌ Skips automatic changelog population
no-changelog - Quick Release
Standard release without changelog updates; GitHub/npm steps remain opt-in.
CLI:
pnpm release-it-preset no-changelogExtends:
{
"extends": "@oorabona/release-it-preset/config/no-changelog"
}Features:
- ✅ Version bumping
- ✅ Git operations
- ☑️ GitHub releases (set
GITHUB_RELEASE=true) - ☑️ npm publishing (set
NPM_PUBLISH=true) - ❌ No changelog updates
republish - Git Tag Move + GitHub Release Update
⚠️ DANGER: Moves an existing git tag to HEAD and updates the GitHub release notes (breaks semver immutability for that tag).
Only use when you need to fix a broken release that requires moving the git tag. This preset does not publish to npm — npm immutability (since 2016) makes republishing an existing version impossible under any dist-tag. See ADR 0005.
Alternatives:
- dist-tag change (e.g. move
latestto a different version):npm dist-tag add @oorabona/release-it-preset@<version> latest - Retry a failed npm/GitHub publish: use the
retry-publishpreset instead
CLI:
pnpm release-it-preset republishExtends:
{
"extends": "@oorabona/release-it-preset/config/republish"
}Features:
- ⚠️ Moves existing git tag
- ✅ Updates changelog for current version
- ☑️ Updates GitHub release (set
GITHUB_RELEASE=true) - ❌ Does not publish to npm (npm immutability — use
npm dist-tag addorretry-publish)
retry-publish - Retry Failed Publishing
Retries npm/GitHub publishing for an existing tag without modifying git history; opt in to each surface via NPM_PUBLISH and GITHUB_RELEASE.
CLI:
# Step 1: Run pre-flight checks (optional)
pnpm release-it-preset retry-publish-preflight
# Advanced (direct compiled call)
# node node_modules/@oorabona/release-it-preset/dist/scripts/retry-publish.js
# Step 2: Retry the publish
pnpm release-it-preset retry-publishExtends:
{
"extends": "@oorabona/release-it-preset/config/retry-publish"
}Features:
- ☑️ Republishes to npm (set
NPM_PUBLISH=true) - ☑️ Updates GitHub release (set
GITHUB_RELEASE=true) - ❌ No version increment
- ❌ No git operations
CLI Usage
The package provides a release-it-preset CLI with four operating modes:
- Zero-Config Mode (auto-detection) - No arguments needed
- Preset Selection Mode - Specify which preset to use
- Passthrough Mode - Direct config file override
- Utility Mode - Helper commands
Zero-Config Mode (Auto-Detection)
The CLI can automatically detect which preset to use from your .release-it.json:
# Just run release-it-preset with no arguments
pnpm release-it-preset
# 🔍 Auto-detected preset: default
# ✅ Config validated: preset "default"
# 📝 Using: /path/to/.release-it.jsonHow it works:
- CLI reads your
.release-it.json - Extracts the preset name from the
extendsfield - Runs that preset automatically
Requirements:
.release-it.jsonmust exist- Must have
extendsfield like"@oorabona/release-it-preset/config/default"
Benefits:
- ✅ Shortest command possible
- ✅ Config file is source of truth
- ✅ No need to remember preset names
- ✅ Follows industry standards (ESLint, TypeScript, Prettier)
Preset Selection Mode
Run release-it with specific configurations:
# Show help
pnpm release-it-preset --help
# Run releases
pnpm release-it-preset default --dry-run
pnpm release-it-preset hotfix --verbose
pnpm release-it-preset changelog-only --ci
pnpm release-it-preset manual-changelogAll additional arguments are passed through to release-it.
Passthrough Mode (Custom Config Override)
Use a custom config file and bypass preset validation:
# Use custom config file
pnpm release-it-preset --config .release-it-manual.json
# 🔀 Passthrough mode: using config .release-it-manual.json
# Bypassing preset validation - direct release-it invocationUse cases:
- Switching presets occasionally - Have multiple config files for different scenarios
- Monorepo workflows - Reference shared configs from parent directories
- Advanced customization - Full control over release-it configuration
Example workflow:
// .release-it.json (default - 95% of time)
{
"extends": "@oorabona/release-it-preset/config/default",
"git": { "requireBranch": "develop" }
}
// .release-it-manual.json (rare - 5% of time)
{
"extends": "@oorabona/release-it-preset/config/manual-changelog",
"git": { "requireBranch": "develop" }
}# Normal release
pnpm release-it-preset # Auto-detects default
# Manual changelog release (rare)
pnpm release-it-preset --config .release-it-manual.jsonBenefits:
- ✅ No need to edit
.release-it.jsonto switch presets - ✅ Config files are explicit and version-controlled
- ✅ Works with monorepo parent directory references
Monorepo Support
Parent directory config references are now supported:
# Monorepo structure
/my-monorepo/
├── .release-it-base.json # Shared configuration
├── packages/
│ ├── core/
│ │ └── .release-it.json # extends: ../../.release-it-base.json
│ └── utils/
│ └── .release-it.json # extends: ../../.release-it-base.json// packages/core/.release-it.json
{
"extends": [
"../../.release-it-base.json", // ✅ Parent reference allowed!
"@oorabona/release-it-preset/config/default"
]
}Security validation:
- ✅ Parent directory references (
../) supported (up to 5 levels) - ✅ Config file extension whitelist (
.json,.js,.cjs,.mjs,.yaml,.yml,.toml) - ✅ File existence validation
- ❌ Absolute paths blocked (use relative paths)
- ❌ Excessive traversal blocked (max
../../../../../../)
Why this is safe:
- Config files are trusted code (developer controls the repository)
- Industry standard pattern (TypeScript, ESLint, Prettier all allow
../) - Multiple validation layers prevent abuse
- No privilege escalation in CLI tool context
See examples/monorepo-workflow.md for complete monorepo guide and examples/monorepo/ for a runnable workspace demo.
Composing with @release-it-plugins/workspaces
This preset focuses on a single package per release-it run. If your monorepo needs bulk publish (iterate over every workspace package + sync cross-package dependency versions), compose this preset with @release-it-plugins/workspaces — the canonical release-it plugin for that workflow.
# Install both
pnpm add -D @oorabona/release-it-preset @release-it-plugins/workspaces release-it@^19// .release-it.json — extends our preset AND loads the workspaces plugin
{
"extends": "@oorabona/release-it-preset/config/default",
"plugins": {
"@release-it-plugins/workspaces": true
}
}Peer compatibility note: @release-it-plugins/workspaces v5.0.3 declares peer release-it ^17 || ^18 || ^19. Our preset declares peer ^19 || ^20. The intersection is ^19, so when composing with the workspaces plugin you must pin release-it to v19. v20 standalone (without the workspaces plugin) is fully supported and recommended for new projects.
release-it-preset doctor does not check whether the workspaces plugin is loaded — it's an opt-in composition. Run it manually after install if you want to verify the plugin's own preflight checks.
When this composition is right for you:
- You release multiple packages from one repo with synchronized versions (all bumped together).
- You want cross-package dependency sync (when
pkg-abumps to 2.0,pkg-b's reference auto-updates).
When our preset alone is enough:
- Independent versioning per package (each package releases when ready). Use
GIT_CHANGELOG_PATH=packages/<pkg>to scope the CHANGELOG. See examples/monorepo/ for the runnable demo.
Utility Commands
Helper commands for project setup and maintenance:
init - Initialize Project
Creates CHANGELOG.md, .release-it.json, and optionally adds scripts to package.json:
# Interactive mode (asks for confirmation)
pnpm release-it-preset init
# Non-interactive mode (skip prompts, use defaults)
pnpm release-it-preset init --yes
# Also scaffold a GitHub Actions publish workflow
pnpm release-it-preset init --yes --with-workflows
# Use a custom workflow filename (default: release.yml)
pnpm release-it-preset init --yes --with-workflows --workflow-name=publish.ymlWhat it does:
- Creates
CHANGELOG.mdwith Keep a Changelog template - Creates
.release-it.jsonwith extends configuration - Optionally adds release scripts to
package.json - Skips existing files in
--yesmode
One-off usage:
pnpm dlx @oorabona/release-it-preset init(ornpx @oorabona/release-it-preset init) runs the CLI without installing it as a dependency.
update - Update Changelog
Updates the [Unreleased] section with commits since last tag:
pnpm release-it-preset updateWhat it does:
- Parses conventional commits since last git tag
- Groups commits by type (Added, Fixed, Changed, etc.)
- Updates [Unreleased] section in CHANGELOG.md
- Generates commit links to repository
- Uses only the conventional commit subject; feel free to edit
CHANGELOG.mdafterwards if you want to add the detailed bullet points that lived in the commit body
validate - Validate Release Readiness
Checks if project is ready for release:
# Standard validation
pnpm release-it-preset validate
# Allow uncommitted changes
pnpm release-it-preset validate --allow-dirtyWhat it checks:
- ✅ CHANGELOG.md exists and is well-formatted
- ✅ [Unreleased] section has content
- ✅ Working directory is clean (unless --allow-dirty)
- ✅ npm authentication works (npm whoami)
- ✅ Current branch is allowed (if GIT_REQUIRE_BRANCH is set)
Exit code 0 if all checks pass, 1 if any fail (useful in CI/pre-commit hooks).
check - Diagnostic Information
Displays configuration and project status:
pnpm release-it-preset checkWhat it shows:
- Environment variables and their values
- Repository information (URL, branch, remote)
- Git tags and latest version
- Commits since last tag
- Configuration files status
- npm authentication status
Useful for debugging release issues.
doctor - Release Readiness Diagnostic
Runs a structured checklist across four categories and outputs a readiness score:
pnpm release-it-preset doctor
pnpm release-it-preset doctor --jsonWhat it checks:
| Category | Checks |
|----------|--------|
| Environment | Known env vars, source (env / default / unset), publish-mode consistency |
| Repository | Git repo presence, branch vs GIT_REQUIRE_BRANCH, latest tag, commit count, dirty WD, upstream tracking, remote URL |
| Configuration | CHANGELOG.md exists + Keep a Changelog format + [Unreleased] content, .release-it.json parseable + extends field, package.json valid semver version, release-it peer range satisfied, release-it major version advisor |
| Readiness Summary | PASS/WARN/FAIL counts, score N/M checks passing, status (READY/WARNINGS/BLOCKED), actionable recommendations |
Exit codes:
0— status isREADYorWARNINGS1— status isBLOCKED(at least oneFAIL)
--json output shape:
{
"environment": { "checks": [...], "vars": [...], "status": "PASS" },
"repository": { "checks": [...], "status": "WARN" },
"configuration": { "checks": [...], "status": "PASS" },
"summary": {
"pass": 10, "warn": 2, "fail": 0, "total": 12,
"score": "10/12 checks passing",
"status": "WARNINGS",
"recommendations": ["Review 2 warning(s) before releasing"]
}
}Use doctor as a pre-release sanity check, and check for the full verbose configuration dump.
check-pr - Pull Request Hygiene
Evaluates PR readiness by analysing commits and changelog changes. Designed for CI usage but safe locally when the required environment variables are set (PR_BASE_REF, PR_HEAD_REF).
PR_BASE_REF=origin/main PR_HEAD_REF=HEAD pnpm release-it-preset check-prOutputs JSON summaries for workflows (base64 encoded) and prints a human-readable report.
retry-publish-preflight - Retry Safety Checks
Runs the retry publish pre-flight script with the same CLI convenience wrapper as other utilities. Verifies that the latest tag exists, matches package.json, and that there are no unexpected workspace changes before attempting a retry.
pnpm release-it-preset retry-publish-preflightUse this before calling pnpm release-it-preset retry-publish when recovering from a failed publish.
pnpm Script Shortcuts
The root package.json defines helper scripts that wrap the CLI so you can run the most common flows with pnpm run:
pnpm release→ run the default release config (release-it-preset default)pnpm run release:default:dry-run→ dry-run the default release configurationpnpm run release:no-changelog→ publish without touching the changelogpnpm run release:changelog-only→ update only the changelogpnpm run release:manual-changelog→ release with manually edited changelog (skip auto-generation)pnpm run release:hotfix→ execute the hotfix workflowpnpm run release:republish→ trigger the republish workflow (dangerous flow)pnpm run release:retry-preflight→ run retry publish safety checkspnpm run release:retry-publish→ retry npm/GitHub publishing for an existing tagpnpm run release:update→ populate the[Unreleased]sectionpnpm run release:validate→ run release validation checkspnpm run release:validate:allow-dirty→ validation that tolerates uncommitted changespnpm run release:check→ show diagnostic information about the current repo
Scripts
Scripts are authored in TypeScript but distributed as compiled ESM JavaScript in dist/scripts. Under normal circumstances you should invoke them via the release-it-preset CLI or the pnpm aliases listed above; the CLI automatically prefers the compiled build and falls back to tsx only for local development. The direct node examples below are provided for automation scenarios where you deliberately want to call the compiled output.
extract-changelog.ts
Extracts the changelog entry for a specific version (used automatically by the release notes generator). If you ever need to call it manually:
node node_modules/@oorabona/release-it-preset/dist/scripts/extract-changelog.js 1.2.3populate-unreleased-changelog.ts
Populates the [Unreleased] section with commits since the last tag using conventional commits.
# Preferred
pnpm release-it-preset update
# or
pnpm run release:update
# Advanced (call compiled output directly)
node node_modules/@oorabona/release-it-preset/dist/scripts/populate-unreleased-changelog.jsSupported commit types:
feat,feature,add→ Addedfix,bugfix→ Fixeddeprecate,deprecated,deprecation→ Deprecatedperf,refactor,style,docs,test,chore,build→ Changedremove,removed,delete,deleted→ Removedsecurity→ Securityci,release,hotfix→ Ignored
Add [skip-changelog] to commit message to exclude it.
republish-changelog.ts
Moves [Unreleased] content to the current version entry (for republishing).
# Preferred
pnpm run release:republish
# or
pnpm release-it-preset republish
# Advanced
node node_modules/@oorabona/release-it-preset/dist/scripts/republish-changelog.jsretry-publish.ts
Performs pre-flight checks before retrying a failed publish.
# Preferred (CLI)
pnpm release-it-preset retry-publish-preflight
# Advanced (call compiled output directly)
node node_modules/@oorabona/release-it-preset/dist/scripts/retry-publish.jsEnvironment Variables
Customize behavior with environment variables:
Changelog
CHANGELOG_FILE- Changelog file path (default:CHANGELOG.md)GIT_CHANGELOG_PATH- Optional. When set to a repository-relative path (e.g.packages/tar-xz), restrict changelog generation to commits touching that path. Useful for monorepo per-package CHANGELOG files. Empty / unset = repository-wide (default).GIT_CHANGELOG_SINCE- Optional. Override thesincebaseline for changelog generation (any git ref: SHA, tag, branch). When set, bypasses both the per-package release-commit detection and thegit describe --tagsfallback. Useful for monorepo workspaces with non-standard release commit patterns. Empty / unset = use auto-detection.CHANGELOG_TYPE_MAP- Optional. JSON string mapping commit types to CHANGELOG section headings. Merged on top of.changelog-types.json(if present) and the built-in defaults. Usefalseas a value to suppress a type entirely. Example:CHANGELOG_TYPE_MAP='{"ops":"### Operations","deps":"### Dependencies"}'.
Custom type map (.changelog-types.json)
Create a .changelog-types.json file in your project root to override or extend the built-in commit-type → section mapping at the project level. The file is merged on top of the built-in defaults; individual keys can be overridden without touching the rest.
Resolution order (highest priority wins):
CHANGELOG_TYPE_MAPenv var (runtime override, e.g. in CI).changelog-types.jsonproject file- Built-in defaults
Example .changelog-types.json:
{
"deps": "### Dependencies",
"ops": "### Operations",
"ci": false
}- String values must be a valid
### Section Heading. falsesuppresses the type (no CHANGELOG entry emitted).- Malformed JSON or invalid values → warning logged, layer ignored, lower-priority map used.
BREAKING CHANGE: footer parsing (Conventional Commits 1.0.0 §6): BREAKING CHANGE: is recognised as a footer only when it appears after a blank-line separator from the preceding paragraph. Mid-body occurrences without the blank line do not promote the commit to breaking. Multiple BREAKING CHANGE: lines in the same footer paragraph each emit a separate entry under ### ⚠️ BREAKING CHANGES.
Git
GIT_COMMIT_MESSAGE- Commit message template. Defaults vary per preset:chore(release): v${version}(default),chore(hotfix): v${version}(hotfix),chore: republish v${version}(republish). Set this env var to override across all presets.GIT_TAG_NAME- Tag name template (default:v${version})GIT_REQUIRE_BRANCH- Required branch (default:main)GIT_REQUIRE_UPSTREAM- Require upstream tracking (default:false)GIT_REQUIRE_CLEAN- Require clean working directory (default:false)GIT_REMOTE- Git remote name (default:origin)GIT_CHANGELOG_COMMAND- Override the git log command used for previews (default filters out release/hotfix/ci commits)GIT_CHANGELOG_DESCRIBE_COMMAND- Override the latest-tag detection command (default:git describe --tags --abbrev=0)
GitHub
GITHUB_RELEASE- Enable GitHub releases (default:false)GITHUB_REPOSITORY- Repository inowner/repoformat (auto-detected from git remote)
npm
NPM_PUBLISH- Enable npm publishing (default:false)NPM_SKIP_CHECKS- Skip npm checks (default:false)NPM_ACCESS- npm access level (default:public)NPM_TAG- Optional. When set, the npm publish step appends--tag <value>(e.g.legacy-v0.10.0). Used to assign version-named dist-tags when republishing older versions solatestis not overwritten. Empty / unset = npm useslatest.
Hotfix
HOTFIX_INCREMENT- Increment kind passed to release-it for thehotfixpreset (default:patch). Accepts any release-it increment value (patch,minor,major, or an explicit version).
ℹ️ By default, the presets skip GitHub releases and npm publishing. Set
GITHUB_RELEASE=trueand/orNPM_PUBLISH=truein the environment (typically in CI) when you are ready to perform those steps.
Example
CHANGELOG_FILE="HISTORY.md" \
GIT_REQUIRE_BRANCH="develop" \
GIT_REQUIRE_CLEAN="true" \
pnpm releaseConfiguration Modes
The preset supports two configuration modes:
Mode 1: Direct Preset Usage (No Config File)
When to use: Simple projects, trust preset defaults, or customize only via environment variables
Don't create .release-it.json. Just run the CLI:
pnpm release-it-preset defaultAll configuration comes from the preset and environment variables.
Pros:
- ✅ Zero config files
- ✅ Consistent behavior across projects
- ✅ Easy to understand
- ✅ Perfect for getting started
Mode 2: Preset + User Overrides (Recommended)
When to use: Customize specific options while keeping preset defaults
Create .release-it.json WITH the extends field:
{
"extends": "@oorabona/release-it-preset/config/default",
"git": {
"requireBranch": "master",
"commitMessage": "chore: release v${version}"
}
}Run with CLI preset:
pnpm release-it-preset defaultHow it works:
- The
extendsfield loads the preset - release-it merges your overrides on top via c12
- Your values take precedence over preset defaults
- CLI validates that
extendsis present; mismatched preset name warns and uses the invoked preset's config for that run
Pros:
- ✅ Recommended for customization
- ✅ Declarative config with explicit preset
- ✅ Industry standard pattern (like ESLint, TypeScript)
- ✅ Guaranteed config merging via release-it's c12
Example: Using hotfix preset but release from master instead of main:
{
"extends": "@oorabona/release-it-preset/config/hotfix",
"git": {
"requireBranch": "master"
}
}pnpm release-it-preset hotfixConfiguration Validation
The CLI validates your .release-it.json to prevent misconfigurations:
Error 1: Missing extends field
# .release-it.json without extends:
{
"git": { "requireBranch": "master" }
}
# Running:
pnpm release-it-preset default
# ❌ Configuration error!
# .release-it.json is missing the required "extends" field.
#
# Without "extends", your config won't merge with the preset.
# This means you'll get release-it defaults instead of preset defaults.
#
# Fix by adding this to .release-it.json:
# {
# "extends": "@oorabona/release-it-preset/config/default",
# ...your overrides
# }Why extends is required: Without it, release-it only loads your config file and uses release-it's own defaults. The preset is never loaded, so you lose important defaults like npm.publish: false.
Note: Preset mismatch (warning, not error)
# .release-it.json extends "default":
{
"extends": "@oorabona/release-it-preset/config/default"
}
# But you run:
pnpm release-it-preset hotfix
# ⚠️ Note: your .release-it.json extends "default"
# but you invoked the "hotfix" preset.
# Using "hotfix" config directly; .release-it.json customizations are ignored for this run.
# To use your customizations, run: release-it-preset defaultNote: invoking a preset different from your
.release-it.jsonextends value now warns and uses the invoked preset's config (was: hard error). Use the matching name to keep your customizations.
Which Mode Should I Use?
| Scenario | Recommended Mode | |----------|------------------| | Quick start, minimal config | Mode 1 (No config file) | | Customize branch/commit/hooks | Mode 2 (Config with extends) | | Environment-only customization | Mode 1 (Use env vars) | | Monorepo with per-package config | Mode 2 (Each package has own config) |
Use Mode 1 to get started, switch to Mode 2 when you need customization.
Borrowing Scripts & Workflows
- The root
package.jsonof this repository shows how to expose convenientpnpm run release:*shortcuts. Feel free to copy that block into your own project (adjust the commands if you only need a subset). - The GitHub Actions workflows under
.github/workflows/*.ymlillustrate how to wire the CLI into CI. They are safe to reuse, provided you review the permissions/secrets section and adapt branch names or triggers to your process.
Release Workflow
Recommended Workflow
Local (Developer):
Make changes and commit with conventional commits
Run
pnpm run release:updateto populate the[Unreleased]section from commitsReview
CHANGELOG.md- you have two options here:Option A: Quick release with auto-generated changelog
- Stage
CHANGELOG.mdas-is - Run
pnpm run release:validateto verify readiness - Dry-run with
pnpm run release:default:dry-run - Execute
pnpm releaseto perform the real release
Option B: Manual changelog editing (recommended for detailed release notes)
- Manually edit
CHANGELOG.md[Unreleased] section (add narrative, reorganize, etc.) - No need to stage or commit
- Run
pnpm run release:validate(orpnpm run release:validate:allow-dirty) - Dry-run with
pnpm run release:manual-changelog --dry-run - Execute
pnpm run release:manual-changelogto release- This skips changelog regeneration, preserving your edits
- Bumps version, moves [Unreleased] to versioned section
- Creates release commit + tag and pushes to origin (GitHub release happens later if
GITHUB_RELEASE=truein CI)
If you change your mind mid-release: If you started with Option A but want to add manual edits when prompted
Commit (chore(release): vX.Y.Z)?, answer No, then press Ctrl+C to abort. Edit yourCHANGELOG.md, then runpnpm run release:manual-changeloginstead. Alternatively, re-runpnpm releaseand select the same version again (the preset's--allow-same-versionmakes this safe).- Stage
Note: GitHub releases and npm publish are skipped locally by default. Enable them with environment variables or let the
publish.ymlworkflow handle both steps after the tag push.
flowchart TD
A[Conventional commits] --> B[pnpm run release:update]
B --> C{Want to edit<br/>changelog manually?}
C -->|No - Auto changelog| D[Stage CHANGELOG.md]
D --> E[pnpm run release:validate]
E --> F[pnpm run release:default:dry-run]
F --> G[pnpm release]
C -->|Yes - Manual editing| H[Edit CHANGELOG.md manually]
H --> I[pnpm run release:validate --allow-dirty]
I --> J[pnpm run release:manual-changelog --dry-run]
J --> K[pnpm run release:manual-changelog]
G --> L[Push commit \u0026 tag]
K --> L
L --> M[Publish workflow runs in CI]CI (GitHub Actions):
- When tag is pushed, CI publishes to npm with provenance
Why This Workflow?
- Single CI entry point - Tag pushes run the
retry-publishpreset, which updates the GitHub release and publishes to npm with provenance in one command. - Local runs stay safe - Without
GITHUB_RELEASE=trueorNPM_PUBLISH=true, the presets only handle changelog updates, commits, and tags. - Better security - Publishing requires CI credentials (GITHUB_TOKEN + NPM_TOKEN), keeping local environments token-free by default.
- Predictable outputs - Release notes are regenerated from the committed changelog, avoiding drift between local runs and CI.
GitHub Actions Setup
Create .github/workflows/publish.yml:
name: Publish Package
on:
push:
tags:
- 'v*'
permissions:
contents: write
id-token: write # For npm provenance
jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
with:
node-version: 20
registry-url: 'https://registry.npmjs.org'
cache: 'pnpm'
- run: pnpm install --frozen-lockfile
- run: pnpm build
- name: Update GitHub release and publish to npm
run: pnpm release-it-preset retry-publish --ci
env:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
NPM_PUBLISH: 'true'
GITHUB_RELEASE: 'true'
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}Required Secrets:
NPM_TOKEN- Automation token from npmjs.com (Settings → Access Tokens → Generate New Token → Automation)GITHUB_TOKENis provided automatically by GitHub Actions (no manual secret needed)
Required Permissions (locally):
- Set
GITHUB_RELEASE=trueand/orNPM_PUBLISH=trueonly when you explicitly want to perform those actions from your machine. ProvideGITHUB_TOKEN/NPM_TOKENas needed.
Alternative: Full CI Release
If you prefer to run the entire release in CI:
on:
workflow_dispatch: # Manual trigger
inputs:
version:
description: 'Version bump type'
required: true
type: choice
options: [patch, minor, major]
permissions:
contents: write # For git operations and GitHub releases
id-token: write # For npm provenance
jobs:
release:
runs-on: ubuntu-latest
steps:
# ... setup steps ...
- run: pnpm release-it-preset default --ci --increment ${{ inputs.version }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
GITHUB_RELEASE: 'true'
NPM_PUBLISH: 'true'GitHub Actions Workflows
This repository includes several GitHub Actions workflows for automated CI/CD and release management.
Reusable Workflows
Two workflows are designed for reuse in your own projects:
🔄 reusable-verify.yml - PR Validation & Hygiene Checks
Validates TypeScript compilation, runs tests, checks release readiness, and evaluates PR hygiene (changelog updates, conventional commits).
When to use: Import this workflow in your PR validation to ensure code quality and release readiness.
Inputs:
| Input | Type | Default | Description |
|-------|------|---------|-------------|
| node-version | string | '20' | Node.js version to use |
| run-tests | boolean | false | Run pnpm test after compilation |
| base-ref | string | '' | Base ref for diff comparisons (e.g., origin/main) |
| head-ref | string | 'HEAD' | Head ref for comparisons |
| install-args | string | '--frozen-lockfile' | Additional pnpm install arguments |
| fetch-depth | number | 0 | Git fetch depth for checkout |
Outputs:
| Output | Description |
|--------|-------------|
| release_validation | 'true' when release validation passes |
| changelog_status | Changelog status: updated, skipped, or missing |
| skip_changelog | 'true' when [skip-changelog] detected in commits |
| conventional_commits | 'true' when conventional commits detected |
| commit_messages | Base64 encoded JSON array of analyzed commit messages |
| changed_files | Base64 encoded JSON array of changed files |
Example usage in your project:
# .github/workflows/validate-pr.yml
name: PR Validation
on:
pull_request:
types: [opened, synchronize, reopened]
jobs:
validate:
uses: oorabona/release-it-preset/.github/workflows/reusable-verify.yml@main
with:
node-version: '20'
base-ref: origin/${{ github.base_ref }}
head-ref: ${{ github.sha }}
run-tests: true
secrets: inherit
comment:
needs: validate
runs-on: ubuntu-latest
if: always()
permissions:
pull-requests: write
steps:
- uses: actions/github-script@v7
with:
script: |
const summary = `## 📋 PR Validation
${needs.validate.outputs.release_validation === 'true' ? '✅' : '⚠️'} Release validation
${needs.validate.outputs.changelog_status === 'updated' ? '✅' : 'ℹ️'} Changelog: ${needs.validate.outputs.changelog_status}
${needs.validate.outputs.conventional_commits === 'true' ? '✅' : 'ℹ️'} Conventional commits
`;
github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: summary
});🔄 build-dist.yml - Build Compiled Distribution
Builds TypeScript sources to dist/ and uploads as artifact for reuse in other jobs.
When to use: When you need compiled outputs across multiple jobs without rebuilding.
Inputs:
| Input | Type | Default | Description |
|-------|------|---------|-------------|
| artifact_name | string | 'dist-build' | Name for the uploaded dist artifact |
| ref | string | (current) | Optional git ref to checkout before building |
Outputs:
| Output | Description |
|--------|-------------|
| artifact_name | Name of the uploaded dist artifact |
Example usage in your project:
# .github/workflows/ci.yml
jobs:
build:
uses: oorabona/release-it-preset/.github/workflows/build-dist.yml@main
with:
artifact_name: my-dist
ref: ${{ github.sha }}
test:
needs: build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/download-artifact@v4
with:
name: ${{ needs.build.outputs.artifact_name }}
path: dist
- run: pnpm testWorkflow Reference
Overview Table
| Workflow | Type | Trigger | Purpose |
|----------|------|---------|---------|
| 🔄 reusable-verify.yml | Reusable | workflow_call | PR validation & hygiene checks |
| 🔄 build-dist.yml | Reusable | workflow_call | Build TypeScript distribution |
| ⚙️ ci.yml | Standalone | Push, PR, Manual | Continuous Integration |
| ✅ validate-pr.yml | Standalone | PR | Pull request validation |
| 🚨 hotfix.yml | Manual | workflow_dispatch | Emergency hotfix releases |
| 🔄 retry-publish.yml | Manual | workflow_dispatch | Retry failed publishing |
| ⚠️ republish.yml | Manual | workflow_dispatch | Republish existing version |
| 📦 publish.yml | Reusable | Tag push, workflow_call | Automated publishing |
You can copy these workflows into your own repository (adjusting names, branches, and secrets to match your context). They work with the release-it-preset CLI defaults.
1. ⚙️ CI (.github/workflows/ci.yml)
Triggers:
- Push to
main - Pull Requests to
main - Manual (
workflow_dispatch)
Jobs:
build-dist- Builds compiled distribution using reusable workflowtests- Runs unit tests with coveragetest-cli- Tests all CLI commands (help, check, validate, init)release- Manual release creation (workflow_dispatch only)
Manual Release:
# Go to Actions → CI → Run workflow
# Select increment type: patch, minor, or majorSecrets required:
NPM_TOKEN- npm automation token (for release job)CODECOV_TOKEN- Codecov upload token (optional)
2. ✅ Validate PR (.github/workflows/validate-pr.yml)
Triggers:
- Pull Request
opened,synchronize,reopened - Can be called as reusable workflow (
workflow_call)
Jobs:
validate- Usesreusable-verify.ymlfor hygiene checkssummarize- Posts validation summary comment on PR
What it checks:
- ✅ TypeScript compilation
- ✅ Release validation (with
--allow-dirty) - ✅ CHANGELOG.md updates (or
[skip-changelog]marker) - ✅ Conventional commits format
- ✅ Commit messages analysis
Permissions required:
permissions:
contents: read
pull-requests: write # For posting commentsNo secrets required (uses GITHUB_TOKEN automatically)
3. 🚨 Hotfix Release (.github/workflows/hotfix.yml)
Trigger: Manual (workflow_dispatch)
Inputs:
| Input | Type | Required | Default | Description |
|-------|------|----------|---------|-------------|
| increment | choice | ✅ | patch | Version bump: patch or minor |
| commit | string | ❌ | latest | Specific commit SHA to release |
| dry_run | boolean | ❌ | false | Test without actual publishing |
Jobs:
validate- Validates TypeScript compilation and buildshotfix- Creates emergency hotfix release and publishes
What it does:
- Validates code at specified commit
- Auto-generates changelog from recent commits
- Creates hotfix release (patch/minor bump)
- Pushes git tag
- Publishes to npm with provenance
- Creates GitHub Release
When to use: Critical bugs needing immediate patch release
Permissions required:
permissions:
contents: write # For git operations
id-token: write # For npm provenanceSecrets required:
NPM_TOKEN- npm automation tokenGITHUB_TOKEN- Provided automatically
4. 🔄 Retry Publish (.github/workflows/retry-publish.yml)
Trigger: Manual (workflow_dispatch)
Inputs:
| Input | Type | Required | Default | Description |
|-------|------|----------|---------|-------------|
| tag_name | string | ❌ | latest tag | Git tag to republish |
| npm_only | boolean | ❌ | false | Publish to npm only (skip GitHub Release) |
| github_only | boolean | ❌ | false | Create GitHub Release only (skip npm) |
Jobs:
determine-tag- Validates and determines which tag to publishbuild-dist- Builds distribution using reusable workflowretry-publish- Republishes to npm and/or GitHub
What it does:
- Verifies git tag exists
- Runs pre-flight checks (
retry-publish.jsscript) - Republishes to selected destination(s)
- Uses existing changelog for release notes
When to use: Previous publish failed (network issue, auth problem, etc.)
Permissions required:
permissions:
contents: write # For GitHub releases
id-token: write # For npm provenanceSecrets required:
NPM_TOKEN- npm automation token (if npm publish enabled)GITHUB_TOKEN- Provided automatically
5. ⚠️ Republish (EXCEPTIONAL) (.github/workflows/republish.yml)
Trigger: Manual (workflow_dispatch)
⚠️ DANGER: Moves existing git tag (breaks semver immutability)
Inputs:
| Input | Type | Required | Description |
|-------|------|----------|-------------|
| version | string | ✅ | Version to republish (e.g., 1.2.3) |
| confirmation | string | ✅ | Must type exactly "I understand the risks" |
Jobs:
pre-flight-checks- Validates confirmation, version format, and tag existencebuild-dist- Builds distribution using reusable workflowvalidate- Validates TypeScript compilationrepublish- Moves git tag and updates GitHub release
What it does:
- Pre-flight safety checks:
- Validates confirmation phrase
- Checks version format
- Verifies tag exists
- Displays warning message
- 10-second safety delay ⏰
- Validates code compilation
- Moves git tag to current commit (⚠️ breaks immutability)
- Updates changelog for current version
- Updates GitHub Release
Note: npm is not republished — npm immutability (since 2016) prevents republishing an existing version. To redirect a dist-tag, use
npm dist-tag add. To retry a failed publish, use theretry-publishpreset.
When to use: ONLY for exceptional emergencies where a published version must be moved to a different commit (e.g. a broken tag pointing to the wrong SHA)
Permissions required:
permissions:
contents: write # For git tag operationsSecrets required:
GITHUB_TOKEN- Provided automatically
Concurrency: Prevents parallel republish operations for same version
6. 📦 Publish (.github/workflows/publish.yml)
Triggers:
- Tag push matching
v*pattern - Can be called as reusable workflow (
workflow_call)
Inputs (for workflow_call):
| Input | Type | Required | Description |
|-------|------|----------|-------------|
| tag | string | ❌ | Override tag (auto-detected from github.ref_name) |
Jobs:
build-dist- Builds distribution using reusable workflowpublish- Updates GitHub release and publishes to npm
What it does:
- Builds compiled distribution
- Runs
release-it-preset retry-publish --ci - Creates/updates GitHub Release with changelog
- Publishes to npm with provenance attestation
When it runs: Automatically triggered when a tag is pushed (e.g., by default or hotfix workflows)
Permissions required:
permissions:
contents: write # For GitHub releases
id-token: write # For npm provenance attestationSecrets required (for workflow_call):
NPM_TOKEN- npm automation token (must be passed explicitly)
Secrets required (for tag push):
NPM_TOKEN- npm automation token (repository secret)GITHUB_TOKEN- Provided automatically
Environment variables set:
GITHUB_RELEASE=true- Enables GitHub release creationNPM_PUBLISH=true- Enables npm publishing
Workflows Summary Diagram
graph TB
subgraph "Reusable Workflows"
RV[🔄 reusable-verify.yml<br/>PR validation & hygiene]
BD[🔄 build-dist.yml<br/>Build TypeScript dist]
end
subgraph "Development Flow"
PR[Pull Request] --> VPR[✅ validate-pr.yml]
VPR --> RV
VPR --> Comment[Post PR comment]
end
subgraph "Release Flow"
Manual[Manual Trigger] --> CI[⚙️ ci.yml]
CI --> BD
CI --> Tag[Create Tag]
Tag --> PUB[📦 publish.yml]
PUB --> BD
PUB --> NPM[npm publish]
PUB --> GH[GitHub Release]
end
subgraph "Emergency Flow"
Critical[Critical Bug] --> HF[🚨 hotfix.yml]
HF --> BD
HF --> Tag
end
subgraph "Recovery Flow"
Failed[Failed Publish] --> RP[🔄 retry-publish.yml]
RP --> BD
RP --> Decision{Retry What?}
Decision -->|npm only| NPM
Decision -->|GitHub only| GH
Decision -->|Both| Both[npm + GitHub]
end
style RV fill:#e1f5fe
style BD fill:#e1f5fe
style VPR fill:#c8e6c9
style CI fill:#fff9c4
style HF fill:#ffccbc
style RP fill:#b2ebf2
style PUB fill:#d1c4e9Best Practices
- Use conventional commits - Enables automatic changelog generation
- Keep [Unreleased] updated - Run
pnpm release-it-preset updateregularly or before releases - Validate before releasing - Run
pnpm release-it-preset validateto catch issues early - Test releases - Use
--dry-runflag to test without publishing - Protect main branch - Require PR reviews before merging
- Use CI for publishing - Let GitHub Actions handle GitHub releases and npm publishing with provenance
- Local runs are for prep - Keep local runs focused on changelog, versioning, and tagging unless you explicitly opt in to publish
Security
This preset implements OWASP security best practices:
Input Validation
All CLI inputs are validated before execution:
- Whitelist validation: Config names and commands are validated against allowed lists
- Argument sanitization: All arguments are checked for dangerous characters (
;,&,|,`,$(), etc.) - Path traversal protection: File paths are validated to prevent directory traversal attacks
Command Injection Prevention
- All
spawn()calls useshell: falseto prevent command injection - Arguments are passed as arrays, not concatenated strings
- No user input is ever executed in a shell context
Architecture
The preset follows SOLID principles:
- Single Responsibility: Each module has one clear purpose
- DRY: Shared configuration builders eliminate code duplication
- Dependency Inversion: User configs have priority over preset defaults
All 213 unit tests verify functionality and security boundaries.
Troubleshooting
Changelog not updating
Run the update command:
pnpm release-it-preset updateGitHub releases failing
Ensure you have a GITHUB_TOKEN with repo scope and opt in to GitHub releases:
GITHUB_RELEASE=true GITHUB_TOKEN=your_token pnpm release-it-preset defaultOr use GitHub CLI authentication:
gh auth login
pnpm release-it-preset defaultnpm publish failing in CI
Check that:
NPM_TOKENsecret is set in repository settings- Token is an automation token (not a publish token)
- Token has permission to publish the package
- Package name is available (not already taken)
Remember to export NPM_PUBLISH=true (and GITHUB_RELEASE=true if you expect a GitHub release) in the workflow or shell where you invoke release-it.
Test locally:
pnpm release-it-preset check # Check npm auth status
pnpm npm whoami # Verify authenticationValidation failing
Run check command to see detailed status:
pnpm release-it-preset checkCommon issues:
- Working directory not clean → commit or stash changes, or use
--allow-dirty - [Unreleased] section empty → run
pnpm release-it-preset update - Not on required branch → checkout correct branch or update
GIT_REQUIRE_BRANCH
npm error Version not changed
This can appear if you interrupt a release, tweak CHANGELOG.md, then retry with the same version. The preset automatically passes --allow-same-version to npm version, so simply re-run pnpm release (or pnpm release-it-preset default --retry) and select the same version—npm will no longer abort.
Exit codes
The CLI follows this convention (stable from v1.0.0 onward):
| Code | Meaning | Examples |
|---|---|---|
| 0 | Success | Command completed; for doctor, READY or WARNINGS status |
| 1 | General failure | Unhandled error, validation failure, doctor BLOCKED status |
| 2 | Precondition failure (CI-friendly) | validate reports CHANGELOG missing or [Unreleased] empty |
| 3..9 | Reserved | Not currently emitted; reserved for future contract additions |
In CI scripts, distinguish exit 1 (try-again-friendly) from exit 2 (precondition not met — require operator action) when chaining commands.
Public API
The full stable surface (CLI commands, environment variables, config exports, GHA workflow inputs, exit codes) is documented in docs/PUBLIC_API.md. Items not listed there are internal and may change in any version.
License
MIT — see LICENSE.
Contributing
PRs and issues welcome. Please read CONTRIBUTING.md before opening a pull request — it covers the Conventional Commits requirement, branch prefixes, the pre-PR checklist, and the testing conventions. By participating you agree to abide by the Code of Conduct (Contributor Covenant 2.1).
For security concerns, please email [email protected] directly rather than opening a public issue. See SECURITY.md for the disclosure policy.
