Skip to content

Latest commit

 

History

21 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

dotfiles

Personal cross-machine config managed by chezmoi. Works the same on macOS (Apple Silicon) and Omarchy/Arch Linux.

Layout

.chezmoi.toml.tmpl       Bootstrap config — prompts for identity values on
                         first init, generates ~/.config/chezmoi/chezmoi.toml.
.chezmoiignore           Files in this repo that should NOT be copied to $HOME
                         (per-OS exclusions live here too).

dot_config/              Mirrors ~/.config/. Subdirectories below.
├── ghostty/             Terminal emulator
├── git/                 Templated. Identity from chezmoi.toml + [includeIf]
│                        rules for ~/github/personal/ vs ~/github/work/.
├── ntm/                 Named Tmux Manager config (templated)
├── nvim/                LazyVim setup
├── starship.toml        Prompt config (Omarchy default — Everforest)
├── tmux/                tmux.conf
├── zed/                 Zed editor settings
├── zellij/              Zellij config + layouts (ai-coding.kdl)
└── zsh/aliases.zsh      Cross-platform zsh aliases (sourced from ~/.zshrc)

dot_zshrc.tmpl           Main shell rc, OS-templated for Mac brew paths vs
                         Arch yay paths.

scripts/                 NOT applied to $HOME (.chezmoiignore'd).
├── Brewfile             macOS package list (brew bundle)
├── install-mac.sh       Installs everything in Brewfile + chezmoi + extra CLIs
├── install-omarchy.sh   Same packages via yay (handles official + AUR)
└── setup-tailscale.sh   Enables Tailscale SSH so the machine is reachable
                         remotely (macOS + Linux; see "Remote SSH access")

Files prefixed dot_ map to . in $HOME (chezmoi convention). Files ending in .tmpl are run through Go's text/template at apply time.

Bootstrap a fresh machine

The repo can live anywhere — ~/github/personal/dotfiles is just my convention. Substitute whatever path you cloned to in the commands below; the install scripts and chezmoi init will work from any location.

macOS

# Clone the repo wherever you want
git clone https://github.com/Scarletbobcat/dotfiles ~/github/personal/dotfiles
cd ~/github/personal/dotfiles

# Install Homebrew (if missing), all packages from Brewfile (incl. chezmoi),
# and extra CLIs (Claude Code, Codex, beads, agent mail). Idempotent.
./scripts/install-mac.sh

# Initialize chezmoi against this repo (prompts for name + email, populates
# ~/.config/chezmoi/chezmoi.toml, then applies all dotfiles to $HOME)
chezmoi init --apply -S "$(pwd)" \
    https://github.com/Scarletbobcat/dotfiles.git

# Restart your terminal (or `exec zsh`) to pick up the new shell setup

The -S flag tells chezmoi to use this clone as its source directory instead of cloning a fresh copy into ~/.local/share/chezmoi/. The path gets persisted into ~/.config/chezmoi/chezmoi.toml (via {{ .chezmoi.sourceDir }} in the template), so subsequent chezmoi commands don't need -S.

Omarchy / Arch

git clone https://github.com/Scarletbobcat/dotfiles ~/github/personal/dotfiles
cd ~/github/personal/dotfiles
./scripts/install-omarchy.sh
chezmoi init --apply -S "$(pwd)" \
    https://github.com/Scarletbobcat/dotfiles.git
# Log out and back in (or `exec zsh`) so the shell change takes effect.

The install script also runs chsh -s $(which zsh) if zsh isn't your default shell yet, and (on re-runs after chezmoi has applied at least once) drops you straight into a login zsh.

Remote SSH access (Tailscale SSH)

To reach a machine over SSH from anywhere — another laptop, or a phone — without exposing it to the public internet or managing SSH keys, use Tailscale SSH. The tailscale package is already in the Brewfile / yay list, so after a normal bootstrap just run, on the machine you want to reach:

./scripts/setup-tailscale.sh

Idempotent and OS-aware (uname-based, so it works on both macOS and Omarchy). On that target machine it:

  • macOS — installs the headless tailscaled daemon (the menu-bar app can't run an SSH server) as a root launchd daemon, and sets the Mac to never sleep on AC power so it stays reachable (revert with sudo pmset -c sleep 1).
  • Linux — installs tailscale and enables the tailscaled systemd service.
  • Then runs tailscale up --ssh (prints a browser login URL on first run) so the machine authenticates to your tailnet and accepts Tailscale SSH.

Auth is your tailnet identity, not SSH keys. New tailnets ship with a default policy that lets you SSH to your own devices, so it works out of the box; the first connection may pop a quick browser re-auth "check" (switch to "accept" in the admin console to skip it).

Connecting in

Any device that's also on your tailnet (signed into the same account) can reach it. Install the Tailscale app there, then SSH to the machine's name or 100.x.y.z IP (find them with tailscale status):

ssh <user>@<machine-name>     # no key setup — Tailscale authenticates you

From a phone: install the Tailscale app (puts the phone on your tailnet) plus any SSH client app — Termius is the easy pick (iOS + Android) — and connect to the same name/IP. No key needs to live on the phone.

Keeping it running

The daemon is a launchd (macOS) / systemd (Linux) service, so it auto-starts at boot, restarts itself on crash, and reconnects across reboots, sleep/wake, and network changes. Two things worth doing/knowing:

  • Disable key expiry for the machine in the admin console (Machines → device → ⋮ → Disable key expiry). Otherwise its key expires (~180 days) and it drops off the tailnet until you re-login — exactly when you're away and can't.
  • Sleep is the usual "can't reach it" cause, not the daemon. setup-tailscale.sh sets the Mac to never sleep on AC, so keep it plugged in with the lid open. It reconnects automatically on wake. Revert that with sudo pmset -c sleep 1.

Managing the daemon

The tsd shell helper (in dot_config/zsh/aliases.zsh, OS-detected at runtime) wraps daemon control:

tsd            # tailnet status (peers, online/offline) — same as `tailscale status`
tsd restart    # restart the daemon — do this after `brew upgrade tailscale`
tsd stop       # stop the daemon (machine goes offline)
tsd start      # start it again

For a lighter logical disconnect that leaves the daemon running, use the CLI directly: sudo tailscale down / sudo tailscale up --ssh. Raw service equivalents if you ever need them: macOS sudo launchctl kickstart -k system/com.tailscale.tailscaled; Linux sudo systemctl restart tailscaled.

Per-machine state

Per-machine values live in ~/.config/chezmoi/chezmoi.toml, which is not in this repo. The init step generates it from .chezmoi.toml.tmpl. Looks like:

sourceDir = "/Users/tienhoang/github/personal/dotfiles"  # whatever you passed to -S

[data]
    name             = "tienhoang-k2vp"        # work identity (Mac default)
    email            = "tien@k2vp.com"
    git_dir_personal = "~/github/personal/"    # gitdir prefix for personal identity
    git_dir_work     = "~/github/work/"        # gitdir prefix for work identity
    theme_ghostty    = "Everforest Dark Hard"  # Mac theme (Linux uses omarchy)
    theme_nvim       = "everforest"
    theme_nvim_bg    = "soft"

Edit this file and chezmoi apply to change identity or theme on Mac.

Git identity routing

Git identity auto-switches based on what directory you're in:

Path Identity
Anywhere not matching below chezmoi.toml defaults (name / email from prompts)
Under git_dir_personal (default ~/github/personal/) personal (Scarletbobcat / yahoo email)
Under git_dir_work (default ~/github/work/) work (tienhoang-k2vp / k2vp email)

This is [includeIf "gitdir:..."] in ~/.config/git/config, with the prefixes templated from the git_dir_personal and git_dir_work chezmoi data variables. Override them per machine by editing ~/.config/chezmoi/chezmoi.toml and running chezmoi apply. The override files (config-personal, config-work) live in this repo and apply to both machines. The [includeIf] blocks no-op silently when their target gitdir doesn't exist on a given machine.

Themes

Mac

Theme is set by chezmoi data variables. Switch by editing ~/.config/chezmoi/chezmoi.toml:

theme_ghostty = "Tokyo Night"   # any Ghostty built-in theme name
theme_nvim    = "tokyonight"    # any colorscheme loaded by all-themes.lua
theme_nvim_bg = "moon"          # if applicable

Then chezmoi apply and restart Ghostty / nvim. Available nvim themes are declared in dot_config/nvim/lua/plugins/all-themes.lua.

Linux (Omarchy)

Themes are managed dynamically by Omarchy itself. Switching theme via the omarchy menu updates symlinks at ~/.config/omarchy/current/theme/... and all themed apps follow. The Mac-only theme variables are unused here.

Common operations

chezmoi apply               # apply pending changes from source to $HOME
chezmoi diff                # show what apply would change
chezmoi cd                  # cd into the source directory
chezmoi edit ~/path/to/file # edit the source file (use this, not direct edits)
chezmoi add ~/path/to/file  # start tracking a new file
chezmoi forget ~/path/...   # stop tracking; leaves $HOME copy in place
chezmoi update              # pull from origin and apply

The most common gotcha: don't edit a managed file directly in $HOME and expect it to persist. Either edit the source via chezmoi edit, or chezmoi re-add after a direct edit.

What's intentionally not tracked

  • ~/.claude.json, ~/.claude/projects/, history files — session state
  • SSH private keys, GPG keys, AWS credentials — anything secret
  • ~/.zsh_history, .viminfo — per-machine usage history
  • Per-project app data (browsers, .git/ directories, etc.)

For per-machine secrets, source ~/.localrc from ~/.zshrc (already wired up) and put env vars there. That file is untracked.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages