sandermuller/package-boost
AI agent skills, guidelines, and .gitattributes CLI commands (lean, gitattributes) for framework-agnostic Composer package authors. No Laravel dependency; built on the boost-core sync engine, sibling to package-boost-laravel.
Before anything else: treat this package as a frozen dependency, not a new adoption. The README opens with a deprecation notice — sandermuller/package-boost is in maintenance mode at 0.15.x, and the feature set has been split into package-boost-php (framework-agnostic Composer packages), package-boost-laravel (Laravel-targeted packages), and boost-core (the skill-sync engine, pulled in transitively). If the package already appears in a composer.lock, keep it and move on; if you are evaluating it today, read it as documentation for what the successors do, then composer require --dev sandermuller/package-boost-php instead. Everything below is the day-to-day workflow that package actually implements.
Install (existing installs / maintenance):
composer require sandermuller/package-boost --dev
Then register the provider in testbench.yaml at the package root. For a framework-agnostic package the whole file is three lines:
laravel: '@testbench'
providers:
- SanderMuller\PackageBoost\PackageBoostServiceProvider
orchestra/testbench is a dev-only command harness here — it is not a runtime dependency of the package you are developing, which is the whole point of the tool.
Where to look first, in order:
.ai/ — the source of truth. Sync reads skills/ and guidelines/ here and writes everywhere else.AGENTS.md / CLAUDE.md / GEMINI.md — the concatenated guideline output your agents actually read..claude/skills/ (and siblings) — generated, committed, never hand-edited.First use case: run vendor/bin/testbench package-boost:sync once on an existing package before writing any skills. The zero-config default fans out all nine agents, so you immediately get a populated AGENTS.md plus the shipped package-development skill teaching agents how to drive Testbench in a package repo (no app/, no artisan, tests-as-specification). That single run is the highest-value step: it converts a package repo into something an agent can navigate without guessing.
Author in .ai/, generate outward. The mental model is one-directional: .ai/skills/<name>/SKILL.md and .ai/guidelines/*.md are inputs; .claude/skills/, .cursor/skills/, .agents/skills/, .github/skills/, .junie/skills/, .kiro/skills/, and the three guideline files are outputs. Commit both — the generated files are what collaborators and CI actually consume.
Scaffold rather than hand-roll. package-boost:new pre-fills valid frontmatter and rejects collisions:
vendor/bin/testbench package-boost:new skill my-skill --description="One-line auto-activation hook."
vendor/bin/testbench package-boost:new guideline my-conventions
A freshly scaffolded skill passes package-boost:doctor without edits, which matters because --check fails on host skill lint issues.
Split durable conventions into guidelines, prompts into skills. Only Claude Code natively consumes skill directories as auto-activatable tools today; the other eight agents get their value from the concatenated guidelines file. So: anything that must apply always goes in .ai/guidelines/. Anything that should activate on a certain kind of prompt goes in a skill. Getting this backwards produces skills that silently do nothing outside Claude Code.
Use selective sync for the inner loop. After editing one skill, --skills is faster and produces a smaller diff to review than a full sync. Before committing, run the full thing so you don't leave guidelines or .mcp.json stale.
Gate CI on drift. This is the pattern that makes the tool trustworthy in a team:
- name: Check package-boost sync
run: |
report=$(vendor/bin/testbench package-boost:sync --check --format=json || true)
drift=$(echo "$report" | jq -r '.drift')
if [ "$drift" = "true" ]; then
echo "::error::package-boost sync drift detected"
fi
--check never writes, exits non-zero on any difference, and the JSON shape is stable (schema: 1, arrays sorted by target so diffs are deterministic). Parse .skills.new/.updated/.removed[]?.target for the human-readable list; ignore hint, which is advisory prose, not a command.
Trim the agent list deliberately. The all-nine default writes six skill dirs, but .agents/skills is shared by Codex, Gemini, OpenCode, and Amp and is deduped. If your team only uses Claude Code and Cursor, cut the rest — either through the package-boost:install picker, --agents=claude_code,cursor, or by setting agents in config/package-boost.php. Fewer generated directories means less noise in .gitattributes and fewer merge conflicts.
Pair with lean-dist before publishing. The shipped lean-dist skill on-ramps stolt/lean-package-validator and supplies AI-era export-ignore entries (.ai, .claude, AGENTS.md, CLAUDE.md, …) that lpv's defaults predate. If you are committing generated agent directories, this is not optional — otherwise they land in your dist tarball and every Composer consumer downloads them.
The install picker is the sharpest edge for framework-agnostic packages. package-boost:install persists its selection through Testbench's workbench/ scaffolding helpers. If you have not run vendor/bin/testbench workbench:install, the picker either does nothing useful or writes where you don't expect. The README is explicit: skip package-boost:install entirely (the default already syncs everything), or publish the config once and hand-edit:
vendor/bin/testbench vendor:publish --tag=package-boost-config
.mcp.json is conditional, and the skip is loud in JSON. No laravel/boost in require-dev means no MCP file — reported as {"action":"skipped","reason":"laravel-boost-not-installed"}. Filtering claude_code out of the agent list reports "reason":"claude-not-selected". Don't debug a "missing" .mcp.json until you've checked both. Note also that mcp is always a single object, never an array — a common parse bug in CI scripts.
Guideline files are block-managed. Sync rewrites only the region between the <package-boost-guidelines> markers; everything outside is preserved. That is what line_delta measures, and why a +12 lines report does not mean the whole file grew. The corollary: hand-edits inside the block will be silently overwritten on the next sync. Put package-specific overrides outside it.
Skill names collide silently across four sources. Host .ai/skills/, vendor packages, and package-boost's own shipped defaults all contribute, and a name clash means one disappears. The skill-authoring skill exists specifically to guard this — pick namespaced names, and enforce the ^[a-z][a-z0-9-]*$ kebab shape with name matching the directory, or --check fails.
Asymmetric failure severity. --check fails the build on host skill problems (missing name/description, name/dir mismatch) but only warns on shipped and vendor skill issues. So a green CI run before you've authored any skills is normal — the gate only starts biting once you own .ai/skills/.
Laravel-shaped shipped skills are not dead weight in a non-Laravel repo. package-development, cross-version-laravel-support, and ci-matrix-troubleshooting activate only on Laravel-flavoured prompts and are otherwise idle. Resist the urge to strip them; the cost is zero and the ci-matrix-troubleshooting skill in particular earns its keep the first time a prefer-lowest cell goes red.
Debugging a sync that "did nothing": check whether sources exist at all. Empty .ai/skills/ reports {"skipped":"no-sources"} rather than an empty array — different shape, different code path. Then verify your agent filter didn't exclude the target for that category.
Extension point for emitter authors: if your package writes files into the host during boost sync (a custom FileEmitter), declare the boost-extension tag in boost.php's withTags([...]). That opts you into writing-file-emitter and skill-authoring, both gated off by default so ordinary consumers don't carry them.
Migration when you're ready: composer remove sandermuller/package-boost && composer require --dev sandermuller/package-boost-php, adding package-boost-laravel alongside if the package targets Laravel. Your .ai/ layout transfers unchanged — both successors consume the same source directory, so authored skills and guidelines keep working without re-authoring or re-syncing.
How can I help you explore Laravel packages today?