Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 37 additions & 31 deletions .github/workflows/bootstrap.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,41 +5,41 @@ on:
branches: [master]
pull_request:

permissions: {} # default-deny; no job here needs the GITHUB_TOKEN

jobs:
ubuntu:
runs-on: ubuntu-latest
permissions:
contents: read # checkout
steps:
- uses: actions/checkout@v6
# Submodules are left to mise's pre-dotfiles hook so that the hook is
# exercised rather than bypassed.
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
submodules: recursive
persist-credentials: false

- name: Run bootstrap
env:
FORCE_OVERWRITE: "1"
SKIP_TPM: "1"
SKIP_DEFAULTS: "1"
SKIP_NVIM: "1"
SKIP_MISE: "1"
run: bash bootstrap.sh
- name: Install mise
run: |
curl -fsSL https://mise.run | sh
echo "$HOME/.local/bin" >> "$GITHUB_PATH"

- name: Verify dotfiles symlinked
- name: Run bootstrap
run: |
set -e
for f in .zshrc .gitconfig .tmux.conf .fzf.zsh .npmrc; do
test -L "$HOME/$f" || { echo "missing symlink: ~/$f"; exit 1; }
done
test -L "$HOME/.gem/credentials"
test -L "$HOME/.gitignore"
test -L "$HOME/.config/nvim"
test -L "$HOME/.config/mise/config.toml"
test -L "$HOME/.config/lsd/colors.yaml"
test -L "$HOME/.config/lsd/config.yaml"
test -L "$HOME/.config/gitleaks/config.toml"
test -L "$HOME/.tmux/loadavg.sh"
test -L "$HOME/.tmux/theme-sync.sh"
test -L "$HOME/.tmux/tmuxline.dark.conf"
test -L "$HOME/.tmux/tmuxline.light.conf"
test -L "$HOME/.tmux/extrakto"
mise trust
# tools: the runtimes in [tools] take far longer than this job is
# worth; task: bootstrap:nvim compiles every treesitter parser.
mise bootstrap -y --force-dotfiles --skip tools,task
# The one task that is cheap and Linux-specific — it creates the
# fd/bat shims the next step asserts on.
mise run bootstrap:linux-shims
# ~/.config/mise/config.toml is a symlink into the repo as of the
# dotfiles step above, so it needs trusting before it can be read.
mise trust ~/.config/mise/config.toml

- name: Verify dotfiles converged
run: mise bootstrap dotfiles status --missing

- name: Verify CLI tools installed
run: |
Expand All @@ -50,20 +50,26 @@ jobs:
test -x "$HOME/.local/bin/fd"
test -x "$HOME/.local/bin/bat"

- name: Verify dry-run is a no-op
- name: Verify re-running is a no-op
run: |
set -e
before=$(find "$HOME" -maxdepth 3 -type l 2>/dev/null | sort | sha256sum)
bash bootstrap.sh --dry-run > /dev/null
mise bootstrap -n --skip tools,task > /dev/null
after=$(find "$HOME" -maxdepth 3 -type l 2>/dev/null | sort | sha256sum)
[[ "$before" == "$after" ]] || { echo "dry-run modified state"; exit 1; }
[ "$before" = "$after" ] || { echo "dry-run modified state"; exit 1; }

