Customize A Runtime#

Use this guide when you want a conda-ship-built runtime with your own package set, runtime name, delegate executable, install location, channels, or documentation URL.

conda-ship is generic. It does not publish a first-party runtime, and it does not reserve a default runtime name. conda-express is one downstream distribution that uses conda-ship to publish cx and cxz; use a runtime name owned by your distribution.

The manifest examples below describe the build input conda-ship consumes. Packaged CLI builds find the runtime template installed next to cs automatically. Source checkouts need either a packaged install that includes cs-template or an explicit --template path.

Choose A Runtime Name#

The runtime name becomes part of the user interface:

  • the executable users run

  • the default install path, ~/.conda/INSTALL_NAME with the conda-home install scheme

  • the metadata file, .RUNTIME.json

  • the bundle environment variable, RUNTIME_BUNDLE

  • the offline environment variable, RUNTIME_OFFLINE

For environment variables, non-alphanumeric characters are converted to underscores. A runtime named demo uses DEMO_BUNDLE and DEMO_OFFLINE.

Use a product-specific name:

[tool.conda-ship]
runtime = "demo"
delegate = "conda"
layout = "online"

Avoid publishing downstream builds as cx or cxz. In the conda ecosystem, those names identify the conda-express artifacts maintained in the jezdez/conda-express repository.

Choose An Install Location#

By default, a runtime uses the conda-home install scheme and installs below ~/.conda/RUNTIME, where RUNTIME is the runtime name. A downstream distribution can choose a different install name without stamping an operating-system-specific path:

[tool.conda-ship]
runtime = "cx"
delegate = "conda"
layout = "online"
install-scheme = "conda-home"
install-name = "express"
cs build

That builds a runtime named cx whose default install path resolves to ~/.conda/express on the user’s machine. Users can still override the resolved path locally with the global runtime option, for example RUNTIME --path PATH bootstrap or RUNTIME --path PATH status.

Choose a product-specific install name. conda-ship does not reserve names under ~/.conda; it writes runtime metadata into bootstrapped prefixes and uses that metadata to avoid overwriting prefixes owned by other tools. The metadata includes the runtime display name, install name, metadata filename, and metadata schema version, so a runtime refuses to use or remove a prefix that belongs to a different stamped runtime.

For a platformdirs-style location, use install-scheme = "user-data". That stores the runtime below the platform user data directory, such as ${XDG_DATA_HOME:-~/.local/share}/conda/INSTALL_NAME on Linux, ~/Library/Application Support/conda/INSTALL_NAME on macOS, and %LOCALAPPDATA%\\conda\\INSTALL_NAME on Windows.

If a downstream package manager owns the runtime binary, set install-method in the manifest or pass it from the release job. The generated runtime uses that value only after uninstall, when it tells users how to remove the runtime binary itself:

[tool.conda-ship]
runtime = "demo"
delegate = "conda"
install-method = "homebrew"

For matrix builds that produce the same runtime for different distribution channels, use cs build --install-method METHOD or the GitHub Action install-method input.

Choose Runtime Packages#

A conda-ship runtime must include:

  • python

  • conda

  • conda-rattler-solver

  • conda-spawn

Additional plugins are a distribution decision. A downstream project records its own plugin set in its manifest and committed lockfile; conda-ship does not choose one for every runtime.

Configure Local Build Input#

Keep package and channel intent in the manifest format owned by your workspace tool. Keep conda-ship-specific build policy in [tool.conda-ship].

Use conda.toml when the project uses conda-workspaces as its primary manifest:

[workspace]
name = "demo"
channels = ["conda-forge"]
platforms = ["linux-64", "osx-arm64", "win-64"]

[feature.ship.dependencies]
python = ">=3.12"
conda = ">=25.1"
conda-rattler-solver = "*"
conda-spawn = ">=0.1.0"
numpy = "*"
pandas = "*"

[environments]
ship = { features = ["ship"], no-default-feature = true }

[tool.conda-ship]
runtime = "demo"
runtime-version = "0.1.0"
delegate = "conda"
layout = "online"
source-environment = "ship"
exclude = ["conda-libmamba-solver"]
docs-url = "https://example.com/demo/"
install-scheme = "conda-home"
install-name = "demo"
install-method = "homebrew"

Refresh the source lockfile:

conda workspace lock

Use this form when a Python project keeps conda-workspaces config in pyproject.toml. conda-workspaces tables live under [tool.conda], while [tool.conda-ship] remains a sibling tool table:

[tool.conda.workspace]
name = "demo"
channels = ["conda-forge"]
platforms = ["linux-64", "osx-arm64", "win-64"]

[tool.conda.feature.ship.dependencies]
python = ">=3.12"
conda = ">=25.1"
conda-rattler-solver = "*"
conda-spawn = ">=0.1.0"

[tool.conda.environments]
ship = { features = ["ship"], no-default-feature = true }

[tool.conda-ship]
runtime = "demo"
runtime-version = "0.1.0"
delegate = "conda"
layout = "online"
source-environment = "ship"
exclude = ["conda-libmamba-solver"]

Refresh the source lockfile:

conda workspace lock

This writes conda.lock.

For Pixi-compatible projects, keep the source environment package intent in Pixi’s own sections. If Pixi config lives in pyproject.toml, the package and channel sections live under [tool.pixi], while [tool.conda-ship] stays at the Python project tool level:

[tool.pixi.workspace]
name = "demo"
channels = ["conda-forge"]
platforms = ["linux-64", "osx-arm64", "win-64"]

[tool.pixi.feature.ship.dependencies]
python = ">=3.12,<3.15"
conda = ">=25.1"
conda-rattler-solver = "*"
conda-spawn = ">=0.1.0"
numpy = "*"
pandas = "*"

[tool.pixi.environments]
ship = { features = ["ship"], no-default-feature = true }

[tool.conda-ship]
runtime = "demo"
runtime-version = "0.1.0"
delegate = "conda"
layout = "online"
source-environment = "ship"
exclude = ["conda-libmamba-solver"]

Refresh the source lockfile:

pixi lock

This writes pixi.lock.

conda-ship consumes the solved ship environment during cs build; it does not replace the workspace solver.

Build the runtime:

cs build

The staged runtime and metadata files are written to dist/.

Build In GitHub Actions#

For CI builds, commit the manifest and lockfile, then point the composite action at that project root:

- uses: actions/checkout@v4

- uses: jezdez/conda-ship@0.2.1
  id: cs
  with:
    root: .

The action does not run conda workspace lock, pixi lock, or any other solve step. That keeps release artifacts tied to reviewed project files.

Build An Embedded Variant#

Use the embedded layout when you want a larger single binary that carries the package archives inside itself:

cs build --layout embedded

The embedded runtime uses the z suffix, so the staged binary is dist/demoz on Unix and dist/demoz.exe on Windows.

The embedded runtime detects its built-in bundle automatically during bootstrap; users do not need to pass --bundle or --offline.