Your Package's AI Guidelines Probably Never Load
Earlier this year we did the obvious thing. We wrote AI guidelines for our stack and put them where they seemed to belong: inside the packages they describe. The OData rules went into the OData package, the Core rules into Core. The package that defines a contract should be the package that teaches it.
That material would never have reached a single one of our users. Not because we had written it badly. Because Laravel Boost is built to stop it.
The line that decides it
Laravel Boost lets a package ship guidelines and Agent Skills that get written into whatever coding agent you use. Which packages may do that is decided in one filter, in src/Install/ThirdPartyPackage.php. The docblock above it says what it is for:
Transitive dependencies are excluded so an indirect package cannot inject guidelines.
And the filter itself:
->filter(fn (Package $package): bool =>
$package->isDirect() && ! PackageRegistry::isFirstParty($package)
)isDirect() comes from laravel/roster, and roster reads it from the require block of the application's own composer.json. Not from the dependency tree. From the file a human wrote.
This is a security boundary, and it is a good one. A guideline is an instruction to an agent that will write code in someone's repository. Without that filter, any package anywhere in your tree could put text in front of your agent at the start of every session, four levels down, without the application ever naming it. Boost closes that at the root. Only what the application asked for by name may speak.
What it cost us
laravelui5/core requires laravelui5/odata, and our own install guide says composer require laravelui5/core. So for every reader who followed our instructions, odata is a transitive dependency.
The OData guidelines lived inside the odata package, in a version we had not tagged yet. Had we shipped it, the people who installed the stack the way we told them to would have received nothing at all. No error, no warning, no line in the output. The material was finished and could not arrive.
The check takes three minutes. Open the composer.json of an application that uses your package. If your package's name is not in the require block, your Boost material does not load. It does not load late or partially. It does not load.
This is worth a minute of anyone's time who ships more than one package. A driver behind a facade package. An engine behind a framework. A paid SDK that requires its own free core. In all three cases the package that carries the deepest knowledge is the one the application never names.
The second gate
A direct dependency is still not enough. Third-party material is opt-in.
php artisan boost:install asks "Which third-party AI guidelines/skills would you like to install?" and records the answer in the application's boost.json. On a non-interactive run the installer skips the question and returns what is already recorded there. With nothing recorded, that is an empty list. A scripted install therefore installs nothing from any third-party package, and reports success while doing it. We read this in laravel/boost v2.9.1, Console\InstallCommand::selectThirdPartyPackages().
As a complaint that is a footnote. As a consent record it is the same decision as the first filter, one level up: a human said yes once, in writing, in the repository. If your pipeline runs the installer, seed the file first.
{
"packages": ["laravelui5/chiron"]
}What we did instead
We took the guidelines out of the runtime packages and gave them a package of their own, which the application requires directly and as a dev dependency. It is called laravelui5/chiron, after the centaur who taught Achilles and never fought a battle himself. It contains no PHP at all. No service provider, no classes, nothing that runs. Boost reads it out of the vendor directory as prose.
One package that the host requires directly dissolves the delivery problem by construction. That was the reason we built it. The second reason only became visible afterwards, and it is the better one.
Guidelines want to be rewritten the week you learn what an agent keeps getting wrong. Runtime packages go out with a tag, a registry rebuild and a smoke test, because they carry contracts other people's code is compiled against. Put both on the same release line and one of them is always wrong: either the guidance waits for a release it has no business blocking, or the contract ships in a hurry it cannot afford.
The part that only works because it is separate
Once the material is its own package, it can do something a file inside a runtime package cannot. It can render against the installation it finds.
Every file Chiron ships is Blade. The guideline renders only the sections for packages that are present. The interesting case is the skill for writing a mutating action, because in our stack that contract differs by what you installed. With the SDK present it teaches the typed handler interface and the transaction the dispatcher opens around it. On a host with Core alone it teaches Core's marker interface, and the fact that Core's dispatcher opens no transaction, so atomicity is the author's job.
It never teaches both. An agent handed a contract that is not installed writes code which does not type-check, and that is worse than an agent told nothing, because the code looks right on the way in.
Skills cannot be installed conditionally, so the five that belong to the SDK carry a branch for the other case. On a Core-only host each renders a short note instead of its body: what Core offers in its place, and why the absence is a deliberate refusal rather than a gap. Four full skills and five notes for a Core host. All nine in full with the SDK.
The other half
Chiron teaches our stack. It does not teach OpenUI5, and an agent working in a UI5 application needs both. That half is covered by the UI5 MCP server, maintained by the UI5 organisation and equally free.
The two meet in a very ordinary failure. Chiron tells an agent that a UI5 library must be declared in two places, manifest.json and ui5.yaml, because missing one fails at runtime with failed to load 'library.js'. The MCP server's run_manifest_validation and run_ui5_linter are what notice when the agent forgets anyway. Instruction on one side, verification on the other. That is a loop that closes.
If you want it
composer require laravelui5/chiron --dev
php artisan boost:installTick laravelui5/chiron when the installer asks. What it contains, and what it renders on which host, is on its page.
The package is the boring half of this post. The boundary is the half worth keeping: Boost decided that instructions to your agent are part of your supply chain, and treats them that way. It was right. We just happened to be standing on the wrong side of it.