Files
dotfiles/README.md
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

229 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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
```bash
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` `chsh`es to it | [fish-shell/fish-shell](https://github.com/fish-shell/fish-shell) |
| `bat` | binary is **`batcat`** on Ubuntu; `config.fish` aliases `cat` to it | [sharkdp/bat](https://github.com/sharkdp/bat) |
| `ripgrep` | `rg` | [BurntSushi/ripgrep](https://github.com/BurntSushi/ripgrep) |
| `jq` | required by `statusline-command.sh` | [jqlang/jq](https://github.com/jqlang/jq) |
| `git` | chezmoi clones the source repo with it | [git/git](https://github.com/git/git) |
| `curl` | fetches the rustup / starship / chezmoi installers | [curl/curl](https://github.com/curl/curl) |
| `nano` | `$EDITOR`; the `nanox` alias forces `TERM=xterm-256color` under Ghostty | [nano-editor.org](https://www.nano-editor.org/) |
| `build-essential` | cc/linker — cargo builds need it | [GNU GCC](https://gcc.gnu.org/) |
| `pkg-config` | build dep for the cargo tools | [pkg-config](https://gitlab.freedesktop.org/pkg-config/pkg-config) |
| `libssl-dev` | OpenSSL headers — atuin links against them | [openssl/openssl](https://github.com/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](https://github.com/atuinsh/atuin) |
| `eza` | `ls` replacement; backs the `l` / `ll` / `lt` / `la` aliases | [eza-community/eza](https://github.com/eza-community/eza) |
| `macchina` | the banner `config.fish` prints on interactive start | [Macchina-CLI/macchina](https://github.com/Macchina-CLI/macchina) |
| `oxker` | terminal Docker container UI | [mrjackwills/oxker](https://github.com/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](https://github.com/rust-lang/rustup) |
Installed via `sh.rustup.rs` with `--no-modify-path``conf.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](https://github.com/starship/starship) |
| `chezmoi` | `~/.local/bin` (user) | [twpayne/chezmoi](https://github.com/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 `.chezmoiignore`d.
`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.
```bash
# 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:
```bash
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`:
```bash
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 `0700` → `0775` and `config.toml` `0600` → `0664`. 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:
```bash
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.