Devcontainer-first dotfiles for my terminal-native development workflow.
This repository manages a small CLI and terminal setup for the environments where development actually happens: devcontainers. It does not try to provision my Mac, WSL2 host, graphical applications, Docker Desktop, OrbStack, Docker Engine, or machine-specific package recipes.
- Portable CLI/development tools through
Brewfile. - Dotfiles through GNU Stow packages under
stow/. - Shell, Git and Starship configuration.
- Installation of the separate Neovim configuration repository into
~/.config/nvim.
- macOS graphical applications.
- Host terminal applications.
- Ghostty configuration.
- Docker Desktop, OrbStack or Docker Engine setup.
- WSL2 provisioning.
- SSH private keys.
- Machine hostname profiles.
- Neovim configuration internals.
- Project-specific language runtimes or dependencies.
Project tooling should normally live in the relevant repository's devcontainer, not in this dotfiles repo.
.
├── Brewfile
├── README.md
├── bootstrap.sh
└── stow
├── git
│ └── .gitconfig
├── shell
│ ├── .config
│ │ └── shell
│ │ ├── env.sh
│ │ └── interactive.sh
│ ├── .bash_profile
│ ├── .bashrc
│ ├── .zprofile
│ ├── .zshrc
│ └── .hushlogin
└── starship
└── .config/starship.toml
Clone the repo inside the devcontainer, then run the bootstrap script:
git clone https://github.com/philbudden/dotfiles.git ~/Developer/dotfiles
cd ~/Developer/dotfiles
./bootstrap.shThe script will:
- Load Homebrew if it is already installed.
- Install Homebrew automatically when it appears to be running inside a container and Homebrew is missing.
- Run
brew bundle --file Brewfile. - Move pre-existing files that would conflict with managed Stow links into
~/.dotfiles-backup/<timestamp>/. - Link the Stow packages into
$HOME. - Clone or update
https://github.com/philbudden/neovim-config.gitinto~/.config/nvim.
After it finishes, restart the shell or run the entrypoint for the current shell:
source ~/.bashrcsource ~/.zshrcHost setup is deliberately out of scope. If I choose to apply the same dotfiles on macOS or WSL2, Homebrew must already be installed. Then I can run:
cd ~/Developer/dotfiles
./bootstrap.shThe script will not install Homebrew automatically on a host. This is intentional: the host should remain mostly untouched, and daily development should happen inside devcontainers.
Brewfile contains portable CLI tools only:
batcoderabbitcopilot-clifdfzfghjqlazygitneovimripgrepstarshipstowunzipzipzoxide
Do not add graphical applications, host services, Docker packages, WSL setup packages, or project-specific runtimes here unless they are genuinely useful across most devcontainers.
Dotfiles are linked with GNU Stow:
stow --dir stow --target "$HOME" shell git starshipRun this manually after changing Stow packages if package installation is not needed.
The shell setup supports both Bash and Zsh without keeping two full configurations in sync.
.config/shell/env.shcontains portable environment and PATH setup..config/shell/interactive.shis reserved for shared aliases and functions that work unchanged in Bash and Zsh..bashrcand.zshrcstay small and contain only shell-specific interactive initialisation, such as Starship, zoxide and fzf..bash_profileand.zprofilehandle login-shell entrypoints.
Use the default shell that fits the environment: Zsh on macOS, Bash in most Linux devcontainers and remote Linux systems, and whichever is least surprising in WSL2.
tmux is intentionally not installed or configured here. It belongs to the host control-plane layer because project sessions live on the host side of the DevPod attach workflow.
GitHub Copilot CLI is intentionally installed here because it is part of the normal development shell inside hosts and devcontainers. Authentication remains outside this bootstrap: log in on the host manually, then let the host control-plane attach commands pass existing GitHub authentication into devcontainer sessions. On macOS it is installed with the Homebrew copilot-cli cask; on Linux, WSL2 and devcontainers it is installed with GitHub's official install script.
CodeRabbit CLI is also installed here because it is part of the terminal-native review workflow. Authentication remains outside this bootstrap. On macOS it is installed with the Homebrew coderabbit cask; on Linux, WSL2 and devcontainers it is installed with CodeRabbit's official install script.
Bootstrap creates a ~/.local/bin/cr symlink to coderabbit only when the short command is missing. The symlink is created by bootstrap rather than Stow because CodeRabbit's Linux installer also creates ~/.local/bin/cr.
On Linux and WSL2, Neovim Treesitter parser installation needs a C compiler. Bootstrap installs Ubuntu/Debian build-essential through apt when cc is missing, because Treesitter needs a normal system compiler rather than a Homebrew GCC package.
neovim is installed as a CLI tool through Brewfile. The actual configuration lives in the separate https://github.com/philbudden/neovim-config.git repository.
During bootstrap, this repo clones that configuration into ~/.config/nvim when it is missing. If ~/.config/nvim is already a clone of the same repository, bootstrap updates it with git pull --ff-only. If another Git-backed Neovim config already exists, bootstrap leaves it unchanged and reports the different origin. If a non-Git config already exists, bootstrap moves it aside with a timestamped .backup.YYYYMMDDHHMMSS suffix before cloning.
To use a different source temporarily:
NVIM_CONFIG_REPO=git@github.com:philbudden/neovim-config.git ./bootstrap.shThe repo manages generic Git defaults only. SSH keys and host-specific Git identities should remain outside the repo.
For multiple GitHub organisations, use SSH host aliases and Git configuration that points individual repositories or directory trees at the right identity. Keep private keys out of this repository.
This repo used to use Chezmoi with hostname-based package profiles. That was useful when hosts were the primary development environments. The current workflow is different: VS Code connects to Mac/WSL hosts, and the real development tooling lives inside devcontainers.
The simpler model is now:
- Build or enter a devcontainer.
- Clone this repo.
- Run
./bootstrap.sh. - Work inside the container.
No hostname detection, templating, package-manager orchestration, GUI app installation, or host provisioning is needed.