Docs

Ship

Release Batches ​

Group pull requests into a named release, see readiness across all of them, and cut one version, changelog entry, tag and GitHub Release.

The dashboard shows this workflow as the Batches tab on the Releases page; the CLI and API keep the train commands and the release_trains feature flag.

When every merge cuts its own version, version numbers stop meaning anything, and nobody can say whether a group of related changes is ready. A release train fixes that. It is for release managers and engineering leads who ship several pull requests together.

Beta, early access. A workspace without access gets 403 FEATURE_EARLY_ACCESS and a link to request it. Flag: release_trains.

A release train is a named group of pull requests that ship together as one version. Each pull request still merges and deploys on its own. When the whole group is ready, you cut the train, and Bumpkit makes one version, one changelog entry, one tag and one GitHub Release for all of it.

How it works ​

  1. You start a train with a name, for example "Enterprise".
  2. Pull requests join it in one of three ways: a label (train:<slug> by default), a milestone, or bumpkit train add. Agents can join their own pull requests through the API or MCP.
  3. Bumpkit works out the train's readiness from each member's release gate decision for its head commit, and, if you ask for it, each member's release health in production.
  4. A release manager approves the current members.
  5. You cut the train. Bumpkit versions every commit since the last tag, writes one changelog entry carrying the train's name, and creates the tag and GitHub Release.

Cutting a train needs the GitHub App on the repository, and the repository needs at least one release tag such as v1.0.0 to version from.

Start a train ​

Terminal
bumpkit train new "Checkout v2"
bumpkit train new Enterprise --milestone "Q4 enterprise"

Bumpkit prints the label to use. Label a pull request with it and the pull request joins the train.

Flag Meaning
--branch The branch the train ships. Default: the repository's default branch.
--label The pull request label that joins it. Default: train.label in bumpkit.yml, else train:<slug>.
--milestone A milestone whose pull requests join it.
--repository owner/name. Default: the origin remote. Works on every bumpkit train command.

Add and remove pull requests ​

Terminal
bumpkit train add "Checkout v2" 412
bumpkit train remove "Checkout v2" 409

add takes --head SHA when the Bumpkit GitHub App can't read the pull request. A head commit given this way is marked as asserted, and the train asks for approval instead of trusting it.

Check readiness ​

Terminal
bumpkit train list --status open
bumpkit train show "Checkout v2"

