| name | create_pr |
| description | Create a pull request in the docs repository for the current branch. Use when the user mentions opening a PR, creating a pull request, submitting changes for review, or preparing documentation for merge. |
create_pr
Overview
This guide covers best practices for creating pull requests in the docs documentation repository, including syncing with main, running linting checks, validating links, and structuring your PR for effective review.
Related Skills
draft_docs - Draft new documentation pages or update existing ones using established style conventions
check_for_broken_links - Check documentation for broken internal and external links before opening PR
Pre-PR Checklist
1. Sync with main
Always merge main into your feature branch before opening a PR.
git fetch origin
git merge origin/main
Resolve any merge conflicts locally before opening the PR.
2. Run linting checks
This repo uses Trunk CLI for linting. Run these checks before opening or updating a PR:
trunk check
trunk fmt
Enabled linters include:
markdownlint - Markdown formatting and style
yamllint - YAML file validation
gitleaks - Secret detection
oxipng - PNG optimization
:::note
Trunk CLI is not vendored in this repo. Install it separately: https://docs.trunk.io/check/usage
:::
3. Check for broken links
Run the link checker to validate all internal and external links:
python3 .agents/skills/check_for_broken_links/check_links.py --internal-only
python3 .agents/skills/check_for_broken_links/check_links.py
Fix any broken links before opening the PR. See the check_for_broken_links skill for detailed guidance on fixing different link types.
4. Review your changes
Before creating a PR, review what you're about to submit:
git --no-pager log origin/main..HEAD --oneline
git --no-pager diff origin/main...HEAD --stat
git --no-pager diff origin/main...HEAD
This helps you:
- Verify all intended changes are included
- Catch unintended changes before review
- Write an accurate PR description
5. Verify sidebar updates
If you added, moved, or renamed any documentation pages:
- Update the sidebar in
src/sidebar.ts. That file is the source of truth; astro.config.mjs only imports it via starlightSidebarTopics(sidebarTopics).
- Ensure the label matches the H1 title in the document, or omit the label and let Starlight derive it.
- Check that the slug is correct: no leading slash and no
.md/.mdx extension.
6. Add redirects for moved/renamed pages
If you renamed or moved a page that's already published, add a redirect to the redirects array in vercel.json at the repo root. Every redirect lives in that one file, including redirects between top-level sections — there is no per-section redirect file and no external redirect tool.
Check existing redirects first to avoid duplicates.
{
"source": "/old/path",
"destination": "/new/path/",
"statusCode": 308
}
Include the trailing slash on destination and the statusCode, matching the existing entries.
PR Description Guidelines
Structure your PR description with these sections, in this order. The feature summary comes first; everything else follows it.
What this feature does (required on drafting PRs)
Open the body with a plain-language summary of what the feature does for the user. This is the first thing a reviewing engineer reads, so it must not be pipeline bookkeeping — which spec produced the draft, which workflow generated it, and which run it came from all belong further down. A reviewer who only reads this section should be able to tell whether the docs describe the right thing.
End the summary with the shipped-in fact, not a forecast. Read the version and date from the release accessor the drift-watch gate already uses, rather than adding a second way to look up a release:
python3 .agents/skills/missing_docs/scripts/check_new_release.py --json > /tmp/release.json || true
python3 -c "import json; d=json.load(open('/tmp/release.json')); print(d['current_version'], d['release_date'])"
Write "shipped in <version> (<date>)". Do not write a target or predicted ship date: there is no trustworthy source for one, and a forecast in a merged PR body ages into a false claim.
Length budget: 75 words maximum, ideally two to four sentences. Drafts are already too wordy; a summary that runs longer than a short paragraph has stopped being a summary. check_pr_body.py enforces the budget, the heading text, and the position.
## What this feature does
Workspace admin roles let a workspace owner delegate whole-workspace management — membership, billing, and cloud agent run visibility — to an admin without handing over ownership. Shipped in `v0.2026.08.18.02.52.stable_00` (`2026-08-18`).
Verify it before submitting, along with the other body checks:
python3 .agents/skills/create_pr/check_pr_body.py /tmp/pr-body.md \
--require-lead-section "## What this feature does"
The check fails if the section is missing, is not the first content in the body, is empty, or exceeds the word budget. Position is checked against content rather than headings, so a body cannot open with a few unheaded lines of spec/workflow/run-ID preamble and still pass. Omit the section — and the flag — only for the small corrections listed under "When a plan can be skipped": typos, link fixes, terminology sweeps, generated updates, and screenshot swaps have no feature to summarize.
Summary
Brief explanation of what the PR accomplishes and why. This is where the pipeline detail goes: the source spec, the generating workflow, the new page path, and the sidebar entry.
Changes
Bulleted list of specific changes, organized by file or area:
## Summary
This PR updates the Terminal and Agent modes documentation for the Oz launch.
## Changes
### src/content/docs/agent-platform/local-agents/interacting-with-agents/terminal-and-agent-modes.md
- Added Getting Started section with first-time and existing user experiences
- Updated keyboard shortcuts with comprehensive tables
- Added fork functionality documentation
### src/sidebar.ts
- Updated navigation entry title
Content design plan (required on drafting PRs)
Any PR that adds a page or makes a substantive update to one must carry the content design plan that preceded the draft. Keeping it next to the diff is the point: a reviewer can then disagree with who the page is for and what job it serves, which is far cheaper to resolve before the prose is written. See .agents/references/content-design-plan.md for the field definitions and .agents/references/docs-worthiness-criteria.md for the gate that runs before it.
## Content design plan
**Audience and JTBD:** A backend engineer connecting their first factory to a self-hosted GitLab instance, who needs runs to authenticate without a personal token.
**Problem:** The GitLab integration page covers GitLab.com only, so self-hosted users follow steps that silently fail at the auth step.
**Goals:**
- The reader can tell whether their GitLab instance needs the self-hosted path.
- The reader can complete the self-hosted connection and confirm it worked.
**Purpose and value:** Without it, self-hosted users file support tickets after the happy path fails. No existing page covers the self-hosted variant.
**Content type:** Procedural — the reader is performing a setup task, not learning a concept.
**Skill and template:** `draft_procedural` / `.agents/templates/procedural.md`
**High-impact scenarios:**
- Covers: self-hosted GitLab with a project access token; verifying the connection.
- Excludes: GitLab behind a corporate proxy — rare, and the proxy config is the user's own infrastructure concern.
For the small corrections listed under "When a plan can be skipped" — typos, link fixes, terminology sweeps, generated updates, screenshot swaps — omit the section rather than filling it with placeholders.
Unverified claims (required on drafting PRs)
Any PR that adds or updates page content must state which UI labels, Settings paths, CLI flags, permission defaults, plan eligibility, and platform-support claims could not be verified against warp-internal, warp-server, or a live build. See step 9.5 of the draft_docs skill.
Include the section even when nothing is outstanding:
## Unverified claims
None — all UI labels, flags, defaults, and eligibility claims were verified against source.
When claims are outstanding, give the reviewer one bullet per claim with what would confirm it:
## Unverified claims
- `--auto-approve` flag name — `cloud-agents.mdx`, "Run an agent" — taken from the PRD; confirm against `TuiArgs` in `warp-internal`.
- **Settings** > **Agents** > **Permissions** path — `permissions.mdx`, "Defaults" — source repos were not available in this environment.
Additional context (optional)
- Link to related issues or discussions
- Screenshots for visual changes
- Notes for reviewers
CLI Workflow
Check if PR exists for current branch
gh pr view --json number,url
Exit code 0 if PR exists, 1 if not.
Create a new PR
:::caution
Always use --body-file instead of --body for PR descriptions. Documentation PRs frequently contain backticks, quotes, and other special characters that get corrupted by shell escaping when passed inline. Write the description to a file first, then reference it.
--body-file avoids shell-escaping corruption, but it does not catch repetition-loop degeneration — a failure mode where the model repeats a phrase or bullet several times and cuts off mid-token (e.g. a sentence ending in an unclosed inline-code span like because `m). That corrupted text is already in the generated body and survives --body-file unchanged. Always run the body integrity checker (check_pr_body.py) before creating or editing a PR.
:::
cat > /tmp/pr-body.md << 'EOF'
One short paragraph: what the feature does for the user, ending with
shipped in `<version>` (`<date>`).
Description of changes
- Change 1
- Change 2
Co-Authored-By: Oz <oz-agent@warp.dev>
EOF
python3 .agents/skills/create_pr/check_pr_body.py /tmp/pr-body.md \
--require-lead-section "## What this feature does"
gh pr create --title "docs: Add feature documentation" --body-file /tmp/pr-body.md
gh pr create --web
Request reviewers (required)
Naming a reviewer in the body is not a review request. A /cc @engineer mention notifies nobody through GitHub's review queue: the PR shows no requested reviewer, never appears in that engineer's "Review requested" filter, and quietly goes unreviewed. Every one of the four ambient-drafted docs PRs — #414, #415, #416, #417 — named reviewers in prose and received zero reviews; three had an empty requested-reviewers list and the fourth had a single reviewer added by hand.
So the mention stays, and a real request is added alongside it. A PR is not complete until gh pr edit --add-reviewer has succeeded and been verified.
A resolution failure must fall back, never no-op. When no owner resolves, assign dannyneira, matching the fallback the release docs workflow already uses (.github/workflows/release-docs-update.yml, "Assign last docs PR reviewer"). An unassignable reviewer is a problem to surface, not a reason to ship an unreviewed PR.
Two details below are load-bearing, and getting either wrong reintroduces the silent drop this section exists to prevent:
- Request one reviewer per call.
gh pr edit --add-reviewer a,b,c sends a single atomic mutation, so one unassignable entry rejects the whole list. Since a resolution routinely mixes users with a team, and a team with no access to this repo cannot be requested here, a comma-joined call can fail wholesale and take every valid owner down with it.
- Verify against the resolved set, not against emptiness. "Is the list non-empty?" passes when the real owner was dropped and only the fallback landed, which looks identical to success.
PR=123
FALLBACK_REVIEWER=dannyneira
REVIEWERS=$(python3 .agents/skills/missing_docs/scripts/suggest_reviewers.py \
--reviewers-only --warp ../warp --warp-server ../warp-server \
warp:app/src/settings/ssh.rs < /dev/null)
RESOLUTION_WAS_EMPTY=0
if [[ -z "$REVIEWERS" ]]; then
echo "warning: no owner resolved - falling back to $FALLBACK_REVIEWER"
REVIEWERS="$FALLBACK_REVIEWER"
RESOLUTION_WAS_EMPTY=1
fi
IFS=',' read -ra WANT <<< "$REVIEWERS"
GOT=()
for R in "${WANT[@]}"; do
if gh pr edit "$PR" --repo warpdotdev/docs --add-reviewer "$R"; then
GOT+=("$R")
else
echo "warning: could not request $R on PR $PR"
fi
done
() {
gh view --repo warpdotdev/docs \
--json reviewRequests --jq
}
REQUESTED=$(read_requested)
() { | ; }
() {
want target
want=$(_norm )
IFS= -ra _have <<<
target ;
[[ == ]] && 0
1
}
(( RESOLUTION_WAS_EMPTY ));
! has_reviewer ;
gh edit --repo warpdotdev/docs --add-reviewer ||
REQUESTED=$(read_requested)
[[ -z ]];
gh edit --repo warpdotdev/docs --add-reviewer ||
REQUESTED=$(read_requested)
[[ -z ]];
1
(( RESOLUTION_WAS_EMPTY )) && ! has_reviewer ;
\
1
IFS= -ra HAVE <<<
MISSING=()
R ;
found=0
H ;
[[ == ]] && { found=1; ; }
(( found )) || MISSING+=()
(( RESOLUTION_WAS_EMPTY ));
(( == ));
\
1
(( > ));
\
A partial result is a reportable outcome, not a pass: if some owners could not be requested, say which ones and why in the run output, so the gap is visible rather than buried. If even the fallback cannot be assigned, report the run as failed. Do not close out a PR whose requested-reviewers list is empty.
:::caution
A team handle resolved from STAKEHOLDERS or CODEOWNERS can only be requested on a repo that team has access to. warpdotdev/oss-maintainers is the root-rule owner in the warp client repo and therefore appears in most resolutions, but it has no access to warpdotdev/docs, so requesting it here fails. That is why step 3 requests one at a time.
:::
:::note
Auto-requesting the review does not make it block merge. Whether an ambient docs PR should require that approval through branch protection is an open question for the docs owner, not something this skill decides.
:::
Update an existing PR
When updating the body of an existing PR, make the smallest change rather than regenerating the whole description from memory — re-emitting a long body is what invites repetition-loop degeneration. Fetch the current body, apply a minimal or additive edit, verify it, then submit.
gh pr view 123 --json body --jq .body > /tmp/pr-body.md
python3 .agents/skills/create_pr/check_pr_body.py /tmp/pr-body.md
gh pr edit 123 --body-file /tmp/pr-body.md
gh pr edit 123 --title "New title"
gh pr edit 123 --add-label documentation
gh pr edit 123 --add-reviewer username
View PR status
gh pr status
gh pr checks
Co-Author Attribution
When creating commits or PRs with AI assistance, include attribution at the end of every commit message or PR description:
Co-Authored-By: Oz <oz-agent@warp.dev>
After Opening the PR
- Confirm the review request landed - Re-read
reviewRequests on the PR. An empty list means the PR is not finished, whatever the body says. See "Request reviewers (required)".
- Monitor for merge conflicts - If main is updated, merge it into your branch
- Respond to review comments - Address feedback promptly
- Re-run checks after changes - Run
trunk check and link checker after making updates
- Verify Astro Starlight preview - Astro Starlight automatically generates a preview for PRs; check that rendering looks correct
Best Practices
- Keep PRs focused - One logical documentation change per PR when possible
- Use descriptive titles - Start with
docs: prefix for documentation changes
- Follow the style guide - Refer to
AGENTS.md for voice, tone, and formatting conventions
- Test locally - Use
npm run dev to preview changes before opening PR
- Include context - Help reviewers understand why changes were made, not just what changed