# Features

## Single-binary bootstrapper

cx is a single static binary (7-11 MB depending on platform) written in Rust. It requires no Python,
no installer framework, and no shell modifications. Download it, run it, and
you have a working conda installation.

## Compile-time lockfile

`build.rs` performs a full dependency solve at `cargo build` time using rattler
crates, producing a [rattler-lock v6](https://github.com/conda/rattler/tree/main/crates/rattler_lock)
lockfile that is embedded into the binary. At runtime, bootstrap skips repodata
fetching and solving entirely — it downloads and installs packages directly from
the locked URLs.

This gives cx deterministic, reproducible bootstraps with ~3–5 second install
times.

## Package exclusion

conda on conda-forge hard-depends on `conda-libmamba-solver`, which pulls in
27 native dependencies (libsolv, libarchive, libcurl, spdlog, etc.). Since cx
uses `conda-rattler-solver` instead, these are unnecessary.

cx removes them via a post-solve transitive dependency pruning algorithm:
after the solver produces a complete solution, cx identifies packages that are
*exclusively* required by the excluded packages and removes them. This reduces
the install from 113 to 86 packages.

## conda-rattler-solver

cx configures [conda-rattler-solver](https://github.com/jaimergp/conda-rattler-solver)
as the default solver via `.condarc`. This solver is based on
[resolvo](https://github.com/mamba-org/resolvo), the fastest SAT solver in the
conda ecosystem, and ships as a pure Python package with
[py-rattler](https://pypi.org/project/py-rattler/) wheels.

## conda-spawn activation

cx ships with [conda-spawn](https://github.com/conda-incubator/conda-spawn)
and disables traditional `conda activate`/`deactivate`/`init`. Instead:

```bash
cx shell myenv          # spawns a subshell with myenv activated
exit                    # leaves the environment
```

No `.bashrc`/`.zshrc` modifications required. Just add `~/.cx/condabin` to
your `PATH`.

## `cx shell` alias

`cx shell` is a convenience alias for `conda spawn`. It works identically:

```bash
cx shell myenv          # same as: conda spawn myenv
```

## Frozen base prefix (CEP 22)

After bootstrap, cx writes a `conda-meta/frozen` marker file per
[CEP 22](https://conda.org/learn/ceps/cep-0022/). This protects the base
prefix from accidental modification. Users should create named environments
for their work:

```bash
cx create -n myenv numpy pandas
cx shell myenv
```

## Auto-bootstrap

If the prefix doesn't exist when you run a conda command, cx automatically
bootstraps before executing:

```bash
# First time: bootstraps ~/.cx, then creates the environment
cx create -n myenv python=3.12
```

## External lockfile support

For custom deployments, you can override the embedded lockfile:

```bash
cx bootstrap --lockfile /path/to/custom.lock
```

Or skip the lockfile entirely for a live solve:

```bash
cx bootstrap --no-lock
```

## Offline bootstrap

cx supports fully offline, air-gapped bootstrap from a local directory of
package archives or from a previously populated package cache. This enables
deployment in restricted-network environments and native installers
(macOS PKG, Windows MSI) that bundle cx alongside a package payload.

Two flags control this behavior:

- `--payload DIR` points to a directory of `.conda` / `.tar.bz2` archives.
  cx pre-populates the rattler package cache from this directory, then
  installs from cache. Without `--offline`, missing packages fall back to
  network download.
- `--offline` disables all network access. All packages must be available
  locally (in the cache or payload). Incompatible with `--no-lock`.

```bash
# Re-use packages from a previous bootstrap (no network)
cx bootstrap --prefix /opt/conda --offline

# Install from a bundled payload directory (fully air-gapped)
cx bootstrap --payload ./packages/ --offline
```

Both flags can also be set via the `CX_PAYLOAD` and `CX_OFFLINE` environment
variables, making them easy to use from native installer post-install scripts.

## Self-contained binary (cxz)

`cxz` takes offline bootstrap one step further: it embeds the package archives
themselves into the binary. One 50-95 MB file (varies by platform), zero network access, drop it
anywhere.

```
cx (7-11 MB)              cxz (50-95 MB)
┌──────────────┐          ┌──────────────┐
│  cx binary   │          │  cxz binary  │
│  (7-11 MB)   │          │  (7-11 MB)   │
├──────────────┤          ├──────────────┤
│  lockfile    │          │  lockfile    │
│  (39 KB)     │          │  (39 KB)     │
│              │          ├──────────────┤
│              │          │  payload.tar │
│              │          │  (varies)    │
└──────────────┘          └──────────────┘
```

`cxz` is the same codebase as `cx`, built with `CX_EMBED_PAYLOAD=1`. It
detects its embedded payload automatically and behaves as if `--payload
--offline` were passed. All other flags and subcommands work identically.

It is distributed via GitHub Releases (alongside `cx`) and as a pre-bootstrapped
Docker image. See the [custom builds guide](guides/custom-builds.md) for
build instructions.

## Uninstall (`cx uninstall`)

cx provides a clean uninstall command that reverses the bootstrap:

```bash
cx uninstall
```

This will:

1. List what will be removed (prefix, named environments, cx binary)
2. Ask for confirmation (`--yes` to skip)
3. Remove the conda prefix and all environments
4. Remove the cx binary
5. Clean up PATH entries from shell profiles

## GitHub Action for custom builds

cx ships a composite GitHub Action and a reusable workflow that let you build
custom cx binaries with your own package set baked in. The build performs a
full compile-time dependency solve, producing a self-contained binary with
an embedded lockfile — just like the official cx releases.

This is powered by the same {ref}`environment variable overrides <env-var-overrides>`
that work locally, but wrapped in a ready-to-use Action.

See the [GitHub Action reference](reference/github-action.md) for inputs,
outputs, and behavior. For a step-by-step walkthrough, see the
[custom builds guide](guides/custom-builds.md).

## conda in the browser (cx-wasm)

cx-wasm compiles the same rattler-based solver and package extractor to
WebAssembly, enabling `conda install` to run entirely client-side in a
[JupyterLite](https://jupyterlite.readthedocs.io/) notebook.

```python
%load_ext conda_emscripten
%conda install lz4
import lz4
```

This runs **real conda** — the actual Python package manager, not a
reimplementation — with cx-wasm replacing the native-code bottlenecks via
conda's plugin API. Packages with C extensions (like `lz4`) work after
installation thanks to automatic shared library loading.

A shard prefetch runs at kernel startup, fetching all repodata shards
in parallel via async JavaScript `fetch()`. This means the solve phase makes
zero network requests — a typical `%conda install lz4` completes in ~3.5
seconds.

See the {doc}`browser guide <guides/browser>` for details, or try the
[live demo](https://jezdez.github.io/conda-express/demo/lab/index.html).

## Multi-platform support

cx builds and tests on 5 platforms via GitHub Actions:

| Platform | Runner |
|---|---|
| linux-x64 | `ubuntu-latest` |
| linux-aarch64 | `ubuntu-24.04-arm` |
| macos-x64 | `macos-15-large` |
| macos-arm64 | `macos-latest` |
| windows-x64 | `windows-latest` |

## PyPI and crates.io distribution

cx is published as `conda-express` on both
[PyPI](https://pypi.org/project/conda-express/) and
[crates.io](https://crates.io/crates/conda-express):

```bash
pip install conda-express       # from PyPI
cargo install conda-express     # from crates.io
```

Both use trusted publishing (OIDC) for secure, tokenless releases.
