Docs Review Pr logo

Docs Review Pr

Organization
elastic
docs-review-pr

Run a full review of an Elastic documentation PR against the docs team review checklist — user focus, technical accuracy, applicability, maintainability, language, and style. Runs the companion review skills and merges everything into one report with a recommended approve, comment, or request-changes call. Use when reviewing a docs PR, checking a branch before requesting review, or deciding whether a docs change is ready to merge.

Overview

Publisherelastic
Repositoryelastic-docs-skills
Skill namedocs-review-pr
Stars
71
Forks
10
Bundled files
2
LicenseApache-2.0
Links
  • Markdown instructions

    A SKILL.md file the model loads on demand, so it only costs tokens when a request actually matches.

  • Works with any LLM

    AI skills are plain Markdown, not provider-specific code, so this works with GPT, Claude, Gemini, Grok, or a local model.

  • 2 bundled files

    Scripts, templates, and references the model can read while it works. Files are read-only and never executed.

  • Open source

    Published by elastic on GitHub. Read the source before you install it.

Installation

Install the Docs Review Pr AI skill in TypingMind to use it with any LLM, or drop it into another agent that reads SKILL.md.

1

Install in TypingMind

TypingMind installs a skill straight from its GitHub folder — it reads SKILL.md, bundles the resource files, and stores the result locally.

  1. Open the app and go to Plugins → Skills.
  2. Choose "Install from GitHub".
  3. Paste the skill folder URL below and confirm.
  4. Enable the skill in any chat where you want it available.
Plugins → Skills → Add skill → From GitHub URL, then paste the folder URL and press Continue.
2

Install in another agent

Any agent that reads the Agent Skills format can use this skill — copy the folder into that agent's skills directory.

Claude Code — .claude/skills
git clone --depth 1 https://github.com/elastic/elastic-docs-skills.git /tmp/elastic-docs-skills
mkdir -p .claude/skills
cp -r /tmp/elastic-docs-skills/skills/review/review-pr .claude/skills/docs-review-pr
Restart Claude Code after copying so it picks up the new skill.

Use it in TypingMind

Enable Docs Review Pr in any TypingMind chat and the model takes it from there. Its name and description sit in the system prompt, and the moment a request matches, the model loads the full instructions itself — you never invoke it by hand, and it costs no tokens until it is actually used.

The model loads Docs Review Pr on its own as soon as a request matches it.

Works with any AI model

AI skills are plain Markdown instructions rather than provider-specific code, so Docs Review Pr is not tied to the model it was written for. Install it once in TypingMind and use it with GPT-5, Claude, Gemini, Grok, DeepSeek, Mistral, Llama, or a local model you run yourself — all on your own API keys.

  • Loaded only when it is needed

    The system prompt carries just the name and description. The instructions are fetched on the first matching request, so an idle skill costs nothing.

  • Switch models mid-chat

    Because the skill is instructions rather than code, changing model does not break it — the next model reads the same SKILL.md.

Skill instructions

This is the SKILL.md content the model loads. Read it before installing — a skill is instructions your model will follow.

You review Elastic documentation pull requests against the docs team review checklist. You produce one merged report covering all six review criteria — user focus, technical accuracy, applicability, maintainability, language, style — and recommend whether to approve, comment, or request changes.

You are an orchestrator. The catalog already has skills that check style, tagging, content type, contradictions, metadata, and code samples. You dispatch those and merge their findings into checklist shape. You do not re-implement their rubrics.

This skill deliberately omits context: fork, which most catalog skills set. It has to stay in the main context to dispatch companions through the Skill and Agent tools and to ask the user about gh pr checkout in Step 1. Each companion forks itself, so their output still stays out of context.

This skill always runs a full review. There is no light or trivial mode. The reviewer decides how much of the report to act on; your job is to produce the complete picture.

Constraints

