A reminder of how to set up my dotfiles on a new machine.
Prerequisite on Ubuntu (e.g. a fresh Docker container) — the Homebrew installer needs curl and git:
sudo apt install curl gitFollow the instructions at https://brew.sh/:
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"After installing, if you want to use brew one time only (without polluting your rc files), load it into the current shell (Linux):
eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv bash)"On macOS, use
eval "$(/opt/homebrew/bin/brew shellenv bash)"instead.
Alternative: Nix Package Manager
sh <(curl --proto '=https' --tlsv1.2 -L https://nixos.org/nix/install)or,
sh <(curl --proto '=https' --tlsv1.2 -L https://nixos.org/nix/install) --no-daemonpersonal choice, especially inside a container
. $HOME/.nix-profile/etc/profile.d/nix.shNote: nix-command and flakes are automatically enabled with chezmoi apply.
brew install zsh chezmoi nushellNote: the package is
nushell, notnu.
Alternative: zsh via system package manager
sudo pacman -S zshsudo dnf install zshsudo apt install zshAlternative: chezmoi via Nix
nix --extra-experimental-features nix-command --extra-experimental-features flakes profile install nixpkgs#chezmoiThen apply:
# github handle after --apply
chezmoi init --apply vimkimchezmoi init --apply only clones when the source directory does not exist
yet; it does not pull remote updates. To sync a patch made on another machine,
either pull-and-apply in one step:
chezmoi updateor, when the machine might have local edits worth checking first:
chezmoi git pull -- --autostash --rebase # just pull the source repo
chezmoi diff # see what apply would change
chezmoi apply # apply when happyNone of these are hard requirements — config.nu quietly skips every tool that is not installed. Recommended for the interactive experience (prompt, history, completions; without carapace, Tab-completion for external commands does not work):
brew install starship atuin carapaceOptional tools
Optional tools used by aliases and helper commands (e.g. eza for l,
fzf/fd/ripgrep for the pickers, lazygit for lz, delta as the git/lazygit
pager):
brew install eza fzf fd ripgrep lazygit deltaMisc dependencies:
brew install mise direnv zoxide fastfetch diffnav ghThe terminal configuration uses Maple Mono. On Fedora, follow Installing Maple Mono Nerd Font.
daily-update (in ~/.config/my-scripts/bin) upgrades Codex, Claude Code, and
the globally installed agent skills in one go:
daily-update # run everything, report stale skills, mark today done
daily-update --status # show current versions and whether today is done
daily-update --stale # list stale skills, changing nothing
daily-update --prune # delete the stale skills that --stale listed
daily-update --reset # clear today's mark so the reminder comes backBoth config.nu and .zshrc call daily-update --remind at the end of
interactive startup. That prints a pending block on every new shell and keeps
printing until daily-update actually runs; the run writes today's date to
~/.cache/daily-update.stamp, which silences the reminder for the rest of the
calendar day. Seeing the reminder never dismisses it, which is the difference
from the PR digest above.
The stamp records that a run happened, not that every step succeeded. A failed step is listed at the end of the run and left for a deliberate re-run, so a network blip cannot trap the reminder in a loop.
Skills come from the skills CLI and are tracked in ~/.agents/.skill-lock.json.
Because ~/.claude/skills/* symlinks into ~/.agents/skills, the single
skills update --global covers both Claude Code and Codex.
skills update never removes anything, and the CLI has no prune command, so a
skill deleted from its source repository stays installed and active forever.
Each run therefore reports what has gone stale and points at --prune. The
startup reminder then names those skills, reading them from cache so it stays
offline and fast; past eight names it summarises the remainder as a count.
A skill is stale only if the lock file claims it and one of these holds:
- it no longer exists in its source repository,
- its directory under
~/.agents/skillsis gone, or - its
~/.claude/skillssymlink is broken.
Everything else is left alone. This matters because the lock file records only
GitHub-sourced installs: the whole my-cubrid-skills collection is installed
from a local path and never appears in it, so treating the lock as an allowlist
would delete every personal skill. Names present in ~/gh/my-cubrid-skills are
additionally protected even if a source repo later publishes the same name.
Two failure modes are guarded explicitly. A gh failure is never read as "the
repository is empty", and because gh api prints its 404 body to stdout, the
upstream list is accepted only when the command succeeds and every line looks
like a bare directory name. --prune moves what it removes into
~/.cache/daily-update/trash/<timestamp>/, with a copy of the lock file, rather
than deleting outright.
Upgrades always resolve ~/.local/bin first rather than trusting the calling
shell's PATH, because the two disagree on this host: zsh finds a mise-managed
npm codex and a stale root-owned /usr/bin/claude (npm global, 2.0.25) that
the nushell login shell never sees. Without the pin, running daily-update
from zsh would upgrade a different install than the one you actually use.
The display-environment, XKB layout, and dead_hamza packaging diagnosis is
recorded in WezTerm on Fedora KDE through Herdr,
including verification and rollback commands.
The KDE Wayland configuration includes a standalone Colemak layout with programming symbols on the unshifted number row. Follow Installing the Colemak Programmer Layout to validate and apply it without shadowing the system US XKB symbols file.
Optional Step: Install oh-my-zsh
I now use nushell instead, by the way.
sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"
mv .zshrc.pre-oh-my-zsh .zshrcOptional Step: Other nix packages
Only if you installed Nix. This might take some time and disk spaces.
my-nix-install.shcd $HOME/.config
git clone https://github.com/vimkim/nvimsudo dnf install xauth
sudo apt install xauth
sudo pacman -S xorg-xauth# /etc/ssh/sshd_config
X11Forwarding yes
X11DisplayOffset 10
X11UseLocalhost yes