Personal dotfiles with modern shell tooling, optimized for Laravel/PHP development. Features fast startup times, smart directory navigation, and modern CLI tools.
Getting started
- Key Features
- Quick Start - clone and run
bin/install - What's Included - Shell & Prompt · Modern CLI Tools · Development Tools · QuickLook Plugins
Reference
- How It Works - Symlinked Files · Sourced Files · Custom Agnoster Theme
- Daily Usage - Smart Navigation · Laravel/PHP Shortcuts · Data Processing · Maintenance Commands
- Version Management - Node.js via fnm · PHP & Composer via Homebrew
- Package Management - the Brewfile and global npm and Composer packages
AI setup
- AI Development Setup - one config for Claude Code and Codex
- Quick Install (Standalone) - the AI setup without the rest of the dotfiles
- Skills - all 19, grouped by purpose
- Scoped Plugins - skills that load only in the repos that need them
- Code Intelligence - Laravel LSP, Intelephense, TypeScript
- Agents - custom subagents
- The Review Workflow - the six lanes behind
review-codeandreview-pr - Settings Worth Knowing
- Sharing With Codex - how one source feeds both harnesses
- Adding New Skills - and the two rules that decide whether a skill gets used
Everything else
- Customization - Personal Aliases & Functions · Project-Specific Variables
- Post-Installation · Tool Comparisons · Utilities · Credits
- 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/installsets up everything including Claude Code
git clone git@github.com:freekmurze/dotfiles.git ~/.dotfiles
cd ~/.dotfiles
bin/install- 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
- 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
- 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
Instant file previews in Finder: code files, markdown, JSON, CSV, patches, and archives.
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 Location | Points To | Purpose |
|---|---|---|
~/.zshrc |
~/.dotfiles/home/.zshrc |
Main Zsh configuration (Oh My Zsh with custom agnoster theme) |
~/.gitconfig |
~/.dotfiles/home/.gitconfig |
Git configuration with delta diff viewer |
~/.global-gitignore |
~/.dotfiles/home/.global-gitignore |
Global Git ignore patterns |
~/.vimrc |
~/.dotfiles/home/.vimrc |
Vim configuration |
~/.vim/ |
~/.dotfiles/home/.vim/ |
Vim runtime files |
~/.mackup.cfg |
~/.dotfiles/macos/.mackup.cfg |
Mackup 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.md |
Agent instructions (Claude reads CLAUDE.md, not AGENTS.md) |
~/.claude/settings.json |
~/.dotfiles/config/claude/settings.json |
Claude Code settings |
~/.codex/AGENTS.md |
~/.dotfiles/config/claude/AGENTS.md |
The 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.json |
Zed editor settings |
~/.config/zed/keymap.json |
~/.dotfiles/config/zed/keymap.json |
Zed custom keybindings |
~/.config/ghostty/config |
~/.dotfiles/config/ghostty/config |
Ghostty 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.jsonThese files are loaded by .zshrc but remain in the dotfiles directory:
home/.aliases- Shell command aliaseshome/.functions- Custom shell functionshome/.exports- Environment variables
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 withgit add)•- Unstaged changes (modified files not yet staged)- Yellow background - Uncommitted changes
- Green background - Clean working directory
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 directorya # php artisan
p # Run Pest/PHPUnit tests
c # composer
mfs # php artisan migrate:fresh --seed
nah # git reset --hard; git clean -df# 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)bin/update # Update all packages and toolsfnm 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 versionsbrew upgrade php # Update PHP to latest
brew upgrade composer # Update ComposerAll Homebrew packages are declared in config/Brewfile. To add a new tool:
echo 'brew "neovim"' >> ~/.dotfiles/config/Brewfile
brew bundle --file=~/.dotfiles/config/BrewfileComplete 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
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
Install just the AI setup without the full dotfiles:
curl -fsSL https://raw.githubusercontent.com/freekmurze/dotfiles/main/bin/install-claude-code | bashThat installs the Claude Code CLI, symlinks the config, and runs bin/link-agent-skills to share the harness-neutral skills with Codex.
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)
| Skill | What it does |
|---|---|
spatie-guidelines |
The single source for Spatie PHP, Laravel, and JavaScript conventions. Style, docblocks, control flow, naming, validation, Blade, package architecture, Pest, git workflow |
react-best-practices |
React hooks, effects, refs, and component design. Scoped to **/*.{tsx,jsx} |
laravel-inertia-react-structure |
Frontend directory structure for Laravel Inertia React apps. Scoped to React files |
livewire-4 |
Livewire 4 components, single-file and multi-file |
spatie-package-skeleton |
Scaffolding a package from package-skeleton-laravel, plus extensibility patterns |
speeding-up-laravel-tests |
Making slow Pest suites fast. Factories, fakes, config caching, LazilyRefreshDatabase |
Review and audit
| Skill | What it does |
|---|---|
review-code |
Runs 6 review lanes in parallel over the working tree, then applies the fixes |
review-pr |
Reviews a GitHub PR, gates on CI, merges, thanks the author. Releases only when asked |
audit-architecture |
Whole-codebase audit of how state and data are modelled. Read-only, ranked P0 to P3 |
Products and publishing (CLI wrappers for things Spatie runs)
| Skill | What it does |
|---|---|
flare |
Triage errors and performance data on flareapp.io |
mailcoach |
Email lists, subscribers, campaigns, automations |
there-there |
Helpdesk tickets, contacts, channels |
update-spatie-docs |
Re-import package docs to spatie.be after a docs PR merges |
write-freek-dev-blogpost |
Draft a post in the freek.dev voice |
typefully |
Draft and schedule social posts |
code-snippet-images |
Render code screenshots for social media |
Tooling
| Skill | What it does |
|---|---|
conductor |
Conductor workspaces and sessions, the CLI, the API, deep links, settings, writing briefs |
ui |
Explore, build, and refine UI through the ui.sh MCP server |
grill-me |
Interrogate a plan until every branch of the decision tree is resolved |
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.
| Plugin | Contents | Enabled |
|---|---|---|
marketing |
29 marketing, CRO, and SEO skills | Per repo, in the ones with a marketing site |
music |
Ableton Live control | Per workspace |
laravel-lsp |
The Laravel language server, see below | Globally |
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.
Three language servers give the agent diagnostics after every edit and real symbol navigation instead of grep.
| Server | Provides | Install |
|---|---|---|
laravel-lsp@skills-dir |
Config keys, route names, view paths, translation strings, middleware aliases, and container bindings, in .blade.php |
composer global require laravel/lsp |
php-lsp |
PHP types, symbols, references, signatures | npm i -g intelephense |
typescript-lsp |
TypeScript and TSX intelligence | npm 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.
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.
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:
- Correctness - bugs, via
/code-review - PHP simplification - via the
laravel-simplifieragent - Spatie conventions - via
spatie-guidelines - Laravel practices - via Laravel Boost's per-repo
laravel-best-practices - React - via
react-best-practices, only when JS or TS changed - 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.
| Setting | Why |
|---|---|
disableClaudeAiConnectors |
Keeps claude.ai account connectors in the desktop app, out of the terminal |
skillOverrides |
Hides 8 bundled skills from the model while keeping them typeable, saving context |
cleanupPeriodDays |
Transcript retention, set to a year |
defaultMode: auto |
A classifier handles approvals instead of prompting on every step |
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-skillsExcluded from sharing: ui (needs a Claude MCP tool), typefully (Claude-specific allowed-tools), and the plugin directories, which have no top-level SKILL.md.
# 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:
- 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.
- 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
Create custom configurations that won't be committed:
mkdir -p ~/.dotfiles-custom/shell
vim ~/.dotfiles-custom/shell/.aliasesThese files are automatically loaded by .zshrc if they exist.
Use direnv for automatic environment loading:
cd my-project
echo 'export DEBUG=true' > .envrc
direnv allowVariables load when you enter the directory and unload when you leave.
-
Restore settings (optional): Run
mackup restoreif you have backups -
Migrate history (upgrading only): Run
migration/migrate-z-to-zoxide.shif you have~/.z
| Old Tool | New Tool | Why Better |
|---|---|---|
| z.sh / autojump | zoxide | Smarter frecency algorithm, Rust speed |
| nvm | fnm | 40x faster, simpler, Rust-based |
| cat | bat | Syntax highlighting, git integration |
| ls | eza | Icons, tree view, git status |
| grep | ripgrep | 5-10x faster, respects .gitignore |
| find | fd | Simpler syntax, 10x faster |
| diff | delta | Side-by-side diffs, syntax highlighting |
| htop | bottom | Better UI, graphs, Rust-based |
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.mdinto Codex, leaving Codex's own built-in skills alone - exclude-from-spotlight - Drop a
.metadata_never_indexmarker into data heavy directories so Spotlight skips them. Local database directories (DBngin and friends) hold hundreds of thousands of constantly rewritten files, which keepsmds_storesbusy 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--pushto also pushmaintoorigin, which clears Conductor's "Changes" view (it diffs againstorigin/main).
Created by Freek Van der Herten. Used by many at Spatie.
See config/Brewfile for complete package list.