This skill is read-only.

  • Never edit a file. Never write a file outside the scratchpad.
  • Never post to GitHub. Never run gh pr review, gh pr comment, or gh pr merge.
  • Dispatch every companion skill in report-only mode, so the guarantee holds transitively. Two companions can write if you let them: docs-applies-to-tagging declares Edit and its validate mode reports or fixes, and docs-validate-code-samples declares Write and can write an output file. Both go through the subagent path only, where the spawn prompt can forbid writes — see Step 3.
  • The one exception is gh pr checkout in Step 1, which you offer and never run without the user saying yes.

Inputs

$ARGUMENTS is a PR number, a GitHub PR URL, a file, or a directory. If empty, review the current branch against its base.

Step 0: Load the rubric

Always read references/review-criteria.md (next to this file). That is the rubric, and it works with no network, no MCP, and no authentication — the case in agentic workflows and CI.

Then, if the elastic-internal-docs MCP is reachable, refresh it against the canonical pages with get_internal_document_by_url and includeBody: true:

PageURL
Docs review checklists/r/docs-content-internal/processes/docs-review-checklists
PR review guidelines/r/docs-content-internal/processes/pr-reviews

The fetched pages take precedence where they differ, and any conflict goes in the report. If the MCP is unavailable or unauthenticated, the reference file alone is enough — say so in the report header with Rubric source: references/review-criteria.md (MCP not reachable) so the reader knows the rubric was not refreshed.

Step 1: Resolve the target

$ARGUMENTSHow to resolve
PR number or GitHub PR URLgh pr view <n> --json number,title,body,author,labels,files,baseRefName,baseRefOid,headRefName,headRefOid,headRepository,isCrossRepository,url and gh pr diff <n>
EmptyCurrent branch against the branch it forked from. First check whether the branch already has a PR — gh pr view with no number resolves one when it exists. If it does, use it and run the PR-only checks. Only when there is no PR do you skip them
File or directory pathTreat the files there as the review scope. There is no diff, so every line counts as in scope — you cannot separate introduced from pre-existing, and Step 5 must say so instead of guessing. PR-only checks are skipped

State which input mode you used in the report header, and whether PR metadata was available. A branch with an open PR gets the full review; a branch without one loses the PR-only checks, and so does a path input. The reader needs to know which.

Resolve the base, in every mode

$BASE and $BASE_REPO are used later in this step to read deleted pages, and in Step 5 to scope findings. Set them during target resolution for whichever mode you are in — not only for branch reviews. A PR review that reaches the deleted-page read with them unset runs git fetch "https://github.com/.git" "", which fails with an unhelpful error.

PR mode — take both from the PR itself. gh pr view has no baseRepository field, so the base repo comes from the PR URL:

BASE=$(gh pr view <n> --json baseRefName -q .baseRefName)
BASE_REPO=$(gh pr view <n> --json url \
  -q '.url | capture("github\\.com/(?<r>[^/]+/[^/]+)/pull").r')

Branch mode — ask GitHub what the branch targets, and fall back to the repository default. Do not use the upstream tracking branch (@{u}): that is where the branch pushes, not what it forked from, so on a pushed branch it resolves to the branch's own remote copy, the diff comes back empty, and you report a clean review of nothing.

BASE=$(gh pr view --json baseRefName -q .baseRefName 2>/dev/null) \
  || BASE=$(gh repo view --json defaultBranchRef -q .defaultBranchRef.name)
BASE_REPO=$(gh repo view --json parent,nameWithOwner \
  -q 'if .parent then .parent.nameWithOwner else .nameWithOwner end')
git fetch "https://github.com/$BASE_REPO.git" "$BASE"
git diff -U0 "$(git merge-base HEAD FETCH_HEAD)"...HEAD

Path mode — there is no diff and no base. Leave both unset and skip every step that needs them, marking those checks Not checked — no base to compare against.

Two things these recipes are careful about:

  • gh pr view with no number resolves the current branch's PR when one exists, which is the most reliable answer about what a branch targets. When it succeeds, the branch is not PR-less: reuse that PR's metadata for labels, author, and body rather than reporting the PR-only checks as skipped.
  • Fetch the base branch from the base repository, not from origin. In a fork clone origin is the fork, so origin/main is the contributor's copy of main — stale, or missing entirely — and diffing against it gives a wrong changed-file set. Fetching by URL into FETCH_HEAD sidesteps the question of what any local remote happens to point at.

