Dot-Zsh
Personal cross-platform shell and workstation bootstrap for:
- Arch Linux
- Ubuntu / Debian-family Linux
- Fedora
- macOS
- WSL
The repo is built around a small bootstrap path and a fuller just-based workflow.
Layout
.
├── Bins/ # Pinned binary versions (nvim, eza, ...)
├── Commands/ # just modules
├── Scripts/ # install/setup scripts
├── Zsh/ # stowed shell files
├── Justfile # main just entrypoint
└── Makefile # lightweight bootstrap entrypoint
Key folders
Zsh/
Stowed into $HOME.
.zshrc.zshenv.zsh_aliases.zsh_prompt.zsh_completion.zsh_secrets.zsh_secrets.example
Scripts/
Main install logic.
base.sh— system/base packages and common toolssetup.sh— full setup flownode.sh,go.sh,rust.sh,python.sh,r.sh,cpp.shbin/install.sh— install pinned repo-managed binariesbin/update.sh— update pinned binary versions
Commands/
Modular just commands.
Commands/Setup/mod.justCommands/Lang/mod.justCommands/Bin/mod.justCommands/Git/mod.just
Bins/
versions.json is the source of truth for pinned binary versions and per-platform asset mappings.
Core workflow
Bootstrap only
Use make setup when you want the lightweight bootstrap path:
make setup
This currently does:
- run
Scripts/base.sh - remove old
Zshstow links - stow
Zsh/into$HOME
It is intentionally small.
Full setup
Use just setup all for the full machine setup:
just setup all
This runs the full flow in Scripts/setup.sh:
- base system setup
- node / pnpm / yarn / bun
- go / gvm
- rust
- python / pyenv / miniforge
- r
- secret-file reconciliation
- backup of conflicting unmanaged dotfiles
- stow
Zsh/
Other useful commands
just setup base
just setup bootstrap
just setup stow
just setup clean
just setup update
just git show
just git editor
just git editor nvim
just lang node
just lang go
just lang rust
just lang python
just lang r
just lang cpp
just bin show
just bin list
just bin install-all
just bin install nvim
just bin releases nvim
just bin list nvim # backwards-compatible shorthand for releases
just bin update nvim
just lang all
If fzf is available, just bin update <tool> can use interactive selection.
just setup all and just setup base now set the default global Git editor to VS Code (code --wait).
If you want to switch to Neovim later, run just git editor nvim.
Secrets model
This repo now treats shell secrets as repo-managed local dotfiles instead of tracked plaintext config.
Source of truth
Zsh/.zsh_secrets
That file is intended to be stowed to:
$HOME/.zsh_secrets
Important notes
.zsh_secretsis ignored by git.zsh_secrets.exampleexists as a template/reference- setup tries to reconcile an existing
$HOME/.zsh_secretssafely - if conflicting unmanaged dotfiles already exist, setup backs them up before stowing
Backup location:
~/.dotzsh-pre-stow-backup/<timestamp>/
Binary management
This repo no longer stores shipped binaries in git.
Instead:
- pinned versions live in
Bins/versions.json - installs go into
~/.local/bin - updates happen through
just bin update <tool>
Current managed binaries include:
nvimeza
Platform behavior:
- Linux: install from pinned release assets
- macOS: install from pinned asset when supported, or use Homebrew formula fallback when configured
Shell behavior
Prompt
Prompt logic lives in:
Zsh/.zsh_prompt
It adds:
- git branch
- git dirty/clean indicator
- conda / direnv context
- repo-scoped project markers
- language version hints
- separator rule between prompts
Completion
Completion logic lives in:
Zsh/.zsh_completion
It adds:
- custom first-word command completion
- recently used commands shown first
- used commands visually marked with
* - wrapper completion bindings for lazy-loaded tools like
gvm,conda,go,node,npm, andnpx
Lazy loading
Several language managers are intentionally lazy-loaded to keep shell startup lighter.
Examples:
nvmgvmpyenvconda
openchamber auto-start is restricted to WSL sessions.
Install size
Measured practical installed footprint on Linux is roughly:
- Ubuntu: about
1.96 GB - Arch: about
1.84 GB - Fedora: about
1.77 GB
So the setup is best thought of as:
~1.8 GB to ~2.0 GB total
Largest components
Measured Ubuntu component breakdown:
- Rust: about
1.5 GB - Python: about
1.1 GB - Go: about
635 MB - Node: about
235 MB ~/.local: about128 MB- R wrapper/user area under
~/.programming/r: very small (~20 KBin that measurement)
Important nuance:
~/.programming/ris intentionally small because it mainly holds wrappers and user-library location- the actual R runtime may still come from the distro package manager or Rig, depending on platform
- so not all R-related disk usage appears under
~/.programming/r
Measured paths
Representative measured path sizes from Linux test runs:
Ubuntu
~/.programming ~3.17 GB
~/.local ~133 MB
/usr/local ~13 MB
Arch
~/.programming ~3.17 GB
~/.local ~133 MB
Fedora
~/.programming ~3.17 GB
~/.local ~133 MB
Those path totals are larger than the final container image delta because some space is shared/overlapping across package layers and installed tooling.
Notes by platform
Linux
- full setup has been exercised in container tests on Ubuntu, Arch, and Fedora x86_64
macOS
- supports Homebrew-based package install flow
- uses
/bin/zshfor shell-change target - handles existing dotfiles and secret symlink reconciliation more carefully
WSL
- WSL-specific logic is used where needed
openchamberis only auto-started in WSL
First-run recommendation
If you are starting clean:
make setup
just setup all
If you only want shell files re-linked:
just setup clean
just setup stow
If you only want to refresh pinned binaries:
just bin install-all
Current philosophy
This repo aims to be:
- owned rather than magical
- reproducible rather than ad hoc
- modular rather than one giant dotfile blob
- explicit about pinned binaries and local secrets
It is not trying to be the smallest possible install. It is trying to be a repeatable personal workstation setup.