sandermuller/boost-core
Sync AI agent config for any PHP project. Author skills, guidelines, and commands once in .ai/ and boost-core publishes them to ten agents, with Composer skill packages, tag scoping, and never clobbering hand-written files.
This is a dev-only CLI, not a runtime library — nothing ships to production and no service provider is required.
llms.txt (structured overview) and llms-install.md (step-by-step install). Read those before the docs site; they're the shortest path to exact command names. If you already use this package, read UPGRADING.md §1.12→1.13 before your next user-scope sync — that section is the difference between a working skill and a silent rename.composer require --dev sandermuller/boost-core. It has no framework dependency, so it drops into Laravel, Symfony, or a plain PHP repo identically..ai/. Your first real use case is one guideline and one agent: write a short guidelines/ file describing your coding conventions (test framework, naming, where things live), declare a single agent in withAgents() — the config surface is a fluent PHP builder, so start with whichever agent your team actually uses (Claude Code or Cursor are the usual entry points) — then run the sync command and inspect the generated files (typically CLAUDE.md or .cursor/rules/*.mdc).
4–5. Verify the artifact, then wire it into Composer. Confirm the generated file looks right in your agent, then add a composer ai:sync script (see below) so nobody has to remember the binary path.--scope=user is a different publishing model with its own paths, its own config file, and its own breaking-change history. Get project scope healthy first; then turn on user scope only if you install packages globally and want their skills available in every repo.If you only do one thing: get a single guideline flowing to a single agent end-to-end before adding a second agent. The value of this package is the fan-out; debugging fan-out and source-of-truth problems simultaneously is miserable.
Single-source authoring. Treat .ai/ as source and every agent's directory as build output. Skills, guidelines, and commands are authored once; the publisher rewrites them into each agent's expected format and path. Enforce this socially: PRs touch .ai/, never the generated files.
Know which scope you're in. Project scope writes into the repo (.ai/ → CLAUDE.md, .cursor/rules/, etc.) with names as authored. User scope writes into ~/.{agent}/skills/<skill>-user/SKILL.md — flat, one directory per skill, and suffixed so a user-scope copy can't hide a project skill of the same name. The two scopes have different naming, different ownership rules, and different cleanup behaviour; don't reason about one using the other's model.
Add agents incrementally. withAgents() is additive, so adoption can be per-developer rather than a team-wide migration. Start with one agent, add Cursor or Copilot when a specific teammate asks, and let the next sync produce only the new artifacts. This keeps diffs reviewable.
Curate user scope with ~/.boost/user-scope.php. This is the new allowlist for globally installed packages: list the skills a package should publish at user scope, and listing one also pulls in that package's metadata.boost-requires dependencies. A package with no entry still publishes every skill — so the file is opt-in narrowing, not opt-in publishing. BoostAutoSync::syncUserScopeOnce() re-syncs once after each edit to it, which makes the curation loop feel live.
Commit the output (recommended) or hook it. Two viable models for project scope:
"post-install-cmd"/"post-update-cmd" scripts calling the sync binary.Pick one and put it in the README — mixed models produce phantom diffs that look like sync bugs. User-scope output should generally not be committed (it lives outside the repo) but should be reproducible from user-scope.php plus the installed global packages.
CI drift gate. Run the sync in CI and fail if git status --porcelain is non-empty afterward. Prefer --check where you can: it now predicts the same skill-name clashes a real --scope=user --all run would hit, so you get clash detection without writing to a HOME directory or racing other CI jobs.
Composer script as the ergonomic entry point:
"scripts": {
"ai:sync": "@php vendor/bin/boost-core sync"
}
Guarded well enough that a --no-dev production install simply won't have the binary; don't call it from deploy hooks.
Upgrade as an explicit step. Because user-scope names are part of the public surface (slash commands, backticked skill names in prompts, links between skills), treat minor bumps as migrations: read UPGRADING.md, run a --check first, then a real sync, then inspect the reaped/renamed paths. A pinned version plus a drift gate turns a behavioural change into a visible diff.
Family packages for framework integration. The docs are organised one section per family package. If you're on Laravel and want Artisan-level integration, use the corresponding family package; boost-core is the framework-agnostic engine underneath. Don't reach for core if a family package already wires your framework's conventions.
Monorepos and shared guidelines. Because it's path-based and framework-free, you can run it from a subdirectory or compose a set of guideline sources — useful for keeping org-wide conventions in one place and project-specific rules in another, then publishing the union per package.
~/.{agent}/skills/<vendor>__<package>/<skill>/ is gone, replaced by flat ~/.{agent}/skills/<skill>-user/SKILL.md across all supported agents (nine at time of writing). /sandermuller__repo-init becomes /repo-init-user. Anything that hardcodes the old path, the old qualified name, or a saved slash-command invocation needs updating. Project-scope output is untouched: if you never pass --scope=user, the upgrade is a no-op for you.~/.{agent}/skills/<package-basename>/ folder (that migration was removed entirely). List the skills directory after upgrading and delete leftovers by hand.~/.claude/skills/foo-user/SKILL.md will silently block publication until you move it aside. Read the refusal, don't just re-run.--scope=user --all reaps removed packages before publishing, so a skill name can change owner in a single run — diff the output, don't assume a stable owner across package installs..md skill links are rewritten for references between one package's published skills. A reference from package A's skill to package B's skill keeps the old name and breaks. Keep cross-package skill references out of your sources, or expect to fix them manually.~/.boost/user-scope.php stops the sync and reaps nothing. Fail-safe, but it means an unrelated typo silently freezes all user-scope updates. If a sync "does nothing," check that file's error output first.CLAUDE.md (or a -user/SKILL.md), the fix belongs in .ai/ or user-scope.php. This is the single most common source of "my rule disappeared" confusion..ai/ sources format-neutral — or use explicit per-agent overrides if you genuinely need a Cursor-only glob. Mixing both silently produces mangled output on the agents you didn't test.withAgents(), confirm whether the previously generated project directory is pruned or orphaned. Test once with a throwaway agent entry before relying on config removal to clean up.user-scope.php to publish only the skills a package really needs. Adding an agent is cheap; bloating the source is not..gitattributes. Generated Markdown on Windows/CRLF checkouts will fight your drift gate. Normalise * text=auto eol=lf for the generated paths..ai/, not the publisher.ls ~/.{agent}/skills/ and confirm you see flat <skill>-user/SKILL.md directories. Seeing <vendor>__<package>/ nesting means a pre-1.13 artifact or a stale sync; seeing nothing means the skill wasn't selected, the clash went to another package, or the target file is owned by something else. Run --check before a real --all run to preview owners and clashes.How can I help you explore Laravel packages today?