silarhi/llms-txt-bundle
A Symfony bundle that automatically generates an llms.txt file for your site, exposing a clean, markdown-based index of your key pages and documentation so large language models can discover and understand your content.
llms.txt surface at all. This bundle automates generation of an llms.txt file (the emerging convention for telling LLM crawlers/answer engines what your site contains) directly from route metadata. It turns an open "should we do AEO/GEO?" question into a small, reversible build./llms.txt request and caches only the routes carrying the llms_txt option alongside the compiled routes (invalidated with them; cache:warmup writes it). Measured: 15.9 ms → 1.8 ms (~9×) at 1,000 attribute routes, 720 ms → 19 ms (~38×) at 10,000. If a previous objection was "our route table is huge," that objection is now weak.cache:warmup and works with a read-only build directory — this unblocks adoption in immutable/containerized deployments (Docker, Kubernetes, read-only release artifacts), which is often the real blocker for build-time-cached features.discovery.link_header (emitting a Link header) is off by default and now requires opting into symfony/web-link. That's a deliberate, costed choice per property rather than a default-on behavior.llms.txt content, and teams already annotating routes with attributes.One framing correction worth carrying into any stakeholder doc: the release data describes a Symfony bundle (silarhi/llms-txt-bundle, %kernel.build_dir%, cache:warmup, Twig preload()/link()), not a Laravel package. Treat this as a Symfony-ecosystem option; a Laravel codebase would need a Laravel-specific equivalent or a static file.
Consider it when:
llms_txt route option (attribute-based routing). The whole value proposition depends on annotating routes.cache:warmup; the feature now fits that pipeline cleanly.link_header off by default, no runtime coupling, easy to remove.Look elsewhere when:
llms.txt committed to the repo. That's cheaper until content churn makes generation worthwhile.llms.txt is a different, still-unstandardized artifact; don't let it stand in for that work.llms.txt convention is not ratified by all LLM vendors; budget this as a cheap hedge, not a strategic commitment.Upgrade caveats before you bump to v1.3.0:
symfony/web-link is now an optional dependency and no longer ships with the bundle. If your app calls preload() / link() / AbstractController::addLink() and was relying on it transitively, add it explicitly or the container build will fail.link_header without symfony/web-link fails at container build time, not at runtime — a build-pipeline failure, so catch it in CI rather than in production.llms_txt option still fails the /llms.txt request, not cache:warmup. Warmup will not surface bad configuration — add a smoke check for /llms.txt to your deploy verification.To executives: This is a low-cost, reversible bet on AI-driven discovery. Answer engines and coding assistants increasingly look for a machine-readable summary of a site; this bundle generates one from metadata we already maintain, so it stays in sync instead of rotting like a hand-written file. The latest release removes the main reason to hesitate — it is now roughly 9–38× faster at scale (sub-20 ms even at 10,000 routes) and works in our read-only container builds. No new dependencies, no default-on surface area, easy to switch off.
To engineering: Small Symfony bundle; v1.3.0 replaces per-request route-collection scanning with a cached list of only the opted-in routes, stored next to the compiled routes and invalidated with them, written by cache:warmup. Read-only build dirs are supported. Two things to action: (1) symfony/web-link is now optional — require it explicitly if we use WebLink anywhere or if we enable link_header, otherwise the container build fails; (2) invalid route options fail the request rather than warmup, so add a deploy-time check on /llms.txt. Note this is Symfony, not Laravel — if the target app is Laravel, this assessment doesn't transfer.
Risk posture: Opt-in per route, link_header off by default, no runtime coupling, trivially removable. The only real exposure is the dependency change at upgrade time, which CI will catch.
How can I help you explore Laravel packages today?