laravel-herd-worktrees
Skill5 starsChanged 11 days agoMITView on GitHub
Create, serve, or remove git worktrees for Laravel projects served by Laravel Herd on macOS. Use when the user needs a branch worktree, a .test URL for one, or per-worktree database isolation.
- Reads credentials
- Deletes or force-pushes
In this repository57 other files it gives its agents.
- AGENTS.mdAGENTS.md
- CLAUDE.mdCLAUDE.md
- architecture-satisfactionSkill
- autopilotSkill
- browser-testSkill
- chatter-scoutSkill
- closeoutSkill
- codebase-designSkill
- code-reviewSkill
- code-smells-auditSkill
- commitSkill
- dependency-auditSkill
- diagnosing-bugsSkill
- domain-modelingSkill
- fix-ci-failuresSkill
- fix-github-issuesSkill
- fix-nightwatch-issuesSkill
- fix-posthog-issuesSkill
- grillingSkill
- grill-meSkill
- grill-with-docsSkill
- handoffSkill
- harness-toolsSkill
- housekeeperSkill
- implementSkill
- implement-specSkill
- improve-codebase-architectureSkill
- panelSkill
- prototypeSkill
- prSkill
- prune-testsSkill
- releaseSkill
- repository-cleanupSkill
- researchSkill
- resolve-review-commentsSkill
- resolving-merge-conflictsSkill
- retroSkill
- run-afterSkill
- scratch-cleanupSkill
- scratch-statusSkill
- setupSkill
- sweepSkill
- tddSkill
- teachSkill
- to-questionnaireSkill
- to-specSkill
- to-ticketsSkill
- triage-github-prSkill
- triageSkill
- ui-designSkill
- upgrade-planSkill
- verifySkill
- wait-whatSkill
- wayfinderSkill
- which-skillSkill
- wizardSkill
- writing-for-agentsSkill
The file
We split this skill into the rules it gives an agent
4 rules. About 0 are common, 1 is distinctive, and 3 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈1
Distinctive · estimate
This author's own choices. Worth a look.
3
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 9
Run several branches of a Laravel project side by side, each a git worktree that Herd serves at its own *.test URL.
- Distinctive: line 25
Remove it with Remove a served worktree.
- Very specific: line 47
When herd_unserve_failed is set (the Herd app is not running) and its database_mode is clone or empty on a server driver, drop its …
- Very specific: line 53
Every skill that creates a worktree or a throwaway database registers each database in <git-common-dir>/scratch-databases, so …
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Laravel Herd + Git Worktrees
Run several branches of a Laravel project side by side, each a git worktree that Herd serves at its own *.test URL. herd workspace run inside a worktree does the setup; this skill owns the recipe around it.
Mental Model
- A worktree has its own
HEAD, and none of the main checkout's untracked state: novendor/,node_modules/,.env, or built assets. herd workspaceinside a git worktree serves that checkout as a workspace of the main checkout's site, at<branch>.<site>.test(a detached worktree is named after its commit). It copies.env; clonesvendor/andnode_modules/from the main checkout (each only while its lockfile matches) andpublic/build; links the host with the main site's HTTPS and PHP version; rewritesAPP_URL,SESSION_DOMAINandSANCTUM_STATEFUL_DOMAINS; clears the config and route caches. Run in the main checkout instead, it makes a copy-on-write clone outside git's worktree list, which no recipe here uses.- Database:
--database=shared(the default) keeps the main checkout's database;cloneandemptycreate<main db>_<branch>on the same server (emptyalso migrates), whichherd workspace:deletedrops again. - What Herd leaves alone:
composer installwhen the lockfile differs,storage:link,.env.testing,APP_KEY, cache and Redis prefixes. A project can cover the last three in a committedherd.yml: see references/isolation.md.
Create a worktree for the user
git worktree add -b <branch> .claude/worktrees/<name> <base>(or the path the user names).- Make it runnable with Bootstrap a bare worktree, passing
--database=empty(a fresh migrated database) or--database=clone(a copy of the main one) instead ofsharedwhen the user wants the worktree's data kept apart. - With
cloneorempty, readdatabase_modeanddatabase_namefrom the--jsonoutput: Herd falls back tosharedwith only a note when it cannot create the database, so say so when it did. Register a created server database per Scratch database registry, sorepository-cleanupsees it. Withempty, runphp artisan migrateonce the bootstrap's step 2 has installedvendor/: Herd's own migration runs before that and only warns whenvendor/was missing. - Give the user the
urland the database.
Remove it with Remove a served worktree.
Bootstrap a bare worktree
A worktree made with plain git worktree add (the PR, issue, and CI recipes in other skills, at .claude/worktrees/<name>) starts bare; so does one the harness made (claude --worktree, a subagent with isolation: worktree). With the leek-skills plugin in Claude Code, a session that opens in such a worktree is told so at start; elsewhere, check for vendor/ yourself before running anything. Make it runnable from inside the worktree, with main set to the main checkout (git worktree list --porcelain | sed -n '1s/^worktree //p'):
- Serve it.
herd workspace --database=shared --json. Keep theurlit prints: that is the worktree's address forverify.sharedleavesDB_DATABASEnaming the main checkout's database (for SQLite, Herd points it at the main checkout's file), so the calling skill's own database (step 3) is the only one created, and the only one its cleanup tracks; run no migration or seeder before step 3. Whenherdis missing, the command fails, or the caller skips serving (a worktree that needs no URL), copy.envfrom$mainyourself, and every path the project'sherd.ymllists underworkspaces.copy(gitignored build output such as an editor bundle thatartisanneeds), then go on: the worktree has no URL, but artisan and tests run. - Dependencies and assets. When the project's
herd.ymldeclaresworkspaces.hooksorworkspaces.copy, read the hook script first: it may already install dependencies on lockfile drift, copy built assets, and set up the test database, so do only what it leaves out, and use the project's own test-database tool when its docs name one. Otherwisecomposer install, sovendor/matches this branch's lock (Herd cloned the main checkout's only when the lockfiles were equal). Do the same fornode_moduleswhen the run builds assets. When Composer hooks require generated assets that do not exist yet (such as@php artisan filament:assetsneeding an editor bundle fromnpm run build), runcomposer install --no-scripts, build the assets, then runcomposer install. Runphp artisan storage:linkwhen the main checkout haspublic/storage(Herd repoints that link only in its own clones). Each tree owns a realvendor/: Composer's autoloader resolvesapp/andtests/relative to it, so a symlinkedvendor/makes Pest run the main checkout's code. - Test environment and database. Copy
.env.testingfrom$mainwhen it exists there and not here. When the calling skill gives the run its own database, setDB_DATABASEto that name in.envand.env.testingbefore any migration or test. When.envputs the cache, queue, or sessions on Redis and the project'sherd.ymlsets no prefixes, setCACHE_PREFIXandREDIS_PREFIXto values unique to this worktree, so parallel worktrees keep their keys apart. - Proof.
git rev-parse HEADequals the commit the run means to test, andtest ! -L vendorpasses. Run nothing until both hold.
Remove a served worktree
From the main checkout (or, for implement-spec, the integration checkout git branch -d checks against), run scripts/remove-worktree.sh <path>, adding --branch <name> when the run's branch goes too. It works in the safe order and prints one JSON line:
- Clean check. A worktree with any
git status --porcelainoutput stays, with its branch and databases:removed: falseand the reason. The calling skill's rule for a refused removal applies. - Unserve. When Herd's own
herd workspaces --all --jsonserves this exact path,herd workspace:delete --force --keep-files -- <site>with that site (never a site read from the checkout, which a branch could plant) (Herd's--forceonly skips a prompt;--keep-filesleaves the checkout for git). Herd drops a database it created (cloneorempty), and the script unregisters it. - Remove.
git worktree remove <path>, never with--force. When git refuses, everything stays; visiting its URL serves it again. - Branch.
git branch -d <name>only after a removal; a refusal keeps the branch, named inbranch_reason. Git's-Dhint is not a go-ahead.
databases lists what is still registered for that path once it is removed ([] when kept, since a kept worktree keeps its databases): the calling skill's own databases. Wait for the script's JSON before dropping anything (if your harness backgrounds a slow command, read its output first): a drop issued earlier runs before git decides, and an unregister issued earlier empties the list. Drop each, and its parallel-testing copies (<database>_test_<N>), with the repo's client (DROP DATABASE IF EXISTS; a SQLite file goes with the checkout), then unregister each one only after its drop succeeded. A failed drop keeps its registry line and is reported.
When herd_unserve_failed is set (the Herd app is not running) and its database_mode is clone or empty on a server driver, drop its database_name yourself and unregister it.
What is left. A calling skill removes without asking what it created whose work has landed, and lists each removal. It asks once only about the rest it created (a worktree git refused, unmerged or queued work): a structured question (harness-tools) with multiSelect: true, one option per item naming its worktree, branch, and databases, nothing pre-ticked, at most 4 per question and further questions for the rest; otherwise one yes/no question in chat: "Can I delete these too?". It removes only what the answer selects, by the steps above; on no, nothing. It skips the question when nothing is left, and names everything kept in its report for repository-cleanup.
Scratch database registry
Every skill that creates a worktree or a throwaway database registers each database in <git-common-dir>/scratch-databases, so repository-cleanup finds what a stopped run left behind. One script owns the file:
bash <this-skill-dir>/scripts/scratch-db.sh register <pgsql|mysql|sqlite> <database> <worktree path, or -> # the moment it is created
bash <this-skill-dir>/scripts/scratch-db.sh unregister <database> # only after a successful drop
bash <this-skill-dir>/scripts/scratch-db.sh list [<worktree path>] # JSONName a scratch database so no checkout config uses it: never a name in the main checkout's .env, .env.testing, or phpunit.xml.
Diagnostics
herd workspaces --json # this site's workspaces and unserved worktrees, with URLs
herd site:info # URL, PHP version, and what .env points at
herd db:connection # the database this checkout's .env reaches
git worktree listCommand reference: references/herd-commands.md.
Out of Scope
- Valet, Linux, Docker / Sail: this skill assumes Herd on macOS.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