shellcheck:
runs-on: ubuntu-latest
permissions:
contents: read # checkout
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
# .claude/scripts/statusline.sh is not covered yet — it has pre-existing
# warnings that want fixing on their own.
- name: Run shellcheck
run: |
sudo apt-get update -qq
sudo apt-get install -y -qq shellcheck
shellcheck bootstrap.sh defaults.sh
shellcheck .tmux/*.sh
7 changes: 3 additions & 4 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
.bundle
.zshrc.local
.vimrc.local
.vim/.undo
.vim/pack/minpac
.vim/.netrwhist
.tmux/plugins
# mise.toml is ignored by the global gitignore (per-project configs stay
# local); this repo's copy is the machine setup itself, so track it
!/mise.toml
# ~/.claude is ignored by the global gitignore; re-include only what we track
!/.claude/
/.claude/*
Expand Down
3 changes: 0 additions & 3 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
[submodule ".vim/pack/minpac/opt/minpac"]
path = .vim/pack/minpac/opt/minpac
url = https://github.com/k-takata/minpac
[submodule ".tmux/extrakto"]
path = .tmux/extrakto
url = https://github.com/laktak/extrakto
Expand Down
2 changes: 1 addition & 1 deletion .tmux.conf
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ bind-key -T copy-mode-vi C-f send-keys -X page-down
# Make session chooser start from 1 instead of 0. See: https://unix.stackexchange.com/a/755474.
bind-key s choose-tree -ZsK '#{?#{e|<:#{line},9},#{e|+:1,#{line}},#{?#{e|<:#{line},35},M-#{a:#{e|+:97,#{e|-:#{line},9}}},}}'

# Switch windows via Ctrl+number. For iTerm2: https://unix.stackexchange.com/a/314150
# Switch windows via Ctrl+number (needs a terminal that sends CSI-u keys)
bind -n C-1 select-window -t 1
bind -n C-2 select-window -t 2
bind -n C-3 select-window -t 3
Expand Down
25 changes: 22 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,25 @@ Personal dotfiles optimized for macOS and zsh. Features modern shell tools, comp
## Installation

```sh
bash -c "$(curl -sL https://raw.github.com/ericboehs/dotfiles/master/bootstrap.sh)"
curl -fsSL https://mise.run | sh
git clone https://github.com/ericboehs/dotfiles ~/Code/github.com/ericboehs/dotfiles
cd ~/Code/github.com/ericboehs/dotfiles && mise trust && mise bootstrap
```

Setup is declared in [mise.toml](mise.toml) rather than scripted, so it
converges — re-running only changes what has drifted. Requires mise 2026.8.4
or newer for the per-package `os` filters; older versions say so and stop.
Useful variations:

```sh
mise bootstrap -n # preview every change, touch nothing
mise bootstrap --only dotfiles # just the $HOME symlinks
mise bootstrap --skip macos-defaults # leave system preferences alone
mise bootstrap dotfiles status # what's linked, and what has drifted
```

Add `--force-dotfiles` if $HOME already has real files where symlinks belong.

Configure git with your personal information:
```sh
cp ~/.gitconfig.private.example ~/.gitconfig.private
Expand Down Expand Up @@ -45,10 +61,13 @@ $EDITOR ~/.gitconfig.private
- Custom status line with zoom indicator
- Auto-renumber windows

### Version Management
### Version Management and Setup

- **Tool**: [mise](https://mise.jdx.dev/) (replaces asdf)
- Manages Node.js, Ruby, Python, and other language runtimes
- Also drives machine setup — packages, `$HOME` symlinks, macOS defaults and
git checkouts are all declared in [mise.toml](mise.toml) and applied with
`mise bootstrap`

### Fuzzy Finder

Expand Down Expand Up @@ -108,7 +127,7 @@ Collection of utility scripts in `bin/` including:
├── .gitconfig # Git configuration
├── .tmux.conf # Tmux configuration
├── .zshrc # Zsh initialization
└── bootstrap.sh # Installation script
└── mise.toml # Declarative machine setup (`mise bootstrap`)
```

## License
Expand Down
4 changes: 2 additions & 2 deletions bin/claude-man
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ monitor_pane() {
if [[ "$NOTIFY_ALWAYS" == true ]]; then
terminal-notifier -title "Claude Session Idle" -message "Session $pane ($pane_title) is now idle"
else
terminal-notifier -title "Claude Session Idle" -message "Session $pane ($pane_title) is now idle" -sender com.googlecode.iterm2
terminal-notifier -title "Claude Session Idle" -message "Session $pane ($pane_title) is now idle" -sender com.mitchellh.ghostty
fi
else
echo "Warning: terminal-notifier not found, skipping notification"
Expand Down Expand Up @@ -339,7 +339,7 @@ monitor_pane() {
if [[ "$NOTIFY_ALWAYS" == true ]]; then
terminal-notifier -title "Claude Low Context" -message "Only $context_percent% context remaining in $pane"
else
terminal-notifier -title "Claude Low Context" -message "Only $context_percent% context remaining in $pane" -sender com.googlecode.iterm2
terminal-notifier -title "Claude Low Context" -message "Only $context_percent% context remaining in $pane" -sender com.mitchellh.ghostty
fi
fi
fi
Expand Down
2 changes: 1 addition & 1 deletion bin/code-editor
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#! /usr/bin/env bash

open -a iTerm
open -a Ghostty
tmux switch-client -t 👨🏼‍💻
2 changes: 1 addition & 1 deletion bin/monitor_tmux_pane
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ send_notification() {
local duration="$2"

if [[ "$USE_TERMINAL_NOTIFIER" == true ]]; then
terminal-notifier -title "Claude Monitor" -message "Claude pane $pane idle for $duration seconds" -sender com.googlecode.iterm2
terminal-notifier -title "Claude Monitor" -message "Claude pane $pane idle for $duration seconds" -sender com.mitchellh.ghostty
else
# Default OS9 notification via tmux
printf '\ePtmux;\e\e]9;Claude pane %s idle for %d seconds\a\e\\' "$pane" "$duration"
Expand Down
Loading