If the resulting diff is empty, stop and say so rather than reporting a clean review — an empty diff nearly always means the base was resolved wrongly, not that there is nothing to review.

Confirm the working tree matches the PR

Do this before reading any file. Several checks in Step 4 — orphaned images, missing redirects, cross-references from parent pages — grep the local repo. If the PR's head ref is not checked out here, those greps read a different tree and you report confidently wrong results.

Compare the commit, not the branch name. A local branch can share a name with the PR's head and point somewhere else entirely. So:

  1. git rev-parse HEAD must equal headRefOid. That single check subsumes branch name, fork, and staleness — a matching commit is a matching tree.
  2. If it does not match, check that you are in the right repository before anything else. Compare gh repo view --json nameWithOwner against the PR's base repository — the owner/name in the PR URL — by owner/name, never by remote URL string, since the SSH and HTTPS forms of one repo differ as text.

Never compare the local repo against headRepository. On a fork PR (isCrossRepository: true) the head repository is the contributor's fork, which nobody has checked out. Fork PRs are reviewed from a clone of the base repo: gh pr checkout fetches the fork's head into a local branch there. Comparing against headRepository would reject every fork PR as the wrong repository — exactly the contributions that most need a careful review.

  • Commit matches — proceed.

  • Not a git repo, or not the PR's base repo — stop. Tell the user which repo to run from.

  • Right repo, wrong ref — check for uncommitted work first with git status --porcelain --untracked-files=no. Only tracked modifications block a switch: if there are any, do not offer to check out, and tell the user to stash or commit. Untracked files do not block, because gh pr checkout leaves them alone — mention them and carry on. When nothing is blocking, ask whether to run gh pr checkout <n>, and wait for an answer. Never check out without one.

  • User declines the checkout — continue in degraded mode. Write each changed file to its own scratchpad path, preserving the repo-relative structure, and review those copies:

    SCRATCH=$(mktemp -d)                       # create it once, reuse for every file
    mkdir -p "$SCRATCH/$(dirname <path>)"
    gh api "repos/{owner}/{repo}/contents/<path>?ref=<headRefOid>" --jq .content \
      | base64 -d > "$SCRATCH/<path>"

    Create $SCRATCH before the first fetch and report the path, so the user can inspect what you reviewed.

    Redirecting to a file is the point — decoded content on stdout gives the later Read, Grep, and companion steps nothing to open. Dispatch companions against the scratchpad paths. Mark every repo-hygiene check in Step 4 as Not checked — ran against a different ref, because the rest of the repo is still at the wrong commit. Do not report them clean.

Read the changed files

Read each changed .md file from end to end, not only the diff hunks. H1 accuracy, admonition stacking, content placement, and heading structure are all page-level properties that a hunk cannot show you.

Deleted and renamed pages need the base version. Once the head ref is checked out, a deleted page — or the source side of a rename — is no longer on disk, and those are exactly the files the orphaned-asset and redirect checks depend on. Read them from the base.

The base commit is usually not in the local clone, so fetch it before reading, or git show fails with a bad-object error:

git fetch "https://github.com/$BASE_REPO.git" "$BASE"
git show "$(git merge-base HEAD FETCH_HEAD)":<path>

When the fetch cannot succeed — a shallow clone, or no access to the base repo — read the file over the API instead, using baseRefOid from the gh pr view output:

gh api "repos/{owner}/{repo}/contents/<path>?ref=<baseRefOid>" --jq .content | base64 -d

If neither works, mark the orphaned-asset and redirect checks Not checked — base version unavailable. Do not infer a deleted page's contents.

Read the non-Markdown files in the diff too. Navigation files (toc.yml, docset.yml) and redirect files are part of the change and decide whether pages build and stay reachable. They are in scope even though the six criteria are about prose.

