Commands

chamoji release

release.mdEdit on GitHub

Cut a release from your git history. chamoji picks the version from your commits, writes the CHANGELOG.md section, bumps your version files, then makes the release commit and an annotated tag. Add --push to push it and create the GitHub release.

CHANGES YOUR REPO MONOREPO-AWARE --json FOR CI AND AGENTS

In a monorepo, a version argument needs exactly one --unit: chamoji has to know which app or package the version is for.

CHANGES YOUR REPOchamoji release

What it does, in order

  1. Checks. A clean working tree, the default branch when git knows origin’s, and the full history. A shallow clone is unshallowed, and tags are fetched from origin first.
  2. Version. The one next-version picks, or the one you give. The tag follows your tags’ style, v1.4.0 or 1.4.0.
  3. CHANGELOG.md. The new section goes above the last release, below any Unreleased section, and older entries stay exactly as they are. A repo without the file gets one written from the whole history.
  4. Version bumps. Every tracked package.json, package-lock.json, pyproject.toml or Cargo.toml that carries the previous version. On a first release, every one that says another version.
  5. Commit and tag. A release commit in your repo’s style, such as 🔖 Release v1.4.0, which later changelogs leave out, and an annotated tag. If anything fails before the tag exists, the repo is reset to where it started.
  6. With --push. Pushes HEAD and the tag, syncs project memory if chamoji init ran in this clone, then creates the GitHub release with the gh CLI. A failed push keeps the local release.

In a repo with release units, each unit with something to release gets its own version, tag and changelog, in one release commit. The units’ version files are bumped, and the others wait. Monorepos explains which commits belong to which unit.

Arguments

  • Name
    version
    Type
    semver · optional
    Description

    A version you choose, such as 2.0.0 or a prerelease like 2.0.0-rc.1. It must be newer than the last release. Leave it out and chamoji picks one from the commits. Without release units, the first release needs one, since there is no tag to count from. In a monorepo it needs exactly one --unit.

Flags

  • Name
    --dry-run
    Type
    boolean
    Description

    Print the version, the files and the notes it would release, and write nothing. A dirty working tree is allowed; the other checks still run, and tags are still fetched. Wins over --push: nothing is committed, tagged or pushed.

  • Name
    --push
    Type
    boolean
    Description

    After the commit and tag, push HEAD and the tag to origin, sync memory if chamoji init ran here, and create the GitHub release with the gh CLI, marked as a prerelease for a prerelease version. Without gh, the push still happens and the output says the GitHub release was not created. In a monorepo it creates one GitHub release per tag, or one for all of them with "githubReleases": "combined".

  • Name
    --unit <name>
    Type
    string · repeatable · monorepos
    Since
    SINCE 0.13.0
    Description

    Release only these units, even when others have changes; the others stay waiting. Repeat it for several. A version argument needs exactly one. Only in a repo with release units; elsewhere, and for an unknown unit, it exits 1.

  • Name
    --any-branch
    Type
    boolean
    Description

    Skip the check that you are on origin’s default branch, for release branches and hotfixes. The other checks still run.

  • Name
    --json
    Type
    boolean
    Description

    Print the result as JSON on stdout, for scripts, CI and agents, with a status of dry-run, released or nothing. Works with every other flag; exit codes stay the same.

  • Name
    --trailer "Key: value"
    Type
    string · repeatable
    Description

    Add a trailer line to the release commit. Repeat it for several lines. Ignored with --dry-run, which makes no commit.

  • Name
    --ai
    Type
    boolean
    Description

    Sort commits the rules can’t place with Jev, as changelog --ai does. Only changes how unplaced commits are grouped, and so the bump. Needs TYPESAFE_API_KEY, or it exits 1.

  • Name
    --config <file>
    Type
    string · default chamoji.config.json
    Description

    Read this config file instead, from a path relative to the current folder. Without it, chamoji reads chamoji.config.json in the current folder, not at the repo root, so run chamoji from the root. A file that doesn’t exist exits 1.

  • Name
    --no-update-check
    Type
    boolean
    Description

    Don’t check npm for a newer chamoji. See the update notice.

Common combinations

chamoji release --dry-run

See what the next release would be before you cut it.

chamoji release --dry-run --json

Let CI or your agent read the next version and notes.

chamoji release --push

Cut and ship it in one step.

chamoji release 2.0.0-rc.1

A prerelease, or any version you choose.

chamoji release --unit web --push

Ship one app in a monorepo now; the rest waits.

chamoji release --any-branch

Release from a hotfix or release branch.

To treat “nothing to release” as success in CI:

chamoji release --push || [ $? -eq 3 ]

Output

These are from real runs in a small repo called widgets, at v0.1.0, with a ✨, a 🐛 and a ✅ commit since. Preview it first:

