# Tools Two levers, and it matters which one you use: | Lever | Installs | Persists | Rebuild? | |---|---|---|---| | **mise** | CLIs, runtimes, language toolchains | yes (in the home volume) | no | | **apt** (`EXTRA_PACKAGES`) | system libraries, `ffmpeg`, `-dev` headers | only in the image | **yes** | Rule of thumb: if `mise use -g ` works, it is live. If it needs shared libraries or is an `apt` package, it goes in `EXTRA_PACKAGES` and gets built as a thin overlay on top of the published image. ## Three tiers, not two 1. **mise by name** — `mise use -g lazygit`, `mise use -g python@3.12`. 2. **mise by backend** — when there is no plain name: `mise use -g npm:`, `pipx:`, `cargo:`, `ubi:/`, `aqua:/`. Tiers 1 and 2 are both live and persistent. 3. **apt** — `EXTRA_PACKAGES` in `.env` + `docker compose -f compose.yml -f compose.user.yml up -d --build`. This builds `Dockerfile.user` (`FROM` the published image) as a small overlay, so it only re-runs that one layer on top of a new base. ## Updates ```bash docker compose pull && docker compose up -d # pull a newer image + recreate docker compose -f compose.yml -f compose.user.yml up -d --build # with an apt overlay ``` The base image is pulled, never rebuilt, for normal users — so an update is fast and reproducible. Your home volume is untouched. Sessions stop while the container is recreated. ## Inside the box, live (mise) ```bash mise use -g lazygit # or: aqua:owner/repo, npm:pkg, pipx:pkg, cargo:pkg, ubi:owner/repo mise use -g python@3.12 mise use -g npm:some-cli mise up # update everything ``` In the box, the `roost-setup` skill knows these tiers: ask your agent to install what a project needs. ## Image overlay (apt) ```bash # .env next to compose.yml: EXTRA_PACKAGES="ffmpeg libpq-dev" docker compose -f compose.yml -f compose.user.yml up -d --build ``` Re-run that command after every pull to re-apply the overlay; the home volume (logins, repos, mise tools) survives. Sessions stop while the container is recreated. ## Default set `TOOLS` in `.env` installs: `herdr uv gh glab npm:ccusage npm:playwright npm:@playwright/mcp`, plus `node@lts`. The base image also carries git, tmux, ripgrep, fd, jq, btop, build-essential, python3-venv, vim, less, openssh. ## Why not sudo? There is deliberately **no sudo and no Docker socket**. Agents run in bypass mode, so root in the container would be root on the host. Keep new dependencies flowing through mise or a reviewed `EXTRA_PACKAGES` change. If a task truly needs to deploy a service, write a compose file in the repo and have a human deploy it.