see it work
Follow a release from commit to publish
Choose an example to see how dispat selects packages, orders their work, and handles failures.
built for your project
Keep the tools your team already uses
Release across languages
Build a Go service, publish an npm library, and push a Docker image in one run. dispat calls the shell commands you configure for each package.
Put dependencies in order
A package waits for the packages it needs. Independent packages can build and publish in parallel. Preview the selected packages and next versions with dispat status.
Use one or several repositories
Start with a single package or a monorepo. For work spread across repositories, link them as Git submodules in a control repository: it can read each linked repository's own commits and tags, or hold every release decision in its own history.
Know what to do when a release stops
dispat writes a Git tag after each successful publish. A package that fails leaves those publications in place, its consumers are held back rather than published from a stale plan, and the next run re-plans the remaining work from the tags. Uploads are never rolled back for you: if a publisher succeeded before its tag was written, check that destination before retrying. Read the recovery guide.
in production
Projects using dispat
The first monorepo dispat releases is its own: every tag, changelog, GitHub release and container image of this project, and this documentation site, ship through a dispat run.
dispat itself: this repository is a polyglot Go, npm, and Docker workspace. It is released by the dispat binary built from its own checkout, and it has been since the very first release. The first stable run cut eleven packages in one release. It rewrote the go.mod files of six Go modules to the released versions, regenerated go.sum files, and tagged each module the way Go expects (pkg/ccme/v1.0.0, services/dispat/v1.0.0). This keeps go install github.com/yohimik/dispat/services/dispat@latest working. It also attached six cross-compiled binaries to the CLI's GitHub release, published the four container images, and released the versioned documentation site. Every package received its own tag, changelog entry, and GitHub release. The release also announces itself: its announce stage renders a card from the release notes it just wrote and posts it to Instagram, LinkedIn, and Discord with crier, from the same Actions run, which the announcement page describes.
crier: a single-package repository, one Go module and one binary, which renders HTML templates to images and video and posts them to fourteen social platforms. It shows that dispat needs no monorepo. Its first release was a breaking change on the rc channel, and eighteen release candidates followed in two days, each with its own changelog entry and its own GitHub release flagged as a prerelease. One transition commit then graduated the train to 1.0.0: the stable version is computed over the whole train rather than counted by hand, and the graduation collects every candidate's notes into the one entry stable readers see. This is the train and graduation flow that Kubernetes runs its own releases through, here driven by conventional commits alone. A moving v1 alias tag is scoped to the stable channel, so uses: yohimik/crier@v1 never picks up a candidate. crier also shows how a release integrates with dispat: the announce stage of the run renders a card from the release-notes variables dispat sets and posts it from the binary the run just built, and its release-changelog example wires the same card into any dispat release as one more publish step. It installs with dispat install yohimik/crier.
get started
Install once. Preview your first release.
The installer downloads the binary for your platform and verifies its checksum. No language runtime is required.
curl -fsSL https://raw.githubusercontent.com/yohimik/dispat/main/install.sh | sh
irm https://raw.githubusercontent.com/yohimik/dispat/main/install.ps1 | iex
Start in your Git repository
Generate a starter configuration, edit its package paths and build and publish commands, then inspect the plan. status leaves your project unchanged.
dispat init
# Edit dispat.json for your packages
dispat status
Installation options and setup guideGitHub Actions and other CI systems
read on
The documentation
- Getting started: install the binary, write one config file, wire the release into CI.
- Concepts: packages and spaces, propagation, the plan, the failure and recovery model.
- One repository or many and A control repository: what each layout costs, and the two ways several repositories release from one plan.
- Examples: a complete setup per package manager, npm to Docker to Android, and editing every package at once.
- CLI and Configuration: every command, every option.
- Go packages: the commit parser, the manifest reader and the manifest writer, importable on their own.
- Commit messages: the Conventional Commits superset that carries release intent.
- Releasing: shared versions, running the release's own steps yourself, releasing part of the graph, and the release lock.
- Script environment: the
DISPAT_*variables a stage receives. - Architecture, Coverage and Test results: how it is built, and what its test suite reaches and does.
libraries
Lightweight libraries, usable on their own
Use dispat's Go libraries in your own tools. Parse commit messages, inspect dependencies, or update manifest versions without running the CLI. The reader and writer share format definitions through pkg/manifest.
pkg/ccme: the commit parser
Parse Conventional Commits and dispat's package scopes, dependency propagation, and prerelease channels. The parser scans the input once. Its formal rules live in SPEC.md.
pkg/scanner: the manifest reader
Read package names, versions, and dependencies from the formats below. Results have a consistent shape and order. Scanning uses bounded local reads and returns valid results alongside any parsing errors.
pkg/writer: the manifest writer
Update supported version declarations while preserving surrounding formatting where the format allows it. Each file is validated before an atomic replacement. The result tells you which edits were applied, missing, or skipped because a value is inherited or calculated.
Languages and manifests the reader and the writer support
| Language / ecosystem | Manifests read and rewritten |
|---|---|
| JavaScript, TypeScript: npm, pnpm, Yarn | package.json |
| Go | go.mod |
| Rust: Cargo | Cargo.toml |
| Python: PEP 621, PEP 735, Poetry, pip | pyproject.toml, requirements*.txt |
| PHP: Composer | composer.json |
| Java, Kotlin, Scala: Maven | pom.xml |
| C#, F#, VB: .NET, NuGet | *.csproj, *.fsproj, *.vbproj, *.nuspec, Directory.Packages.props, packages.config |
| Dart, Flutter: pub | pubspec.yaml |
| Ruby: Bundler, RubyGems | Gemfile, *.gemspec |
| Swift, Objective-C: iOS, CocoaPods | Info.plist, project.pbxproj, Podfile, *.podspec |
| Kotlin, Java: Android, Gradle | AndroidManifest.xml, libs.versions.toml, build.gradle(.kts) |
| Docker: images and Compose | Dockerfile, Containerfile, compose.yaml, docker-compose.yml, and their .override spellings |
| Unity | Packages/manifest.json, ProjectSettings/ProjectSettings.asset |
| Godot | project.godot, plugin.cfg, export_presets.cfg |
| Unreal Engine | *.uproject, *.uplugin, Config/DefaultGame.ini, Config/DefaultEngine.ini |
| Defold | game.project |
| O3DE | project.json, gem.json |
| Aqua tool management | aqua.yaml, aqua.yml, hidden and directory variants |
dispat compute reads these manifests to derive package dependencies. Enable autoVersion to update supported declarations during a release. Mobile build numbers are separate from package versions; change them explicitly with --set-build. See Aqua manifest support for supported imports and version declarations.
lineage
Inspiration
dispat draws on tools and ideas that make complex work easier to inspect, compose, and recover:
- Linux and Git guided the CLI design: focused commands, explicit inputs, useful exit codes, and tools that work together. The shell tools used on Linux inspired
dispat ifanddispat for, which expose familiar conditional and looping control flow as commands. Linux's permission classes (others, group, owner) also inspired the configuration scopes: global defaults for all packages, space settings for a group of packages, and a package's own settings. Git also supplies the history and release records that let you inspect how a release was planned and what it completed. - Docker Compose, Swarm, and Kubernetes inspired the move from local configuration to coordinated systems. Compose describes services in YAML, and compatible service definitions can become a Swarm stack running across machines. Kubernetes uses declarative manifests to describe cluster workloads. dispat brings that idea to releases: start with packages in one repository, then link repositories into a coordinated release workflow while keeping each repository's package configuration.
- Database recovery and sagas inspired the approach to reliable releases: record completed work, coordinate concurrent runs, and recover after partial failure. Garcia-Molina and Salem's Sagas (1987) describes long transactions made of smaller, independently committed steps. dispat applies that structure to publishing: it writes a Git tag after each successful publish and uses those records to plan unfinished work. A release lock coordinates concurrent runs, without a separate release database or lock service. If a publisher succeeds before its tag is written, check the destination before retrying. See recovery behavior.
- Lerna, and the workspaces of npm and pnpm it grew up beside. Between them they proved that many packages in one repository can share a dependency graph. They also proved that versioning and publishing all of them can be one command. dispat takes that idea beyond JavaScript and rebuilds it around an explicit dependency graph and an explicit error model.
- Conventional Commits: commit messages as machine-readable release intent. The dispat parser,
pkg/ccme, implements a strict superset of Conventional Commits 1.0.0 that adds the monorepo dimension. It treats scopes as packages and handles propagation depth and prerelease channels.
community
Have questions or issues?
Want to share a project you release with dispat? Come and say hello on Discord. Bugs and feature requests are welcome as GitHub issues too, whichever suits you better.