Skip to content

docs: add agent instructions footer to .md pages, document markdown + search API in llms.txt - #3426

Open
jannikmaierhoefer wants to merge 4 commits into
mainfrom
claude/reo-dev-docs-questions-338069
Open

docs: add agent instructions footer to .md pages, document markdown + search API in llms.txt#3426
jannikmaierhoefer wants to merge 4 commits into
mainfrom
claude/reo-dev-docs-questions-338069

Conversation

@jannikmaierhoefer

@jannikmaierhoefer jannikmaierhoefer commented Jul 29, 2026

Copy link
Copy Markdown
Member

Motivation

Agents reach our Markdown through three paths — the .md URL suffix, Accept: text/markdown negotiation, and the docs MCP getLangfuseDocsPage tool — but a page currently tells them nothing about the rest of our agent surface. An agent that lands on a page which doesn't answer its question has to guess.

Compare docs.reo.dev (GitBook), where every .md response ends with an # Agent Instructions block documenting a ?ask= RAG endpoint. That's how an agent self-discovers the capability without being told. We have the equivalent capabilities — /api/search-docs, /api/mcp, llms.txt, the agent skill, the CLI — but nothing advertises them at the point of use.

Changes

1. Agent instructions footer on every .md page — new lib/agent-instructions-footer.js, appended in scripts/copy_md_sources.js to all 953 generated pages plus the 2 md-override/ pages. It covers:

  • the .md / Accept: text/markdown convention, and this page's own Markdown URL
  • /api/search-docs with a runnable curl example
  • llms.txt and the per-section indexes
  • the docs MCP server endpoint and transport
  • install the agent skill before instrumenting; read the tracing best-practices page
  • verify parameters against api.reference.langfuse.com rather than inferring from examples
  • the CLI for programmatic access
  • don't hardcode cloud.langfuse.com — read the host from LANGFUSE_BASE_URL

2. llms.txt gains ## Markdown Access and ## Docs Search API sections — it already documented the MCP server and skill, but neither the .md convention nor /api/search-docs.

3. ## REST Endpoint [#rest-endpoint] anchor added to content/docs/docs-mcp.mdx so the new llms.txt deep link resolves.

Notes

  • The footer heading is an H2, not an H1: scripts/check-h1-headings.js walks the whole repo including public/md-src after a local build, and a second # heading would fail the check_h1 job.
  • Kept deliberately short — it's appended to ~1k pages and costs context on every fetch. The module docstring says to add a line only if it changes what an agent would do.

Verification

  • node scripts/copy_md_sources.js → 953 files + 2 overrides, each with exactly one footer
  • node scripts/check-h1-headings.js → passes across generated output
  • prettier --check → clean on all four files
  • new llms.txt block rendered and inspected (the script itself needs public/sitemap-0.xml from a full build)

🤖 Generated with Claude Code


Follow-up in this PR: PDF export fix

/api/md-to-pdf renders from public/md-src, so the footer would have shipped inside every human-facing PDF download. app/api/md-to-pdf/route.ts now strips everything from AGENT_FOOTER_MARKER onwards before parsing. Verified: 30,880 → 28,544 bytes on docs/observability/get-started.md, original ending restored, and markdown without the marker passes through untouched.

The PDF route is the only human-facing md-src consumer — the other paths (.md rewrite, Accept: text/markdown negotiation, MCP getLangfuseDocsPage) are all agent-facing and should keep the footer.

Greptile Summary

Adds agent-discovery guidance to generated Markdown documentation.

  • Appends a shared agent-instructions footer to generated and overridden Markdown pages.
  • Documents Markdown access and the documentation search API in llms.txt.
  • Adds an explicit REST endpoint anchor to the Docs MCP page.

Confidence Score: 4/5

The PR appears safe to merge, with a non-blocking documentation correction needed for the homepage Markdown URL convention.

The generated footer works for ordinary and overridden page paths, but its universal suffix instruction directs homepage consumers to /.md even though the generated root artifact is /md-src/index.md.

Files Needing Attention: lib/agent-instructions-footer.js

Prompt To Fix All With AI
### Issue 1
lib/agent-instructions-footer.js:38-40
**Homepage suffix guidance is inaccurate**

The footer says every page supports appending `.md`, but applying that convention to `https://langfuse.com/` produces `/.md`, while the generated homepage Markdown is stored as `/md-src/index.md` and the root-specific rewrite only handles `Accept: text/markdown`. This directs agents following the documented convention to a nonexistent Markdown path.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Reviews (1): Last reviewed commit: "docs: add agent instructions footer to ...." | Re-trigger Greptile

