cctop 0.33.2

An htop-like terminal monitor for AI coding agent sessions on Linux (Claude Code, Codex, Cursor, Devin, Gemini CLI, OpenCode, Pi, Windsurf)
# Installing cctop

[← back to the README](../README.md)

cctop runs on Linux, including WSL. It reads Linux process tables and drives
agents over ptys and unix sockets, and there is no macOS or Windows build.

cctop is a single binary. It links no system libraries and needs no runtime, so
"installing" it means putting one file on your `PATH`. That includes the
multiplexer its tabs' agents run in: rmux is built in, so there is no `rmux` or
tmux to install alongside it.

## Let the script do it

```bash
curl -fsSL https://raw.githubusercontent.com/flolep2607/cctop/main/install.sh | sh
```

It works out your architecture from `uname -m`, fetches that archive from the
latest release, verifies it against the `.sha256` published beside it, and
installs the binary into `/usr/local/bin` — or `~/.local/bin` if that directory
is not yours to write, printing the line to add to your profile when the
fallback is not on your `PATH` either. `sudo` is used only if the install needs
it, and a `sudo` that cannot run (no tty, no askpass, no sudo at all) falls
back rather than stopping.

Then, if `sshfs` is missing, it offers to install it — what
[`cctop sandbox`](integrations.md#an-agent-here-working-there) needs — with
`[y/N]`, so pressing Enter changes nothing. The question is asked on the
terminal even under `curl | sh`, and skipped where there is none. To answer it
in advance:

```bash
curl -fsSL https://raw.githubusercontent.com/flolep2607/cctop/main/install.sh | CCTOP_WITH_SSHFS=1 sh
curl -fsSL https://raw.githubusercontent.com/flolep2607/cctop/main/install.sh | sh -s -- --with-sshfs
```

(`CCTOP_WITH_SSHFS=0` or `--without-sshfs` to skip it.) It uses whichever of
apt-get, dnf, yum, pacman, zypper and apk it finds, through `sudo` unless you
are root, and prints the command before running it. A failed sshfs install is
reported and does not undo the cctop one.

Nothing is unpacked until the checksum has been checked, and a mismatch stops
the install instead of warning about it afterwards. To read it before running
it, `curl -fsSLO` it and look.

## Download a binary by hand

A release ships two archives, x86_64 and aarch64, both statically linked against
musl — so either runs on any distro, glibc or not. Grab the one for your
architecture from the
[latest release](https://github.com/flolep2607/cctop/releases/latest) and put
`cctop` somewhere on your `PATH`:

```bash
# x86_64
d=$(mktemp -d)
curl -fsSL https://github.com/flolep2607/cctop/releases/latest/download/cctop-x86_64-unknown-linux-musl.tar.gz | tar xz -C "$d"
sudo install -m755 "$d/cctop" /usr/local/bin/cctop && rm -rf "$d"
```

```bash
# aarch64
d=$(mktemp -d)
curl -fsSL https://github.com/flolep2607/cctop/releases/latest/download/cctop-aarch64-unknown-linux-musl.tar.gz | tar xz -C "$d"
sudo install -m755 "$d/cctop" /usr/local/bin/cctop && rm -rf "$d"
```

The archive holds one file, called `cctop`, which is why each of these unpacks
into a temporary directory rather than into whatever directory you are standing
in. Run one inside a cctop checkout and tar stops at
`Cannot open: File exists`; the `install` that follows then finds the crate
directory where it expected the binary, reports `omitting directory 'cctop'`,
and leaves nothing on your `PATH`.

Every archive ships with a `.sha256` file next to it, named for the archive
rather than after it — `cctop-x86_64-unknown-linux-musl.sha256`, not
`cctop-x86_64-unknown-linux-musl.tar.gz.sha256`, which is a 404:

```bash
d=$(mktemp -d)
curl -fsSL -O --output-dir "$d" https://github.com/flolep2607/cctop/releases/latest/download/cctop-x86_64-unknown-linux-musl.sha256
curl -fsSL -O --output-dir "$d" https://github.com/flolep2607/cctop/releases/latest/download/cctop-x86_64-unknown-linux-musl.tar.gz
(cd "$d" && sha256sum -c cctop-x86_64-unknown-linux-musl.sha256)
```

## Staying up to date

A downloaded binary has no package manager behind it, so `cctop --update`
fetches the newest release for your architecture and replaces the running
executable in place:

```bash
cctop --update
```

Replacing the binary needs write access to the directory it lives in. The install
above puts it in `/usr/local/bin` with `sudo`, so updating it needs `sudo` too:

```bash
sudo cctop --update
```

An update that lands prints what it brought, one heading per version crossed,
so a machine three versions behind sees all three rather than only the newest:

```
Updated 0.7.0 -> 0.7.3.

What changed since 0.7.0:

  0.7.1
    - Codex accounts per subscription, and a tab you can close without losing
      your place

  0.7.2
    - Fix the login hint for a named account, and add a run skill that drives
      the TUI

  0.7.3
    - the signals between cctop and its agents stop getting lost

Full notes: https://github.com/flolep2607/cctop/releases
```

The notes come from the GitHub releases themselves, fetched after the binary is
already in place — so a network that fails at that moment costs you the summary
and not the update, and you get the link instead.

cctop checks for a new release once an hour in the background and, when one
exists, says so in the footer. The next time you start it, it installs that
release before opening: the version was already known, so nothing is waited on
to discover it, and the download is the only pause. It then prints what changed,
waits for you to press Enter, and starts as the new version.

Startup is the only moment it will do this. Nothing is open yet — no terminal
held, no agent hosted, no pane to lose — so the new binary can simply take the
place of the old one. That is not true of any later moment, which is why an
update that becomes available while cctop is running waits for the next start
rather than interrupting the one you are in.

A release counts once its binary for your machine is attached, so cctop never
offers one it cannot fetch yet. It installs a given version over a given binary
at most once: if that version is installed and the old one still starts, it says
so on each start instead of downloading again. Each update it attempts leaves a
line in `update.log` in the cache directory, which is the thing to attach to a
report about one that went wrong.

To start on the version you already have, pass `--no-auto-update`. To stop it
happening at all, set `"auto_update": false` in `ui-prefs.json` under your cache
directory (`~/.cache/cctop`); `cctop --update` still works whenever you want
it. `cctop claude` and the other
agent aliases skip it too — you are waiting on an agent, and a download between
the command and the agent starting is not what you asked for.

If cargo installed cctop, it asks instead of acting:

```
cctop 0.7.6 is out, and cargo installed this one (0.7.5) — replacing the binary
here would leave `cargo install --list` naming a version that is gone.
Run `cargo install cctop --version 0.7.6 --locked`? It builds from source. [y] update / [n] not now:
```

Answering `y` runs exactly that command, with cargo's own output on screen, and
starts the new version when it finishes. The objection was never the file —
`~/.cargo/bin` is writable — but the bookkeeping, and `cargo install` is what
keeps cargo's record straight. It builds from source, so it takes minutes, which
is why it is a question and not a default. With
[cargo-binstall](https://github.com/cargo-bins/cargo-binstall) on your `PATH`
the command offered is `cargo binstall cctop --version … --locked --no-confirm`
instead, which fetches the release archive in seconds and keeps the same
record. Answering `n` is remembered against
that version and the question waits for the next release; `cctop --update` asks
again whenever you want it.

A package manager other than cargo is left alone entirely — cctop will not touch
a binary something else is responsible for. Update it the way you installed it.

A `cargo build` output is left alone as well, for bookkeeping of a quieter kind:
cargo's fingerprint sits beside `target/debug/cctop` and would go on calling
whatever replaced it the build it produced — the update would land, and
`cargo build` would report the file fresh and never put the real one back.
`cargo install cctop --force` is how the release reaches PATH.

## With cargo

```bash
cargo binstall cctop
```

[cargo-binstall](https://github.com/cargo-bins/cargo-binstall) downloads the
release archive, the same static binary the script installs, and records it
the way `cargo install` would — so nothing has to compile. Without binstall,
cargo builds it from crates.io:

```bash
cargo install cctop
```

Or straight from the repository, without waiting for a release:

```bash
cargo install --git https://github.com/flolep2607/cctop
```

## From source

```bash
git clone https://github.com/flolep2607/cctop
cd cctop
cargo build --release
```

The binary lands at `target/release/cctop`. It links no system libraries and
needs no runtime — a single file you can copy anywhere.

Building requires Rust 1.88 or newer (the code uses let-chains).