My dotfiles

August 17, 2026 · View on GitHub

Terminal

Personal dotfiles with modern shell tooling, optimized for Laravel/PHP development. Features fast startup times, smart directory navigation, and modern CLI tools.

Contents

Getting started

Reference

AI setup

Everything else


Key Features

  • Custom Agnoster Theme - Clean powerline prompt with no branch symbols, for changes
  • Version-Controlled AI Setup - Skills, agents, settings, and instructions for both Claude Code and Codex, from one source
  • Framework-Aware Code Intelligence - Laravel LSP, Intelephense, and TypeScript language servers wired into the agent
  • Fast Tools - fnm, zoxide, ripgrep, bat, eza (all Rust-based for speed)
  • One Command Install - bin/install sets up everything including Claude Code

Quick Start

git clone git@github.com:freekmurze/dotfiles.git ~/.dotfiles
cd ~/.dotfiles
bin/install

What's Included

Shell & Prompt

  • Oh My Zsh - Framework for managing Zsh configuration (with agnoster theme by default)
  • zoxide - Smart directory jumping based on frecency
  • fzf - Fuzzy finder for files and history
  • direnv - Automatic environment variables per directory

Modern CLI Tools

  • fnm - Fast Node.js version manager
  • bat - Cat with syntax highlighting
  • eza - Modern ls replacement with icons
  • ripgrep - Fast grep alternative
  • fd - Fast find alternative
  • git-delta - Better git diffs
  • jq - JSON processor and formatter
  • yq - YAML processor and formatter
  • bottom - Modern system monitor

Development Tools

  • PHP - Latest version via Homebrew
  • Composer - Dependency manager via Homebrew
  • Node.js - LTS version managed via fnm
  • Laravel Valet - Local development server
  • MySQL - Database with auto-start

QuickLook Plugins

Instant file previews in Finder: code files, markdown, JSON, CSV, patches, and archives.


How It Works

Symlinked Files

The installation creates symlinks from your home directory to the dotfiles repository. This allows you to version control your configuration while keeping files in their expected locations.

