@monochange/cli
v0.8.1
Published
CLI for cross-ecosystem monorepo release planning with monochange
Maintainers
Readme
monochange
manage versions and releases for your multiplatform, multilanguage monorepo
monochange is a release-planning toolkit for monorepos that span more than one package ecosystem.
It discovers packages, normalizes dependency data, applies group rules, turns explicit change files into release plans, and can run config-defined release preparation from those same inputs.
Use it when your repository has outgrown one-ecosystem release tooling and you want one model for Cargo, npm/pnpm/Bun, Deno, Dart/Flutter, Python, and Go.
Who monochange is for
- maintainers of monorepos that span more than one package ecosystem
- teams replacing ad hoc release scripts with explicit, reviewable change files
- people who want one safe release-planning model before adding provider automation
First 10 minutes
Install the prebuilt CLI from npm:
npm install -g @monochange/cli
monochange --help
monochange --helpIf you prefer a Rust-native install, use cargo install monochange instead.
Then run one safe local walkthrough:
Generate a starter config from the packages monochange detects:
monochange initmonochange init writes an annotated, minimal monochange.toml without default [cli.*] workflow aliases. The binary exposes immutable monochange step * commands for every built-in step when you need a direct, config-free entry point; add [cli.*] tables only for repository-specific named workflows.
For automated CI setup, include the --provider flag:
monochange init --provider githubThis configures the [source] section, generates CLI commands for commit-release and release-pr, and creates GitHub Actions workflows.
Validate the workspace:
monochange step validateDiscover the package ids you will use in commands and changesets:
monochange step discover --format jsonCreate one change file for a package id:
monochange run change --package <id> --bump patch --reason "describe the change"Most changes should target a package id. Use group ids only when the change is intentionally owned by the whole group.
When a package is only changing because another dependency or version group moved first, author that context explicitly instead of relying on anonymous propagation:
monochange run change --package <dependent-id> --bump none --caused-by <upstream-id> --reason "dependency-only follow-up"Preview the release plan safely:
monochange run release --dry-run --format jsonAdd --diff when you want unified file previews for version and changelog updates without mutating the workspace:
monochange run release --dry-run --diffThis first run is safe: nothing is published. Stop here until you are ready to prepare release files locally.
When you are ready to prepare the release locally, run monochange run release.
If you do not know which package id to target, rerun monochange step discover --format json and copy an id directly from the output.
Next steps
- Start here — the shortest beginner path through installation,
monochange init, and--dry-run - Installation — npm, Cargo, optional assistant tooling, and repository-development setup
- Your first release plan — a fuller walkthrough built around generated config
- Discovery — what monochange finds and how ids are rendered
- Configuration reference — evolve the generated config once the basics feel familiar
- Groups and shared release identity — when to reach for group ids instead of package ids
Why use monochange?
- use one release-planning model across several language ecosystems
- replace ad hoc scripts with explicit change files and deterministic release output
- keep related packages synchronized with
[group.<id>] - propagate dependent bumps through one normalized dependency graph
- expose repository-defined workflow commands as
monochange run <command>from[cli.<command>]entries inmonochange.toml
Advanced workflows
GitHub automation
monochange can promote one prepared release into several source-provider automation flows without changing the underlying release-plan model.
monochange run release --dry-run --format jsonrefreshes the cached manifest and shows downstream automation data, including authored changesets plus linked release context metadatamonochange step publish-release --dry-run --format jsonpreviews provider release payloads before publishingmonochange step open-release-request --dry-run --format jsonpreviews the release branch, commit, and release-request body- when
[source.pull_requests].verified_commits = trueandOpenReleaseRequestruns on GitHub Actions for the configured GitHub repository, the GitHub provider pushes a normal release branch commit first, then attempts to replace it with a Git Database API commit that GitHub reports as verified; if verification or the API update fails, the normal pushed commit remains in place monochange step release-record --from <tag>inspects the durable release declaration stored in the release commit bodymonochange step tag-release --from HEAD --dry-run --format jsonpreviews the post-merge release tag set declared by that durable recordmonochange step retarget-release --from <tag> --dry-runpreviews a release-retarget plan before mutating tags- changelog templates can render linked change owners, review requests, commits, and closed issues through
{{ context }}or fine-grained metadata variables monochange step affected-packages --format json --verify --changed-paths ...evaluates pull-request changeset policy from CI-supplied paths and labels without requiring a config-defined wrapper commandmonochange step diagnose-changesets --format jsonshows all discovered changeset context or restricts to explicit inputs
Tag-release JSON for follow-up workflows
When a post-merge workflow needs to trigger follow-up release work, prefer monochange step tag-release --from HEAD --format json and read the release tag by package or group id from the top-level tags object:
{
"tags": {
"main": "v1.2.3",
"sdk": "sdk/v1.2.3"
}
}name/version examples such as sdk/v1.2.3 correspond to a tag template like {{ name }}/v{{ version }}.
The tags object is intentionally flat because package ids and group ids share the same monochange namespace. A workspace cannot have both a package and a group with the same id, so workflows do not need separate tags.packages and tags.groups branches or prefixed lookup keys. This makes automation stable and explicit: use .tags.<id> for the package or group whose release should drive the next step.
A package or group might not be released in a particular release commit. Handle that by checking whether tags has an entry for the id you care about. If there is no tag attached to that id, you can assume that release did not include that package or group and skip that follow-up workflow.
For example, a repository with [group.main] can trigger a downstream GitHub release workflow from the main group tag with:
monochange step tag-release --from HEAD --format json >/tmp/tag-report.json
tag="$(jq -r '.tags.main // empty' /tmp/tag-report.json)"
if [ -z "$tag" ]; then
echo "No main group tag found in tag-report.json, skipping release trigger"
exit 0
fi
gh workflow run release.yml --ref "$tag" -f tag="$tag"Avoid indexing tagResults[0] for workflow control. tagResults remains the audit log of tag operations, while tags is the stable id-addressable map for automation.
Assistant setup and MCP
Assistant tooling is optional.
When you want AI-assisted workflows, monochange ships built-in setup guidance and an MCP server:
monochange help skill
monochange skill -a pi -y
monochange help subagents
monochange subagents pi
monochange mcpSee Advanced: Assistant setup and MCP for the full setup flow.
What monochange can do today
- discover Cargo, npm/pnpm/Bun, Deno, Dart, Flutter, Python, and Go packages
- normalize dependency edges across ecosystems
- coordinate shared package groups from
monochange.toml - compute release plans from explicit change input
- expose repository-defined workflow commands as
monochange run <command>from[cli.<command>]definitions - run config-defined release commands from
.changeset/*.md - render changelogs through structured release notes and configurable formats
- emit stable release-manifest JSON for downstream automation
- preview or publish provider releases and release requests from typed command steps and shared release data
- inspect durable release records from tags or descendant commits with
monochange step release-record - create post-merge release tags from a merged release commit with
monochange step tag-release --from HEAD - repair a recent source/provider release by retargeting its release tags with
monochange step retarget-release - inspect changeset context and review metadata with
monochange step diagnose-changesetsfor both human and automation workflows - apply Rust semver evidence when provided
- expose a bundled assistant skill plus a stdio MCP server with
monochange mcp - publish the CLI as
@monochange/cliand the bundled agent skill as@monochange/skill - publish end-user documentation through the mdBook in
docs/
Workspace crates
monochange— end-user CLI and orchestration layer for discovery, planning, and CLI-defined release commands.monochange_core— shared domain model for packages, dependency edges, groups, change signals, and release plans.monochange_config— loadsmonochange.toml, parses.changeset/*.md, and validates CLI command inputs.monochange_graph— propagates release impact through dependency edges and synchronized groups.monochange_github— converts release manifests into GitHub release payloads and publishing operations.monochange_gitlab— converts release manifests into GitLab release payloads and merge-request operations.monochange_gitea— converts release manifests into Gitea release payloads and pull-request operations.monochange_forgejo— converts release manifests into Forgejo automation requests.monochange_hosting— shared release-request abstractions for GitHub, GitLab, Gitea, and Forgejo providers.monochange_publish— publishing support and trusted-publishing capability helpers for package registries.monochange_ecmascript— shared JavaScript/TypeScript ecosystem utilities for npm, Deno, and JSR discovery.monochange_semver— merges requested bumps with compatibility-provider evidence.monochange_telemetry— local-only telemetry event sink and privacy-preserving event schema helpers.monochange_cargo— Cargo discovery plus Rust semver evidence integration.monochange_npm— npm, pnpm, and Bun workspace discovery.monochange_deno— Deno workspace and package discovery.monochange_dart— Dart and Flutter workspace discovery.monochange_python— Python uv workspace, Poetry, and pyproject.toml discovery.monochange_go— Go module discovery, go.mod dependency rewrites, and tag-based release metadata.
Repository development
Enter the reproducible development shell and install workspace tooling:
devenv shell
install:all
monochange step validate
monochange step discover --format json
monochange run change --package monochange --bump minor --reason "add release planning"
monochange step diagnose-changesets --format json
monochange run release --dry-run --format json
monochange step publish-release --dry-run --format json
monochange step open-release-request --dry-run --format json
monochange step release-record --from v1.2.3
monochange step tag-release --from HEAD --dry-run --format json
monochange step publish-readiness --from HEAD --output .monochange/readiness.json
monochange step placeholder-publish --from HEAD --output .monochange/bootstrap-result.json
monochange step publish-readiness --from HEAD --output .monochange/readiness.json
monochange step plan-publish-rate-limits --readiness .monochange/readiness.json --format json
monochange step publish-packages --output .monochange/publish-result.json
monochange step retarget-release --from v1.2.3 --target HEAD --dry-run
monochange run releaseUseful commands:
monochange --help
monochange --help
docs:check # verify mdt shared-doc synchronization
docs:update # synchronize shared docs via mdt update
schema:check # verify committed JSON schemas are current
schema:update # regenerate schema assets from source
monochange step validate
lint:all
test:all
coverage:all
coverage:patch
build:all
build:bookSee docs/ for user-facing guides and CONTRIBUTING.md for contribution expectations.
