name: repo-init description: Bootstrap or upgrade a repo with the canonical Sander/hihaho dev setup. Triggers when the user says "set up this repo", "scaffold a new package", "audit this repo against the standard", "upgrade tooling here", or "set up a new Laravel project / package / phpstan extension / rector extension".
repo-init
Routes the agent through a fixed entry flow, then to the right per-(category × mode) phase file. All phases, checklists, references, and stubs live in $REPO_INIT_HOME — read them in place.
Pre-flight (run once per session)
Before any phase:
Resolve
REPO_INIT_HOME:- Run
composer global config hometo get the global Composer dir. - Compute
REPO_INIT_HOME=<composer-global-home>/vendor/sandermuller/repo-initand remember the absolute path for the rest of the session. - If your shell tool spawns a fresh subshell per command (Claude Code default): inline-substitute the absolute path in every subsequent command (e.g.
cat /Users/<u>/.composer/vendor/sandermuller/repo-init/phases/bootstrap-laravel-package.mdinstead ofcat $REPO_INIT_HOME/phases/...). The$REPO_INIT_HOMEshorthand used throughout phase files / references is a documentation convention — substitute it before running shell commands. - Verify
<resolved-REPO_INIT_HOME>/SPEC.mdexists. - Escape hatch: if
./vendor/sandermuller/repo-init/SPEC.mdexists in the target cwd, use that path instead (project-local install shadows global).
- Run
If
REPO_INIT_HOME/SPEC.mdis missing: tell the user:Repo-init isn't installed. Run
composer global require sandermuller/repo-initto install it (one-time, machine-wide). Then ask me again. And stop.Verify skill is synced to user-level dir: check
~/.claude/skills/sandermuller__repo-init/SKILL.mdexists. boost-core 0.2.0+ auto-syncs this oncomposer global require/composer global update(global-context auto-sync writes to~/.{agent}/skills/{vendor}__{package}/for every globally-installed package withresources/boost/skills/; boost-core 0.4.0+ namespaces the dir by the full{vendor}__{package}slug and auto-migrates the legacy~/.{agent}/skills/repo-init/dir on first sync post-upgrade). If missing — fallback:cd $REPO_INIT_HOME && vendor/bin/boost sync --scope=user(Propagates into
~/.claude/skills/,~/.cursor/skills/,~/.amp/skills/, etc.)Proceed to the routing flow below.
Decide intent
Three modes:
- Bootstrap — new repo, about to create or fill an empty directory.
- Audit — existing repo, list gaps against the canonical setup. Read-only.
- Upgrade — existing repo, apply fixes. Re-runs the audit first.
If unclear from the user's prompt, ask.
Decide category
For bootstrap, ask the user which category. For audit/upgrade, read the target's composer.json and follow $REPO_INIT_HOME/references/detection-rules.md.
Seven categories:
| Category | Detection signal |
|---|---|
laravel-project |
type: project + laravel/framework in require |
phpstan-extension |
type: phpstan-extension OR extra.phpstan.includes |
rector-extension |
type: rector-extension OR extra.rector.includes |
laravel-package |
type: library + (extra.laravel.providers OR illuminate/* OR socialiteproviders/manager OR spatie/laravel-package-tools) |
composer-plugin |
type: composer-plugin |
skill-bundle |
type: library + sandermuller/boost-core in require (ships resources/boost/skills/, no src/) |
php-package |
type: library + none of the above |
Sub-flags for laravel-package:
- If
spatie/laravel-package-toolsis inrequire: use thelaravel-package-spatiestub variant (hihaho-style). Otherwise uselaravel-package(sander-style). - If
filament/filamentis inrequireOR user wants a Filament plugin: bootstrap routes tophases/bootstrap-filament-plugin.mdinstead. Audit / upgrade fall through to laravel-package phases. - If
laravel/novais inrequireOR user wants a Nova tool: bootstrap routes tophases/bootstrap-nova-tool.md. Audit / upgrade fall through to laravel-package phases.
Sub-flags for composer-plugin:
command-provider— plugin class implementsCapableANDgetCapabilities()returnsCommandProvider. Audit verifies the provider class exists and commands extendComposer\Command\BaseCommand(or adapter pattern).event-subscriber— plugin class implementsEventSubscriberInterface. Audit verifies subscribed events are validScriptEventsconstants.boost-skill-provider—resources/boost/skills/dir present. Treated as informational; boost-core handles discovery.
Ambiguous → ask the user.
Open the phase file
Read $REPO_INIT_HOME/phases/<mode>-<category>.md end-to-end. Follow it top-to-bottom. Don't improvise — every step you need is in the file.
Knobs to collect (bootstrap mode)
Before opening a bootstrap phase, gather these. Skill prompts the user for any you can't infer.
vendor(e.g.sandermuller,hihaho, custom) — required.name(kebab-case) — OPTIONAL. If provided, scaffold into./<name>/; if absent, scaffold into cwd (which must be empty modulo.git/). If cwd-empty precondition fails, stop and ask for aname.php— default8.3. Accepted:8.3,8.4,8.5.8.2rejected (laravel/pao floor).laravel(laravel-package only) — default^12.0||^13.0. (Laravel 11 dropped in 0.3.0 due to pao conflict.)test-framework— defaultpestfor vendorsandermuller,phpunitfor vendorhihaho.phpstan-extensionalwaysphpunit.with-hihaho-rules— defaultyfor vendorhihaho,Notherwise.with-security-advisories— defaultN.skill-tags— thesandermuller/boost-skillstags to activate in the scaffolded.config/boost.php. Walk the user through this interactively — presentphp,frontend,github,jiraas a checklist and let them confirm/adjust; do not silently auto-config. Pre-select sensible defaults by category: php-package / laravel-package / phpstan-extension / rector-extension / composer-plugin / skill-bundle pre-selectphp; addfrontendfor a frontend-facing package;github/jiraare opt-in. Picking none is valid. The chosen tags fill the__SKILL_TAGS__placeholder inside the array argument of->withTags([__SKILL_TAGS__])in.config/boost.phpas a quoted comma list (e.g.'php', 'jira'); none →->withTags([])(the universal boost-skills skills still sync). boost-core 0.20+ takes an array, not variadic args.laravel-projecthas no.config/boost.php— skip this knob for it.
Greenfield package bootstrap (no composer.json yet)
For bootstrap-laravel-package, bootstrap-php-package, bootstrap-phpstan-extension, bootstrap-rector-extension, bootstrap-composer-plugin in a brand-new dir:
- Apply target-dir rule:
mkdir <name> && cd <name>ifnamewas provided; otherwise verify cwd is empty modulo.git/. - Open
$REPO_INIT_HOME/phases/bootstrap-<category>.mdand follow it. The phase's first step copies a stubcomposer.jsonfrom$REPO_INIT_HOME/stubs/<category>/directly into cwd — nocomposer initprelude needed.
For bootstrap-laravel-project, laravel new <name> (or laravel new . if name absent) creates the dir + Laravel skeleton in step 1; step 2 layers our additions on top.
No composer require --dev sandermuller/repo-init step is needed in the target repo. Repo-init lives globally; the target stays clean.
After every phase: what's next
Phase files end with a "What's next" prompt. Typical:
Bootstrap done. Want to run an audit next, or are you done with repo-init for now?
There's nothing to "remove" from the target — repo-init was never installed there. The skill simply stops.
Safety rails the agent must honour
All documented in phase files; summary:
- Per-category never-touch list (
$REPO_INIT_HOME/checklists/per-category-never-touch.md) —config/auth*.php,app/Policies/,.env*,.git/,vendor/,node_modules/. Always honoured. - Git-dirty guard (audit + upgrade modes only) — run
git status --porcelainbefore any write; skip paths whose 2-character status prefix indicates modified/added/untracked state (MM,??, or a singleM/Ain either column). Bootstrap exempts itself because cwd-must-be-empty is the precondition. - larastan vs phpstan exclusivity — never
composer requireboth in the same call. Phase files spell out which is right per category.
Updating repo-init
composer global update sandermuller/repo-init
The user-level skill auto-re-syncs via boost-core's global-context auto-sync hook (POST_AUTOLOAD_DUMP under composer global). Manual fallback:
cd $REPO_INIT_HOME && vendor/bin/boost sync --scope=user
Project-local install (escape hatch)
If a user wants to pin a specific repo-init version per project:
composer require --dev sandermuller/repo-init
The skill's pre-flight detects this and uses the project-local install as REPO_INIT_HOME (shadowing the global install). Self-removal then becomes composer remove --dev sandermuller/repo-init for that target.