SIGN IN SIGN UP
TryGhost / Ghost UNCLAIMED

Independent technology for modern publishing, memberships, subscriptions and newsletters.

0 0 121 JavaScript

Added stateless llms.txt service with dependency injection (#28042)

ref https://github.com/TryGhost/Ghost/pull/27400

Implements the llms.txt specification for Ghost, providing
machine-readable content to AI agents and LLM tooling. The
feature is gated behind a private labs flag (llmsTxt) and the
existing llms_enabled setting, so it ships dark by default.

**Endpoints and routing**

Four routes serve the index and full-text files: /llms.txt,
/llms-full.txt, and their .well-known/ aliases. Per-entry
markdown is available at /<slug>.md via scoped suffix routes
registered directly on CollectionRouter and StaticPagesRouter,
reusing the existing entryLookup pipeline rather than a broad
regex. This preserves _respectDominantRouter, permalink
redirect handling, and all other routing features. Content
negotiation via Accept: text/markdown on canonical post/page
URLs also works, returning the same markdown with Vary: Accept
and a Content-Location header.

**Architecture**

The service layer is fully stateless — no in-memory cache, no
event listeners. Every request computes its response fresh and
relies on HTTP Cache-Control (default 1h) for CDN/proxy
caching. All dependencies are injected via factory functions
(createLlmsService, createLlmsHandler, createLlmsDiscovery)
with no module-level singleton imports; the service is created
once at boot in site.js and exposed via Express app.set().
markdown.js is a pure module with zero Ghost imports.

**Content handling**

llms-full.txt uses paginated DB queries (100 per batch) with
a 5 MiB budget to bound response size on large sites. Queries
include withRelated: ['tags', 'authors'] so the URL service
can substitute :primary_tag/:primary_author in permalink
templates. Non-public .md requests return 403 with a markdown
explanation rather than a silent 404. Discovery headers (Link
and X-Llms-Txt) are injected into all HTML responses via
on-headers middleware when the feature is enabled.

**Observability**

Handler errors are logged with structured fields ([llms]
prefix, event name, route) and forwarded to Sentry with
matching tags, following the theme upload error pattern.

Co-Authored-By: John O'Nolan <john@onolan.org>
H
Hannah Wolfe committed
1d7179f991d4ce0344e03f02230111035e620872
Parent: 96b5fe5
Committed by GitHub <noreply@github.com> on 5/28/2026, 1:09:20 PM