Laravel herd worktrees
Personal collection of agent skills for Claude
npx -y skills add leek/agent-skills --skill laravel-herd-worktreesAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 3 stars3 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Use when working with Laravel projects served by Laravel Herd alongside git worktrees on macOS. Triggers on "laravel herd worktree", "new worktree for laravel", "herd parked sites worktree", "multiple branches herd", "composer install per worktree", ".test url for branch", "isolate php version per worktree", or any task that creates, lists, or removes a git worktree inside a Herd-served Laravel project. Covers site routing, per-worktree `.env`/database/cache isolation, and fast dependency install strategy.
SKILL.md
5.8 KB, as published. Nobody here has run it
Laravel Herd + Git Worktrees
Run multiple branches of a Laravel project in parallel, each reachable at its own *.test URL through Laravel Herd, with isolated dependencies, env, database, and caches.
Mental Model
- A worktree is a sibling directory of the main checkout with its own
HEAD. Composer/Node deps,vendor/,node_modules/,storage/, andbootstrap/cache/are per-worktree — never share via symlink. - Herd's parked directory auto-serves every immediate subdirectory as
<dir>.test. Park the parent of all worktrees once and every new worktree gets a URL for free. .envis untracked, so it must be re-created in each worktree.APP_URL,DB_DATABASE, cache prefixes must differ per worktree to prevent cross-branch bleed.
When to Use This Skill
- User asks to create a worktree for a Laravel app served by Herd.
- User reports
vendor/, migrations, cache, or.envproblems after switching worktrees. - User wants per-branch URL like
myapp-feat.testwithout manual Nginx/Valet config. - User wants the same Laravel project on multiple PHP versions simultaneously.
Workflow
1. One-time setup
Park the parent directory that holds the main checkout (worktrees become siblings of the main checkout, so they land in the same parked dir):
cd ~/Code # parent of your laravel project
herd park
Verify:
herd parked
Each immediate subdir is now <name>.test. Adding a worktree at ~/Code/myapp-feat makes myapp-feat.test resolve immediately.
If parking the parent is not desired (other non-Laravel dirs live there), use explicit herd link per worktree instead — see references/herd-commands.md.
2. Create a new worktree
Use the helper script. It creates the worktree, copies .env, rewrites APP_URL + DB_DATABASE + cache prefixes, installs deps, generates app key, and runs migrations.
bash scripts/worktree-new.sh <branch-suffix> <base-branch> [--driver sqlite|mysql|pgsql]
Example:
bash scripts/worktree-new.sh feat-billing main --driver sqlite
Result: ../myapp-feat-billing/ exists, myapp-feat-billing.test works, isolated DB.
See scripts/worktree-new.sh for the exact transformations applied to .env.
3. Remove a worktree
bash scripts/worktree-rm.sh <branch-suffix> [--drop-db]
Runs git worktree remove, optionally drops the per-worktree DB, and herd unlinks if a manual link exists.
4. Switch PHP version per worktree (optional)
cd ../myapp-legacy
herd isolate [email protected]
Site uses 8.1; sibling worktrees keep their isolated or default version. herd isolated lists all overrides. herd unisolate reverts.
Per-Worktree Isolation Rules
| Concern | Rule |
|---|---|
vendor/ | Always per-worktree. Never symlink. |
node_modules/ | Always per-worktree. Never symlink. Use pnpm for fastest installs (content-addressable store). |
.env | Copy from main, rewrite APP_URL, DB_DATABASE, CACHE_PREFIX, SESSION_COOKIE, REDIS_PREFIX. |
APP_KEY | Run php artisan key:generate in each worktree. |
| Database | SQLite: per-worktree file. MySQL/Postgres: per-worktree DB name <app>_<suffix>. |
| Redis | Set unique REDIS_PREFIX (or different REDIS_DB index). |
storage/, bootstrap/cache/ | Per-worktree. Run php artisan optimize:clear after install. |
storage/app/public symlink | Re-run php artisan storage:link in the new worktree. |
Full rationale: references/isolation.md. DB strategy details (sharing seeds, schema dumps, fresh vs. migrate): references/db-strategies.md.
Common Pitfalls
- Sharing
vendor/via symlink — breaks when branches have different package versions; autoload class maps drift. - Forgetting
php artisan key:generate— encrypted cookies/sessions fail silently across worktrees that shareAPP_KEY. - Same
SESSION_COOKIEacross*.testsiblings — cookies leak between branches because they share the.testparent domain. Set a uniqueSESSION_COOKIEper worktree. - Same Redis DB without prefix — cache keys collide; one branch invalidates another's cache.
- Running
composer installagainst a stalecomposer.lockafter rebasing — always re-run install after switching base branches inside a worktree. - Herd not picking up new worktree — happens if the parent isn't parked or if the worktree directory name contains characters Herd rejects (stick to
[a-z0-9-]).
Quick Diagnostics
herd parked # confirm parent is parked
herd isolated # list per-site PHP overrides
herd which-php # PHP version Herd resolves for current dir
git worktree list # all worktrees + branches
ls -1 ../ | grep <app> # worktree dirs as Herd sees them
If a .test URL 404s: check herd parked includes the parent, dir name is lowercase, and php artisan route:list works inside the worktree.
Out of Scope
- Valet — different tool. Herd-only here.
- Linux Herd — paths and CLI differ; this skill assumes macOS Herd.
- Docker / Sail — covered by other workflows. Worktrees still work but routing is via Docker, not Herd.