Keep a record of which lines the diff actually touched — gh pr diff <n> for a PR, or git diff -U0 <base>...HEAD for a branch. A name-only listing is not enough: Step 5 needs line ranges to separate what this PR introduced from what it merely sits next to. For a file or directory input there is no diff at all, so treat every line as in scope and say so in the report rather than guessing which lines are new.

Step 2: Note the author signal

From the PR review guidelines. This shapes emphasis, not depth — the full checklist runs either way.

AuthorWhere to focus
DeveloperUsually safe to assume the information is technically correct. Weight language and style.
Writer, with a developer taggedNote that a pending technical review might trigger significant changes worth re-reviewing.
Non-writer, non-developer (for example, a customer-facing team)For anything beyond a typo fix, flag that a writer with subject matter expertise should take it, and that a technical reviewer might still be needed.

gh pr view gives you a GitHub login, not a role. Infer the author type only from real evidence — team membership you can see, how the PR describes itself, the repos the author normally touches. When the evidence is thin, record Author signal: unknown and weight nothing. An invented author type silently reshapes the whole review.

Record this as one line in the report header.

Step 3: Dispatch the companion skills

Every companion whose Gate condition is satisfied runs on every review — there is no tier that skips a companion. Two gates are conditional, because a code-sample validator has nothing to say about a PR with no code blocks, and the tagging skill has nothing to say about a diff that never touches applies_to. Check the Gate column before dispatching. Do not run a gated companion on a PR it does not apply to.

#CompanionDispatchGateFindings report under
1docs-check-styleEitherAlwaysLanguage, Style
2docs-flag-jargon-skillEitherAlwaysLanguage
3docs-content-type-checkerEitherAlwaysUser focus
4docs-check-contradictionsEitherAlwaysTechnical accuracy
5docs-frontmatter-auditEitherAlwaysUser focus
6docs-applies-to-taggingSubagent onlyDiff touches applies_to or version-scoped contentApplicability
7docs-validate-code-samplesSubagent onlyDiff adds or changes code blocksTechnical accuracy

Seven companions, seven separate dispatches. Never combine two into one call or one subagent. The last column says where a companion's findings are reported; it is not a grouping key. Companions 1 and 2 both feed Language, and 3 and 5 both feed User focus, but each is its own dispatch with its own rubric — bundling them means one of the two rubrics silently does not run, and the run table then claims coverage you do not have.

The five Always-gated companions are dispatched on every review without exception. "Not dispatched" is never a valid outcome for them — if one could not be reached, it is Not installed or did not return, and it is reported that way.

Every companion maps onto one of the six report sections. Nothing produces a seventh — docs-frontmatter-audit findings belong under User focus, as findability and metadata.

How to dispatch

Most companions set disable-model-invocation: true. That hides them from the model's skill listing when they are installed standalone, but it does not hide them when they are installed as part of the elastic-docs-skills plugin — the plugin-prefixed form stays invocable.

The Path column decides where each companion goes. Read-only companions try path 1 and drop to path 2 if it fails; write-capable companions go straight to path 2. Record which path each one actually used, and report it.

  1. Skill tool — read-only companions only, per the Path column. Pass one file to review as args. Use the plugin-prefixed frontmatter name, elastic-docs-skills:docs-content-type-checker, which is the form the README documents. Fall back to the bare name if the prefixed one is refused. The prefixed form is what reaches a companion that sets disable-model-invocation: true.

    A companion that declares Edit or Write never goes down this path. args is the only thing you control on a Skill call, and asking politely for validation is not a guarantee: docs-applies-to-tagging treats a file path as validate mode, and validate mode still reports or fixes. The subagent spawn prompt is the only channel that can actually forbid a write, so applies-to-tagging and docs-validate-code-samples always use path 2, even when the Skill tool would accept them.

    One changed file per call. Companions declare <file-or-directory> and glob $ARGUMENTS, so a space-separated list is read as one bad path, not many good ones. Invoke once per changed file. Pass a directory only when it contains exactly the changed set and nothing else — otherwise the companion globs unrelated pages and their findings leak into the report and skew the recommendation. When in doubt, one file per call. This applies to both dispatch paths.

  2. Subagent. The required path for write-capable companions, and the fallback whenever both Skill name forms are refused or unlisted. Spawn one subagent per companion, all in a single message so they run in parallel. Each subagent:

    • Locates the companion's SKILL.md by globbing ~/.claude/skills/*/SKILL.md, ~/.claude/plugins/**/skills/**/SKILL.md, and the local repo's skills/**/SKILL.md, matching on either the directory name or the frontmatter name: field.
    • Executes those instructions verbatim against the changed files, substituting a single path for $ARGUMENTS — one file, or the common parent directory — following the same one-target rule as path 1.
    • Returns a compact findings list: file, line, severity, finding. Not the companion's full report.

    Reading the rubric from the companion is what keeps this skill thin. Never copy a companion's rules into this file.

  3. Not installed. If a companion is nowhere to be found, mark its criterion Not checked — <skill> not installed and give the install command:

    npx --yes skills@latest add elastic/elastic-docs-skills --skill <name> -g

    Use the companion's frontmatter name:docs-check-contradictions, not its check-contradictions directory. Directory names are for locating files on disk, nothing else.

