Dotfiles, mac setup, apps & backups configs.
Warning: If you want to give these dotfiles a try, you should first fork this repository, review the code, and remove things you don’t want or need. This config uses zsh, oh-my-zsh and tmux, if you don't want to use any of those, check Brew install file.
- Just command runner
- Brew (mac setup)
Read all scripts before executing them.
- Configure iCloud, SSH, etc.
git clone https://github.com/gabrielkoerich/dotfiles.gitjust setupto setup macosjust install brewto install brew & dependenciesjust install fontsto install fontsjust install caskto install cask appsjust install agentsto install coding agents & base skillsjust syncto sync the dotfiles to~- Run
just restoreto restore app settings
To sync the dotfiles, run step 8 again.
Note: sync intentionally excludes ~/.ssh so keys and SSH host/user config stay local. Public SSH hardening template is versioned at home/.config/ssh/sshd-hardening.public.conf.
Main config coverage:
- Shell:
home/.zshrchome/.zprofilehome/.aliaseshome/.functionshome/.exportshome/.path
- Tmux:
home/.tmux.confhome/.tmux/*helpers (renew.sh,yank.sh, remote profile)home/.tmux/tmxsession helper
- Neovim:
home/.config/nvim
- Terminal:
home/.config/ghostty
- Mackup:
home/.mackup.cfghome/.mackup/*.cfg
- Agent tooling:
home/.codexhome/.claudehome/.config/opencode
- SSH templates:
home/.config/ssh/sshd-hardening.public.confhome/.config/ssh/sshd-hardening.tailscale.confhome/.config/ssh/sshd-hardening.cloudflare.conf
If you want to skip parts of this setup, selectively run install targets and remove unneeded config files before just sync.
backup # Run mackup backup & uninstall
doctor # Validate tooling + pinned refs + security files
exact-apply # Apply closest deterministic machine baseline
exact-check # Check drift against repo baseline
install target # Install <target>, options: [brew, fonts, cask, agents, security, cron]
install-profile # Install package set from profiles/*.txt
install-report # Generate machine/tool report in .build/reports/
pre-commit-install # Install local pre-commit hooks
pre-commit-run # Run pre-commit checks on all files
restore # Restore mackup backup
security-all # Audit dotfiles scripts including vendored private/
security-ci # Run strict audit with semgrep required (CI-equivalent)
security-strict # Run strict repo-wide security audit
setup # Run macos setup
sync # Sync dotfiles to home directory
test target args="" # Test mackup, options [backup, restore]
test-install # Run bats tests for install/security scripts
# Encrypted file workflows (age)
crypto-keygen
encrypt-file <in> <out.age>
decrypt-file <in.age> <out>
encrypt-dir <src-dir> <out.tar.age>
decrypt-dir <in.tar.age> <out-dir>Encryption commands use AGE_RECIPIENT when set; otherwise they derive the recipient from AGE_KEY_FILE (default: ~/.config/age/dotfiles.agekey).
bin/security-audit: repo-wide shell/security audit (--strictfor CI mode).github/workflows/quality.yml: quality + security checks (shell syntax, strict audit, semgrep, tests, gitleaks).pre-commit-config.yaml: local hooks for hygiene + secrets + strict audit.gitleaks.toml: secrets scanning configuration
Recommended bootstrap:
brew bundle --file Brewfilejust pre-commit-installjust security-cijust doctor
Goal: reproduce the closest deterministic match from this repository.
just exact-apply: applies Brewfile (with cleanup), fonts, agents, dotfiles sync, and final checks.just exact-check: verifies drift against Brewfile + doctor + strict security audit.
Important limits:
- macOS version/hardware-specific defaults may differ.
- App-internal state and cloud-synced settings may differ.
- External services and credentials are not reproduced automatically.
bin/install/agents installs external repositories at pinned commit SHAs:
gabrielkoerich/orchestratorgabrielkoerich/skillsanthropics/skills
To update a pin safely:
- Review upstream changes.
- Update the ref constant in
bin/install/agents. - Run
just security-strict. - Re-run
just install agentson a clean machine/test profile.
You can safely keep encrypted artifacts in a public repository if:
- plaintext never gets committed
- private key is stored outside git
- encryption keys/recipients are rotated when needed
This repo uses age helpers in bin/crypto/ and ignores common plaintext/decrypted artifacts in .gitignore.
Suggested layout:
secrets/encrypted/*.agecommittedsecrets/plain/*local-only (ignored)- key in
~/.config/age/dotfiles.agekey(ignored)
- Defined prefix:
ctrl + A - Split horizontal:
prefix + | - Split vertical:
prefix + _
The tmux config now supports durable sessions:
- Manual save:
prefix + S - Manual restore:
prefix + T - Auto-save: every 15 minutes (
tmux-continuum) - Auto-restore on tmux start (
tmux-continuum+tmux-resurrect)
Helper command:
~/.tmux/tmx-> ensures/attaches to a long-livedmainsession~/.tmux/tmx ensure-> createsmainsession if missing, without attaching
Optional env overrides:
TMX_SESSION_NAME(default:main)TMX_SESSION_ROOT(default:$HOME)
Install and sign in:
brew install --cask tailscaletailscale up --ssh
Apply the Tailscale-only SSH hardening template:
just tailscale-ssh-harden(useswhoamifor__SSH_USER__)- Optional manual path:
export SSH_USER="<your-user>"sed "s/__SSH_USER__/${SSH_USER}/g" home/.config/ssh/sshd-hardening.tailscale.conf | sudo tee /etc/ssh/sshd_config.d/99-tailscale-hardening.conf >/dev/nullsudo sshd -tsudo launchctl kickstart -k system/com.openssh.sshd
Verify from a non-Tailscale network that SSH is denied, then verify access via Tailscale still works.
Cloudflare Tunnel proxies SSH through Cloudflare's network — no ports exposed to the internet. The cloudflared CLI is free for this use case.
cloudflaredinstalled (brew install cloudflared)- Cloudflare account with a domain (DNS managed by Cloudflare)
- Authenticate cloudflared:
cloudflared tunnel login - Create a tunnel:
cloudflared tunnel create my-ssh - Configure the tunnel (
~/.cloudflared/config.yml):tunnel: my-ssh credentials-file: /Users/<you>/.cloudflared/<tunnel-id>.json ingress: - hostname: ssh.example.com service: ssh://localhost:22 - service: http_status:404
- Route DNS:
cloudflared tunnel route dns my-ssh ssh.example.com - Apply SSH hardening:
just cloudflare-ssh-harden - Run the tunnel:
cloudflared tunnel run my-ssh
- Install cloudflared on the client machine.
- Add to
~/.ssh/config:Host ssh.example.com ProxyCommand cloudflared access ssh --hostname %h User <your-user> - Connect:
ssh ssh.example.com
Common steps (all profiles):
- Enable SSH on Mac:
sudo systemsetup -setremotelogin on - Create/import a dedicated SSH key in Termius.
- Add Termius public key to Mac:
mkdir -p ~/.ssh && chmod 700 ~/.sshappend key to~/.ssh/authorized_keyschmod 600 ~/.ssh/authorized_keys
- Apply hardening:
just tailscale-ssh-harden - In Termius, connect using:
- Host: Mac Tailscale IP (100.x.x.x)
- User: your macOS user
- Auth: the key from step 2
- Attach persistent session:
tmx
Requires the Cloudflare WARP app on your iPhone/iPad.
- Apply hardening:
just cloudflare-ssh-harden - In Cloudflare Zero Trust dashboard:
- Go to Settings > WARP Client > Device enrollment permissions
- Add an enrollment rule (e.g. email matching your account)
- On iPhone, open the 1.1.1.1/WARP app:
- Go to Settings > Account > Login to Cloudflare Zero Trust
- Enter your Zero Trust org name and authenticate
- In Termius, connect using:
- Host:
ssh.example.com(your tunnel hostname) - User: your macOS user
- Auth: the key from step 2
- Host:
- Attach persistent session:
tmx
Notes:
- With Cloudflare Tunnel, no ports are exposed — WARP routes traffic through Cloudflare's network to your tunnel.
- With Tailscale, traffic stays on the mesh VPN.
- Both profiles enforce key-only auth. Do not enable password auth.
Copyright (c) Gabriel Koerich
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.