Context used:


Note

Low Risk
Build-time markdown generation and PDF preprocessing only; no auth or runtime API behavior changes beyond stripping a known HTML comment marker in PDF generation.

Overview
Adds a shared Agent Instructions footer to generated public/md-src Markdown so agents landing on a single page can discover .md access, /api/search-docs, llms.txt, the agent skill, and related guidance without guessing.

Build pipeline: New lib/agent-instructions-footer.js is appended in scripts/copy_md_sources.js for all generated pages and md-override/ copies, with privacy, cookie-policy, and imprint excluded and a post-build check that those paths still exist. llms.txt gains Markdown Access and Docs Search API sections (before MCP). docs-mcp.mdx gets a #rest-endpoint anchor for deep links.

PDF export: /api/md-to-pdf strips content from AGENT_FOOTER_MARKER onward so human PDFs do not include agent-only curl/MCP blocks.

Reviewed by Cursor Bugbot for commit 91891b7. Bugbot is set up for automated code reviews on this repo. Configure here.

…n/search in llms.txt

Agents reach our markdown through the ".md" URL suffix, Accept: text/markdown
negotiation, or the docs MCP getLangfuseDocsPage tool, but a page gives them no
way to discover the rest of our agent surface. An agent that cannot answer from
the current page has to guess.

Every generated page in public/md-src now ends with a short "Agent
Instructions" section (the pattern GitBook-hosted docs use) naming: the .md
convention, /api/search-docs for semantic search, llms.txt, the docs MCP
server, the Langfuse agent skill, the CLI, the API reference, and a warning not
to hardcode the EU region. Applied to md-override/ pages too.

llms.txt previously documented the MCP server and skill but not the .md
convention or /api/search-docs; both now have their own sections with runnable
curl examples.

The footer heading is an H2 because scripts/check-h1-headings.js walks
public/md-src after a local build and would fail on a second H1.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@dosubot dosubot Bot added the size:L This PR changes 100-499 lines, ignoring generated files. label Jul 29, 2026
@vercel

vercel Bot commented Jul 29, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
langfuse-docs Ready Ready Preview Aug 10, 2026 1:01pm

Request Review

@dosubot dosubot Bot added the docs label Jul 29, 2026
@github-actions

Copy link
Copy Markdown

@claude review