Never stand in for a companion that did not run

This applies to every reason a companion produced nothing — not installed, refused, errored, or dispatched and never returned.

  • Do not write findings for that companion's criterion yourself, and do not label the gap a manual assessment. Your own checks are Step 4's list; they are not a substitute for a companion's rubric, which is the whole reason the companion exists.
  • Mark the criterion Not checked, say which companion and why, and leave it at that. A criterion that looks covered because you filled it in by hand is worse than an admitted gap, because nobody can tell the difference in the report.
  • The exception is a finding you genuinely made yourself under Step 4. Source it docs-review-pr and keep it in its own row — never merge it into a missing companion's slot.

Report-only mode is mandatory

On the Skill path, pass arguments that ask for validation or review only, never generation or fixes — and remember that this is a request, not an enforcement, which is why write-capable companions are excluded from that path. On the subagent path, put this in the spawn prompt verbatim:

Do not Edit or Write any file. Do not modify the working tree. Return findings only.

Wait for every companion before reporting

Both dispatch paths fork and run in the background. Results arrive as notifications, not as return values from the call you made.

  • Do not begin Step 5 until every dispatched companion has returned.
  • Never predict, summarize, or invent what a pending companion will say. Fabricating companion output is the worst failure this skill can have, because the report format makes it look attributed and verified.
  • If a companion errors or never returns, mark its criterion Not checked — companion did not return and carry on with the rest. Do not fill the gap with your own assessment; see Never stand in for a companion that did not run.

Before writing the report, check the count. The run table must have exactly seven rows, one per companion in the dispatch table. Every Always-gated companion must read Ran, Not installed, or did not return — never Not dispatched. If a row says you skipped one, you either missed it or bundled it into another call; go back and dispatch it.

Step 4: Run the checks no companion covers

This is your own contribution to the review. Scope every finding to what the PR changed.

User focus

  • Change serves the user's task and sits in the correct place on the page.
  • Paragraphs are short, and lists, tables, and admonitions break up dense content.
  • Lead-in sentences set topic boundaries and tell the reader how to think about what follows.
  • The benefit of the feature or path is stated, not only its mechanics. Check this in three places: the intro/description (user benefit, not just mechanics), each decision point (tradeoff, not just description of both options), and the title (does the page deliver what the title promises?).
  • All impacted pages are assessed and updated, including reference pages that use a newly introduced concept.
  • A new feature is contextualized on its parent page against the product landscape.
  • The page declares its content type in frontmatter as type:. When docs-content-type-checker identifies the page as a how-to, tutorial, overview, or troubleshooting page and the frontmatter carries no type: field, recommend adding it — naming the type it should be. Do this for edited pages, not only new ones: an existing page never passed through a template, so the field is the one most often missing. Recommend it even when nothing consumes the field yet. Structural findings about a content type without the tag that names it leave the reader to infer what you already determined.

