domverse 47d9b7b6ef docs: inventory the software setup.sh installs
Lists every apt package, cargo tool, and install-script binary with its
upstream, grouped by how it arrives — the three build deps are separated
out since they exist only to compile the cargo tools and nothing uses them
at runtime, and rustup is placed with the tools that force it rather than
listed as a peer.

Records the reasons that are invisible from the package list: bat's binary
is batcat on Ubuntu so the cat alias depends on it, jq backs the Claude
statusline, and rustup uses --no-modify-path because conf.d/rustup.fish
already sources cargo's env.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 16:02:28 +02:00

dotfiles

Shell + tooling setup for a fresh Ubuntu box: fish · starship · atuin · eza · macchina, plus the Claude Code statusline.

Two layers, deliberately split:

Layer Owns Tool
Provisioning apt packages, rust toolchain, starship, default shell setup.sh (root)
Dotfile state everything under $HOME chezmoi (user)

setup.sh does the root work and then hands off to chezmoi. Nothing that needs sudo lives inside chezmoi, and nothing under $HOME is touched by the script.

Fresh box

git clone https://git.domverse-berlin.eu/domverse/dotfiles.git
cd dotfiles
sudo bash setup.sh

Run it as your normal user via sudo — the script reads SUDO_USER to know whose home to set up, and refuses to run as root directly.

Expect 1020 minutes: atuin, eza, macchina and oxker are built from source with cargo install --locked, which needs the rust toolchain. That's the deliberate trade for matching the currently-running versions exactly rather than taking whatever apt ships.

What gets installed

Everything setup.sh puts on the box, and where it comes from.

apt packages

Package What for Upstream
fish the shell itself; setup.sh chshes to it fish-shell/fish-shell
bat binary is batcat on Ubuntu; config.fish aliases cat to it sharkdp/bat
ripgrep rg BurntSushi/ripgrep
jq required by statusline-command.sh jqlang/jq
git chezmoi clones the source repo with it git/git
curl fetches the rustup / starship / chezmoi installers curl/curl
nano $EDITOR; the nanox alias forces TERM=xterm-256color under Ghostty nano-editor.org
build-essential cc/linker — cargo builds need it GNU GCC
pkg-config build dep for the cargo tools pkg-config
libssl-dev OpenSSL headers — atuin links against them openssl/openssl

The last three exist only to compile the cargo tools below. Nothing uses them at runtime.

Built from source with cargo install --locked

Tool What for Upstream
atuin shell history w/ sync + encryption atuinsh/atuin
eza ls replacement; backs the l / ll / lt / la aliases eza-community/eza
macchina the banner config.fish prints on interactive start Macchina-CLI/macchina
oxker terminal Docker container UI mrjackwills/oxker

This is the slow part — 1020 minutes cold. Built from source deliberately, to match the versions running on the origin box rather than whatever apt ships. That makes the rust toolchain a mandatory build dependency:

Tool What for Upstream
rustup + cargo toolchain for the four tools above rust-lang/rustup

Installed via sh.rustup.rs with --no-modify-pathconf.d/rustup.fish already sources ~/.cargo/env.fish, and the installer would otherwise add a second PATH edit. Lands in ~/.cargo, owned by the user, not root.

Installed via upstream install scripts

Tool Where it lands Upstream
starship /usr/local/bin (root) starship/starship
chezmoi ~/.local/bin (user) twpayne/chezmoi

Both are curl … | sh from the projects' own domains (starship.rs, get.chezmoi.io).

Not installed here

fnm (node) and dtop/opencode are out of scope — their own installers write conf.d/fnm.fish and conf.d/dtop.env.fish, which are .chezmoiignored. config.fish adds ~/.opencode/bin to PATH only if that directory already exists.

chezmoi on another VPS

setup.sh already does all of this. Use this path only when you want the dotfiles without the provisioning layer (no apt, no rust, no chsh) — e.g. a box where the tools are already there, or where you don't have root.

# 1. install chezmoi (user-local, no root)
sh -c "$(curl -fsLS get.chezmoi.io)" -- -b "$HOME/.local/bin"
export PATH="$HOME/.local/bin:$PATH"

# 2. pin the umask BEFORE the first apply — see Notes, this is load-bearing
mkdir -p ~/.config/chezmoi
printf 'umask = 0o022\n' >> ~/.config/chezmoi/chezmoi.toml

# 3. pull the source state (private repo — needs Gitea credentials)
chezmoi init https://git.domverse-berlin.eu/domverse/dotfiles.git

# 4. look before you leap
chezmoi diff

# 5. write it out
chezmoi apply

