From 991e393b784e8fcf1e63d7576df992b2b3c0c851 Mon Sep 17 00:00:00 2001 From: Portal Code Bot Date: Wed, 19 Nov 2025 15:35:39 +0000 Subject: [PATCH 1/7] docs(ai): add consolidated AI tools page, Kapa guidance, and prose updates --- docusaurus/docs/ai-tools.md | 58 +++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 docusaurus/docs/ai-tools.md diff --git a/docusaurus/docs/ai-tools.md b/docusaurus/docs/ai-tools.md new file mode 100644 index 0000000000..d01416f500 --- /dev/null +++ b/docusaurus/docs/ai-tools.md @@ -0,0 +1,58 @@ +--- +title: AI tools in Strapi docs +description: One place to discover and use all AI-related helpers available on the Strapi documentation site. +tags: +- ai +- llms +- productivity +toc_max_heading_level: 3 +--- + + +Use this page to quickly find and use AI helpers across the Strapi docs: copy a page’s Markdown, open a chat prefilled with context, or download purpose‑built summaries for LLMs. + + +# AI tools in Strapi docs + +Strapi documentation includes a few AI‑oriented helpers designed to make it easier to ask questions about the docs, learn from code examples, and share focused context with an assistant. + +All AI options live in the AI toolbar at the top of each documentation page. From there, you can copy the current page as raw Markdown, open a new chat in your preferred assistant with the page prefilled as context, or open purpose‑built text files tailored for LLMs. + +Use Copy Markdown when you want an assistant to reason over the exact source of the page you are reading. This copies the raw Markdown to your clipboard so you can paste it into a chat or IDE assistant. + +When you need site‑wide context, prefer one of the LLMs files: +- LLMs.txt provides a concise, link‑rich overview of pages. Open `/llms.txt` to get a lightweight map of the docs that you can copy or share with an assistant as high‑level context. +- LLMs-full.txt contains the entire documentation in a single file. Open `/llms-full.txt` when full‑site context is required. The file is large. +- LLMs-code.txt extracts all code examples, grouped by page and section with language and file‑path hints. Open `/llms-code.txt` for code‑centric work (migrations, refactors, API discovery). Pair examples with their page URL for best results. + +To start a conversation without copy‑pasting, use the Open with LLM buttons in the toolbar. “Open with ChatGPT” and “Open with Claude” open a new tab and prefill a brief prompt that references the current page (often in your browser language). This is the fastest way to ask, “Read this page so I can ask questions about it.” + +## Tips for better results + +- Include the page URL: Reference the exact page (and section anchor, if relevant) so the assistant grounds its answer. +- Be explicit about Strapi version: Mention Strapi v5 (or your version) and plugin versions to avoid outdated code. +- Pair examples with context: If you share a code snippet from `/llms-code.txt`, also link the page it comes from. +- Ask for “explain first, then propose”: Request an explanation of the docs’ guidance before asking for code. + +## Guidance for IDE AI tools (Cursor, Copilot, etc.) + +If your IDE assistant struggles to generate correct Strapi code (for example, custom backend code or plugin services): + +- Start from docs: Provide the assistant with the page URL and a relevant code example from `/llms-code.txt`. +- Clarify the goal and constraints: Describe your use case, expected inputs/outputs, and that you are targeting Strapi v5. +- Prefer public extension points: Ask for solutions using documented APIs (controllers, services, middlewares, policies, and plugin extension points) instead of relying on private internals. +- Verify against the docs: Ask the assistant to cite the pages or sections it relied on. + +Related request: see the discussion about improving AI outcomes with Strapi code generation in the issue tracker. + +## Kapa chatbot + +The Strapi docs include an integrated Kapa chatbot to help you explore topics and code examples without leaving the page. + +- Sidebar entry point: Click Ask AI in the left sidebar (next to search) to open the Kapa panel and start a conversation about anything in the docs. +- Code‑block entry point: Hover any substantial code block and click Ask AI to ask for an explanation or adaptation of that snippet. +- Deep thinking mode: For more thorough answers, enable Kapa’s deep thinking mode (slower, but better for multi‑step reasoning or complex refactors). + +:::info Privacy note +When you copy or share documentation content with third‑party tools, ensure you handle data safely and follow your organization’s policies. +::: From e8bb0d08fffdd2aea67746dda0f8b0c97c4ef112 Mon Sep 17 00:00:00 2001 From: Portal Code Bot Date: Thu, 20 Nov 2025 09:19:56 +0000 Subject: [PATCH 2/7] Add AI tools sidebar link to CMS/Cloud and polish ai-tools page wording --- docusaurus/docs/ai-tools.md | 4 ++-- docusaurus/sidebars.js | 19 ++++++++++++++----- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/docusaurus/docs/ai-tools.md b/docusaurus/docs/ai-tools.md index d01416f500..261fe18ff8 100644 --- a/docusaurus/docs/ai-tools.md +++ b/docusaurus/docs/ai-tools.md @@ -9,14 +9,14 @@ toc_max_heading_level: 3 --- -Use this page to quickly find and use AI helpers across the Strapi docs: copy a page’s Markdown, open a chat prefilled with context, or download purpose‑built summaries for LLMs. +Use this page to quickly find and use AI helpers across the Strapi docs: copy a page’s Markdown, open a chat prefilled with context, or retrieve purpose‑built text files for LLMs. # AI tools in Strapi docs Strapi documentation includes a few AI‑oriented helpers designed to make it easier to ask questions about the docs, learn from code examples, and share focused context with an assistant. -All AI options live in the AI toolbar at the top of each documentation page. From there, you can copy the current page as raw Markdown, open a new chat in your preferred assistant with the page prefilled as context, or open purpose‑built text files tailored for LLMs. +All AI options live in the AI toolbar at the top of each documentation page. From there, you can copy the current page as raw Markdown, open a new chat in your preferred assistant with the page prefilled as context, or open text files tailored for LLMs. Use Copy Markdown when you want an assistant to reason over the exact source of the page you are reading. This copies the raw Markdown to your clipboard so you can paste it into a chat or IDE assistant. diff --git a/docusaurus/sidebars.js b/docusaurus/sidebars.js index 03b7a41e58..10450b7ee6 100644 --- a/docusaurus/sidebars.js +++ b/docusaurus/sidebars.js @@ -15,11 +15,13 @@ /** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */ const sidebars = { cmsSidebar: [ - // { - // type: 'html', - // value: ' Docs Contribution Program', // The HTML to be rendered - // defaultStyle: true, // Use the default menu item styling - // }, + { + // Prominent entry for AI-related helpers + type: 'html', + value: ' AI tools in docs', + defaultStyle: true, + className: 'sidebar-ai-tools', + }, { // Getting Started type: 'category', @@ -548,6 +550,13 @@ const sidebars = { ], cloudSidebar: [ + { + // Prominent entry for AI-related helpers + type: 'html', + value: ' AI tools in docs', + defaultStyle: true, + className: 'sidebar-ai-tools', + }, { // Getting Started type: 'category', From 5ae02b2fb4440580bbfe3456bacea60d97c02a25 Mon Sep 17 00:00:00 2001 From: Portal Code Bot Date: Thu, 20 Nov 2025 09:24:58 +0000 Subject: [PATCH 3/7] AI tools page: add crosslink to Strapi AI admin panel settings --- docusaurus/docs/ai-tools.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docusaurus/docs/ai-tools.md b/docusaurus/docs/ai-tools.md index 261fe18ff8..be6245708c 100644 --- a/docusaurus/docs/ai-tools.md +++ b/docusaurus/docs/ai-tools.md @@ -53,6 +53,8 @@ The Strapi docs include an integrated Kapa chatbot to help you explore topics an - Code‑block entry point: Hover any substantial code block and click Ask AI to ask for an explanation or adaptation of that snippet. - Deep thinking mode: For more thorough answers, enable Kapa’s deep thinking mode (slower, but better for multi‑step reasoning or complex refactors). +For admin‑panel AI features and settings, see the Strapi AI section of the Admin panel configuration page: /cms/configurations/admin-panel#strapi-ai. + :::info Privacy note When you copy or share documentation content with third‑party tools, ensure you handle data safely and follow your organization’s policies. ::: From f6583e086f1b925225f2b15dcf3b5e9fbf56b763 Mon Sep 17 00:00:00 2001 From: Pierre Wizla Date: Thu, 20 Nov 2025 14:08:59 +0000 Subject: [PATCH 4/7] [experimental] Use customFields.aiToolsPath and reference it in both sidebars HTML links --- docusaurus/docusaurus.config.js | 6 ++++++ docusaurus/sidebars.js | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/docusaurus/docusaurus.config.js b/docusaurus/docusaurus.config.js index 31ad315373..e6cdf261f5 100644 --- a/docusaurus/docusaurus.config.js +++ b/docusaurus/docusaurus.config.js @@ -17,6 +17,12 @@ const config = { onBrokenAnchors: 'throw', favicon: 'https://strapi.io/assets/favicon-32x32.png', + // Custom fields used across the site (kept minimal and documented) + customFields: { + // Centralized path for the AI tools page so we can reference it from multiple places + aiToolsPath: '/ai-tools', + }, + // Even if you don't use internalization, you can use this field to set useful // metadata like html lang. For example, if your site is Chinese, you may want // to replace "en" with "zh-Hans". diff --git a/docusaurus/sidebars.js b/docusaurus/sidebars.js index 10450b7ee6..02928580a1 100644 --- a/docusaurus/sidebars.js +++ b/docusaurus/sidebars.js @@ -18,7 +18,7 @@ const sidebars = { { // Prominent entry for AI-related helpers type: 'html', - value: ' AI tools in docs', + value: ` AI tools in docs`, defaultStyle: true, className: 'sidebar-ai-tools', }, @@ -553,7 +553,7 @@ const sidebars = { { // Prominent entry for AI-related helpers type: 'html', - value: ' AI tools in docs', + value: ` AI tools in docs`, defaultStyle: true, className: 'sidebar-ai-tools', }, From 0c5af6a8cad09e76376cad1b397e7862feb38e01 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Fri, 21 Nov 2025 09:27:06 +0000 Subject: [PATCH 5/7] docs(sidebar): add AI options HTML entry via const and insert into CMS sidebar --- docusaurus/sidebars.js | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/docusaurus/sidebars.js b/docusaurus/sidebars.js index 02928580a1..01f36282b6 100644 --- a/docusaurus/sidebars.js +++ b/docusaurus/sidebars.js @@ -12,16 +12,28 @@ // @ts-check +/** + * Custom HTML sidebar entries + * Using const for reuse and easier maintenance + */ +const AI_OPTIONS_HTML = { + type: 'html', + // Link into the existing Strapi AI section until a dedicated page exists + value: + ' AI options', + defaultStyle: true, +}; + /** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */ const sidebars = { cmsSidebar: [ - { - // Prominent entry for AI-related helpers - type: 'html', - value: ` AI tools in docs`, - defaultStyle: true, - className: 'sidebar-ai-tools', - }, + // Quick entry for AI options + AI_OPTIONS_HTML, + // { + // type: 'html', + // value: ' Docs Contribution Program', // The HTML to be rendered + // defaultStyle: true, // Use the default menu item styling + // }, { // Getting Started type: 'category', @@ -550,13 +562,6 @@ const sidebars = { ], cloudSidebar: [ - { - // Prominent entry for AI-related helpers - type: 'html', - value: ` AI tools in docs`, - defaultStyle: true, - className: 'sidebar-ai-tools', - }, { // Getting Started type: 'category', From dc551d387c38ce5d343bdfe60552152462bc253a Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Fri, 21 Nov 2025 10:13:39 +0000 Subject: [PATCH 6/7] ci: strip any 'auto-generated by AI' type labels on PRs and prevent future use --- .../workflows/prevent-ai-generated-label.yml | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 .github/workflows/prevent-ai-generated-label.yml diff --git a/.github/workflows/prevent-ai-generated-label.yml b/.github/workflows/prevent-ai-generated-label.yml new file mode 100644 index 0000000000..bf7a93813c --- /dev/null +++ b/.github/workflows/prevent-ai-generated-label.yml @@ -0,0 +1,53 @@ +name: Prevent "auto-generated by AI" label on PRs + +on: + pull_request: + types: [opened, edited, synchronize, labeled] + +permissions: + contents: read + pull-requests: write + +jobs: + strip-label: + runs-on: ubuntu-latest + steps: + - name: Remove forbidden AI label if present + uses: actions/github-script@v7 + with: + script: | + const forbiddenLabels = [ + 'auto-generated by AI', + 'AI-generated', + 'ai generated', + 'auto generated by ai', + 'generated by ai', + ].map(l => l.toLowerCase()); + + const pr = context.payload.pull_request; + if (!pr) { + core.info('No pull_request context; skipping'); + return; + } + + const prNumber = pr.number; + const existing = (pr.labels || []).map(l => l.name.toLowerCase()); + const toRemove = existing.filter(l => forbiddenLabels.includes(l)); + + if (toRemove.length === 0) { + core.info('No forbidden labels to remove.'); + return; + } + + for (const label of toRemove) { + core.info(`Removing label '${label}' from PR #${prNumber}`); + await github.rest.issues.removeLabel({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: prNumber, + name: label, + }).catch(() => {}); + } + + core.setOutput('removed', toRemove.join(',')); + From 0ae1040932cd15e82432c9602f10fcf601b614e9 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Fri, 21 Nov 2025 10:15:23 +0000 Subject: [PATCH 7/7] ci: add manual workflow to bulk-remove AI-generated labels from PRs (with dry-run) --- .github/workflows/remove-ai-labels.yml | 100 +++++++++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 .github/workflows/remove-ai-labels.yml diff --git a/.github/workflows/remove-ai-labels.yml b/.github/workflows/remove-ai-labels.yml new file mode 100644 index 0000000000..5302963578 --- /dev/null +++ b/.github/workflows/remove-ai-labels.yml @@ -0,0 +1,100 @@ +name: Bulk remove AI-generated labels from PRs + +on: + workflow_dispatch: + inputs: + state: + description: "PR state to process (open|closed|all)" + default: "all" + required: true + days: + description: "Lookback window in days for closed PRs (ignored for open)" + default: "120" + required: true + labels: + description: "Comma-separated labels to remove (case-insensitive)" + default: "auto-generated by AI,AI-generated,ai generated,auto generated by ai,generated by ai" + required: true + dry_run: + description: "If true, only logs matches without removing" + default: "false" + required: true + +permissions: + contents: read + pull-requests: write + +jobs: + scrub: + runs-on: ubuntu-latest + steps: + - name: Remove labels from PRs + uses: actions/github-script@v7 + with: + script: | + const state = core.getInput('state'); + const days = parseInt(core.getInput('days'), 10) || 120; + const dryRun = /^true$/i.test(core.getInput('dry_run')); + const labels = core.getInput('labels') + .split(',') + .map(s => s.trim().toLowerCase()) + .filter(Boolean); + + core.info(`Processing state='${state}', days='${days}', dry_run='${dryRun}', labels=[${labels.join(', ')}]`); + + const per_page = 100; + + async function* iteratePRs(targetState) { + let page = 1; + while (true) { + const { data } = await github.rest.pulls.list({ + owner: context.repo.owner, + repo: context.repo.repo, + state: targetState === 'all' ? 'all' : targetState, + per_page, + page, + }); + if (!data || data.length === 0) break; + for (const pr of data) yield pr; + if (data.length < per_page) break; + page += 1; + } + } + + const cutoff = Date.now() - days * 24 * 3600 * 1000; + + let totalReviewed = 0; + let totalEdited = 0; + for await (const pr of iteratePRs(state)) { + totalReviewed += 1; + if (state !== 'open') { + const updatedAt = Date.parse(pr.updated_at || pr.closed_at || pr.merged_at || pr.created_at); + if (isFinite(updatedAt) && updatedAt < cutoff) continue; + } + + const labelNames = (pr.labels || []).map(l => (typeof l === 'string' ? l : l.name)).filter(Boolean); + const present = labelNames.map(n => n.toLowerCase()).filter(n => labels.includes(n)); + if (present.length === 0) continue; + + core.info(`PR #${pr.number} matches [${present.join(', ')}]`); + if (dryRun) continue; + + for (const name of present) { + try { + await github.rest.issues.removeLabel({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: pr.number, + name, + }); + totalEdited += 1; + } catch (e) { + core.warning(`Failed to remove '${name}' from #${pr.number}: ${e.message}`); + } + } + } + + core.info(`Reviewed PRs: ${totalReviewed} | Labels removed ops: ${totalEdited}`); + core.setOutput('reviewed', totalReviewed); + core.setOutput('edited', totalEdited); +