A batteries-included dotfiles repository that turns a fresh macOS machine into a
fast, robust local development environment in a couple of commands. One run
installs the tools, the next deploys the configuration β no manual copy/paste,
no remembering which brew install flags you used last time.
- Fast onboarding β go from a blank Mac to a working terminal, shell, editor, Kubernetes tooling, and AI assistant in under 10 minutes.
- Reproducible β
Brewfileis the single source of truth for tools, and GNU Stow handles configuration as transparent symlinks. No templating, no hidden state. - Idempotent and re-runnable β every script is safe to run twice. Existing configs are backed up to a timestamped directory before anything is replaced.
- Selective β interactive menus let you pick which tools and configs to
install. Use
--allfor unattended/CI installs. - Personalization without forking β secrets like your git identity live in
~/.gitconfig.local(untracked); shared preferences live in the repo. The same pattern applies to Claude Code settings via.sampletemplates that are merged into your local config.
This repository contains personal dotfiles for macOS, managed with GNU Stow. It includes configurations for:
- Zsh β shell with aliases, completions, and prompt customization
- Git β version control settings and global ignores
- Vim β minimal text editor configuration
- Ghostty β terminal emulator settings
- k9s β Kubernetes cluster management UI
- Claude Code β AI coding assistant: behavioral rules, permissions, hooks, statusline, sub-agents, and slash commands (see Claude Code Configuration)
- mise β dev tools and environment manager
# Clone the repository
git clone git@github.com:IvanKuzyshyn/dotfiles.git ~/dotfiles
cd ~/dotfiles
# Install tools
./install.sh
# Deploy configurations
./bootstrap.sh
# Restart your shell
exec zshBoth scripts present an interactive selection menu β toggle items on/off before proceeding. Pass --all to skip the menu and select everything (useful for CI or scripted setups).
The install.sh script installs all required tools:
./install.sh # interactive menu
./install.sh --all # non-interactive, install everythingHomebrew packages and casks (managed via Brewfile):
- GNU Stow (config management)
- k9s, kubectl (Kubernetes)
- awscli, gh (Cloud & GitHub)
- jq, yq (JSON/YAML processors)
- ncdu (Disk usage analyzer)
- git, go (Development)
- mise (Dev tools & env manager)
- gitleaks (Secret scanning for pre-commit + CI)
- Ghostty (Terminal emulator)
- Raycast (Productivity launcher)
- Cursor (AI code editor)
- Docker (Docker Desktop)
Other tools (dedicated installers):
- Rust (via rustup)
- oh-my-zsh with plugins (zsh-autosuggestions, zsh-syntax-highlighting)
- nvm + Node.js LTS
- Claude Code (via npm)
The bootstrap.sh script creates symlinks using GNU Stow:
./bootstrap.sh # interactive menu
./bootstrap.sh --all # non-interactive, deploy everythingWhat happens:
- Auto-detects configs from
configs/*/directories - Prompts for your git name and email (creates
~/.gitconfig.local) - Backs up existing configs to
~/.dotfiles_backup_<timestamp> - Creates symlinks from this repo to your home directory
- Shows verbose output of what's being linked
Check that symlinks are created:
ls -la ~ | grep "^l"You should see symlinks for .zshrc, .gitconfig, .vimrc, etc.
This repository ships with gitleaks wired into two layers to prevent accidental commits of tokens, API keys, or other sensitive data:
- Pre-commit hook (
.githooks/pre-commit) β scans staged changes withgitleaks protect --staged --redact. Enabled for this repo by./install.sh(item:git-hooks), which runsgit config core.hooksPath .githookslocally β no global config is touched. - GitHub Actions (
.github/workflows/gitleaks.yml) β scans every push tomainand every PR via the officialgitleaks/gitleaks-action. Acts as a CI safety net for cases where the local hook is bypassed (e.g.git commit --no-verify).
If gitleaks reports a false positive, add an allowlist entry to a .gitleaks.toml
at the repo root. The default ruleset is used otherwise.
dotfiles/
βββ .gitignore # Excludes IDE and OS files
βββ .stowrc # Stow configuration
βββ .githooks/
β βββ pre-commit # gitleaks scan on staged changes
βββ .github/
β βββ workflows/
β βββ gitleaks.yml # CI secret scan on push/PR
βββ Brewfile # Homebrew packages and casks (single source of truth)
βββ install.sh # Tool installation script
βββ bootstrap.sh # Config deployment script
βββ README.md # This file
βββ AGENTS.md # AI agent guidance
βββ lib/
β βββ menu.sh # Shared interactive selection menu library
βββ configs/ # Tool configurations (stow packages)
βββ zsh/
β βββ .zshrc # Shell configuration
βββ git/
β βββ .gitconfig # Git settings
β βββ .gitignore_global # Global Git ignores
βββ vim/
β βββ .vimrc # Vim configuration
βββ ghostty/
β βββ .config/ghostty/config
βββ k9s/
β βββ .config/k9s/config.yaml
βββ claude/
β βββ .claude/
β βββ settings.sample.json # Permissions, hooks, env, statusline
β βββ CLAUDE.sample.md # Global behavioral rules
β βββ agents/ # Specialized sub-agents
β β βββ code-reviewer.md
β β βββ debugger.md
β βββ commands/ # Slash commands
β β βββ session-summary.md
β βββ hooks/ # Lifecycle hooks
β β βββ log-event.sh
β β βββ validate-bash.sh
β βββ scripts/
β βββ statusline.sh # Custom statusline renderer
βββ mise/
βββ .config/mise/config.toml
- Aliases: Kubernetes (
k,kgp), Git (gs,gco), and directory shortcuts - Completions: kubectl, AWS CLI, GitHub CLI
- Prompt: Git branch integration with color coding
- Tool Integration: nvm, Rust (cargo)
- User: Personalized during bootstrap (stored in
~/.gitconfig.local) - Aliases: Common shortcuts (
st,co,lg) - Global Ignores: OS files, IDE configs, language artifacts
The git configuration uses an include pattern to separate personal identity
from shared preferences. Your name and email are stored in ~/.gitconfig.local,
which is not tracked in the repository.
- kubectl aliases: Speed up cluster management
- k9s config: UI preferences and performance settings
- Global config: Auto-installs missing tools, uses precompiled binaries
- Per-project: Drop a
mise.tomlin any project for tool version management
Claude Code is Anthropic's CLI for AI-assisted development. This repo ships a complete, opinionated setup that covers behavior, safety, observability, and workflow ergonomics.
./install.sh installs the Claude Code CLI as a global npm package
(@anthropic-ai/claude-code). After install, configuration lives under
~/.claude/, which ./bootstrap.sh populates from configs/claude/.claude/.
The Claude config uses a .sample template pattern so that the repository can
ship sensible defaults without overwriting your personal customizations:
| Repo file | Deployed as | Behavior on re-run |
|---|---|---|
.claude/settings.sample.json |
~/.claude/settings.json |
Deep-merged with your existing file β your settings win on conflict, arrays are deduplicated |
.claude/CLAUDE.sample.md |
~/.claude/CLAUDE.md |
Created from template if missing; otherwise left alone |
.claude/agents/*.md |
~/.claude/agents/*.md |
Plain symlinks via Stow (live updates from the repo) |
.claude/commands/*.md |
~/.claude/commands/*.md |
Plain symlinks via Stow |
.claude/hooks/*.sh |
~/.claude/hooks/*.sh |
Plain symlinks via Stow |
.claude/scripts/*.sh |
~/.claude/scripts/*.sh |
Plain symlinks via Stow |
The merge logic for settings.json is implemented in bootstrap.sh using jq
β see the *.sample.* handling block. Your local edits to settings.json
survive future bootstrap runs.
"env": {
"BASH_DEFAULT_TIMEOUT_MS": "120000",
"CLAUDE_CODE_DISABLE_FEEDBACK_SURVEY": "1",
"CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC": "1",
"CLAUDE_CODE_FILE_READ_MAX_OUTPUT_TOKENS": "64000",
"CLAUDE_CODE_MAX_OUTPUT_TOKENS": "64000",
"DISABLE_TELEMETRY": "1"
}- Generous output token budgets for long file reads.
- Telemetry and non-essential network traffic disabled.
- 2-minute default Bash timeout (overridable per call).
alwaysThinkingEnabled: trueβ extended thinking is on for every turn.includeCoAuthoredBy: falseβ Claude does not addCo-Authored-Bytrailers to commits.cleanupPeriodDays: 99999β effectively disables transcript auto-cleanup so past sessions remain available locally.
Permissions follow the principle of least privilege:
allowβ fast, read-only/safe operations run without prompting:git,gh <view|list>,kubectl get|describe|logs, language toolchains (npm,yarn,pnpm,cargo,go), search/inspection tools (rg,fd,jq,bat), andWebSearch.denyβ never allowed, even with confirmation. Covers secrets and shell rc files:.env*,.envrc,.zshrc,.bashrc,.profile,.zsh_history,/etc/zprofile,/etc/zshrc,node_modules, etc. Both Read and Write are blocked.askβ Claude must request confirmation before running. Covers destructive or remote-affecting commands:rm,mv,cp,sudo,curl,wget,ssh,git push|rebase|reset|checkout|clean|branch -D,gh repo delete,gh secret set|delete,kubectl apply|delete, anddocker.
Edit ~/.claude/settings.json directly to tighten or loosen these β your
changes are preserved on the next ./bootstrap.sh.
Hooks are shell commands the harness runs at specific lifecycle points. Two hook scripts ship with this repo:
hooks/log-event.sh β universal event logger. Wired up to every supported
event:
| Event | Purpose |
|---|---|
SessionStart |
Logged at the start of every session |
SessionEnd |
Logged when the session ends |
UserPromptSubmit |
Captures each user message |
PreToolUse |
Fires before any tool call (also: Bash validator below) |
PostToolUse |
Fires after any tool call |
Stop |
Fires when the assistant turn ends |
PreCompact |
Before context auto-compaction |
PostCompact |
After context auto-compaction |
Notification |
When the harness needs your attention (e.g. permission ask) |
Events are appended as JSONL to $CLAUDE_PROJECT_DIR/.claude/hook-events.jsonl
when invoked inside a project, otherwise ~/.claude/hook-events.jsonl. Use
this for usage analytics, cost tracking, or post-hoc debugging:
jq -r 'select(.event == "PreToolUse") | .input.tool_name' \
~/.claude/hook-events.jsonl | sort | uniq -c | sort -rnhooks/validate-bash.sh β a PreToolUse matcher for Bash calls. Blocks
commands that touch sensitive directories (node_modules/, .env, .git/,
dist/, build/, .next/, .vscode/, .idea/). Exits with status 2 to
prevent execution.
"statusLine": {
"type": "command",
"command": "~/.claude/scripts/statusline.sh"
}scripts/statusline.sh renders a compact one-liner with:
- current directory and git branch
- active model
- session lines added/removed (colored)
- session duration (auto-scaled to ms/s/m/h)
- accumulated cost (only when > $0)
- a 15-cell context-window progress bar with percentage
Example:
/dotfiles (extend-claude-config) | claude-opus-4-7 +42 -7 in 3m for $0.18 | βββββββββββββββ 53%
CLAUDE.md is loaded into every Claude Code session as user-level system
instructions. The template (CLAUDE.sample.md) encodes preferences for:
- Behavior β direct, concise, no sycophancy, push back with technical reasons rather than agreeing reflexively.
- Writing code β smallest reasonable changes, match surrounding style, do not touch unrelated code or whitespace, never remove non-false comments.
- Systematic debugging β investigate root cause, never patch symptoms, one hypothesis at a time.
- Version control β concise imperative commit messages, frequent commits, WIP branches when ambiguous.
- GitHub β use
ghhigh-level commands, never rawgh apicalls. - Comments β explain why, not what.
Edit ~/.claude/CLAUDE.md to customize per-machine; project-specific
overrides go in CLAUDE.md/AGENTS.md at the project root.
Sub-agents are specialized personas with their own tool allowlist that Claude can dispatch for focused tasks.
agents/code-reviewer.md β Senior code reviewer. Tools: Read, Grep,
Glob, Bash. Runs git diff, scans modified files, and returns feedback
organized by priority (critical / warning / suggestion) with concrete fixes.
agents/debugger.md β Root-cause debugger. Tools: Read, Edit, Bash,
Grep, Glob. Captures the failure, isolates the location, forms hypotheses,
and applies a minimal fix with a verification step.
Add new agents by dropping a Markdown file into configs/claude/.claude/agents/
with frontmatter (name, description, tools) followed by the system
prompt body.
/session-summary β generates session_{slug}_{timestamp}.md containing
key actions, total cost, efficiency insights, possible process improvements,
turn count, and observations. Useful for keeping a personal log of long
sessions.
Add new commands by dropping a Markdown file into
configs/claude/.claude/commands/. The filename (minus .md) becomes the
slash command name.
# Edit settings (merged on next bootstrap; your edits win)
vim ~/.claude/settings.json
# Add a project-specific override (loaded for that project only)
echo "Use Python 3.12 conventions." > /path/to/project/CLAUDE.md
# Add a new sub-agent (tracked in this repo)
vim configs/claude/.claude/agents/security-auditor.md
# Add a new slash command (tracked in this repo)
vim configs/claude/.claude/commands/release-notes.md
# Re-deploy
./bootstrap.sh# Tail events live
tail -f ~/.claude/hook-events.jsonl | jq .
# Count tool calls in the current project
jq -r 'select(.event == "PostToolUse") | .input.tool_name' \
.claude/hook-events.jsonl | sort | uniq -cAdd one line to Brewfile:
brew "newtool" # CLI package
cask "newapp" # GUI applicationThen run ./install.sh and select "homebrew-tools".
-
Create a new directory in
configs/:mkdir -p configs/newtool
-
Add config files (will be symlinked to
$HOME):configs/newtool/.newtoolrc
-
Deploy (the config is auto-detected β no script changes required):
./bootstrap.sh
The bootstrap script detects conflicts automatically and offers to back up or remove existing files. If you need to resolve manually:
# Remove existing configs (they're backed up)
rm ~/.zshrc ~/.gitconfig ~/.vimrc
# Try again
./bootstrap.sh# Install individually
brew install <tool-name>
# Or re-run the full install
./install.shCheck for broken links:
find ~ -maxdepth 1 -type l ! -exec test -e {} \; -printRemove and restow if needed:
cd ~/dotfiles
stow -D zsh # Unstow
stow zsh # RestowThis is a personal dotfiles repository, but you're welcome to:
- Fork and customize - Use this as a starting point for your own setup
- Share ideas - Open an issue to suggest improvements or share configurations
- Report issues - Let me know if something doesn't work as expected
# Fork the repository
# Clone your fork
git clone git@github.com:yourusername/dotfiles.git ~/dotfiles
cd ~/dotfiles
# Customize configurations to your preferences
vim configs/git/.gitconfig
vim configs/zsh/.zshrc
# Deploy your customized configs
./bootstrap.shPublic domain via Unlicense. Use freely.