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, second set of sessions |
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"]
tmux["tmux<br/>sessions + shell functions"]
cmux["cmux<br/>workspaces"]
registry["projects.toml<br/>projects / workon / mkproject"]
hs["Hammerspoon<br/>windows + hotkeys"]
sync["Syncthing<br/>~/Projects, ~/Work"]
repo --> homesick --> shell
homesick --> hs
homesick --> tmux
just --> brew
just --> mise
just --> uv
shell --> tmux
shell --> registry
registry --> tmux
cmux --> tmux
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 | tmux | home/.tmux.conf; functions in home/.bashrc.d/20-tmux.bash |
| Terminal windows | cmux | home/bin/cmux-* keep workspaces and sessions in step |
| Where projects live | the project registry | ~/Projects/projects.toml, edited by projects; opened by workon and mkproject in home/.bashrc.d/60-workon.bash |
| Windows and app hotkeys | Hammerspoon | home/.hammerspoon/ |
| Editor settings | Sublime Text | home/.config/sublime-text/, linked by just macos::sublime-link |
| 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.bashdefinesworkonandmkproject.~/.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 projects resolve 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.