Findability and logical flow

  • The page sits in the correct place in the information architecture.
  • Cross-references point into the page from its parents, so users are not stranded. Grep the repo for links into any new or moved page.
  • Headings run about 50–60 characters where practical, and describe the page distinctly from similar ones.
  • The page discloses progressively: the reader gets what they need in the order they need it.
  • Warnings and cautions appear before the step or content they warn about, not after.
  • Conceptual choices use contrasting pairs, options carry value propositions near the decision point, and branching decisions use nested navigation.
  • No existing page already covers this ground. Check with the elastic-docs MCP tool find_related_docs on the page topic.

Technical accuracy evidence

You cannot confirm that an SME reviewed a change. You can report whether the evidence is there.

  • Look in the PR body, review comments, branch name, and any linked issue for an SME sign-off, an eng review, or an authoritative source.
  • Check whether new code samples are described as tested.
  • State plainly which it is: evidence present and where, or evidence absent. Never infer technical correctness from confident prose.

Check the docs against the code change they describe

When that evidence is a code PR or commitelastic/elasticsearch#12345, a GitHub PR URL, "Docs for kibana#678", a branch named after an issue — do not stop at noting it exists. Read it and compare. A linked code change pins the repository, the ref, and the version, so this is the one technical check you can make without guessing which source to trust. Skip this whole block when no code change is referenced; never go looking for one to scan.

  1. Resolve the reference and read both sides:

    gh pr view <n> --repo <owner/repo> --json title,body,state,mergedAt,baseRefName,files
    gh pr diff <n> --repo <owner/repo>

    Pass the number with --repo, or a full PR URL. The shorthand gh pr view elastic/elasticsearch#12345 does not work — gh reads it as a branch name and reports no PR found, which looks like a missing PR rather than a bad command.

  2. Pull the checkable facts out of the code diff: setting, flag, and parameter names; default values, limits, and enum values; error and log message text; and any added or changed tests, which assert intended behavior more reliably than comments describe it.

  3. Compare each against what the docs change asserts. Report under Technical accuracy, citing the code PR and the file in its diff, so the writer can follow the same trail.

Four things to get right, because each is a way to be confidently wrong:

  • Version. The code PR's baseRefName tells you which branch it landed on. Cross-check that against the page's applies_to. Docs tagged for 9.2 describing a change that landed on 8.19 is a real finding, and one nothing else in this review would catch.
  • Merge state. An unmerged code PR describes intended behavior that can still change. Say so rather than treating it as settled.
  • Absence proves nothing. A docs claim missing from the code diff is not wrong — the diff is one change, not the whole product. Only flag a direct conflict: the docs say one value, the code says another.
  • Matching is not verification. Report what matched and where. Never write that a change is technically correct because a diff agreed with it; the same rule that governs confident prose governs confident diffs.

Applicability checks outside the tagging skill

  • Prerequisites are still accurate after the change, covering permissions, setup, and assumed knowledge.
  • No new permission or setup dependency is left unstated.
  • Deployment types and versions are called out in prerequisites when they differ from page-level tagging.
  • Deployment scope is correct: relevant types are covered or signposted, shared processes stay deployment-agnostic, and self-managed, ECE, and ECK are treated as distinct deployment types rather than collapsed into one customer-operated group. They share core Elasticsearch functionality; the difference is how a deployment is run, not what it can do.

Maintainability and repository hygiene

  • No procedure or value is duplicated from somewhere it already lives. A cross-reference or a snippet is better. When a section embeds reference material (parameter descriptions, format explanations, API syntax, full procedures), use find_related_docs or search_docs to check whether a dedicated page already covers it. Flag intra-page duplication too — read Option 1 and Option 2, or Method A and Method B, side by side.
  • No remaining page links to or references a deleted or moved page by its old path. Grep the repo for the old path and for its anchors.
  • No deleted image or snippet is still referenced by another page. Grep the repo for each removed asset path.
  • Every renamed, moved, or deleted page has a matching redirect entry, including renamed anchors. Flag a missing one High, because it breaks live links. The file is redirects.yml or _redirects.yml, next to the content set's docset.yml or _docset.yml — check both names before reporting one missing, or you will raise false findings.
  • No generated or automated reference material is hand-edited. The fix belongs at the source.
  • Screenshots, diagrams, and non-Elastic external links earn their ongoing maintenance cost.

