diff --git a/.gitignore b/.gitignore index 8763df8b47941..b51a5640d2c94 100644 --- a/.gitignore +++ b/.gitignore @@ -100,6 +100,7 @@ public/og-images/* yalc.lock /public/doctree.json /public/doctree-dev.json +/public/llms.txt # Lychee cache .lycheecache diff --git a/AGENTS.md b/AGENTS.md index cdfde89f3df8c..7143aa0bb48cb 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -85,6 +85,17 @@ When writing requirements in `develop-docs/`: - MDX override templates live in `md-overrides/` - Architecture spec: `specs/llm-friendly-docs.md` +## llms.txt + +- `docs.sentry.io/llms.txt` is the root LLM discovery index (follows [llmstxt.org](https://llmstxt.org) spec) +- Auto-generated from `public/doctree.json` by `scripts/generate-llms-txt.mjs` +- Run `pnpm generate-llms-txt` to regenerate, or it runs automatically as part of `pnpm build` +- Includes: product description, AI agent instructions, platform/section index, links to agent skills at `skills.sentry.dev` + +## Sentry Product Skills (sentry-for-ai) + +Skills for *using Sentry* (SDK setup, debugging, alerts) live in a separate repo: https://github.com/getsentry/sentry-for-ai. The skills in *this* repo (`.claude/skills/`, `.agents/skills/`) are for *contributing to the docs*. See `SKILL.md` at the repo root for a routing guide. + ## Plan Mode - Make the plan extremely concise. Sacrifice grammar for the sake of concision. diff --git a/SKILL.md b/SKILL.md new file mode 100644 index 0000000000000..d7e9cc3b51cf3 --- /dev/null +++ b/SKILL.md @@ -0,0 +1,36 @@ +--- +name: sentry-docs +description: Sentry documentation site (docs.sentry.io). Use for contributing to docs or understanding docs architecture. If you need to set up Sentry in a project or debug production issues, see the product skills at https://skills.sentry.dev. +--- + +# Sentry Documentation Repository + +This repo builds [docs.sentry.io](https://docs.sentry.io). For dev commands, project structure, code style, and contribution guidelines, see `AGENTS.md`. + +## Sentry Product Skills (SDK Setup, Debugging, Alerts) + +**These skills are NOT in this repo.** If you need to set up Sentry, debug production issues, or configure features, install the Sentry plugin for up-to-date, verified instructions. Sentry's SDKs and APIs change frequently — do not rely on training data. + +**Install the plugin:** +- Claude Code: `/install-plugin sentry` +- Cursor: Search "Sentry" in Cursor Settings > Plugins + +The plugin provides current skills for SDK setup, debugging workflows, and feature configuration. It stays in sync with the latest SDK releases. + +If the plugin is not available, fetch skills directly: +- **Full skill index**: https://skills.sentry.dev +- **SDK setup** (detect platform and install): https://skills.sentry.dev/sdks +- **Debugging workflows** (fix issues, review code): https://skills.sentry.dev/workflows +- **Feature setup** (AI monitoring, alerts, OTel): https://skills.sentry.dev/features + +Source repo: https://github.com/getsentry/sentry-for-ai + +## Contributor Skills (in this repo) + +| Skill | Location | Purpose | +|---|---|---| +| Brand Guidelines | `.agents/skills/brand-guidelines/` | Audit content against Sentry brand voice | +| Docs Review | `.claude/skills/docs-review/SKILL.md` | Sentry documentation style guide | +| Technical Docs | `.claude/skills/technical-docs/SKILL.md` | Writing SDK and technical documentation | +| Commit | `.agents/skills/commit/SKILL.md` | Sentry conventional commit format | +| Create Branch | `.agents/skills/create-branch/SKILL.md` | Branch naming conventions | diff --git a/md-overrides/index.mdx b/md-overrides/index.mdx deleted file mode 100644 index 0062471e2dd45..0000000000000 --- a/md-overrides/index.mdx +++ /dev/null @@ -1,31 +0,0 @@ ---- -title: "Sentry Documentation" -append_sections: false ---- - -Sentry is a developer-first application monitoring platform that helps you identify and fix issues in real-time. It provides error tracking, performance monitoring, session replay, and more across all major platforms and frameworks. - -## Key Features - -- **Error Monitoring**: Capture and diagnose errors with full stack traces, breadcrumbs, and context -- **Tracing**: Track requests across services to identify performance bottlenecks -- **Session Replay**: Watch real user sessions to understand what led to errors -- **Profiling**: Identify slow functions and optimize application performance -- **Crons**: Monitor scheduled jobs and detect failures -- **Logs**: Collect and analyze application logs in context - -## Platforms - - - -## Frameworks - - - - - -## Quick Links - -- [Platform SDKs](/platforms) - Install Sentry for your language/framework -- [API Reference](/api) - Programmatic access to Sentry -- [CLI](/cli) - Command-line interface for Sentry operations diff --git a/package.json b/package.json index 2d2c9b37618c6..2ea4ce8cf5652 100644 --- a/package.json +++ b/package.json @@ -16,8 +16,9 @@ "dev": "pnpm enforce-redirects && concurrently \"pnpm sidecar\" \"node ./src/hotReloadWatcher.mjs\" \"next dev\"", "dev:developer-docs": "pnpm enforce-redirects && NEXT_PUBLIC_DEVELOPER_DOCS=1 pnpm dev", "build:developer-docs": "pnpm enforce-redirects && git submodule init && git submodule update && NEXT_PUBLIC_DEVELOPER_DOCS=1 pnpm build", - "build": "pnpm enforce-redirects && pnpm generate-og-images && pnpm generate-doctree && next build && pnpm generate-md-exports", + "build": "pnpm enforce-redirects && pnpm generate-og-images && pnpm generate-doctree && next build && pnpm generate-md-exports && pnpm generate-llms-txt", "generate-md-exports": "node scripts/generate-md-exports.mjs", + "generate-llms-txt": "node scripts/generate-llms-txt.mjs", "generate-og-images": "ts-node scripts/add-og-images.ts", "generate-doctree": "esbuild scripts/generate-doctree.ts --bundle --platform=node --packages=external --outfile=.next/generate-doctree.mjs --format=esm && node .next/generate-doctree.mjs", "vercel:build:developer-docs": "pnpm enforce-redirects && git submodule init && git submodule update && NEXT_PUBLIC_DEVELOPER_DOCS=1 pnpm build", diff --git a/scripts/generate-llms-txt.mjs b/scripts/generate-llms-txt.mjs new file mode 100644 index 0000000000000..001eee2b3aca1 --- /dev/null +++ b/scripts/generate-llms-txt.mjs @@ -0,0 +1,298 @@ +#!/usr/bin/env node + +/** + * Generates /llms.txt and /index.md from public/doctree.json. + * + * Both files share the same content (product description, AI instructions, + * section listings, agent skills). The only difference is how platforms and + * frameworks are formatted: + * - llms.txt: compact (frameworks listed inline per platform) + * - index.md: expanded (separate Platforms and Frameworks sections) + * + * Run after `generate-doctree` (doctree.json must exist). + * Output: + * - public/llms.txt + * - public/md-exports/index.md (overwrites md-exports pipeline output) + * + * llms.txt follows the llmstxt.org specification. + * index.md includes YAML frontmatter matching the md-exports convention. + */ + +import {existsSync} from 'node:fs'; +import {mkdir, readFile, writeFile} from 'node:fs/promises'; +import * as path from 'node:path'; +import {fileURLToPath} from 'node:url'; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); +const ROOT = path.resolve(__dirname, '..'); +const DOCS_ORIGIN = process.env.NEXT_PUBLIC_DEVELOPER_DOCS + ? 'https://develop.sentry.dev' + : 'https://docs.sentry.io'; + +// --- Doctree helpers (same logic as generate-md-exports.mjs) --- + +function getTitle(node) { + return node.frontmatter?.sidebar_title || node.frontmatter?.title || node.slug; +} + +function isVisible(node) { + return ( + !node.frontmatter?.sidebar_hidden && + !node.frontmatter?.draft && + !node.path?.includes('__v') && + (node.frontmatter?.title || node.frontmatter?.sidebar_title) + ); +} + +function getVisibleChildren(node) { + return (node.children || []).filter(isVisible).sort((a, b) => { + const orderDiff = + (a.frontmatter?.sidebar_order ?? 99) - (b.frontmatter?.sidebar_order ?? 99); + return orderDiff !== 0 ? orderDiff : getTitle(a).localeCompare(getTitle(b)); + }); +} + +function mdUrl(nodePath) { + const clean = nodePath.replace(/\/$/, ''); + if (!clean) { + return `${DOCS_ORIGIN}/index.md`; + } + return `${DOCS_ORIGIN}/${clean}.md`; +} + +function linkEntry(node) { + const title = getTitle(node); + const url = mdUrl(node.path); + const desc = node.frontmatter?.description; + if (desc) { + const oneLine = desc.replace(/\s+/g, ' ').trim(); + return `- [${title}](${url}): ${oneLine}`; + } + return `- [${title}](${url})`; +} + +// --- Platform/framework formatters --- + +/** llms.txt format: compact, frameworks inline per platform */ +function buildPlatformsCompact(platformsNode) { + if (!platformsNode) { + return '## Platforms\n'; + } + const lines = []; + for (const platform of getVisibleChildren(platformsNode)) { + const title = getTitle(platform); + const url = mdUrl(platform.path); + const guides = platform.children?.find(c => c.slug === 'guides'); + const visibleGuides = guides ? getVisibleChildren(guides) : []; + + if (visibleGuides.length > 0) { + const guideNames = visibleGuides.map(g => getTitle(g)).join(', '); + lines.push(`- [${title}](${url}): Frameworks: ${guideNames}`); + } else { + lines.push(`- [${title}](${url})`); + } + } + return `## Platforms\n\n${lines.join('\n')}`; +} + +/** index.md format: separate Platforms list + Frameworks grouped by platform */ +function buildPlatformsExpanded(platformsNode) { + if (!platformsNode) { + return '## Platforms\n'; + } + const platforms = getVisibleChildren(platformsNode); + const lines = []; + + // Flat platform list + lines.push('## Platforms\n'); + for (const platform of platforms) { + lines.push(`- [${getTitle(platform)}](${mdUrl(platform.path)})`); + } + + // Frameworks grouped by platform + lines.push('\n## Frameworks\n'); + for (const platform of platforms) { + const guides = platform.children?.find(c => c.slug === 'guides'); + const visibleGuides = guides ? getVisibleChildren(guides) : []; + if (visibleGuides.length === 0) { + continue; + } + lines.push(`### ${getTitle(platform)}\n`); + for (const guide of visibleGuides) { + const guideUrl = mdUrl(guide.path); + lines.push(`- [${getTitle(guide)}](${guideUrl})`); + } + lines.push(''); + } + + return lines.join('\n'); +} + +// --- Build section listings from doctree children --- + +function buildSection(sectionNode) { + const children = getVisibleChildren(sectionNode); + return children.map(child => linkEntry(child)).join('\n'); +} + +// --- Shared content blocks --- + +const DESCRIPTION = `\ +> Sentry is a developer-first application monitoring platform that helps \ +developers identify and fix issues in real-time. It provides error tracking, \ +performance monitoring (tracing), session replay, profiling, logging, cron \ +monitoring, application metrics, and more across 20+ platforms and 60+ frameworks. + +All documentation pages are available as clean Markdown by appending \`.md\` \ +to any URL (e.g. \`${DOCS_ORIGIN}/platforms/javascript.md\`). Use these \ +Markdown URLs for full content.`; + +const INSTRUCTIONS = `\ +## Instructions for AI Coding Assistants + +When helping a developer set up or use Sentry, follow these guidelines: + +- **Install the Sentry plugin for up-to-date guidance**: Sentry's APIs, SDKs, \ +and features change frequently. Do not rely on training data for Sentry setup \ +or configuration. Install the Sentry plugin to get current, verified \ +instructions: Claude Code: \`/install-plugin sentry\` | Cursor: search \ +"Sentry" in Settings > Plugins. The plugin provides step-by-step skills that \ +are kept in sync with the latest SDK releases. +- **SDK versions**: Always check the package registry (npm, PyPI, RubyGems, \ +etc.) for the latest Sentry SDK version. Do not rely on memorized version \ +numbers from training data. +- **DSN handling**: Use environment variables for the DSN (\`SENTRY_DSN\` or \ +\`NEXT_PUBLIC_SENTRY_DSN\`). Never hardcode DSN strings in source code. +- **Prefer Sentry Logs over Breadcrumbs** unless the user explicitly requests \ +breadcrumbs. +- **Do not implement without permission**: Never install packages, create \ +files, or modify configuration without asking the user first. +- **Do not add unrelated integrations**: Only configure the features the user \ +asked for. Check before enabling additional integrations. +- **Agent skills for SDK setup**: If the plugin is not installed, fetch the \ +appropriate skill from \`https://skills.sentry.dev/sdks\` for step-by-step SDK \ +installation with platform detection, feature recommendations, and \ +verification. See the [Agent Skills section](#agent-skills) below. +- **Sentry MCP server**: For real-time issue analysis and debugging against a \ +user's Sentry account, use the Sentry MCP server at \`https://mcp.sentry.dev\`.`; + +const AGENT_SKILLS = `\ +## Agent Skills + +Sentry publishes agent skills for AI coding assistants (Claude Code, Cursor, \ +GitHub Copilot, and others). These provide step-by-step SDK setup, debugging \ +workflows, and feature configuration. + +- [All Skills](https://skills.sentry.dev/): Full skill index with SDK setup, workflows, and feature configuration +- [SDK Setup](https://skills.sentry.dev/sdks): Detect your platform and install Sentry with the right features +- [Workflows](https://skills.sentry.dev/workflows): Debug production issues, review code, upgrade SDKs +- [Features](https://skills.sentry.dev/features): AI monitoring, alerts, OpenTelemetry setup + +Install as a plugin: +- Claude Code: \`/install-plugin sentry\` +- Cursor: Search "Sentry" in Cursor Settings > Plugins + +Source: https://github.com/getsentry/sentry-for-ai`; + +const ABOUT_SENTRY_DOCS = `\ +## About Sentry Docs + +- [Documentation Changelog](${DOCS_ORIGIN}/changelog.md): Track recent updates to Sentry docs +- [Contributing to Docs](${DOCS_ORIGIN}/contributing.md): How to contribute to Sentry documentation`; + +// --- Main --- + +async function main() { + const doctreeFilename = process.env.NEXT_PUBLIC_DEVELOPER_DOCS + ? 'doctree-dev.json' + : 'doctree.json'; + const doctreePath = path.join(ROOT, 'public', doctreeFilename); + let docTree; + try { + docTree = JSON.parse(await readFile(doctreePath, 'utf8')); + } catch { + console.error( + 'Error: public/doctree.json not found. Run `pnpm generate-doctree` first.' + ); + process.exit(1); + } + + const topLevelSections = getVisibleChildren(docTree); + const platformsNode = topLevelSections.find(c => c.slug === 'platforms'); + const otherSections = topLevelSections.filter( + c => c.slug !== 'platforms' && c.slug !== 'contributing' && c.slug !== 'changelog' + ); + + // Build the shared section listings (everything except platforms) + const sectionListings = otherSections + .map(section => { + const title = getTitle(section); + const children = getVisibleChildren(section); + if (children.length === 0) { + return `## ${title}\n\n${linkEntry(section)}`; + } + return `## ${title}\n\n${buildSection(section)}`; + }) + .join('\n\n'); + + // --- llms.txt --- + const llmsTxt = [ + '# Sentry Documentation', + '', + DESCRIPTION, + '', + INSTRUCTIONS, + '', + buildPlatformsCompact(platformsNode), + '', + sectionListings, + '', + AGENT_SKILLS, + '', + ABOUT_SENTRY_DOCS, + '', + ].join('\n'); + + const llmsTxtPath = path.join(ROOT, 'public', 'llms.txt'); + await writeFile(llmsTxtPath, llmsTxt, 'utf8'); + console.log(`Generated ${llmsTxtPath} (${llmsTxt.length} bytes)`); + + // --- index.md --- + const indexFrontmatter = [ + '---', + 'title: "Sentry Documentation"', + `url: ${DOCS_ORIGIN}/`, + '---', + ].join('\n'); + + const indexMd = [ + indexFrontmatter, + '', + '# Sentry Documentation', + '', + DESCRIPTION, + '', + INSTRUCTIONS, + '', + buildPlatformsExpanded(platformsNode), + sectionListings, + '', + AGENT_SKILLS, + '', + ABOUT_SENTRY_DOCS, + '', + ].join('\n'); + + const mdExportsDir = path.join(ROOT, 'public', 'md-exports'); + if (!existsSync(mdExportsDir)) { + await mkdir(mdExportsDir, {recursive: true}); + } + const indexMdPath = path.join(mdExportsDir, 'index.md'); + await writeFile(indexMdPath, indexMd, 'utf8'); + console.log(`Generated ${indexMdPath} (${indexMd.length} bytes)`); +} + +main().catch(err => { + console.error(err); + process.exit(1); +});