Symlink LocationPoints ToPurpose
~/.zshrc~/.dotfiles/home/.zshrcMain Zsh configuration (Oh My Zsh with custom agnoster theme)
~/.gitconfig~/.dotfiles/home/.gitconfigGit configuration with delta diff viewer
~/.global-gitignore~/.dotfiles/home/.global-gitignoreGlobal Git ignore patterns
~/.vimrc~/.dotfiles/home/.vimrcVim configuration
~/.vim/~/.dotfiles/home/.vim/Vim runtime files
~/.mackup.cfg~/.dotfiles/macos/.mackup.cfgMackup backup configuration
~/.claude/skills~/.dotfiles/config/claude/skills/All Claude Code skills (version-controlled)
~/.claude/agents~/.dotfiles/config/claude/agents/All Claude Code agents (version-controlled)
~/.claude/CLAUDE.md~/.dotfiles/config/claude/AGENTS.mdAgent instructions (Claude reads CLAUDE.md, not AGENTS.md)
~/.claude/settings.json~/.dotfiles/config/claude/settings.jsonClaude Code settings
~/.codex/AGENTS.md~/.dotfiles/config/claude/AGENTS.mdThe same instructions, read natively by Codex
~/.codex/skills/*~/.dotfiles/config/claude/skills/*One symlink per shared skill, see bin/link-agent-skills
~/.config/zed/settings.json~/.dotfiles/config/zed/settings.jsonZed editor settings
~/.config/zed/keymap.json~/.dotfiles/config/zed/keymap.jsonZed custom keybindings
~/.config/ghostty/config~/.dotfiles/config/ghostty/configGhostty terminal settings

To manually symlink the Zed configuration (if not using bin/install):

mkdir -p ~/.config/zed
ln -sf ~/.dotfiles/config/zed/settings.json ~/.config/zed/settings.json
ln -sf ~/.dotfiles/config/zed/keymap.json ~/.config/zed/keymap.json

Sourced Files

These files are loaded by .zshrc but remain in the dotfiles directory:

  • home/.aliases - Shell command aliases
  • home/.functions - Custom shell functions
  • home/.exports - Environment variables

Custom Agnoster Theme

The default configuration uses a customized agnoster theme stored in oh-my-zsh-custom/themes/agnoster.zsh-theme:

Customizations:

  • No git branch symbol (cleaner look)
  • Uses for unstaged changes instead of ±
  • Powerline arrows for segment separators
  • Requires a font with powerline glyphs

Git Status Symbols:

  • - Staged changes (files added with git add)
  • - Unstaged changes (modified files not yet staged)
  • Yellow background - Uncommitted changes
  • Green background - Clean working directory

Daily Usage

Smart Navigation

z dotfiles          # Jump to frequently used directories
zi                  # Interactive directory picker
Ctrl+R              # Fuzzy search command history
Ctrl+T              # Fuzzy find files
Alt+C               # Fuzzy change directory

Laravel/PHP Shortcuts

a                   # php artisan
p                   # Run Pest/PHPUnit tests
c                   # composer
mfs                 # php artisan migrate:fresh --seed
nah                 # git reset --hard; git clean -df

Data Processing

# JSON processing with jq
curl api.github.com/users/freekmurze | jq
cat composer.json | jq '.require'
php artisan tinker --execute="echo json_encode(User::first());" | jq

# YAML processing with yq
yq '.jobs' .github/workflows/ci.yml
yq -o json docker-compose.yml

# System monitoring
btm                 # Modern system monitor (aliased from top/htop)

Maintenance Commands

bin/update          # Update all packages and tools

Version Management

Node.js (via fnm)

fnm install --lts     # Install latest LTS
fnm use lts-latest    # Use latest LTS
fnm install 20        # Install specific version
fnm use 20            # Switch to specific version
fnm list              # Show installed versions

PHP & Composer (via Homebrew)

brew upgrade php      # Update PHP to latest
brew upgrade composer # Update Composer

Package Management

All Homebrew packages are declared in config/Brewfile. To add a new tool:

echo 'brew "neovim"' >> ~/.dotfiles/config/Brewfile
brew bundle --file=~/.dotfiles/config/Brewfile

Complete package list:

  • Core: node, php, composer, pkg-config, wget, httpie, ncdu, hub, ack, doctl, 1password-cli, git-secret, imagemagick, mysql, yarn, ghostscript, mackup
  • Modern CLI: zoxide, bat, eza, ripgrep, fd, git-delta, fnm, fzf, direnv, jq, yq, bottom, zsh-autosuggestions
  • QuickLook: qlcolorcode, qlstephen, qlmarkdown, quicklook-json, qlprettypatch, quicklook-csv, betterzip, suspicious-package
  • PHP Extensions: imagick, memcached, xdebug, redis
  • Global npm: agent-browser, intelephense, typescript-language-server, typescript
  • Global Composer: laravel/envoy, spatie/phpunit-watcher, laravel/valet, laravel/lsp

AI Development Setup

Everything the agents need lives in config/claude/, and both Claude Code and Codex read it from there. Nothing is duplicated per tool.

config/claude/
├── AGENTS.md          the instructions, read by both harnesses
├── settings.json      Claude Code settings, permissions, hooks
├── agents/            custom subagents
└── skills/            19 skills, plus 3 scoped plugins

Quick Install (Standalone)

Install just the AI setup without the full dotfiles:

curl -fsSL https://raw.githubusercontent.com/freekmurze/dotfiles/main/bin/install-claude-code | bash

That installs the Claude Code CLI, symlinks the config, and runs bin/link-agent-skills to share the harness-neutral skills with Codex.

Skills

All skills live in config/claude/skills/ and are version-controlled. On a new Mac they are available immediately after the installer runs.

Code and conventions (loaded automatically when relevant)

SkillWhat it does
spatie-guidelinesThe single source for Spatie PHP, Laravel, and JavaScript conventions. Style, docblocks, control flow, naming, validation, Blade, package architecture, Pest, git workflow
react-best-practicesReact hooks, effects, refs, and component design. Scoped to **/*.{tsx,jsx}
laravel-inertia-react-structureFrontend directory structure for Laravel Inertia React apps. Scoped to React files
livewire-4Livewire 4 components, single-file and multi-file
spatie-package-skeletonScaffolding a package from package-skeleton-laravel, plus extensibility patterns
speeding-up-laravel-testsMaking slow Pest suites fast. Factories, fakes, config caching, LazilyRefreshDatabase

Review and audit

SkillWhat it does
review-codeRuns 6 review lanes in parallel over the working tree, then applies the fixes
review-prReviews a GitHub PR, gates on CI, merges, thanks the author. Releases only when asked
audit-architectureWhole-codebase audit of how state and data are modelled. Read-only, ranked P0 to P3

Products and publishing (CLI wrappers for things Spatie runs)

SkillWhat it does
flareTriage errors and performance data on flareapp.io
mailcoachEmail lists, subscribers, campaigns, automations
there-thereHelpdesk tickets, contacts, channels
update-spatie-docsRe-import package docs to spatie.be after a docs PR merges
write-freek-dev-blogpostDraft a post in the freek.dev voice
typefullyDraft and schedule social posts
code-snippet-imagesRender code screenshots for social media

Tooling

SkillWhat it does
conductorConductor workspaces and sessions, the CLI, the API, deep links, settings, writing briefs
uiExplore, build, and refine UI through the ui.sh MCP server
grill-meInterrogate a plan until every branch of the decision tree is resolved

Scoped Plugins

Any directory under skills/ with a .claude-plugin/plugin.json loads as a plugin named <name>@skills-dir. Plugins can be turned off globally and enabled per repository, so situational skills cost nothing in unrelated sessions.

PluginContentsEnabled
marketing29 marketing, CRO, and SEO skillsPer repo, in the ones with a marketing site
musicAbleton Live controlPer workspace
laravel-lspThe Laravel language server, see belowGlobally

To enable one in a repository, add it to that repo's .claude/settings.json:

{
  "enabledPlugins": {
    "marketing@skills-dir": true
  }
}

Project-scope plugins only load from the directory you launch from, so start the CLI at the repository root.

Code Intelligence

Three language servers give the agent diagnostics after every edit and real symbol navigation instead of grep.

ServerProvidesInstall
laravel-lsp@skills-dirConfig keys, route names, view paths, translation strings, middleware aliases, and container bindings, in .blade.phpcomposer global require laravel/lsp
php-lspPHP types, symbols, references, signaturesnpm i -g intelephense
typescript-lspTypeScript and TSX intelligencenpm i -g typescript-language-server typescript

Laravel LSP is first-party (announced at Laracon US 2026) and has no official Claude plugin, so skills/laravel-lsp/ wraps it in a small .lsp.json. Its phpEnvironment defaults to auto, which finds Herd and Valet without configuration.

Claude Code registers one server per file extension, so the two PHP servers split the work: Intelephense takes .php for types, undefined methods, and references, and Laravel LSP takes .blade.php for route names, view paths, and translation strings. To flip that priority, disable php-lsp and add ".php" back to skills/laravel-lsp/.lsp.json.

Agents

Custom subagents live in config/claude/agents/.

  • laravel-feature-builder - Implements new features across models, controllers, migrations, and views

Most delegation now happens through plugins instead, notably the laravel-simplifier:laravel-simplifier agent from Taylor's laravel marketplace, which is lane 2 of the review workflow.

The Review Workflow

review-code and review-pr share one definition of what a review is, in skills/review-code/references/lanes.md. Six lanes run in parallel:

  1. Correctness - bugs, via /code-review
  2. PHP simplification - via the laravel-simplifier agent
  3. Spatie conventions - via spatie-guidelines
  4. Laravel practices - via Laravel Boost's per-repo laravel-best-practices
  5. React - via react-best-practices, only when JS or TS changed
  6. Security - authorization, mass assignment, injection, XSS, secrets, SSRF, PII in logs

