How the pieces fit together¶
The dotfiles are one git repository, checked out at ~/.homesick/repos/dotfiles
on three Macs. Everything under home/ is linked into ~. A small set of
tools then divides the work between them. This page says which tool owns what,
so you know where to look when something needs to change.
The three Macs¶
| Key | ssh name | Role |
|---|---|---|
studio |
mac-studio-2023 |
Desktop, most long-running tmux sessions |
mini |
mac-mini-pro-2023 |
Desktop, tmux sessions for side projects |
air |
mba-2025 |
Laptop; reports MacBook-Air-2025 as its own hostname |
The short keys and ssh names live in the [machines] table of the
project registry. Every script that reaches another Mac reads
that table, so a machine is added once and known everywhere.
~/Projects and ~/Work are Syncthing folders. The same directories exist on
all three Macs, which is why a directory's presence proves nothing about where
you work on it. The registry records that instead.
Who owns what¶
flowchart TD
repo["~/.homesick/repos/dotfiles<br/>(git)"]
homesick["homesick<br/>symlinks home/ into ~"]
brew["Homebrew<br/>Brewfile per host"]
just["just<br/>home/justfile + .justfiles/"]
mise["mise<br/>go, node, ruby, rust, bun, deno"]
uv["uv<br/>python + CLI tools"]
shell["bash<br/>.bash_profile, direnv, Starship"]
herdr["herdr<br/>agent workspaces + sessions"]
registry["projects.toml<br/>projects / workon / mkproject"]
hs["Hammerspoon<br/>windows + hotkeys"]
sync["Syncthing<br/>~/Projects, ~/Work"]
repo --> homesick --> shell
homesick --> hs
just --> brew --> herdr
just --> mise
just --> uv
shell --> registry
sync -. mirrors .-> registry
| Concern | Owner | Where it is configured |
|---|---|---|
Getting files into ~ |
homesick | homeslice.toml lists the links; .homesick_subdir names folders whose children are linked one by one |
| Packages and apps | Homebrew | home/Brewfile is the generic install list; home/Brewfile.<Host> is what each Mac actually has |
| Tasks you run by hand | just | home/justfile plus one module per topic in home/.justfiles/ |
| Language runtimes | mise | home/.config/mise/config.toml; Python is disabled there on purpose |
| Python interpreters and CLI tools | uv | home/.justfiles/python.justfile; uv python install --default owns python on the PATH |
| Per-directory environment | direnv | home/.config/direnv/direnvrc defines layout uv and use tmux |
| Prompt | Starship | home/.config/starship.toml |
| Terminal sessions and workspaces | herdr | ~/.config/herdr/config.toml per Mac, not in the repo; other Macs saved with herdr machine add |
| Clipboard across the Macs | ssh-clipboard | home/.justfiles/ssh-clipboard.justfile; peers in ~/.config/ssh-clipboard/config.json per Mac |
| Where projects live | the project registry | ~/Projects/projects.toml, edited by the Rust projects; opened by workon and mkproject in home/.bashrc.d/61-workon.bash |
| Compiled tools | Rust / cargo | the rust/ Cargo workspace: projects and homesick-new; just rust-install builds them into ~/.local/bin |
| Windows and app hotkeys | Hammerspoon | home/.hammerspoon/ |
| Launcher and workflows | Alfred | ~/Library/Application Support/Alfred/ per Mac, not in the repo; backed up by a workflow |
| Editor settings | Sublime Text | home/.config/sublime-text/, linked by just macos::sublime-link |
| Agent approvals | Moshi | moshi-hook daemon via brew services; moshi-hook install writes agent hook configs, moshi-hook doctor checks the host |
| Hardware buttons | Elgato Stream Deck | ~/Library/Application Support/com.elgato.StreamDeck/ProfilesV3/ |
| Lint | prek | .pre-commit-config.yaml, run by just lint and by CI |
| This manual | Zensical | zensical.toml and docs/, published by the Docs workflow |
How a shell starts¶
~/.bash_profilesources every~/.bashrc.d/*.bashfile in name order: exports, tmux, aliases, functions, secrets, the OS file, then workon.50-osx.bashand50-linux.basheach start with aunamecheck and return on the other OS.60-workon-archive.bashdefines the archivedworkon-archiveandmkproject-archive;61-workon.bashdefinesworkonandmkproject, thin wrappers around the Rustprojects.~/.bashrcsources20-tmux.bash, starts Starship, and installs the direnv hook.- If
TMUX_AUTOATTACHis set,20-tmux.bashattaches the named session. A project's.envrcsets that variable throughuse tmux.
To add shell config, drop a numbered .bash file into home/.bashrc.d/. Nothing else needs editing.
The result: cd into a project, direnv activates its venv and, when the
project asked for it, drops you into its tmux session.
How a project is opened¶
workon <name> asks the Rust projects where the project lives. The answer is
one of three things:
| Answer | What happens |
|---|---|
| No machine recorded | cd and activate here; the directory is on every Mac |
| This machine | cd and activate here |
| Another machine | mosh to it, and attach its tmux session when the entry says tmux = true |
A project not in the registry falls back to a scan of ~/Projects, ~/Work,
and ~/.virtualenvs, so the old behaviour still works. The full decision tree
is in How workon resolves a project.
How the Macs see each other¶
Names resolve over Tailscale MagicDNS or ~/.ssh/config. Remote commands use
one-shot, non-interactive ssh with BatchMode=yes, so a host that would prompt
fails fast instead of hanging. tmux-remote-ls and workon --sessions probe
every Mac at once and skip the one you are sitting at. cmux can answer the
same question through its own rpc, and the scripts try that first.
What is deliberately not here¶
- No
gh-pagesbranch. The manual deploys from a workflow artifact. - No pyenv. uv provides every Python. The old
~/.pyenvdirectories are leftovers, see Maintenance. - No virtualenvwrapper.
~/.virtualenvsstill exists as an archive of old environments, andworkonstill looks there as a last resort. - Sublime Text settings are in
home/.config/sublime-text/and linked byjust macos::sublime-link, not by homesick, because thePackages/Userfolder also holds files the editor writes itself.