Scope discipline

  • The change commits to no roadmap items and no future plans.
  • The change carries no implementation details or decision history that users do not need.

Preview cleanliness

  • No literal {{ reaches the rendered output, and every substitution resolves.
  • No admonitions are stacked back to back. Merge them into one callout or into the narrative. Scan for consecutive pairs — two admonitions separated only by whitespace count as stacked even if each looks fine individually.
  • Roughly three or fewer admonitions sit in one area, so they still stand out.
  • No stray bullets, leftover comments, or broken tables and tabsets appear.
  • Badges render, and section- or line-level applies_to tags work alongside page-level tags.
  • Link text is meaningful, and new or changed links resolve.

PR mechanics

Skip this block when the input was a path rather than a PR.

  • Backporting labels are present and correct for the target branches. Read them with gh pr view --json labels.
  • No unfinished content remains: TODOs, placeholder text, or commented-out drafts.
  • The title and H1 are still accurate and in sentence case after the change.

Step 5: Merge and report

One report, sectioned by the six criteria in checklist order.

Header

Target: <PR #, title, URL — or branch/path>
Author signal: <author type → where you focused>
Rubric source: internal MCP | embedded fallback — <reason>
Working tree: head ref checked out | degraded — <what was skipped>

Then a companion run table: each skill, and whether it ran, and through which path, was skipped (not relevant, with the reason), or is not installed.

Findings

Group by criterion: User focus, Technical accuracy, Applicability, Maintainability, Language, Style. Under each, one line per finding:

| Severity | file:line | Finding | Guideline | Source |
  • Severity — High when a user following the page fails or is misled, or when live links break. Medium when the content is inconsistent or unclear but still usable. Low for nuance.
  • Guideline — a link to the rule that decides the finding, from the Rule citations table in references/review-criteria.md. Link the section anchor when the table lists one, otherwise the page that governs the criterion. Cite the rule the finding actually rests on, not the section it happens to sit in: a missing description is a metadata and findability rule, not seo#headings; an ambiguous trigger condition is a clarity problem, not grammar-spelling. A criterion name such as "Technical accuracy" is not a citation — it names where the finding is filed, not what decides it. If nothing in the table fits, leave the column empty rather than reaching for the nearest link; a wrong citation sends the writer to a rule that does not say what you claim. The column holds a link or nothing — a bare word such as findability, or a criterion name, is not a citation and must not appear there. Every Language and Style finding must carry one, and so must any other finding a specific page decides. A writer who disagrees needs somewhere to go and check; "the style guide says so" is not a citation. When a companion reports a rule name of its own, such as a Vale rule like Elastic.OxfordComma, include that too, so the writer knows which check fired. Never invent an anchor — if nothing listed covers it, cite the page and say which part applies.
  • Source — which companion skill produced it, or docs-review-pr for your own checks. The reader needs to know what to re-run.
  • Mark a criterion Clean when it was checked and nothing came back. Mark it Not checked when no check ran. These are different things — never present the second as the first. Both are section-level statuses: write them as a line under the section heading, never as a row in the findings table with "Clean" in the Severity column. A findings table holds findings; a section with none has no table.
  • Use the same table for every section. Do not switch between tables and loose Severity: / Finding: blocks partway through the report — one format throughout, so the reader can scan it.
  • All six sections appear, always. A section with no findings carries a one-line status — Clean, or Not checked with the reason — never a bare heading with nothing under it. An empty section reads as an oversight, and the reader cannot tell whether it passed or was skipped.
  • Name each companion exactly as the dispatch table does, every time it appears. docs-flag-jargon-skill and docs-flag-jargon are not two sources.
  • A clean PR is a valid result. Never pad the report with trivia to look thorough. If a criterion produced nothing worth the author's time, it is Clean and you move on. A short report on a good PR is the correct output, not a sign you missed something.

Recurring patterns

When one issue repeats across the PR, report it once as a pattern with a count and a couple of examples. Per the review etiquette in the PR review guidelines, a single global comment beats commenting on every instance.

Pre-existing issues

Anything you noticed that this PR did not introduce goes in its own section, clearly labeled. The author is not responsible for unrelated debt, and mixing the two makes a review feel arbitrary.

This section holds problems, not praise. A good change the PR makes belongs under What is working; putting it here tells the author their improvement is a pre-existing defect. If there are no pre-existing issues, say so in one line.

What is working

Where the content is strong, say so, briefly and specifically. Positive feedback reinforces good writing habits and makes the review less daunting.

Recommended action

Build this list from the findings above, never from memory. Each action item restates one finding you already wrote, in the same direction. Do not re-derive a fix while summarising: that is how a report ends up telling the author to change select to click when its own finding said the opposite, and the summary is the part people act on. Before writing an item, re-read the finding it comes from and check the direction matches. If an item has no finding above it, either it does not belong in the list or the finding is missing from the report.

One of Approve, Comment, or Request changes, with the reasoning:

  • Approve — meets the quality threshold. Minor optional suggestions go in as comments rather than blocking.
  • Comment — you have questions or non-blocking feedback.
  • Request changes — below the quality threshold, or the change prevents users from succeeding with the product or feature. Blocking is a normal part of maintaining quality, not a judgment on the author.

Closing caveat

End with this, so nobody treats the report as the review itself:

This is a first pass, not a substitute for review. AI-generated results are not always accurate — confirm findings before acting on them.

Bundled files

The model reads these on demand while the skill is loaded. They are exposed as readable files and are never executed.

Frequently asked questions

What does the Docs Review Pr AI skill do?

Run a full review of an Elastic documentation PR against the docs team review checklist — user focus, technical accuracy, applicability, maintainability, language, and style. Runs the companion review skills and merges everything into one report with a recommended approve, comment, or request-changes call. Use when reviewing a docs PR, checking a branch before requesting review, or deciding whether a docs change is ready to merge.

Why use Docs Review Pr on TypingMind?

Because you install it once and use it with any model. Docs Review Pr is plain Markdown rather than provider-specific code, so the same skill runs on GPT-5, Claude, Gemini, Grok, or a local model — and you can switch model mid-chat without it breaking. TypingMind runs on your own API keys, so you pay providers directly instead of a per-seat subscription, and your skills and chats stay in your own storage.

How do I install Docs Review Pr in TypingMind?

Open Plugins → Skills → Install from GitHub in TypingMind and paste https://github.com/elastic/elastic-docs-skills/tree/main/skills/review/review-pr. TypingMind reads its SKILL.md and bundles its files and installs it as a skill you can enable per chat.

Which AI models can use Docs Review Pr?

Any model you connect in TypingMind. AI skills are plain Markdown instructions rather than provider-specific code, so GPT, Claude, Gemini, Grok, and local models can all load this skill when a request matches it.

How many AI models can I use with Docs Review Pr?

As many as you like. As long as a model supports skills, you can use Docs Review Pr with it — GPT, Claude, Gemini, Grok, DeepSeek, Mistral, Llama and more — all on TypingMind with your own API keys.

Is the Docs Review Pr AI skill free?

Yes. It is published on GitHub by elastic under the Apache-2.0 license. You only pay your own AI provider for the tokens you use.

What are AI skills?

An AI skill is a reusable instruction bundle that teaches an AI model how to do one specific task. It follows the open Agent Skills format: a SKILL.md file with a name and description, plus any scripts, templates or reference files the model may need. The model reads the instructions only when your request matches the skill, so an installed skill costs nothing until it is used.

How are AI skills different from plugins or MCP servers?

A plugin or MCP server gives a model new tools to call — code that runs somewhere and returns a result. An AI skill gives the model knowledge and process instead: how to approach a task, which steps to follow, what good output looks like. Skills are plain Markdown, so they need no server, no API key and no runtime, and they work with any model.

View all

Set up your own AI workspace now

Get notified about new features and future giveaways by subscribing to our newsletter 👇