> ## Documentation Index
> Fetch the complete documentation index at: https://docs.almond.bot/llms.txt
> Use this file to discover all available pages before exploring further.

# rt.install

> Build and install the required axol-rt hardware control core.

Builds and installs the `axol-rt` Rust realtime core, the sole production hardware control backend for teleop and every other arm-motion command. It runs automatically as a step of [`provision`](/cli/provision); run it by hand to (re)build on demand:

```bash theme={null}
axol rt.install
```

On Linux this also grants the built `axol-rt` binary two narrowly scoped
capabilities: `CAP_SYS_NICE`, used by its two CAN threads to enter their
real-time scheduling class, and `CAP_IPC_LOCK`, which lets it lock its memory
(`mlockall`) past the unprivileged `RLIMIT_MEMLOCK` so a page reclaimed under
recording I/O pressure can never fault a CAN thread mid-tick. The step escalates on
its own: directly as root (the installer and the system service), otherwise
through passwordless or already-cached `sudo`, or one password prompt on a
terminal. It is skipped entirely when the binary already carries both
capabilities, which reading needs no privilege for. Only a run with none of
those fails, and it prints the exact `sudo setcap` command to run once. The control core refuses to arm if its requested real-time
scheduler cannot be established, so a normal scheduler pause can never occur
after the motors enable; a failed memory lock is only reported (the core runs
unlocked, as every session did before it locked at all).

Three concerns, each idempotent and self-gating:

* **Toolchain** — if no working `cargo` is available (PATH or `~/.cargo/bin`), a minimal stable Rust toolchain is installed via rustup (no sudo; lands in `~/.cargo`). Candidates are probed before use, so a rustup shim inherited from another user's PATH does not block the bootstrap.
* **Sources** — a dev checkout builds the in-repo crate (`rust/axol-rt`). Tool installs have no sources on disk, so the crate is fetched into `~/.almond/axol-rt-src` at the exact ref matching the installed package: the git commit for `uv tool install git+...` installs, or the `v<version>` release tag for PyPI installs. A tool install made from a local checkout (`uv tool install /path/to/axol`) builds that checkout's crate. When none of that applies (a wheel file, a release that predates the crate), or guesses wrong, set `AXOL_RT_SOURCE` to a checkout path or to `<git url>@<branch|tag|commit>` — e.g. `AXOL_RT_SOURCE=https://github.com/almond-bot/axol@main axol rt.install`. An explicit override always rebuilds.
* **Binary** — dev checkouts leave it in `rust/axol-rt/target/release/` (where the rt link already looks, and where a manual `cargo build` stays authoritative). Tool installs copy it into `UV_TOOL_BIN_DIR` when that environment variable is set, or to `~/.local/bin/axol-rt` otherwise, and stamp the built ref so re-running `provision` at the same version skips the build. The hosted installer sets `UV_TOOL_BIN_DIR=/usr/local/bin`, so its binary lands at `/usr/local/bin/axol-rt` alongside the `axol` launcher.

The binary lookup order at runtime is `AXOL_RT_BIN` (env override), then the current checkout's repo build, then `axol-rt` on PATH — so a manual checkout build or an explicit override wins over the provisioned copy.

The package and the binary must speak the same wire protocol. Python declares its generation in the core's config (`proto <n>` — `CONFIG_PROTO` in `almond_axol.rt.link`, currently `3`), and a binary built from a different layout refuses to configure — before any motor is touched — with a message naming the fix (`config: client speaks proto …, this axol-rt speaks proto …`); the session then fails with `axol-rt … refused the configuration and exited`. That is the signal to rebuild: `axol rt.install`, or `cargo build --release` in `rust/axol-rt` for a checkout whose `target/release/` binary has gone stale.

<Note>
  A failed rustup download, source fetch, build, or capability setup is
  warning-only inside plain `axol provision`. Pass `--require-rt` to make that
  failure exit non-zero; the hosted installer and self-updater use this strict
  form. Running `axol rt.install` directly also surfaces the full error.
</Note>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.