diff --git a/.github/workflows/auto-merge-mintlify.yml b/.github/workflows/auto-merge-mintlify.yml deleted file mode 100644 index d614b5f55b..0000000000 --- a/.github/workflows/auto-merge-mintlify.yml +++ /dev/null @@ -1,19 +0,0 @@ -name: Auto-merge Mintlify Bot PRs - -on: - pull_request: - types: [opened, synchronize] - -jobs: - auto-merge: - if: github.actor == 'mintlify[bot]' - runs-on: ubuntu-latest - permissions: - contents: write - pull-requests: write - - steps: - - name: Enable auto-merge - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: gh pr merge "${{ github.event.pull_request.number }}" --repo "${{ github.repository }}" --auto --squash diff --git a/.github/workflows/mintlify-triage.yml b/.github/workflows/mintlify-triage.yml new file mode 100644 index 0000000000..1d37f4281c --- /dev/null +++ b/.github/workflows/mintlify-triage.yml @@ -0,0 +1,63 @@ +name: Mintlify PR Triage + +# Auto-triages documentation PRs opened by the Mintlify bot. A Claude classifier +# verifies each PR against the actual code, then takes exactly ONE action: +# - MERGE (enable auto-merge; it lands only after CI passes) when it can +# positively confirm the docs are accurate, user-facing, and apply cleanly. +# - CLOSE in every other case — stale / backend-internal / inaccurate / +# duplicate, or anything it cannot confidently verify (bias to close). +# Replaces the previous "auto-merge every bot PR" workflow. + +on: + pull_request: + types: [opened] + +concurrency: + group: mintlify-triage-${{ github.event.pull_request.number }} + cancel-in-progress: true + +jobs: + triage: + # Gate on the PR author, not github.actor (which is spoofable and is the + # human, not the bot, on reopen). + if: github.event.pull_request.user.login == 'mintlify[bot]' + runs-on: ubuntu-latest + permissions: + contents: write # enable auto-merge + pull-requests: write # close / comment + id-token: write # claude-code-action auth + actions: read # read CI status + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 1 # full file tree (code + docs) so feature greps work + persist-credentials: false # job has write perms; Claude uses gh, not git auth + + - name: Classify and act + uses: anthropics/claude-code-action@v1 + with: + anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} + additional_permissions: | + actions: read + claude_args: >- + --model claude-sonnet-4-6 + --allowed-tools "Bash(gh pr view:*),Bash(gh pr diff:*),Bash(gh pr merge:*),Bash(gh pr close:*),Bash(gh pr comment:*),Bash(git grep:*),Bash(git log:*),Bash(git show:*),Bash(git ls-files:*),Grep,Glob,Read" + prompt: | + You are the documentation-PR triager for ${{ github.repository }}. PR #${{ github.event.pull_request.number }} was opened by the Mintlify docs bot. Decide and execute EXACTLY ONE outcome: MERGE or CLOSE. Bias toward CLOSE — only MERGE when you can positively verify the PR is good. Everything published must be user-facing, accurate, and free of backend/internal detail. Do not ask questions; take the action yourself with the gh CLI. + + Investigate first (read-only): + - Diff + metadata: `gh pr diff ${{ github.event.pull_request.number }}` and `gh pr view ${{ github.event.pull_request.number }} --json files,mergeable,mergeStateStatus,title,body`. A non-mergeable / conflicting PR usually means it targets a page that was renamed or deleted (stale). + - Confirm any feature the PR documents actually exists in the code: `git grep -i "" -- mcpjam-inspector/ sdk/`. If you cannot find it, treat the feature as non-existent. + - Check whether the content is already documented: `git grep -i "" -- docs/`. + + MERGE only if you can confirm ALL of: the PR is mergeable; every target page still exists; the feature is present in the code; the content is user-facing and accurate; and it is not a duplicate or editing anything under `docs/contributing/**`. + + CLOSE in every other case — stale (deleted/renamed page or not mergeable); backend/internal content (Convex, internal HTTP endpoints/routes, environment variables, secrets/keys, server-side persistence or runtime, internal source-file paths); a feature you cannot find in the code; a duplicate; a clear factual error versus the code; OR anything you are not confident enough to merge. Closing is safe and cheap — the bot regenerates a fresh PR when the code changes again. + + Execute exactly one, then stop: + - MERGE → `gh pr merge ${{ github.event.pull_request.number }} --auto --squash` + - CLOSE → `gh pr close ${{ github.event.pull_request.number }} --comment ""` + + Keep the comment to a single sentence. diff --git a/.github/workflows/update-docs.yml b/.github/workflows/update-docs.yml index fcc0767f11..f3c9882937 100644 --- a/.github/workflows/update-docs.yml +++ b/.github/workflows/update-docs.yml @@ -6,8 +6,9 @@ on: jobs: update-docs: - # Only run if PR was actually merged (not just closed) - if: github.event.pull_request.merged == true + # Only run when a non-bot PR is actually merged. Skipping mintlify[bot]'s own + # merged docs PRs prevents a generate -> auto-merge -> generate loop. + if: github.event.pull_request.merged == true && github.event.pull_request.user.login != 'mintlify[bot]' runs-on: ubuntu-latest steps: @@ -70,13 +71,15 @@ jobs: '```', ``, `## Instructions`, - `First, review the merged diff and the repository's \`docs/\` directory to assess whether documentation changes are actually needed. If no relevant updates are needed, make no file changes and do not open a PR.`, + `First, review the merged diff and the repository's \`docs/\` directory to decide whether USER-FACING documentation actually needs to change. If not, make no changes and do not open a PR.`, ``, - `If updates are needed, categorize the change and update only the appropriate docs under \`docs/\`. We have two main types of docs:`, - `1. **Feature docs** (how users use features)`, - `2. **Contributing docs** (engineering concepts for technical contributors) live under \`docs/contributing/\` and \`docs/evals/\``, + `Hard rules:`, + `- Only edit user-facing feature docs. NEVER create or modify anything under \`docs/contributing/**\` — that directory is internal and off-limits to this agent.`, + `- NEVER document backend or internal implementation details: Convex, internal HTTP endpoints or routes, environment variables, secrets or keys, server-side persistence/runtime mechanics, or internal source-file paths.`, + `- Ground every statement in the provided diff and the current code/docs. Do NOT invent features, flags, tools, defaults, or numbers; if you cannot confirm a detail from the diff or the repository, omit it.`, + `- Target the CURRENT docs structure. If the relevant page appears to have been renamed or removed, update the current equivalent page instead of recreating the old one; check \`docs/docs.json\` for the live page list.`, ``, - `Keep edits minimal, precise, and user-focused. When adding/moving pages, update \`docs/docs.json\` to keep navigation accurate. Use concise commit messages and open a focused PR only when changes are required. Use .mmd files for diagrams and other visual content if needed.`, + `Keep edits minimal, precise, and user-focused. When adding or moving pages, update \`docs/docs.json\` so navigation stays accurate. Use concise commit messages and open a single focused PR only when user-facing changes are required. Use .mmd files for diagrams and other visual content if needed.`, ].join('\n'); const url = `https://api.mintlify.com/v1/agent/${projectId}/job`;