Skip to content

Try it without installing anything

A container with tmux, the binary, the config with everything turned on, five fake projects and a guided tour that walks through the bindings one at a time. Nothing is mounted from your machine and nothing is published off it, so the whole thing goes away with the container.

Terminal window
docker run --rm -it lonkarorg/tmux-companion:playground

From a clone, scripts/playground.sh builds the image and runs it. The first build compiles the crate inside the image and takes a few minutes; the rest reuse the cargo layer.

Terminal window
scripts/playground.sh # build if needed, then run
scripts/playground.sh shell # a shell in the image, no tour
scripts/playground.sh a11y # the accessibility walkthrough, no tour
scripts/playground.sh a11y on # the same, with the accessibility settings on
scripts/playground.sh smoke # check the image is what the tour claims
scripts/playground.sh tourpass # drive the tour with keys, hardened and plain

The tour works the same with the container locked down: a read-only image, no network, no capabilities, and a cap on processes and memory. The home directory and /tmp become tmpfs, so nothing is written to disk at all.

Terminal window
docker run --rm -it \
--read-only --tmpfs /tmp --tmpfs /home/play:uid=1000,gid=1000 \
--network=none --cap-drop=ALL --security-opt=no-new-privileges \
--pids-limit=512 --memory=512m \
lonkarorg/tmux-companion:playground

scripts/playground.sh runs with these flags; PLAIN=1 scripts/playground.sh runs without them.

Each published image is signed with cosign by the workflow that built it, with no key: the signature names .github/workflows/playground.yml and the tag it ran at. To check one:

Terminal window
cosign verify lonkarorg/tmux-companion:playground \
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
--certificate-identity-regexp '^https://github.com/lonkar-org/tmux-companion/\.github/workflows/playground\.yml@'

The image also carries an SBOM and a build provenance attestation:

Terminal window
docker buildx imagetools inspect lonkarorg/tmux-companion:playground --format '{{ json .SBOM }}'
docker buildx imagetools inspect lonkarorg/tmux-companion:playground --format '{{ json .Provenance }}'

If you start the container from inside a tmux session, Ctrl-b goes to that server and the playground never sees it, so every binding in the tour looks broken. Use a terminal that is not already in tmux.

Nested anyway, press the prefix twice: Ctrl-b Ctrl-b ? reaches the inner tmux. The entrypoint says so and waits before attaching when it sees $TMUX.

Two of the bindings are Alt-s and Alt-a. Terminal.app and iTerm2 send an accented character for Option until they are told otherwise:

Terminal.app Settings, Profiles, Keyboard, “Use Option as Meta key”
iTerm2 Settings, Profiles, Keys, Left Option key: Esc+
Ghostty macos-option-as-alt = true
Alacritty, kitty, WezTerm already send it

The playground binds the same two to the prefix as well, so prefix P opens the project picker and prefix A toggles, and nothing has to be configured before the tour works. Those two are playground scaffolding; the shipped config uses the Alt keys.

Two tmux sessions. You start in playground, a shell in ~/projects/orchard-api, and the tour waits in instructions.

prefix then i the tour (prefix is Ctrl-b)
Alt-s the project picker

Step one offers a detour: press t for nine screens of tmux itself — what a server and a client are, what the prefix is for, how sessions, windows and panes nest, and what detaching actually does, with a diagram for each and four screens of keys to press. Nothing in the detour is checked. It ends with learntmux.dev, which is 42 tasks against a real tmux in the browser, and returns you to step two.

The tour is eighteen steps. Each one says what to press, sets the step on a second status line so it is still in front of you after you have switched sessions, and waits for Enter. Some steps check that the thing actually happened and say so when it did not; s skips one and q leaves the tour for a shell. tour starts it again.

This is the one thing the image cannot do for you. Glyphs are rendered by the terminal on your machine, so a Nerd Font has to be installed and selected there, not in the container. The first step of the tour prints four of them so you can see whether yours works.

Everything works without the font. It reads worse.

A container has no battery, so that segment stays empty. The network counters sit below the threshold the bandwidth segment draws at unless something is transferring, so that one is usually empty too. Both are there on a laptop, and tmux-companion doctor inside the container says what it can and cannot see.

The window segment is off, the same as in the bar the author runs: drawing windows through tmux-companion window costs one process spawn per window per redraw, and tmux redraws on pane output as well as on the timer.

Each one is in a different state, so the git segment has something different to say in each:

orchard-api clean
orchard-web three modified, one untracked
sparrow-cli staged and modified at once, on a branch long enough to be truncated
lantern-docs detached HEAD, one untracked file
anvil-infra two commits ahead of its upstream

orchard-api/build.log holds a compiler error with a path, a line and a column in it, for the copy-mode o binding to open.

playground/DOCKERHUB.md is what Docker Hub shows on the image’s page. It is pushed by the last step of .github/workflows/playground.yml, on a tag, so it is reviewed like anything else rather than pasted into a web form and left to drift. That step needs the Docker Hub token to carry delete scope as well as read and write, and it is continue-on-error, because a description that did not update is not worth failing a release whose image is already pushed.

Everything the playground runs is a file in the image:

~/.config/tmux/companion.conf docs/tmux.conf.full.example, unchanged
~/.config/tmux/playground.conf the tour’s scaffolding, not part of the tool
~/.config/tmux-companion/config.toml the layout the projects open with
/opt/playground/config.example.toml every option, annotated

docker cp <container>:/home/play/.config/tmux/companion.conf . copies one out, or read them in the container and copy what you want.

Install it properly, then themes.