/api/md-to-pdf renders from public/md-src, so the agent instructions footer
would have appeared in every human-facing PDF download. Drop everything from
the marker onwards before parsing. The marker constant is exported from
lib/agent-instructions-footer.js so the two stay in sync.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Comment on lines +85 to +96
/**
* Append the agent instructions footer to a page's markdown. Applied to every
* generated page (including md-override/ files) so agents that land on any
* single .md page can discover the rest of the agent surface: the ".md"
* convention, /api/search-docs, llms.txt, the docs MCP server, and the skill.
* @param {string} markdown
* @param {string} destRel path relative to public/md-src, e.g. "docs/foo.md"
* @returns {string}
*/
function appendAgentInstructionsFooter(markdown, destRel) {
const footer = buildAgentInstructionsFooter(`${SITE_URL}/${destRel}`);
return `${markdown.replace(/\s*$/, "")}\n\n${footer}`;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 appendAgentInstructionsFooter() in scripts/copy_md_sources.js runs unconditionally on every generated page, so it also gets appended to public/md-src/privacy.md and cookie-policy.md, and app/api/md-to-pdf/route.ts renders that markdown straight to PDF without stripping the footer. That means the 'download as PDF' link on the Privacy Policy and Cookie Policy pages now ships end users a legal document that ends with a curl/MCP/GitHub-issue 'Agent Instructions' section. Fix by excluding marketing/legal pages from the footer in copy_md_sources.js, or stripping the AGENT_FOOTER_MARKER block in md-to-pdf/route.ts before rendering.

Extended reasoning...

This PR adds appendAgentInstructionsFooter() and calls it unconditionally inside copyAll() (scripts/copy_md_sources.js:198) for every file written to public/md-src/**, with no exclusion by content type or section. lib/content-dir-map.js maps the marketing content directory to the empty URL prefix (marketing: ""), so content/marketing/privacy.mdx and cookie-policy.mdx are written out as public/md-src/privacy.md and public/md-src/cookie-policy.md — both now carrying the new ## Agent Instructions footer (curl examples for /api/search-docs, MCP server endpoint info, agent-skill install instructions, and a "Found an error in these docs? open an issue on GitHub" line).

Both privacy.mdx and cookie-policy.mdx contain a human-facing "download as PDF" link (<a href="/api/md-to-pdf?url=/privacy.md">, similarly for cookie-policy). app/api/md-to-pdf/route.ts rewrites that URL to /md-src/<path>.md, fetches the file verbatim, strips only the YAML frontmatter block, runs stripMdxForPlainMarkdown and removeAnchorTags, and renders the remainder to HTML/PDF via marked. None of those steps recognize or strip the AGENT_FOOTER_MARKER/## Agent Instructions block, so it renders straight into the generated PDF.

Proof, step by step:

  1. scripts/copy_md_sources.js copies content/marketing/privacy.mdxpublic/md-src/privacy.md, then unconditionally calls appendAgentInstructionsFooter(processed, "privacy.md"), appending the full footer block after a --- separator.
  2. A site visitor on /privacy clicks "download as PDF", which hits /api/md-to-pdf?url=/privacy.md.
  3. The route fetches public/md-src/privacy.md verbatim, strips frontmatter only, and converts the rest (including the appended footer) to PDF.
  4. The resulting PDF — the one a user or a legal/compliance reviewer downloads as "the Privacy Policy" — ends with a section containing curl -sG "https://langfuse.com/api/search-docs" ..., MCP server connection details, a skill-install instruction, and a GitHub issue link.

Nothing crashes and the PDF still generates correctly, but the content is objectively wrong for the document type: a Privacy Policy / Cookie Policy is a legal artifact, and shipping AI-agent tooling instructions inside it is inappropriate and would look like a bug (or a copy-paste error) to any reader who scrolls to the end, including legal/compliance reviewers relying on that PDF as the canonical policy text. This is a fresh regression introduced by this PR — before it, public/md-src/privacy.md (and the PDF derived from it) was clean policy text.

The fix is small: either skip the footer for non-agent-relevant sections (e.g., only apply it under docs/integrations/self-hosting, matching the PR's own stated intent of making "the docs" self-describing for agents — the Privacy Policy is not part of that surface), or strip the AGENT_FOOTER_MARKER-delimited block in app/api/md-to-pdf/route.ts before rendering to PDF, alongside the existing frontmatter-stripping step.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Valid, and fixed in f1a9884 — though the two halves of this had different statuses.

PDF rendering was already handled in 14a33fb, pushed ~2 minutes after the commit this review ran against (1b30c45). app/api/md-to-pdf/route.ts strips everything from AGENT_FOOTER_MARKER onwards before parsing.

The .md route was still affected, which the PDF fix did not cover: https://langfuse.com/privacy.md and /cookie-policy.md still ended with "Found an error in these docs? open an issue", appended to a legal document. Taking the other suggested route for this — privacy.md, cookie-policy.md, and imprint.md now skip the footer entirely via AGENT_FOOTER_EXCLUDED_PAGES. The PDF strip stays in as a second line of defense for any page that gains a md-to-pdf link later.

I used a narrow exclusion list rather than an allowlist of docs/integrations/self-hosting, because blog/, changelog/, guides/, faq/, and content/security/** (the trust center — "is Langfuse SOC 2 compliant?") are all pages agents legitimately land on and should be able to navigate out of. changelog/ already carries its own agent notice, so it clearly belongs to the agent surface.

Added verifyFooterExclusions(), which fails the build if an entry in the set no longer matches a generated page — otherwise renaming a legal page silently turns its exclusion into a no-op and the footer creeps back. Verified it exits 1 with a clear message on a stale entry.

Result: 950 of 953 pages carry the footer; the 3 legal pages do not.

PR review flagged that the footer was appended to every generated page,
including privacy.md, cookie-policy.md, and imprint.md. A privacy policy whose
last section is curl examples, MCP connection details, and "found an error?
open a GitHub issue" reads as a copy-paste error — and privacy and
cookie-policy are the two pages that expose a "download as PDF" link.

The PDF export already strips the footer (14a33fb), which covered the PDF half
of the report, but the .md route still served it on /privacy.md and
/cookie-policy.md. These pages now skip the footer entirely; the PDF strip
stays as a second line of defense for any page that gains a PDF link later.

verifyFooterExclusions() fails the build if an entry in
AGENT_FOOTER_EXCLUDED_PAGES no longer matches a generated page, so renaming a
legal page cannot silently turn its exclusion into a no-op.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The docs MCP server is already documented in llms.txt and on /docs/docs-mcp,
and an agent reading a page through getLangfuseDocsPage does not need the page
to tell it about MCP. The region line was general SDK guidance rather than
something the footer needs to carry on every page.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

docs size:L This PR changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant