sandermuller/package-boost
Deprecated: sandermuller/package-boost is split into successors. Use package-boost-php for framework-agnostic Composer packages, package-boost-laravel for Laravel packages, or project-boost for PHP apps. Legacy 0.15.x remains for existing installs.
package-boost:doctor --fix. Runs package-boost:sync --prune --prune-orphans and package-boost:lean under the hood, then rebuilds the report from the post-fix state. Exit code is driven solely by the post-fix DoctorReport::hasIssues() — sync's prune refusal warns but exits 0, so doctor's rebuilt report is the single authoritative status source.fix outcome contract. With --fix --format=json, the payload gains an additive top-level fix object recording each category's attempted (what doctor saw pre-fix) and resolved (what actually changed). Refusals — for example sync declining to prune a Copilot file with user content — surface as { attempted: true, resolved: false }, distinguishable from a noop ({ attempted: false, resolved: false }). schema stays 1 (additive change).DoctorReport::hasIssues() previously failed on any SKILL.md frontmatter issue, including third-party vendor packages the operator can't patch. It now mirrors SyncCommand::hasHostFrontmatterIssues: only issues under host .ai/skills/ or under package-boost's own bundled resources/boost/skills/ flip exit code. Third-party vendor issues remain rendered (as warnings) but exit-zero..github/copilot-instructions.md via bare file existence — including hand-authored Copilot files without the <package-boost-guidelines> tag, where sync --prune is a no-op. The flag now requires the tag, matching SyncCommand::warnAboutLegacyCopilotInstructions. Hand-authored Copilot files are no longer flagged.Full Changelog: https://github.com/SanderMuller/package-boost/compare/0.14.0...0.15.0
Three new commands round out the package-boost toolbelt: a one-shot
doctor diagnostic, a managed-block .gitattributes writer (lean),
and a frontmatter-aware skill/guideline scaffolder (new). sync
gains --prune-orphans and a host-only SKILL.md frontmatter linter
in --check. Internal classes move under Console\Internal\ so the
public command surface is finally clearly demarcated.
package-boost:doctor command. Aggregates the checks that
were previously scattered across sync --check, install, and the
legacy / orphan warnings into a single report: configured +
effective agents, sync drift counts, SKILL.md frontmatter issues,
deselected-agent orphans, vendor skill collisions, MCP / Boost
detection, the legacy Copilot file, and the .gitattributes
managed block. Exits non-zero on any finding. --format=json emits
a stable shape (schema: 1) parseable by jq.package-boost:lean command. Idempotently writes a managed
# >>> package-boost (managed) >>> / # <<< package-boost (managed) <<< block into .gitattributes covering AI-era
export-ignore paths (.ai/, .claude/, .cursor/, .agents/,
.junie/, .kiro/, AGENTS.md, CLAUDE.md, GEMINI.md, …) so
composer archive / Packagist --prefer-dist tarballs stay lean.
User-authored entries outside the marker block are preserved
verbatim. --check fails CI on drift. The shipped lean-dist
skill teaches the validation side
(stolt/lean-package-validator); this command handles the write
side.package-boost:new command. Scaffolds .ai/skills/<name>/SKILL.md
or .ai/guidelines/<name>.md with frontmatter pre-filled.
Rejects collisions unless --force is passed, and validates the
name against the same kebab-case shape (^[a-z][a-z0-9-]*$) the
frontmatter linter enforces — a freshly scaffolded skill always
passes package-boost:doctor without further edits.sync --prune-orphans. Deletes generated artefacts for agents
that fell out of package-boost.agents: skill dirs are removed
wholesale (sync writes them in their entirety), guideline files
have just the <package-boost-guidelines> block stripped (the file
is deleted only when nothing but whitespace remains, so
user-authored content outside the block is preserved), and
.mcp.json has the laravel-boost entry removed when
claude_code is deselected. Replaces the prior warn-only
behaviour, which still ships as the default.SKILL.md frontmatter linter in sync --check. Host-authored
.ai/skills/<name>/SKILL.md files now fail --check when missing
required frontmatter (name, description) or when name /
directory disagree. Shipped and vendor skills surface the same
issues as warnings only; CI catches host issues before they ship..gitattributes managed block in this repo. Now self-hosting
package-boost:lean — the same managed block ships in this
repository's .gitattributes. stolt/lean-package-validator is
installed as a dev dep for archive validation.BoostDetector, DeselectedAgentArtifacts,
LegacyCopilotInstructions, SyncAction, SyncFormatter, SyncPlan,
SyncReporter, SyncSources, SyncWriter, plus new DoctorReport,
PackageRoot, SkillFrontmatter, and SyncPlanner, all move under
SanderMuller\PackageBoost\Console\Internal\. They were already
[@internal](https://github.com/internal) final readonly; the namespace move makes the boundary
visible at a glance. Anything outside Console\Internal\ is the
public surface..ai/skills/ source becomes useful to each tool the
moment it ships skill support — no re-author or re-sync required.boost:update deprecated alias. Hidden, deprecated alias of
package-boost:sync since 0.8.0. Anyone still invoking
boost:update should switch to package-boost:sync; the previous
release already emitted a deprecation warning on every invocation.composer update sandermuller/package-boost
vendor/bin/testbench package-boost:sync
vendor/bin/testbench package-boost:lean
vendor/bin/testbench package-boost:doctor
Re-syncing rewrites the <package-boost-guidelines> block and skill
dirs in every selected agent's directory. package-boost:lean
writes the managed .gitattributes block (idempotent — safe to
re-run). package-boost:doctor is a read-only diagnostic; run it to
surface any remaining drift in one shot.
Full Changelog: https://github.com/SanderMuller/package-boost/compare/0.13.0...0.14.0
Package-boost now treats every Composer package as in-scope, not just
Laravel packages. The shipped foundation guideline no longer asserts
"This codebase is a Laravel package" unconditionally — generated
CLAUDE.md / AGENTS.md content is correct for framework-agnostic
adopters from the first sync.
app/, semver discipline, tests-as-spec, public API discipline) are unconditional. Testbench / php artisan / laravel/boost guidance lives under ## If your package targets Laravel. After re-syncing, framework-agnostic packages stop seeing Laravel claims in their generated guideline files; Laravel-targeted packages keep all the Laravel guidance — it just lives below the new H2.### Framework-agnostic packages README subsection. Walks through the verified Testbench-as-dev-dep recipe (composer require orchestra/testbench --dev, minimal testbench.yaml with laravel: '[@testbench](https://github.com/testbench)', run sync). Notes that .mcp.json generation is skipped automatically when laravel/boost isn't installed. Calls out the package-boost:install workbench-helpers requirement so framework-agnostic adopters don't hit a silent break after sync.Console\BoostDetector (final readonly, [@internal](https://github.com/internal)). Extracts the Laravel-Boost-presence check used by MCP sync. The container-binding seam (package-boost.boost-detector) is honoured only while runningUnitTests() is true, so a stray service provider in a downstream app can't flip MCP sync on or off — production behaviour stays anchored to the package graph (class_exists(BoostServiceProvider::class, false)).package-boost:install error message rewritten. When the workbench config path can't be resolved, the command now lists three concrete recovery paths (install Testbench + re-run via vendor/bin/testbench, skip install entirely and use the zero-config "all agents" default, or hand-edit workbench/config/package-boost.php) instead of a single bare "requires Orchestra Testbench" line.## If your package targets Laravel marker and scans the framework-agnostic preamble for nine claim-shape patterns (is a laravel, targets laravel package, assume a laravel, …) — phrasing variants of the original bug class are rejected regardless of exact wording. A second test exercises the genuine laravel-boost-not-installed MCP-skip branch through the new detector seam, dodging the suite-wide stub provider that had been masking it.composer update sandermuller/package-boost
vendor/bin/testbench package-boost:sync
Re-syncing rewrites the <package-boost-guidelines> block in every
selected agent's guideline file with the new framework-neutral
foundation. No code changes required — the upgrade is generated-output
only.
Full Changelog: https://github.com/SanderMuller/package-boost/compare/0.12.0...0.13.0
skill-authoring skill — teaches the four things models routinely get wrong on a new SKILL.md: namespacing to avoid silent collisions, frontmatter that actually triggers auto-activation, the .ai/skills/ vs resources/boost/skills/ source-dir choice, and the package-boost:sync regeneration step. Documents all three real collision modes (host masks vendor, vendor masks vendor, vendor masks package-boost default) so authors can reason about precedence without reading the sync code.SyncSources behaviour. Prevents the shipped collision table from drifting from the code.ai-guidelines skill trimmed. Skill-authoring mechanics now defer to the new shipped skill; the trimmed version keeps only repo-specific dogfooding guidance and corrects the prior "commit generated files together" instruction (this repo gitignores them per release-automation).Ships a … skill bullet list had silently fallen 3 entries behind resources/boost/skills/ — ci-matrix-troubleshooting, cross-version-laravel-support, and now skill-authoring — all added.composer update sandermuller/package-boost
vendor/bin/testbench package-boost:sync
The first sync after upgrading writes the new skill-authoring skill to every selected agent's skill dir. Existing skills are unaffected.
Full Changelog: https://github.com/SanderMuller/package-boost/compare/0.11.0...0.12.0
Three new vendor-shipped skills propagate to consumer Laravel packages
via package-boost:sync, teaching maintainers how to write good README
files, GitHub release bodies, and UPGRADING.md guides.
readme skill — teaches the two README shapes (stub vs comprehensive), required sections per shape, voice, and a canonical staleness-audit pattern. Distilled from a survey of 11 well-maintained Laravel packages.release-notes skill — defaults to GitHub's auto-generated format and overrides only when major/breaking. Includes a "Bookwork to cut" list (no Internals sections, no Why-now narrative, no empty Compatibility blocks, no Test-hygiene reports).upgrading skill — per-major sections in reverse-chronological order, version-comment-labelled before/after code, stable H2 anchors that release-notes' breaking-change bullets link to. Recognises four real filename conventions (UPGRADING.md, docs/upgrading.md, etc.) without prescribing one.## Breaking changes bullets each end with [UPGRADING.md#anchor], and the host-internal pre-release skill validates the contract via a new 5d matrix row that fires on breaking releases only.references/laravel-package.md carries ecosystem conventions and is loaded advisorily when composer.json shows laravel/framework / illuminate/* / Filament / Livewire / Nova deps.composer update sandermuller/package-boost
vendor/bin/testbench package-boost:sync
The first sync after upgrading writes the three new skills (and their references/ subdirs) to every selected agent's skill dir. Existing skills are unaffected.
Full Changelog: https://github.com/SanderMuller/package-boost/compare/0.10.1...0.11.0
package-boost:install was writing the literal four characters
${indent} to the start of the rewritten 'agents' => ..., line,
producing invalid PHP in workbench/config/package-boost.php:
${indent}'agents' => ['claude_code', 'copilot'],
The preg_replace replacement string used ${indent} as a named-
group backreference, but PHP only honours positional backreferences
($1, ${1}) in preg_replace replacements — named ones are
emitted verbatim. Switched to $1 against the (now-unnamed) first
capture group; existing comments, indentation, and unrelated config
keys still survive the rewrite.
Full Changelog: https://github.com/SanderMuller/package-boost/compare/0.10.0...0.10.1
Three guideline files (CLAUDE.md, AGENTS.md, GEMINI.md) and
six unique skill dirs:
| Agent | Guidelines | Skills dir |
|---|---|---|
| Claude Code | CLAUDE.md |
.claude/skills |
| Cursor | AGENTS.md |
.cursor/skills |
| GitHub Copilot | AGENTS.md |
.github/skills |
| Codex CLI | AGENTS.md |
.agents/skills |
| Gemini CLI | GEMINI.md |
.agents/skills |
| Junie | AGENTS.md |
.junie/skills |
| Kiro | AGENTS.md |
.kiro/skills |
| OpenCode | AGENTS.md |
.agents/skills |
| Amp | AGENTS.md |
.agents/skills |
.agents/skills is shared across Codex, Gemini, OpenCode, and Amp —
sync writes there once and dedupes.
package-boost:install commandInteractive picker for the agent set:
vendor/bin/testbench package-boost:install
Defaults pre-fill in this order: existing package-boost.agents
config → import from laravel/boost's boost.json if Boost is
installed → detection-marker scan against the project (.cursor/,
.kiro/, CLAUDE.md, etc.) → all 9. The selection persists to
workbench/config/package-boost.php via a single-line regex-replace
of the 'agents' => key, preserving comments and unrelated keys.
Non-interactive flags: --all, --agents=claude_code,cursor,
--no-import. Adversarial config shapes (multi-line array, missing
key, hand-customised formatting) refuse with a clear diagnostic.
agents config key// config/package-boost.php
'agents' => null, // null = all 9; or e.g. ['claude_code', 'cursor']
Unknown agent names trigger a non-fatal warning naming each typo and
listing the supported set, so a misconfigured selection is visible
without breaking sync. When claude_code is filtered out, MCP sync
is skipped (--check reports claude-not-selected) — per-agent MCP
serializers are out of scope for this release.
.github/copilot-instructions.mdUpstream Boost migrated Copilot guidelines from
.github/copilot-instructions.md into AGENTS.md. Package-boost
matches that — the legacy file is no longer written. Sync detects
the leftover with our <package-boost-guidelines> tag block and
warns. To remove it automatically:
vendor/bin/testbench package-boost:sync --prune
--prune refuses if the file has user content outside the block,
or if the block has been hand-edited / is stale relative to
current .ai/ sources. Run a regular package-boost:sync first to
refresh the block, then --prune to clean up.
When package-boost.agents is narrowed after a previous broader
sync (for example, dropping from "all" to ['claude_code']), the
generated files for the now-deselected agents stay on disk —
.cursor/skills/, GEMINI.md, .mcp.json, etc. Sync now scans for
these and warns:
WARN Generated artifacts exist for agents NOT in `package-boost.agents`:
- .cursor/skills/ (14 entries)
- GEMINI.md (contains <package-boost-guidelines> block)
- .mcp.json (laravel-boost mcpServers entry present)
These were synced under a previous selection. Re-include the agent
or delete the paths manually.
Auto-removal is intentionally not done — guideline files may carry user content outside the package-boost-guidelines block. Surface and let the user decide.
claude-not-selected skip reason--format=json adds a stable shape for the gated MCP case:
{ "mcp": { "action": "skipped", "reason": "claude-not-selected" } }
Joins the existing laravel-boost-not-installed reason. The
schema's skipped semantics are unchanged; only the reason
identifier is new.
.github/copilot-instructions.md is no longer written. Existing
consumers will see a warning on the next sync; clean up via
package-boost:sync --prune or by deleting the file manually. No
config or API change is required — Copilot reads AGENTS.md now,
which package-boost has been writing alongside CLAUDE.md since
0.7.0.
Agents\Registry is the single source of truth for agent paths,
detection markers, and selection filtering. The 9 entries are
frozen against laravel/boost@8ed9f84 (verified by direct source
read of src/Install/Agents/* and src/BoostManager.php:22-32).Agents\BoostImporter reads boost.json at the project root,
filters against the registry, returns null for missing /
malformed / unknown-only inputs.Console\DeselectedAgentArtifacts enumerates orphans across
skills, guidelines, and MCP for the warning above.Console\LegacyCopilotInstructions owns the legacy-file detect /
prune contract, with the prune-safety check that compares the
file's tag block to the freshly composed expected block.SyncCommand's class cognitive complexity stays under PHPStan's
budget by extracting the post-categories rendering and final-exit
decisions into named helpers.Full Changelog: https://github.com/SanderMuller/package-boost/compare/0.9.0...0.10.0
Discovers skills and guidelines shipped by sibling packages.
package-boost:sync now walks vendor/*/*/resources/boost/ and
merges contributions between the shipped defaults and the host's
.ai/. First native path that doesn't rely on Laravel Boost's
Composer resolver, sidestepping the testbench-skeleton discovery
bug that blocks Boost's own scan under package development.
Any installed Composer package that ships
resources/boost/skills/<name>/SKILL.md or
resources/boost/guidelines/*.md is now picked up by
package-boost:sync automatically. Load order:
vendor/name).ai/For skills, later entries override earlier ones on name
collisions — host/.ai/skills/<name> always wins over a vendor
skill of the same name. For guidelines, each source
contributes its own block and they concatenate in load order,
separated by ---.
This means a package author can ship, for example, a
resources/boost/skills/fluent-validation-testing/SKILL.md
bundled with their library, and downstream consumers running
package-boost:sync will pick it up in their .claude/skills/
and .github/skills/ directories alongside their own content —
no extra wiring, no manual copy.
Two new keys in config/package-boost.php, both shipped with
sensible defaults so existing consumers see the behavior
activate on composer update with no publish step required:
'discover_vendor_packages' => true,
'excluded_vendor_packages' => [
'sandermuller/package-boost',
],
discover_vendor_packages — toggle off to restore 0.8.x
behavior (shipped + host .ai/ only). No consumer has asked
for this yet; the flag exists as an escape hatch.excluded_vendor_packages — skip specific packages by
vendor/name. Default excludes package-boost itself so a
transitively-installed copy can't double-ingest shipped
content through its own resources/boost/.Beyond the configurable exclude list, SyncSources::vendorDirs()
realpath-compares each vendor match against the shipped
resources/boost/<kind> directory and drops exact matches. This
is structural, not user-tunable — so even a consumer who
deliberately clears excluded_vendor_packages can't double-
ingest shipped skills through a symlinked dev checkout or a
transitive dep surfacing package-boost under its own vendor/
tree.
Laravel Boost's upstream package discovery reads
base_path('composer.json'), which under Testbench resolves to
the testbench-core skeleton with no require entries. That
means resources/boost/{skills,guidelines}/ content shipped by
third-party packages is invisible to Boost itself when run via
vendor/bin/testbench boost:install inside a package repo.
Package Boost's shipped-bundling approach (0.3.3+) carried
package-boost's own skills through this gap. Vendor discovery
(0.9.0) extends the same idea to arbitrary packages — any
dependency that ships resources/boost/ gets surfaced, whether
Boost is installed or not.
composer update sandermuller/package-boost
vendor/bin/testbench package-boost:sync
The first sync after upgrading may add skills or guidelines
contributed by your existing dependencies. Review the generated
.claude/skills/ / .github/skills/ / guideline blocks; if a
vendor contribution isn't wanted, add its vendor/name to
excluded_vendor_packages in a published config file.
If you previously relied on your .ai/skills/<name> containing
the only copy of a given skill name, behavior is unchanged —
host .ai/ still wins on collisions.
No breaking changes. No schema changes to --format=json
output — vendor contributions flow through the existing
skills / guidelines arrays indistinguishably from shipped
and host entries, so CI gates on the JSON drift report continue
to work.
Config file additions are forward-compatible: consumers on a
published 0.8.x package-boost.php keep working because
applyUserConfigOverrides uses array_replace (missing keys
retain shipped defaults).
SyncSources::vendorDirs() globs
vendor/*/*/resources/boost/<kind> with GLOB_ONLYDIR, sorts
by vendor/name, and filters via exclude list + realpath
guard.SyncSources::dirs() sequence between shipped and host
.ai/, so all of planSkills, planGuidelines, and
--check drift detection work without modification.tests/SyncCommandTest.php:
discovery, host-wins-on-collision, guideline merge,
--check drift reporting, discover_vendor_packages=false,
excluded_vendor_packages respect, and the self-mirror
realpath guard. Total suite: 53 passing, 184 assertions.Hygiene release. No code changes, no schema changes. Ships the repo housekeeping that accumulated since 0.8.0 — nothing here requires downstream action.
New Composer auto-sync hook section in the README under Composer
script, documenting three variants that pair well with the 0.4.0
--check gate:
[@php](https://github.com/php) vendor/bin/testbench package-boost:sync --check as a post-autoload-dump entry. Fails
the install if anything drifted.--check; friendlier but
leaves uncommitted changes on a dirty branch.--check --skills --guidelines so Boost-less packages don't see the "Laravel Boost
is not installed" warn on every composer run (direct response to
the js-store peer's 0.8.0 verification feedback).Cross-platform note: the hook form works on both posix (/bin/sh)
and Windows (cmd.exe). Chained shell operators (&&, ||) are
not portable across composer's shell layers — use separate array
entries if you need multiple steps.
Cross-linked from the shipped package-development skill's
Syncing section so discoverability works both from the README and
from the skill bundle downstream users see.
CHANGELOG.mdCHANGELOG.md now lives at the repo root, auto-maintained by a new
.github/workflows/update-changelog.yml workflow. On each published
GitHub release the workflow prepends the release body to
CHANGELOG.md and commits back to main via
stefanzweifel/changelog-updater-action. Seeded with entries from
v0.4.0 through v0.8.0.
README now links to CHANGELOG.md between How It Differs and
License.
README header carries four badges matching the sibling package's
style: Packagist version, test workflow status, code-style workflow
status, Laravel compatibility. Existing content-only badge (Laravel
Compatibility) updated to ?style=flat for visual consistency.
.ai/guidelines/ and .ai/skills/ are now committed:
release-automation (explains the
CHANGELOG.md automation), verification-before-completion
(evidence-before-claims rule, mirrored from laravel-fluent-
validation with a preamble note pointing at the canonical copy).ai-guidelines, backend-quality, bug-fixing,
code-review, codex-review, evaluate, implement-spec,
pr-review-feedback, pre-release, write-spec — 10 workflow
skills carried over from the sibling, adapted where they
referenced fluent-validation internals (backend-quality's
benchmark group → rector; bug-fixing's FluentRule example →
SyncCommand fixture; pr-review-feedback's GraphQL repo name;
pre-release rewritten for package-boost's matrix). The
autoresearch skill was deliberately skipped — its premise is
autonomous perf-optimization with a benchmark harness, which
package-boost doesn't have.testbench.yaml is now committed (previously gitignored) so
contributors can run vendor/bin/testbench package-boost:sync
without manual setup.
Generated outputs (CLAUDE.md, AGENTS.md, .github/copilot- instructions.md, .claude/skills/, .github/skills/) remain
gitignored — the sync-command tests exercise those exact filesystem
paths and would clobber any committed copies every pest run. Run
sync locally after composer install.
tests/SyncCommandTest.php::wipeArtifacts() now targets only
test-created fixtures (test-skill, keep-me, stale-skill,
test.md) so committed .ai/ content survives the suite. One test
(it ships foundation guideline even without a user .ai/guidelines directory) renames-and-restores the dogfood guidelines dir to
exercise the no-user-guidelines path that downstream consumers hit
before authoring their own content.
composer update sandermuller/package-boost
Nothing changes at runtime. Consumers see the README additions and
the new CHANGELOG.md link on the next visit to the repo.
If you want the auto-sync hook in your own package, add the
relevant post-autoload-dump variant from the README to your
package's composer.json scripts block.
No breaking changes. No schema changes. No config schema changes. Text and JSON sync output byte-compatible with 0.8.0.
Hygiene release. Ships a deprecation alias for the command name that keeps showing up in stale skill bundles.
Closes a silent-drift hole in --check that affected any consumer
on a filesystem without symlink support (Windows-without-dev-mode,
some sandboxed CI runners). Before 0.7.0, SyncCommand::linkOrCopy
fell back to a recursive file copy when [@symlink](https://github.com/symlink)() failed — and
every subsequent --check reported those copied skill directories
as unchanged regardless of whether the shipped skill's content
had drifted. CI passed, local content was stale, nobody knew.
Documentation-only release. Pins the --format=json schema-v1
contract ahead of the first downstream CI integration (landing in
laravel-fluent-validation v1.13) — locks the shape so future
consumers don't have to guess what fields mean or hit the same
mcp-as-array foot-gun as the pre-integration peer review caught.
Structured output for package-boost:sync. CI scripts and release
automation can now parse drift detection results instead of regex-
matching glyph lines. Directly requested by the
laravel-fluent-validation peer after 0.4.0's --check landed;
deferred two releases while the trigger-word skills (0.5.0) shipped
first.
Shipped content release — driven by real feedback from two downstream
peers (laravel-fluent-validation, laravel-js-store) running
package-boost 0.3–0.4 in anger. Two new skills land, the foundation
stops assuming Pest-first, and Boost-specific commands move into
their own table so PHPUnit-only and Boost-less packages stop reading
dead copy.
Cosmetic follow-up to 0.4.0: the MCP: section of package-boost:sync
output now emits a total: ... summary line matching the Skills and
Guidelines sections.
Two major additions driven by real-world feedback from users running
package-boost against their packages: a CI drift-check mode and
per-target delta output on every sync. Also hardens .mcp.json
handling against malformed input.
--check mode for CIvendor/bin/testbench package-boost:sync --check
Computes planned actions, writes nothing, exits non-zero if any skill,
guideline, or MCP target diverges from its source. Use in CI to catch
commits where .ai/* content was edited but the generated files
(.claude/, .github/, CLAUDE.md, AGENTS.md, .mcp.json)
weren't re-synced.
Combines with the subcommand flags:
vendor/bin/testbench package-boost:sync --check --guidelines
Every sync now shows a per-target line for changes, with glyphs and a per-category summary:
Skills:
+ .claude/skills/package-development
+ .github/skills/package-development
total: 2 new, 0 unchanged
Guidelines:
~ CLAUDE.md (+12 lines)
~ AGENTS.md (+12 lines)
~ .github/copilot-instructions.md (+12 lines)
total: 3 updated
MCP:
= .mcp.json (unchanged; not listed)
Glyphs:
| glyph | meaning |
|---|---|
+ |
new — target doesn't exist yet |
~ |
updated — content or symlink target differs |
- |
removed — stale target no longer in sources |
= |
unchanged — hidden by default, counted in summary |
Skill updates annotate the new symlink target:
~ .claude/skills/package-development (symlink → ../../vendor/sandermuller/package-boost/resources/boost/skills/package-development)
Guideline updates show line-delta:
~ CLAUDE.md (+12 lines)
--show-unchanged flagvendor/bin/testbench package-boost:sync --show-unchanged
Default output is compact — unchanged targets are folded into
total: ... rather than listed per line, to avoid flooding large
guideline trees. Pass --show-unchanged to print every = entry
for debugging. Explicit flag name chosen over -v / --verbose
because Symfony already owns those for log verbosity.
.mcp.json hardeningPrevious versions assumed .mcp.json was always valid and
mcpServers was always an array. v0.4.0 survives:
null, invalid JSON, or scalar roots ("hello", 42) — treated
as empty config.mcpServers being a scalar — coerced to array before adding the
laravel-boost entry.Four regression tests guard these paths.
composer update sandermuller/package-boost
vendor/bin/testbench package-boost:sync
Add a drift check to CI. Example GitHub Actions step:
- name: Check package-boost sync
run: vendor/bin/testbench package-boost:sync --check
Downstream --check will report drift on the first run after upgrade:
CLAUDE.md, AGENTS.md,
.github/copilot-instructions.md all pick up the runner-agnostic
row, new sub-table, trimmed Cross-Version section..claude/skills/package-development/SKILL.md and
.github/skills/package-development/SKILL.md pick up the Authoring
guidelines section + the Cross-Version trim + the table reshape..claude/skills/cross-version-laravel-support/
and .claude/skills/ci-matrix-troubleshooting/ appear (plus their
.github/skills/ mirrors).Expected one-time re-sync.
SHIPPED_SKILLS constant so each new shipped
skill gets automatic coverage via a Pest dataset-driven test.
No more per-skill test-count drift.ROADMAP.md + specs/ directory in the repo as the plan
of record for 0.5.x / 0.6.x / 0.7.x work.SyncReporter — pure functions for planning actions
(planSkillAction, planGuidelineAction, planMcpAction),
rendering glyphs, line-delta computation, and relative-path
calculation. No side effects, fully unit-testable.SyncSources — shipped-then-user directory iteration for
skills and guidelines, plus safe .mcp.json reading that handles
malformed input.SyncCommand shrunk to orchestration + IO; class cognitive
complexity stays under the project's guardrail.array_any() (PHP 8.4-only) usage replaced with a
collection-based drift check — was failing the CI matrix's
PHP 8.2 / 8.3 cells before the fix landed.storage/logs/ now gitignored; a test-generated laravel.log
had been accidentally committed in a prior release and
un-tracked.Before (0.4.0):
Skills:
total: 24 unchanged
Guidelines:
total: 3 unchanged
MCP:
After (0.4.1):
Skills:
total: 24 unchanged
Guidelines:
total: 3 unchanged
MCP:
total: 1 unchanged
The three categories now render uniformly. --show-unchanged still
controls whether the per-target = .mcp.json line is printed
alongside the summary.
--format=json: structured output for CI parsing. Tracked for
a follow-up; current stdout diff is enough for most CI gates via
exit code.No breaking changes. Existing CI jobs that run
vendor/bin/testbench package-boost:sync without flags continue to
work; they now produce delta output alongside the previous "Synced …"
info lines.
How can I help you explore Laravel packages today?