Skip to content

Commit f980c8b

Browse files
committed
update readme
1 parent 2e33608 commit f980c8b

1 file changed

Lines changed: 113 additions & 48 deletions

File tree

README.md

Lines changed: 113 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,41 @@
1-
# dotfiles
1+
<div align="center">
22

3-
macOS configuration files managed with [GNU Stow](https://www.gnu.org/software/stow/).
3+
# ⚙️ dotfiles
44

5-
Assumes macOS with zsh. Homebrew is detected at both the Apple Silicon
6-
(`/opt/homebrew`) and Intel (`/usr/local`) prefixes.
5+
<p><strong>macOS configuration, managed with <a href="https://www.gnu.org/software/stow/">GNU Stow</a></strong></p>
6+
7+
<p>
8+
<a href="https://github.com/itsdanieldk/dotfiles/actions/workflows/lint.yml"><img src="https://github.com/itsdanieldk/dotfiles/actions/workflows/lint.yml/badge.svg" alt="lint"></a>
9+
<img src="https://img.shields.io/badge/platform-macOS-000000.svg?logo=apple" alt="Platform: macOS">
10+
<img src="https://img.shields.io/badge/shell-zsh-4EAA25.svg" alt="Shell: zsh">
11+
<img src="https://img.shields.io/badge/managed%20with-GNU%20Stow-4E9A06.svg" alt="Managed with GNU Stow">
12+
<img src="https://img.shields.io/badge/theme-Catppuccin%20Frapp%C3%A9-8caaee.svg" alt="Theme: Catppuccin Frappé">
13+
<a href="LICENSE.md"><img src="https://img.shields.io/badge/license-Unlicense-blue.svg" alt="License: Unlicense"></a>
14+
</p>
15+
16+
</div>
17+
18+
---
19+
20+
Every top-level directory is a [stow](https://www.gnu.org/software/stow/) package whose contents
21+
mirror `$HOME` (`zsh/.zshrc``~/.zshrc`), linked by a single interactive `./install`. Assumes
22+
macOS with zsh; Homebrew is detected at both the Apple Silicon (`/opt/homebrew`) and Intel
23+
(`/usr/local`) prefixes. Everything is tuned for one specific machine — see [Requirements](#requirements).
24+
25+
- **Leaf-only symlinks** — stow runs `--no-folding`, so app-managed directories (`~/.ssh`, `~/.claude`) stay real folders and only tracked files are linked; runtime state and secrets never land inside the repo
26+
- **One interactive installer**`./install` prompts y/N before each step and is driven by a commented [`Brewfile`](Brewfile) that is the source of truth for packages
27+
- **Catppuccin Frappé everywhere** — kitty, Neovim, bat, btop, lazygit, delta, fzf, SketchyBar and JankyBorders share one palette
28+
- **Tuned for one machine** — a Mac Studio (M4 Max) driving a single 2560×1440 external; AeroSpace and SketchyBar assume exactly that
29+
- **Layout-aware keys** — workspaces live on `ctrl-<digit>`, because `alt-<digit>` is where the Danish layout hides `[ ] { } \`
30+
- **Private by default**`.zprofile` opts out of every telemetry channel in the stack, and allowlist `.gitignore`s keep credentials uncommittable
31+
32+
## Requirements
33+
34+
macOS with zsh, and [GNU Stow](https://www.gnu.org/software/stow/) (installed by the Brewfile). The
35+
window-manager and status-bar configs assume a **Mac Studio (M4 Max) driving one 2560×1440 external
36+
display** — no battery, no built-in display, no notch. AeroSpace and SketchyBar are tuned for exactly
37+
that: no per-monitor gaps, no forced workspace-to-monitor assignment, no notch arithmetic.
38+
Reintroducing multi-monitor or laptop assumptions needs a second display actually present.
739

840
## Install
941

@@ -13,7 +45,8 @@ cd ~/dotfiles
1345
./install
1446
```
1547

16-
The install script interactively prompts (y/N) before each step:
48+
`install` is a **zsh** script (it uses `read -q`, `print` and the `*(/)` glob qualifier), so
49+
shellcheck can't read it — syntax-check with `zsh -n install`. It prompts (y/N) before each step:
1750

1851
1. Xcode Command Line Tools
1952
2. Homebrew
@@ -22,31 +55,52 @@ The install script interactively prompts (y/N) before each step:
2255
5. Oh My Zsh
2356
6. Oh My Zsh theme (powerlevel10k)
2457
7. Oh My Zsh custom plugins (fzf-tab, zsh-autosuggestions, zsh-syntax-highlighting)
25-
8. macOS defaults (Finder, Dock, keyboard, screenshots, trackpad, misc power-user)
58+
8. macOS defaults (Finder, Dock, menu bar, keyboard, launcher, screenshots, trackpad, misc power-user)
2659
9. Stow dotfile linking (errors on conflict by default)
2760

28-
Step 8 includes a separate, individually-prompted step that **disables the
29-
Gatekeeper "downloaded from the internet" warning** (`LSQuarantine`). It is the
30-
one prompt that weakens a security control — answer `N` to keep the warning.
61+
Step 8 includes a separate, individually-prompted step that **disables the Gatekeeper "downloaded
62+
from the internet" warning** (`LSQuarantine`). It is the one prompt that weakens a security control —
63+
answer `N` to keep the warning.
3164

3265
Flags:
66+
3367
- `--yes` / `-y` — non-interactive (auto-yes to all prompts)
3468
- `--adopt` — allow stow to resolve conflicts by adopting `$HOME` files into the repo (**destructive**: overwrites tracked configs; review `git diff` after)
3569

70+
## Stow Packages
71+
72+
| Package | Contents |
73+
|---------|----------|
74+
| `aerospace` | [AeroSpace](https://github.com/nikitabobko/AeroSpace) tiling WM. Numeric workspaces on `ctrl-1``ctrl-9` (**not** `alt` — that is where a Danish layout keeps `[ ] { } \`), focus/move on `alt-hjkl`. Launches `borders` and `sketchybar` at startup. Needs Accessibility permission |
75+
| `bat` | bat config (Catppuccin Frappé theme) |
76+
| `borders` | [JankyBorders](https://github.com/FelixKratz/JankyBorders) focus ring (`bordersrc`), Catppuccin Frappé mauve/surface1. Started by AeroSpace, not `brew services`, so it reads the stowed config |
77+
| `btop` | btop Catppuccin Frappé theme (the install script seeds `color_theme = "catppuccin_frappe"` for you) |
78+
| `claude` | Claude Code settings and statusline |
79+
| `git` | `.gitconfig` with delta pager, global gitignore. Repos under `~/work/` commit with the work identity — the rule is inert until that directory exists |
80+
| `hushlogin` | Suppresses the "Last login" message |
81+
| `kitty` | Kitty terminal (Catppuccin Frappé, Fira Code Nerd Font Mono) |
82+
| `lazygit` | lazygit config (Catppuccin Frappé theme, delta pager) |
83+
| `nvim` | Neovim (lazy.nvim, Treesitter, Telescope, Catppuccin Frappé) |
84+
| `raycast` | [Raycast](https://www.raycast.com) script commands. Raycast's own settings are not file-based, so only this directory is tracked — add it under Settings > Script Commands > Add Script Directory |
85+
| `sketchybar` | [SketchyBar](https://github.com/FelixKratz/SketchyBar) status bar with plugins and Swift helpers. Driven by AeroSpace workspace-change events; lint with [`scripts/lint-sketchybar.sh`](scripts/lint-sketchybar.sh) |
86+
| `ssh` | SSH config with macOS Keychain, hardened algorithms. Put machine-local hosts in `~/.ssh/config.local` (included first, untracked) |
87+
| `zsh` | `.zshrc` (Oh My Zsh + Powerlevel10k, fzf, zoxide, direnv, aliases), `.p10k.zsh`, `.zprofile` |
88+
3689
## Homebrew Packages
3790

38-
Installed from the [`Brewfile`](Brewfile) (step 3), which is grouped and commented —
39-
treat it as the source of truth. By group:
91+
Installed from the [`Brewfile`](Brewfile) (step 3), which is grouped and commented — treat it as the
92+
source of truth. By group:
4093

4194
**Formulae**
4295

4396
- **Core**`stow`, `git`, `neovim`
44-
- **Modern CLI replacements**`ripgrep`, `fd`, `bat`, `eza`, `fzf`, `jq`, `zoxide`
45-
- **Utilities**`btop`, `dust`, `yq`, `tealdeer`, `tree`, `fastfetch`, `marp-cli`
46-
- **Git & dev tools**`gh`, `git-delta`, `lazygit`, `lazydocker`
97+
- **Modern CLI replacements**`ripgrep`, `fd`, `bat`, `eza`, `fzf`, `jq`, `zoxide`, `media-control`
98+
- **Utilities**`fastfetch`, `btop`, `dust`, `yq`, `tealdeer`, `tree`, `marp-cli`
99+
- **Git & dev tools**`gh`, `git-delta`, `lazygit`, `lazydocker`, `shellcheck`
47100
- **Languages & runtimes**`node`, `pnpm`, `elixir`, `elm`, `powershell`, with `direnv` for per-project env
48101
- **Azure**`azure-cli`, `azd`, `azure-functions-core-tools@4`, `azurite` (Storage emulator), `bicep`
49102
- **Containers & Kubernetes**`docker`, `docker-compose`, `kubectl`, `helm`, `k9s`, and Azure's `kubelogin` for AKS/Entra ID auth
103+
- **Window management & bar**`borders` (JankyBorders), `sketchybar`, `ical-buddy` and `macmon` (both feed SketchyBar)
50104
- **AI**`ollama`
51105

52106
**Casks**
@@ -55,33 +109,16 @@ treat it as the source of truth. By group:
55109
- **Terminal & editors** — Kitty, VS Code, JetBrains Toolbox
56110
- **Dev tooling** — .NET SDK 10, Docker Desktop, Yaak
57111
- **AI** — Claude, Claude Code, Codex, Copilot CLI
58-
- **Notes & productivity** — Obsidian
112+
- **Notes & productivity** — Obsidian, Raycast
59113
- **Browsers & media** — Chrome, IINA, Discord
60114
- **Remote access** — TeamViewer
61115
- **Window management** — AeroSpace
62-
- **System & hardware** — MonitorControl, macs-fan-control, logi-options+, Focusrite Control, Philips Hue Sync, OnyX, thaw
116+
- **System & hardware** — MonitorControl, macs-fan-control, logi-options+, Focusrite Control 2, OnyX, Philips Hue Sync
63117
- **Games** — Steam
64118

65-
Several packages come from third-party taps (Azure's, `isen-ng`, `nikitabobko`).
66-
Homebrew 6+ refuses to load from an untrusted tap, so the install script grants
67-
each declared tap trust as it adds it.
68-
69-
## Stow Packages
70-
71-
| Package | Contents |
72-
|---------|----------|
73-
| `aerospace` | [AeroSpace](https://github.com/nikitabobko/AeroSpace) tiling WM. Numeric workspaces on `ctrl-1``ctrl-9` (**not** `alt` — that is where a Danish layout keeps `[ ] { } \`), focus/move on `alt-hjkl`. Needs Accessibility permission; does **not** start at login |
74-
| `bat` | bat config (Catppuccin Frappé theme) |
75-
| `btop` | btop Catppuccin Frappé theme (the install script seeds `color_theme = "catppuccin_frappe"` for you) |
76-
| `claude` | Claude Code settings and statusline |
77-
| `git` | `.gitconfig` with delta pager, global gitignore. Repos under `~/work/` commit with the work identity — the rule is inert until that directory exists |
78-
| `hushlogin` | Suppresses "Last login" message |
79-
| `kitty` | Kitty terminal (Catppuccin Frappé, Fira Code Nerd Font Mono) |
80-
| `lazygit` | lazygit config (Catppuccin Frappé theme, delta pager) |
81-
| `nvim` | Neovim (lazy.nvim, Treesitter, Telescope, Catppuccin Frappé) |
82-
| `raycast` | [Raycast](https://www.raycast.com) script commands. Raycast's own settings are not file-based, so only this directory is tracked — add it under Settings > Script Commands > Add Script Directory |
83-
| `ssh` | SSH config with macOS Keychain, hardened algorithms. Put machine-local hosts in `~/.ssh/config.local` (included first, untracked) |
84-
| `zsh` | `.zshrc` (Oh My Zsh + Powerlevel10k, fzf, zoxide, direnv, aliases), `.p10k.zsh`, `.zprofile` |
119+
Several packages come from third-party taps (`isen-ng`, Azure's, `nikitabobko`, `FelixKratz`).
120+
Homebrew 6+ refuses to load from an untrusted tap, so the install script grants each declared tap
121+
trust as it adds it.
85122

86123
## Zsh Plugins
87124

@@ -101,6 +138,7 @@ The install script can configure:
101138

102139
- **Finder** — show hidden files, extensions, path/status bar, list view, folders on top, search current folder, unhide `~/Library`, no `.DS_Store` on network/USB
103140
- **Dock** — minimize to app icon, hide recent apps, no space rearranging, icon size, faster animations (auto-hide timings are tuned, but auto-hide itself is left to you)
141+
- **Menu bar** — optionally auto-hide it (offered only if SketchyBar starts at login, so the two bars don't stack)
104142
- **Keyboard** — fast key repeat, below what System Settings can express (`KeyRepeat=1.5`, `InitialKeyRepeat=12`, in 15 ms ticks — the slider bottoms out at 2 and 15). Also disables auto-correct, smart quotes and smart dashes, and enables full keyboard access. Takes effect after logout/login
105143
- **Launcher** — disables the Spotlight (`⌘Space`) and Finder-search (`⌘⌥Space`) shortcuts so Raycast can take the key. `⌥Space` is deliberately *not* used: kitty runs `macos_option_as_alt left`, so it would swallow zsh's `expand-history`
106144
- **Screenshots** — save to `~/Pictures/Screenshots`, PNG format, no shadow
@@ -119,27 +157,54 @@ The install script can configure:
119157
| `AZURE_DEV_COLLECT_TELEMETRY=no` | azd |
120158
| `HOMEBREW_NO_ANALYTICS=1` | Homebrew |
121159

122-
These reach anything launched from a shell that sourced `.zprofile`, which
123-
includes VS Code's integrated terminal but not apps launched from Finder. For a
124-
setting that holds regardless of environment, `brew analytics off` writes
125-
Homebrew's own persistent config.
160+
These reach anything launched from a shell that sourced `.zprofile`, which includes VS Code's
161+
integrated terminal but not apps launched from Finder. For a setting that holds regardless of
162+
environment, `brew analytics off` writes Homebrew's own persistent config.
126163

127164
## Ignore files
128165

129166
Two, with different scopes:
130167

131-
- **`.gitignore`** — this repo only. Mostly allowlists: the `ssh` and `claude`
132-
packages ignore everything and re-include just the tracked configs, so app
133-
runtime state and credentials can't be committed.
134-
- **`git/.config/git/ignore`** — stowed to `~/.config/git/ignore` and applied to
135-
**every** repo on the machine. Git finds it there automatically; no
136-
`core.excludesfile` needed.
168+
- **`.gitignore`** — this repo only. Mostly allowlists: the `ssh` and `claude` packages ignore
169+
everything and re-include just the tracked configs, so app runtime state and credentials can't be
170+
committed.
171+
- **`git/.config/git/ignore`** — stowed to `~/.config/git/ignore` and applied to **every** repo on
172+
the machine. Git finds it there automatically; no `core.excludesfile` needed.
173+
174+
Note that gitignore has no trailing-comment syntax — `pattern # note` silently stops matching. Keep
175+
comments on their own lines.
176+
177+
## Gotchas
178+
179+
Each of these has been rediscovered more than once. Some fail *silently*.
180+
181+
> **A new file in an existing package needs a re-stow.** Because stow runs `--no-folding`,
182+
> directories are real and only tracked leaf files are symlinked. Editing an existing file takes
183+
> effect immediately; adding a *new* one does not until you re-stow that package.
137184
138-
Note that gitignore has no trailing-comment syntax — `pattern # note` silently
139-
stops matching. Keep comments on their own lines.
185+
> **Workspaces are on `ctrl`, not `alt` — leave them there.** On the Danish layout `[ ] { } \` live
186+
> on the Option layer of the digit row, so binding `alt-<digit>` makes them untypable system-wide.
187+
> `cmd` is not an escape (`cmd-alt-8``[`). The same holds for Norwegian/Swedish/Finnish/German.
188+
189+
> **`.zshrc` load order is load-bearing.** Powerlevel10k's instant prompt must come first — nothing
190+
> may print to stdout before it — and in `plugins=()` **`fzf-tab` must precede `zsh-autosuggestions`
191+
> and `zsh-syntax-highlighting`**, or completion and highlighting silently break.
192+
193+
> **SketchyBar fails silently.** An item that hides itself with `drawing=off` must also set
194+
> `updates=on` or it never runs again; new plugin scripts need `chmod +x`; and a plugin has less TCC
195+
> access than your terminal, so a read that works by hand can `EPERM` in the bar.
196+
> [`scripts/lint-sketchybar.sh`](scripts/lint-sketchybar.sh) catches the first kinds.
197+
198+
> **The installer reads the Brewfile from FD 3.** `ask()`'s `read -q` consumes stdin, so the package
199+
> loop uses `... <&3; done 3< Brewfile`. Converting it to a plain `< Brewfile` makes every prompt eat
200+
> the next line, silently skipping packages.
140201
141202
## Re-stow
142203

143204
```zsh
144205
stow -d ~/dotfiles --no-folding -R <package>
145206
```
207+
208+
## License
209+
210+
Released into the public domain under [The Unlicense](LICENSE.md). Take any of it.

0 commit comments

Comments
 (0)