show lists every pull request with the latest gate decision Bumpkit made on a diff it fetched itself (through the GitHub App or a connected GitLab, Bitbucket or Azure DevOps repository; a bumpkit gate decision doesn't count) and its health, plus the train's overall verdict and the reasons behind it. The verdict is the worst of the reasons:

Verdict Meaning
ready Every rule is met. You can cut the train.
waiting Something is still in progress: a member isn't merged, has no gate decision against your default branch for its head commit yet, or the train has no members.
needs_approval A member needs approval, a head commit was asserted rather than read from GitHub, or the train needs more release manager approvals.
blocked A member fails the gate, the train carries more breaking changes than allowed, a member is unhealthy in production, or Bumpkit couldn't read the train policy.

Readiness also lists what the train carries across all members: breaking changes, migrations, new environment variables and the product areas it reaches.

bumpkit train list --status accepts open, ready, blocked, cut or abandoned.

Approve and cut ​

Approving and cutting need a person signed in to the dashboard. Open the batch under Releases, then choose Approve batch and Start release. An API key is refused: bumpkit train approve, bumpkit train cut, the MCP tools and the API answer 403 HUMAN_APPROVAL_REQUIRED with the link to the batch page.

An approval covers the train's members as they are when you approve. If members change, earlier approvals stop counting.

Only a workspace owner or admin, or a release manager named in train.require_approval who approved the current members, can cut a train.

If the train isn't ready, a workspace owner or admin can still cut it by entering a reason of 10 to 500 characters on the batch page.

The reason is kept in the audit record. This is refused when the repository's bumpkit.yml sets gate.break_glass: false. See Hotfixes & Break Glass.

Policy ​

Add a train: section to bumpkit.yml on the branch the train ships:

YAML
train:
  label: "train:{slug}"
  require_all_pass: true
  max_breaking: 0
  require_approval:
    teams: ["@acme/release-managers"]
    count: 1
  block_on_unhealthy_deploys: true
  release_workflow: release.yml
Key Default Meaning
label train:{slug} The label that joins a pull request to a train. At most 50 characters.
require_all_pass true When true, members that need approval or have no gate decision yet hold the train. A failing member always blocks it.
max_breaking no limit The most breaking changes the train may carry. Must not be negative.
require_approval none Release manager approvals needed: approvers, teams (as @org/team) and count (up to 10; leave it out for one approval).
block_on_unhealthy_deploys false Block the train when a member is regressed or degraded in production.
release_workflow none A workflow file name such as release.yml. When set, cutting the train dispatches that workflow with the train's name as the name input, instead of Bumpkit creating the GitHub Release itself.

From an agent ​

The MCP server has train_list, train_new, train_sync, train_status, join_train, train_remove, train_approve and train_cut. Approving and cutting a train needs a person signed in to the dashboard: train_approve and train_cut are refused with the link to the batch page. See MCP Server.

API ​

Method and path What it does
GET /v1/trains List trains
POST /v1/trains Start a train
GET /v1/trains/{id} Get a train
DELETE /v1/trains/{id} Abandon a train (member key)
POST /v1/trains/{id}/members Add a pull request
DELETE /v1/trains/{id}/members/{number} Remove a pull request
POST /v1/trains/{id}/sync Refresh members from the label and milestone (member key)
GET /v1/trains/{id}/readiness Readiness and reasons
POST /v1/trains/{id}/approve Always 403 HUMAN_APPROVAL_REQUIRED for a key. A person approves in the dashboard
POST /v1/trains/{id}/cut Always 403 HUMAN_APPROVAL_REQUIRED for a key. A person cuts in the dashboard

Endpoints marked "member key" need an API key that belongs to a workspace member, so Bumpkit can record who approved or cut the train. See the API Reference for authentication and errors, and the Worked Examples for a train from start to cut.

Release across repositories ​

Beta, early access. A workspace without access gets 403 FEATURE_EARLY_ACCESS and a link to request it. Flag: multi_repo_trains. It also needs release_trains and cross_repo_impact.

When a change spans a library and the services that use it, the order matters: the library ships first. A multi-repo train ships one release across repositories in dependency order, and tells you why each step comes where it does.

  1. Start the train on the Batches tab of the Releases page, or from the CLI. Name it and pick at least two repositories, up to 20.
  2. Each repository gets its own batch with the same name and label. Label pull requests in each repository to join its step, as with any batch. These batches show on the train's page, not in the list of single-repository batches, and bumpkit train list still lists them.
  3. Bumpkit reads the order from your service graph. A repository ships after whatever it depends on, including through a repository that isn't on the train.
  4. A person approves and starts each step in the dashboard, in order.
Terminal
bumpkit train multi new "October release" --repo acme/lib --repo acme/api
bumpkit train multi show "October release"
bumpkit train multi sync "October release"

The order and why ​

Every step says why it sits where it does, with the file and line behind each edge, like After acme/lib: it depends on lib ^1.0.0 (package.json:4). Repositories with no known edge between them, on a train the graph otherwise connects, share a step, and either can go first.

Bumpkit doesn't guess. No step can start, and the page asks a person to set the order, when:

What the train shows What it means
not_mapped A repository isn't on the service map, so Bumpkit can't see what it depends on.
truncated A repository has more files than Bumpkit could read for the graph, so its dependencies may be incomplete.
cycle These repositories depend on each other, so no order is safe to prove.
no_edge No dependency connects these repositories, so Bumpkit can't say which goes first.
order_conflict The service map changed and now disagrees with the saved order.

Setting the order needs a person signed in to the dashboard, with write access. Their email goes on the order and in the audit log. Bumpkit refuses an order that contradicts an edge it can prove, except inside a cycle, and steps that already started stay ahead of the rest. bumpkit train multi order with an API key gets 403 HUMAN_APPROVAL_REQUIRED and the link to the train's page.

Each step's state ​

Each step has its own gate result, from its batch's readiness. A step that isn't released holds every later step, and Bumpkit never skips one. That holds on the batch's own page too: cutting a held step answers 409 MULTI_TRAIN_HELD. An owner's break-glass reason covers a step that isn't ready, never one that's out of turn.

State What it means
needs_order A person has to set the order first.
held An earlier step hasn't released. The step still shows its own gate result.
waiting, needs_approval, blocked This step's turn, and its gate result is what holds it.
ready This step can start.
publishing The release started and hasn't finished.
failed The release didn't finish. The step says why, with its number of attempts.
released The tag and GitHub Release exist, or the release workflow was requested.
abandoned The step's batch was abandoned, so later steps stay held. Abandon the train and start a new one.
unreadable Bumpkit couldn't read this step's gate results. Try again in a minute.

A partial failure stays visible: the train says how many repositories released and which one stopped. Retry a failed step from the train's page; Bumpkit picks up where it stopped, and doesn't touch the steps already out. Syncing tries every repository, and one that fails shows its own error without stopping the others. Abandoning a train leaves releases that are already out alone.

Agents can start and read a train, but approving, cutting, retrying and setting the order all need a person in the dashboard. Each step's approvals follow that repository's train.require_approval.

The service map ​

The Batches tab shows your services and the edges between them, providers on the left. Each service shows its health from its latest recorded deployment and its last published release. A service with no deployment says so; record deploys with bumpkit deploy to see its health. Pick a service to open its version history. Tab through the map with a keyboard, and on a phone it becomes a list with the same data.

Terminal
bumpkit train map

Grouped releases ​

Beta, early access. A workspace without access gets 403 FEATURE_EARLY_ACCESS and a link to request it. Flag: grouped_releases.

A grouped release is everything merged to the default branch since the last release tag, shipped as one version. You don't pick pull requests: Bumpkit takes the whole range.

  1. Prepare. Run bumpkit release prepare, choose Prepare release on the dashboard's Releases page, or type /bumpkit prepare owner/repo in Slack. Bumpkit finds the last vX.Y.Z tag (or the first commit when there's none), lists the merged pull requests and commits up to the branch head, runs one check over the range, suggests the next version and writes the notes. There's one open draft per repository; preparing again refreshes it.

    With Draft a release after every merge on (the default), you don't have to ask. Every time a pull request merges to the default branch, Bumpkit refreshes the draft and posts or updates its Slack card, so the next release is always ready to review. Owners turn it off on the Releases page or with bumpkit settings set --draft-after-merge off; then a release is drafted only when someone prepares one.

  2. Review the notes. Bumpkit writes the notes once per audience from the same changelog and proven findings as notes per audience. Internal-only work, like internal tooling, tests and test infrastructure, docs-internal changes and redirects, drafts, unreleased or not-yet-public work, detection internals and internal process, goes to the Internal section, which the customer notes leave out. So customer notes only list what customers can use. Read any audience with bumpkit release show RELEASE_ID --audience customer (or engineering, support, security, leadership, or one you defined), or pick its tab on the release page. To change them, edit the box on that tab, run bumpkit release notes RELEASE_ID --audience customer --file notes.md (or pipe the notes on stdin), or regenerate them with --regenerate. Agents use show_release with audience and edit_release_notes. Anyone who can prepare releases can edit a draft; once a release is approved, only owners, admins, policy admins and approvers can, and every change goes in the audit log. A draft or approved release from before notes per audience gets them written the first time you open it or publish it.

  3. Approve. A person approves or denies the draft on the dashboard, in Slack, or with bumpkit release approve RELEASE_ID (or deny), which asks you to confirm in the browser. API keys and MCP tools can't vote: POST /v1/releases/{id}/approve answers 403 HUMAN_APPROVAL_REQUIRED. A vote is tied to the head it was prepared at, so a refreshed draft needs a new review.

  4. Publish. After approval, publish from the dashboard, Slack or bumpkit release publish RELEASE_ID. Bumpkit creates the tag and GitHub Release through the GitHub App and updates the public changelog with the customer notes, posts the engineering notes to Slack, and updates any connected Notion or Confluence page with the engineering notes. Owners change which audience a target gets on the Releases page, with bumpkit settings set --publish-audience slack=support, the settings_set MCP tool (publish_audiences) or PATCH /v1/settings. Each target is recorded on its own: if one fails, publish again and only the failed ones are retried.

    Merging never publishes anything: a release ships only when a person publishes it. Because the GitHub App creates the release, GitHub workflows that run on: release: types: [published] start right after you publish, so they can build your artifacts and attach them to that same release. Leave the notes alone; Bumpkit already wrote them.

Published releases make up the version history on the Releases page and in bumpkit release list --status published. If published notes need a fix, owners and admins can correct them everywhere they were published with bumpkit release correct. Agents can prepare and read releases with the prepare_release, show_release and list_releases MCP tools and edit draft notes with edit_release_notes, but can't approve or publish them.

↑↓ to move, Enter to open