v0.5.0
Added
- Conditional skill filtering by tags. A skill declares tags in its
SKILL.mdfrontmatter under the Agent Skills standard's sanctionedmetadataextension point —metadata.boost-tags, a space-delimited string. A project declares the tags it wants inboost.phpvia->withTags(Tag::Php, 'jira', ...). During project-scopeboost:synca vendor skill is fanned out only when every tag it declares is among the project's tags, so a project never receives — and the AI agent's skill-selection index never even sees thedescriptionof — skills irrelevant to it. Untagged skills always ship. A malformedmetadata.boost-tagsfails closed (the skill ships nowhere) rather than silently becoming untagged and leaking. When a skill stops shipping, its previously-synced agent-directory output is pruned — safely: only directories boost-core itself wrote, never through symlinks;boost:sync --checkreports the would-be deletion as drift without performing it. ->withExcludedSkills(['vendor/package:skill-name'])— a per-skill deny-list that drops specific vendor skills regardless of tags, for when you want a vendor's bundle minus one entry.SanderMuller\BoostCore\Enums\Tagenum — a non-authoritative convenience enum givingboost.phpauthors autocomplete for common tags without closing the (open, free-string) tag vocabulary:->withTags()accepts bothTagcases and raw strings.composer boost:doctortag report. A new section reports the project's declared tags, the runtime union of tags across installed allowlisted skills, per-skill tag status (eligible / filtered / excluded / invalid), and likely-typo hints for near-duplicate tags.- boost-core now distributes a
boost-config-shapeskill (resources/boost/skills/) — installing boost-core gives downstream AI agents a skill describingboost.php's structure, including the newwithTags()/withExcludedSkills()calls.
Changed
BoostConfigWriteris now format-preserving. Whenboost.phpis rewritten (e.g.boost:installre-running against an existing file), comments, blank-line layout, and unrelated formatting are preserved instead of being normalised away — the writer mutates only the nodes it must, via PHP-Parser'sprintFormatPreservingprinter.- The
Agentenum is emitted in short form (Agent::CLAUDE_CODE, not\SanderMuller\BoostCore\Enums\Agent::CLAUDE_CODE) when theboost.phpbeing written already imports the enum, so generated config matches hand-written style.
Fixed
- No more spurious self-collision warning during
composer globaloperations. boost-core's owndev-mainbranch-alias surfaced the root package as a ComposerAliasPackage, whichrunGlobalSyncthen iterated a second time — tripping the basename-collision guard against boost-core itself. Alias entries are now skipped during global sync, and the staledev-main → 0.3.x-devbranch-alias has been dropped fromcomposer.jsonentirely (a regularly-tagged plugin gains nothing from it).
Internal
- New
SkillTagFilter,SkillTagDiagnostics,FilteredSkillPruner,Enums\Tag, andConfig\BoostConfigPrinterclasses carry the feature; the tag filter runs inSyncEngine::resolveSkills()before collision resolution so only shippable skills enter resolution.
Upgrade notes
composer require sandermuller/boost-core:^0.5.0. The upgrade is hands-off — there is no migration and no behaviour change for existing installs. Tag filtering stays inert until a skill declares metadata.boost-tags and a project declares ->withTags(); until then every skill ships exactly as before. Bundle packages (sandermuller/project-boost, sandermuller/package-boost-php, sandermuller/package-boost-laravel) roll the new boost-core through transitively as they re-tag.
Note for skill publishers: tagging a skill that consumers already receive is a consumer-visible change — a project that has not declared the matching tag will stop receiving that skill on its next sync. Tag skills from the start, or treat adding a tag to a shipped skill as a breaking change for that package.
Full changelog: 0.4.0...0.5.0