Notes on the above:

  • Step 2 must come before step 4. The umask is read at apply time; applying first and fixing the config after leaves wrong modes on disk.
  • Step 3 needs repo access. The repo is private. Either have credential.helper=store already populated, or clone over SSH: chezmoi init git@git.domverse-berlin.eu:domverse/dotfiles.git.
  • The source clone lands in ~/.local/share/chezmoi (chezmoi's default). This box is the exception — it sets sourceDir = /home/crabix/projects/dotfiles in ~/.config/chezmoi/chezmoi.toml because the repo predates chezmoi. On a fresh box, don't set sourceDir; the default is what setup.sh expects.
  • .chezmoiroot contains home, so the source root is home/, not the repo root. setup.sh and README.md sit outside chezmoi's view by design.
  • If ~ already has real dotfiles, chezmoi diff in step 4 shows exactly what gets clobbered. Back them up with modes intact first: cp -a ~/.config/fish ~/.config/atuin ~/backup/dotfiles-preapply-$(date -u +%Y%m%dT%H%M%SZ)/
  • Then do the Manual steps below (atuin key, git identity) — they are not specific to setup.sh.

Day-to-day

Configs are managed by chezmoi, so the file in ~/.config is a copy, not a symlink. Edit through chezmoi or your change gets overwritten on the next apply:

chezmoi edit ~/.config/fish/config.fish   # edit source
chezmoi diff                              # what drifted on this box?
chezmoi apply                             # write source -> $HOME
chezmoi cd                                # jump to the source repo, then git push

The fishconfig alias is wired to chezmoi edit for this reason.

What's tracked

home/
  dot_bashrc                                  ~/.bashrc  (stock + atuin init)
  dot_gitconfig                               ~/.gitconfig
  dot_config/fish/config.fish.tmpl            aliases, eza, init lines
  dot_config/fish/conf.d/rustup.fish          sources ~/.cargo/env.fish
  dot_config/atuin/config.toml
  dot_config/starship.toml                    stock-equivalent, pinned
  dot_claude/executable_statusline-command.sh statusline (needs jq)

What's deliberately NOT tracked

See home/.chezmoiignore. The load-bearing exclusions:

  • ~/.local/share/atuin/key — the sync encryption key. Tracked by hand in secrets.yml. Restore it before the first atuin sync, or history encrypted on other hosts will not decrypt.
  • ~/.git-credentials — plaintext tokens (.gitconfig sets helper = store).
  • ~/.claude/settings.json — pins the model and sets skipDangerousModePermissionPrompt; a per-box decision, set by hand.
  • conf.d/fnm.fish, conf.d/dtop.env.fish — node/opencode toolchains, out of scope. Their installers write these themselves.
  • fish_variables — machine-local state, fish rewrites it.

Manual steps after setup.sh

The script prints these; repeated here because they're easy to miss:

  1. atuin — restore key from secrets.yml into ~/.local/share/atuin/key, then atuin login -u <user> and atuin sync.
  2. git identity — not set globally, only credential.helper=store:
    git config --global user.name  '<name>'
    git config --global user.email '<email>'
    
  3. Log out and back in for the fish shell change to take effect.

chezmoi gotchas

Learned the hard way while building this. Don't rediscover them.

  • chezmoi does not preserve file modes. It tracks only the executable_ and private_ source attributes and derives the actual mode from the umask at apply time. With umask 002 (the default for this user), ~/.config/atuin/ silently goes 07000775 and config.toml 06000664. Correct modes need both halves:

    • the source attribute — private_atuin/private_config.toml, and
    • umask = 0o022 in ~/.config/chezmoi/chezmoi.toml (setup.sh writes this).

    Always chezmoi diff before trusting a dotfiles repo on a new box; the mode lines are quiet and easy to scroll past.

  • Never pipe chezmoi apply into a truncating command. chezmoi apply --verbose | head -20 SIGPIPEs chezmoi partway through, leaving the apply incomplete — files sorting after the cutoff are never written. Worse, $? reports head's exit status (0), so it looks like it succeeded. Redirect to a file and read that instead:

    chezmoi apply --verbose > /tmp/apply.log 2>&1; echo "exit=$?"
    
  • The file in ~ is a copy, not a symlink. Editing ~/.config/fish/config.fish directly gets silently clobbered on the next apply. Use chezmoi edit. The fishconfig alias points at chezmoi edit for exactly this reason.

  • chezmoi init on a box with existing dotfiles overwrites without asking once you apply. chezmoi diff first, always.

Notes

  • config.fish aliases cat to batcat — on Ubuntu the bat binary really is batcat, so the apt bat package is a hard dependency of the fish config.
  • rustup is installed with --no-modify-path: conf.d/rustup.fish already sources ~/.cargo/env.fish, and the installer would otherwise add a second PATH edit.
  • starship.toml is currently equivalent to stock defaults. It exists so the prompt is pinned to a known config rather than tracking version defaults.
Description
Shell + tooling setup for a fresh box: fish, starship, atuin, eza, macchina + Claude statusline. setup.sh provisions, chezmoi owns $HOME.
Readme 49 KiB
Languages
Shell 100%