You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I’m considering building an open-source developer tool called OmniShip.
The idea is to make release tooling language- and platform-agnostic.
Check it. Build it. Ship it.
Most release tooling today is still shaped around a particular language, package manager, build system, or ecosystem. That works well until a project becomes more complex, starts targeting multiple platforms, mixes technologies, or needs a release process that does not fit the assumptions of the tool.
OmniShip would take a different approach.
The core should not care whether a project is written in Go, Rust, Python, Zig, C++, JavaScript, or something else entirely.
If a command can validate the project, produce an artifact, or deliver that artifact somewhere, OmniShip should be able to orchestrate it.
The release model would have exactly three top-level stages:
Check
↓
Build
↓
Ship
Check
Check is everything that must succeed before a release is allowed to continue.
This could include:
tests
linting
type checking
security checks
format validation
generated-file checks
custom commands
The important part is that Check is not just a flat list of commands.
Each stage in OmniShip would contain its own execution graph.
Native multi-platform builds should be a normal use case rather than an exceptional workflow.
Artifacts would be first-class objects inside OmniShip. Operations could consume existing artifacts, transform them, and produce new ones.
Ship
Ship is intentionally broader than publish.
Depending on the project, shipping may mean:
creating a GitHub release
publishing to PyPI
publishing to npm
publishing to crates.io
pushing a container image
signing or notarizing artifacts
updating a package repository
deploying something
All of these are different forms of getting a successfully built result to its destination.
The Ship stage would have the same graph model as Check and Build.
This could allow OmniShip to generate starter configurations from detected plugins while still keeping the final release graph portable, readable, and editable by the user.
The YAML should be a stable public configuration format rather than a serialization of Python internals.
Implementation
I’m currently leaning toward Python for the implementation.
OmniShip will mostly be an orchestration and integration system rather than a CPU-heavy program. Python gives the project a simple plugin model, good async and subprocess support, straightforward configuration handling, and a low barrier for contributors.
The project can still keep a strict internal structure through typing, protocols, explicit models, and a carefully defined plugin API.
Distribution would remain straightforward through tools such as:
uv tool install omniship
The goal
The main goal is to make releasing software feel consistent regardless of what the software itself is built with.
A small project might have three operations.
A large project might have dozens of branches, platforms, artifacts, and shipping destinations.
Both should still be understandable through the same model:
Check. Build. Ship.
I’d like to hear thoughts especially around the graph model, plugin API, artifact flow, configuration format, caching semantics, and where the boundary between core behavior and plugin behavior should sit.
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
OmniShip — Universal release orchestration
I’m considering building an open-source developer tool called
OmniShip.The idea is to make release tooling language- and platform-agnostic.
Most release tooling today is still shaped around a particular language, package manager, build system, or ecosystem. That works well until a project becomes more complex, starts targeting multiple platforms, mixes technologies, or needs a release process that does not fit the assumptions of the tool.
OmniShipwould take a different approach.The core should not care whether a project is written in Go, Rust, Python, Zig, C++, JavaScript, or something else entirely.
If a command can validate the project, produce an artifact, or deliver that artifact somewhere, OmniShip should be able to orchestrate it.
The release model would have exactly three top-level stages:
Check
Checkis everything that must succeed before a release is allowed to continue.This could include:
The important part is that Check is not just a flat list of commands.
Each stage in OmniShip would contain its own execution graph.
For example:
Operations can depend on other operations, fan out into parallel branches, and join again later.
Sequential and parallel execution would therefore come naturally from dependencies rather than from a separate execution mode.
Build
Buildproduces the artifacts that will eventually be shipped.Those artifacts could be anything:
A build graph might look like:
Native multi-platform builds should be a normal use case rather than an exceptional workflow.
Artifacts would be first-class objects inside OmniShip. Operations could consume existing artifacts, transform them, and produce new ones.
Ship
Shipis intentionally broader thanpublish.Depending on the project, shipping may mean:
All of these are different forms of getting a successfully built result to its destination.
The Ship stage would have the same graph model as Check and Build.
For example:
Signing therefore does not need to be a top-level release stage. It is simply one possible operation inside a shipping flow.
By default, the three stages would behave as barriers:
More advanced behavior such as caching, selective execution, or controlled overrides could be added without complicating the default model.
Plugin-first architecture
I want OmniShip to be fully modular.
The core should stay relatively small and focus on things such as:
Ecosystem-specific behavior should live in plugins.
Plugins could provide operations such as:
A plugin should be able to expose one operation or a whole group of related capabilities.
For example, a Rust-oriented plugin might provide Cargo project detection, builds, testing, version handling, and crates.io publishing.
First-party plugins and community plugins should use the same public plugin API.
The goal is that adding support for a new ecosystem should normally mean writing a plugin, not modifying OmniShip core.
At the same time, arbitrary commands should remain a first-class capability.
A project should never be blocked because an OmniShip plugin does not exist for its build system yet.
If this works:
then OmniShip should be able to compose it into a Check, Build, or Ship graph.
Plugins should improve ergonomics and provide structured behavior, but they should not define the limits of what OmniShip can release.
Declarative configuration
Another direction I want to explore is making plugin operations convertible into a declarative YAML representation.
Plugins would expose capabilities and configuration schemas, while YAML would describe how those capabilities are connected.
For example:
This could allow OmniShip to generate starter configurations from detected plugins while still keeping the final release graph portable, readable, and editable by the user.
The YAML should be a stable public configuration format rather than a serialization of Python internals.
Implementation
I’m currently leaning toward Python for the implementation.
OmniShip will mostly be an orchestration and integration system rather than a CPU-heavy program. Python gives the project a simple plugin model, good async and subprocess support, straightforward configuration handling, and a low barrier for contributors.
The project can still keep a strict internal structure through typing, protocols, explicit models, and a carefully defined plugin API.
Distribution would remain straightforward through tools such as:
The goal
The main goal is to make releasing software feel consistent regardless of what the software itself is built with.
A small project might have three operations.
A large project might have dozens of branches, platforms, artifacts, and shipping destinations.
Both should still be understandable through the same model:
I’d like to hear thoughts especially around the graph model, plugin API, artifact flow, configuration format, caching semantics, and where the boundary between core behavior and plugin behavior should sit.
All contributions are welcome.
All reactions