Findings are deduplicated, and security outranks correctness, which outranks conventions. Both defect lanes require a concrete failure scenario, so "consider adding a null check" does not count as a finding.

The lanes file has a per-harness table, so the same review runs under Codex using its review-agent skill.

Settings Worth Knowing

SettingWhy
disableClaudeAiConnectorsKeeps claude.ai account connectors in the desktop app, out of the terminal
skillOverridesHides 8 bundled skills from the model while keeping them typeable, saving context
cleanupPeriodDaysTranscript retention, set to a year
defaultMode: autoA classifier handles approvals instead of prompting on every step

Sharing With Codex

Codex reads AGENTS.md natively and Claude Code reads CLAUDE.md, so one file is symlinked under both names. Skills are a different story: Codex keeps its own ~/.codex/skills/ alongside its built-in .system skills, so a directory symlink would destroy those. bin/link-agent-skills links the harness-neutral skills one by one instead.

bin/link-agent-skills

Excluded from sharing: ui (needs a Claude MCP tool), typefully (Claude-specific allowed-tools), and the plugin directories, which have no top-level SKILL.md.

Adding New Skills

# Install a skill (adds directly to your dotfiles)
npx skills add <owner/repo>

# Share it with Codex too, if it is harness-neutral
# (add it to the SHARED list in bin/link-agent-skills)
bin/link-agent-skills

cd ~/.dotfiles
git add config/claude/skills/
git commit -m "Add new skill"

Two rules that decide whether a skill ever gets used:

  1. The name and description determine everything. A skill named after a person, or after a quarter of what it does, will not be found. Write the description around the phrases you would actually type.
  2. Keep the body short and push detail into references/. A skill body stays in context for the rest of the session once loaded, while reference files load only when needed.

Browse more skills at skills.sh


Customization

Personal Aliases & Functions

Create custom configurations that won't be committed:

mkdir -p ~/.dotfiles-custom/shell
vim ~/.dotfiles-custom/shell/.aliases

These files are automatically loaded by .zshrc if they exist.

Project-Specific Variables

Use direnv for automatic environment loading:

cd my-project
echo 'export DEBUG=true' > .envrc
direnv allow

Variables load when you enter the directory and unload when you leave.


Post-Installation

  1. Restore settings (optional): Run mackup restore if you have backups

  2. Migrate history (upgrading only): Run migration/migrate-z-to-zoxide.sh if you have ~/.z


Tool Comparisons

Old ToolNew ToolWhy Better
z.sh / autojumpzoxideSmarter frecency algorithm, Rust speed
nvmfnm40x faster, simpler, Rust-based
catbatSyntax highlighting, git integration
lsezaIcons, tree view, git status
grepripgrep5-10x faster, respects .gitignore
findfdSimpler syntax, 10x faster
diffdeltaSide-by-side diffs, syntax highlighting
htopbottomBetter UI, graphs, Rust-based

Utilities

The bin/ directory contains helper scripts:

  • install - Main installation script (idempotent, safe to re-run)
  • install-claude-code - Standalone installer for the AI setup: the CLI, the symlinks, and the Codex links
  • link-agent-skills - Symlink the harness-neutral skills and AGENTS.md into Codex, leaving Codex's own built-in skills alone
  • exclude-from-spotlight - Drop a .metadata_never_index marker into data heavy directories so Spotlight skips them. Local database directories (DBngin and friends) hold hundreds of thousands of constantly rewritten files, which keeps mds_stores busy indefinitely.
  • update - Update dotfiles, Homebrew, npm, and Composer packages
  • doctor - Health check and diagnostic tool
  • conductor-merge - Fast-forward the current Conductor workspace branch into main (which lives in another git worktree). Use --push to also push main to origin, which clears Conductor's "Changes" view (it diffs against origin/main).

Credits

Created by Freek Van der Herten. Used by many at Spatie.

See config/Brewfile for complete package list.