chamoji release --dry-run

Would release v0.2.0 (minor, from v0.1.0).
files: CHANGELOG.md, package.json

## v0.2.0 - 2026-11-05

### Added

- ✨ Add a range mode to the date picker (3565b84)

### Fixed

- 🐛 Close the dialog on Escape (a13acb6)

### Maintenance

- ✅ Test the range mode (d6e8b65)

The same preview for a script:

chamoji release --dry-run --json

{
  "status": "dry-run",
  "version": "0.2.0",
  "tag": "v0.2.0",
  "bump": "minor",
  "from": "v0.1.0",
  "files": [
    "CHANGELOG.md",
    "package.json"
  ],
  "warnings": [],
  "notes": "## v0.2.0 - 2026-11-05\n\n### Added\n\n- ✨ Add a range mode to the date picker (3565b84)\n\n### Fixed\n\n- 🐛 Close the dialog on Escape (a13acb6)\n\n### Maintenance\n\n- ✅ Test the range mode (d6e8b65)"
}

Without --push, the output says how to ship the release, and how to undo it before you do:

chamoji release 0.1.0

Released v0.1.0 (first release).
changelog: CHANGELOG.md, created from the full history
bumped: no manifest carried the old version
commit: ef90ddf 🔖 Release v0.1.0
tag: v0.1.0 (annotated)
pushed: no; to ship: git push origin HEAD v0.1.0
undo before pushing: git tag -d v0.1.0 && git reset --hard 0f7511f

## v0.1.0 - 2026-11-05

…

With --push. This run had a stand-in gh on the PATH that records the call and succeeds. The repo had workstreams in memory, but chamoji init hadn’t run in this clone, so memory wasn’t synced:

chamoji release --push

Released v0.3.0 (minor, from v0.2.1).
changelog: CHANGELOG.md, new section added above the previous release; older entries untouched
bumped: package.json
commit: a8332d9 🔖 Release v0.3.0
tag: v0.3.0 (annotated)
pushed: yes (HEAD and v0.3.0); GitHub release created
memory: not synced; run chamoji init to share it with origin

## v0.3.0 - 2026-11-05

…

The call it made was gh release create v0.3.0 --title v0.3.0 --notes-file .git/chamoji-release-notes.md, with the file’s full path. Without gh, the push still happens:

chamoji release --push

Released v0.2.1 (patch, from v0.2.0).
changelog: CHANGELOG.md, new section added above the previous release; older entries untouched
bumped: package.json
commit: 3feff78 🔖 Release v0.2.1
tag: v0.2.1 (annotated)
pushed: yes (HEAD and v0.2.1); GitHub release not created: no gh CLI, so no GitHub release

…

When no commit since the last tag implies a bump, it lists what is waiting and exits 3:

chamoji release

Nothing to release: no commit since v0.2.0 implies a version bump.
Unreleased commits:
- 📝 Add a usage example to the readme

In shop, whose two apps release on their own, --unit web releases web and says what mobile has waiting:

chamoji release --unit web

Released web/v1.2.0.
web  1.2.0 → 1.2.0  first  2 own, 1 shared
files: apps/web/CHANGELOG.md, apps/web/package.json
commit: b6d392c 🔖 Release web/v1.2.0
tags: web/v1.2.0 (annotated)
pushed: no; to ship: git push origin HEAD web/v1.2.0
mobile: left out by --unit (2 changes of its own, 1 shared waiting)
undo before pushing: git tag -d web/v1.2.0 && git reset --hard 31673c1

## web/v1.2.0

## 1.2.0 - 2026-11-05

### Added

- ✨ Add the checkout page (ab41693)
- 🎉 Begin the shop (51bca17)

### Fixed

- 🐛 Fix the button's focus ring (ae44eff) (via `packages/ui`)

Each failed check says what to do:

Checks

$ chamoji release
chamoji: the working tree has uncommitted changes; commit or stash them first:
M src/picker.js

Exit codes

  • Name
    0
    Description
    Released, or the dry run worked.
  • Name
    3
    Description
    Nothing to release since the last tag.
  • Name
    2
    Description

    A check failed: a dirty working tree, the wrong branch, a shallow clone it couldn’t unshallow, a version that isn’t semver or isn’t newer, a first release with no version, or a tag that already exists. In a monorepo, also a version file it can’t set: a versionFiles entry that is missing or a symlink, a file it can’t set the version in, a dependency range it can’t set, or a version that differs from its fixed group’s. Also for a release section from a newer chamoji.

  • Name
    1
    Description

    Anything else, such as a failed push, an unknown unit, or a version without --unit in a monorepo.

Exit codes has every command’s codes.

Was this page helpful?