Create or update a pull request for the current branch. Idempotent -- safe to run at any stage.
No direct pushes
Every change opens a pull request. Markdown is no exception: a Skill or instruction file changes agent behaviour in every repository, and a README change still earns a review. Never push to origin/main directly.
A Markdown-only pull request runs no CI where workflows filter Markdown at the event. Where a changes job skips the other jobs, it reports one passed changes check and skipped checks. A skipped check counts as passed. In both shapes the review is the whole gate, so treat the review outcome as the check.
When to invoke
Invoke on intent, not on phrasing. If the next command you are about to run is git switch -c, git commit, git push, or gh pr create, stop: this skill owns that sequence. Run it instead of the raw commands.
None of these are reasons to skip it:
- The user never said "PR". Once a fix is written and verified, "fix", "ship it", "land this", or a bare "yes" all mean land it. The trigger list in the description is examples, not a required wording.
- The change is small. A one-line fix or a docs edit still needs the repo's template, the AI disclosure, a body with no verification section, and green CI. Size changes none of that.
- Invoking costs a turn. Rewriting a hand-made PR body costs more, and a PR pushed without Step 4 can fail CI in front of a reviewer.
- You already ran the git commands. Then a PR exists and is probably wrong. Re-enter here anyway -- Step 1 detects the existing PR and Step 5 syncs it in place.
Running the git and gh commands by hand is the failure mode this skill exists to prevent.
Gotchas
- Never amend published commits -- CI and reviewers lose context. Always fix-forward with new commits.
- Never
--forcepush during a PR -- rewrites shared history. Usegit push(regular) after new commits. - A newer base alone needs no pull request commit. If strict branch protection requires an updated head, use the repository's normal update path. Restart CI and Review for the resulting head. Otherwise merge the base only when GitHub reports merge conflicts.
- Never
--no-verify-- if hooks fail, fix the underlying issue. gh pr mergerefuses a pull request that has a child -- GitHub asks for the stack merge. Usegh stack merge, and expect a child to turn CONFLICTING when its parent squash merges alone. Repair steps in references/stacked-prs.md.- Never move unknown changes -- primary checkout changes may belong to another task. Copy only changes this task owns.
gh pr createfails silently with bad body -- always use HEREDOC for the body, never inline quotes.- CI flakes vs real failures -- if the same check fails twice with different errors, it's flaky. If same error, it's real. Don't retry flakes more than once.
- CodeRabbit reviews can be noisy -- address security/correctness findings, but style suggestions are optional. Don't block the loop on nitpicks.
- Worktree cleanup -- if you forget
wt remove, orphaned worktrees accumulate. Clean up after merge.
Data Storage
Track PR history for reference across sessions:
# After creating/updating a PR, log it
echo "$(date -I) $(git branch --show-current) PR_URL" >> "${CLAUDE_PLUGIN_DATA}/pr-history.log"Read previous PRs when context is useful (e.g., finding related PRs, avoiding duplicate work).
Step 0: Own a Branch
git status --short
git branch --show-currentBefore any edit, follow the worktree isolation contract. It provides the atomic live-agent claim used below.
Keep the primary checkout read only. Mutate only in this task's wt worktree with a live claim.
Use origin/main for independent work, or the intended parent ref for stacked work.
Read the absolute worktree path from wt list --format=json and use it for every later command.
The shared contract owns creation, acquisition, renewal, and cleanup.
If this task's changes already exist in the primary checkout, leave that checkout untouched. List every verified task-owned path. Export git diff --cached --binary -- PATHS and git diff --binary -- PATHS separately. Apply the cached patch with git apply --index, then apply the unstaged patch. Copy owned untracked files individually. Compare every owned source path with its destination before continuing. Never reset, clean, stash, or overwrite the source checkout.
Never share a mutation worktree between tasks. Never use wt switch --clobber to resolve a path collision.
Step 1: Detect State
Run IN PARALLEL:
Bash: git log main..HEAD --oneline
Bash: git diff main...HEAD --stat
Bash: gh issue list --state open --limit 20 --json number,title
Bash: gh pr list --state open --limit 20 --json number,title,headRefName,baseRefName
Bash: gh pr view --json number,title,body,url 2>&1Determine what exists:
- No commits ahead of main and no uncommitted changes -> nothing to do, tell user
- PR exists -> we're syncing title/body, skip to Step 4
- No PR -> creating fresh, continue to Step 2
Stacked work
Read the open pull requests. If this change does not build, pass, or make sense without one of their diffs, it is stacked work: base the branch on that pull request in Step 0 and target it in Step 5.
Related but independent work is not stacked work. It targets origin/main, even when it touches the same files or closes a sibling issue. Independent pull requests merge in parallel; a stack merges in order and every child waits for its parent.
references/stacked-prs.md has the gh stack commands, the ones this skill bans, and the merge and repair steps.
Step 2: Find Related Issues
From the last 20 open issues, match titles against the branch name and commit messages. Use keyword overlap -- no need to be exact. If $ARGUMENTS contains an issue number, include that directly.
Step 3: Build PR Content
See references/conventional-commits.md for commit format rules.
Title: Conventional commit format -- feat:, fix:, docs:, chore:, etc. Under 70 chars. Use scopes where
appropriate (e.g., feat(auth):, fix(ui):).
Use the repo's effective template if it has one. Check .github/PULL_REQUEST_TEMPLATE.md, .github/pull_request_template.md, and docs/PULL_REQUEST_TEMPLATE.md. If none exists locally, read files.pull_request_template from repos/OWNER/REPO/community/profile. This resolves inherited templates from the owner's .github repository. Fetch the returned url, fill that template, and add only the required AI disclosure. Only use this fallback when the community profile has no template:
### 🔗 Linked issue
Resolves #NUMBER
<!-- or "Related to #NUMBER" if not a full fix -->
### ❓ Type of change
- [ ] 📖 Documentation
- [ ] 🐞 Bug fix
- [ ] 👌 Enhancement
- [ ] ✨ New feature
- [ ] 🧹 Chore
- [ ] ⚠️ Breaking change
### 📚 Description
<!-- why this is needed, then 1 to 2 sentences on what changed -->
> 🤖 AI disclosure: [Harlan Agent Kit](https://github.com/harlan-zw/harlan-agent-kit) modified this description. [My AI open-source policy](https://harlanzw.com/blog/ai-in-open-source).Reproduce that block character for character, including every emoji. Do not restyle it per repo.
Add ### ⚠️ Breaking Changes and ### 📝 Migration only when the change actually breaks or needs an operator step. Migration text is for the person running it: the command, the ordering constraint, and what it cannot recover.
Description gate
Load the installed Brundlefly pull-request-summary Skill before writing or revising the body.
Use ~/.agents/skills/pull-request-summary/SKILL.md in Codex.
Use the configured Claude Skills directory or OpenCode's configured Skill paths in those providers.
If it is missing, run pnpm sync:skills from Harlan Agent Kit, then load it.
Stop publication if the Skill cannot load. Do not substitute a second description rubric.
Supply the intended base, complete net diff, user intent, effective template, and current body when updating. Add these local description requirements:
- Use the effective template and preserve its required comments and sections.
- Omit verification, testing, and QA sections or mentions. CI owns that evidence. Evidence CI cannot produce belongs in the self-identified Agent comment from Step 5.
- Add Breaking Changes and Migration sections only when the operator needs them.
- Include relevant measured benchmarks. Never invent or estimate a figure.
- Append the exact AI disclosure from Step 3. Preserve it on every rewrite. Refuse publication if the disclosure is missing or changed.
- Preserve author notes, attachments, and reviewer decisions outside the requested edit.
- Include the PR Lens diagram when the Diagram rules below require it.
Use the returned body only after its description checks pass. Resolve required-input gaps before publishing dependent text. This Skill retains title rules, branches, commits, publication, CI, and Review. Re-read the remote body before an update. Reconcile concurrent edits before replacing it.
Diagram
Before writing the description, decide whether the change earns a diagram. Read the pr-lens skill and use its threshold: three or more modules, a crossed boundary, or a sequence a reviewer must follow. If it qualifies, author and render the graph document there, then reference the top architecture view from the description with a Markdown image and pass the same path to --attach on gh pr create or gh pr edit. One view is normal. Two is the ceiling unless the change is a large refactor.
A diagram goes in the description, after the why and before the AI disclosure. Never in a trailing comment.
Before pushing, load the installed Brundlefly im-part-human Skill for the title and description.
Preserve the Description gate, template, and disclosure.
After prose edits, repeat the pull-request-summary description checks.
Step 4: Verify
Run check before pushing (lint, typecheck, tests). Add pnpm build when the package publishes a build. Fix any failures before proceeding.
Step 5: Push & Create or Update
# Push if remote is behind
git push -u origin HEADIf PR exists -> update it:
HARLAN_AGENT_PR_SKILL=1 gh pr edit NUMBER --title "TITLE" --body "$(cat <<'EOF'
BODY
EOF
)"If no PR -> create it:
HARLAN_AGENT_PR_SKILL=1 gh pr create --title "TITLE" --body "$(cat <<'EOF'
BODY
EOF
)"For stacked work, add --base PARENT_BRANCH to gh pr create, then link it with gh stack link as the reference says: it only appends to the top of a stack. Open the description with Stacked on #PARENT_PR. Read references/stacked-prs.md before either command.
When Step 3 rendered a diagram, add --attach .pr-lens/<view>-dark-<hash>.svg for each image the body references. GitHub CLI rewrites the Markdown path to the uploaded asset.
Record the pull request URL. Continue to Step 6 after creation or update.
Log the URL to ${CLAUDE_PLUGIN_DATA}/pr-history.log.
For an Agent-submitted pull request in a repository tracked by harlan-github-agent, add harlan-agent-review.
This requests Review in Manual Selection mode and prevents prose classification from skipping it in Auto mode.
Read the matching Service Item with its authenticated /api/items/pull-request-status?repository=OWNER%2FREPO&number=NUMBER endpoint.
If it returns dismissed: true, leave the request label unset and report the Dismissal to Harlan.
A Dismissal survives new head commits.
If this step just created the pull request, a 404 can mean the Service has not observed it yet.
Add the Review request label, then wait for exact Item status before any fallback Review.
For an existing pull request, retry a 404 after the next Service observation.
Report a continuing 404 as missing Service state. For other responses, require dismissed: false before adding the label.
If the label is absent, create it with gh label create harlan-agent-review --color 8250df --description "Requests automated Review and repair".
Then add it to the pull request:
HARLAN_AGENT_PR_SKILL=1 gh pr edit NUMBER --add-label harlan-agent-reviewRecord the UTC time of this Review request for the current head SHA in the session scratchpad. Reset that time after every later push that changes the head. Do not add the label to an outside contributor's pull request. Never treat the label as a Review outcome.
Let the agent merge it
harlan-github-agent reviews every pull request it tracks. Add harlan-agent-auto-merge when the change holds no judgement, and the service merges it after a READY review:
- comments or wording inside non-Markdown files, with no behaviour change
- Markdown that nothing executes: a README, docs, or a blog post
- dependency bump or lockfile refresh
- formatting, lint autofix, or generated file refresh
- changelog or version bump
Never add the label to a change a reviewer must judge: source behaviour, public API, configuration, CI workflow, authentication, authorization, payments, data handling, or user-visible copy. Markdown an agent reads as instructions counts as source behaviour: Skills, agent-context/, CLAUDE.md, AGENTS.md, GLOSSARY.md, and .github templates. When unsure, leave it off. A missing label costs one human merge. A wrong label ships an unreviewed change.
Read references/auto-merge.md for the exact conditions. A repository whose service block sets auto_merge.pull_requests: every needs no label; the service merges every trusted pull request there after a READY review at that repository's minimum confidence.
gh label create harlan-agent-auto-merge --color 0e8a16 --description "Lets harlan-github-agent merge this after a READY review" 2>/dev/null || true
gh pr edit NUMBER --add-label harlan-agent-auto-mergePass --label harlan-agent-auto-merge to gh pr create instead when the label already exists. Remove it with gh pr edit NUMBER --remove-label harlan-agent-auto-merge when the pull request grows past the change it was added for.
Verification evidence goes here, as a comment, not in the description. Post it directly only on a repo the user owns or maintains, since it is part of submitting their own PR. Anywhere else, show the draft and let them post it. Post one only when you did something CI cannot show: ran a migration against a restored database, exercised the change in a browser, checked an authorization boundary by hand. Skip it entirely when the proof is just lint, typecheck, and the test suite; CI already reports those.
gh pr comment NUMBER --body "$(cat <<'EOF'
Checked by hand, since CI cannot cover it:
- Backfill on a 5 Aug 2026 live restore produced 7,438 snapshots, rerun added none
- Signed agreement kept the same SHA256 after editing venue, purchaser, and contract ID
- Crafted Staff export request returned 403
EOF
)"Keep it to the checks a reviewer would otherwise have to repeat. Prose lines, not ticked boxes.
Screenshots and video
For a visible change, read and follow media before capture, inspection, or upload. Keep verification evidence in a self-identified Agent comment. Do not attach screenshots of passing checks.
Step 6: Wait for CI and Review
For a tracked pull request, use pull request watching for repeated waiting. The Control CLI subscribes to Service events. Do not create a GitHub polling loop.
Keep ownership after submitting or updating the pull request. Complete this step for the current head SHA.
Green CI alone does not finish an Agent-submitted pull request tracked by harlan-github-agent.
If the Service controller publishes the pull request from an implementation Agent's result, that Agent returns first.
The controller owns Review, Repair, and this wait; waiting inside its implementation Task would stop Review from starting.
- Read the current head SHA with
gh pr view NUMBER --json headRefOid --jq .headRefOid. - Wait for GitHub Actions check runs. Use
gh run list --commit HEAD_SHA --limit 100to find this head's runs. Keep one observer for each repository and run ID. Reuse its foreground shell session after tool yields. For public repositories, useagent-gh run watch RUN_ID --repo OWNER/REPO --exit-status --interval 60 --compactfor each pending run. Then confirm every applicable run passed. For verified private repositories, scope eachgh run watchwithHARLAN_AGENT_GITHUB_PRIVATE=OWNER/REPO. Pass--interval 60 --compactthere too. Never use GitHub's default three-second interval. Write the repository, head SHA, run IDs, and observer sessions to the task receipt. If interrupted, read each saved run once, then resume only unfinished runs. Do not restart completed stages. Do not usegh pr checks --watchwhile Review is queued; the service's own check run can keep it waiting. A Markdown-only pull request may have no check runs, or only skipped ones besidechanges. Confirm that its workflows exclude the changed paths. Count a skipped check as passed. - Read the trusted
harlan-github-agentmarked comment and matching Review outcome label. Read issue comments withgh api repos/OWNER/REPO/issues/NUMBER/comments --paginate. Match<!-- harlan-agent-kit:pr-triage -->and<!-- reviewed-sha: HEAD_SHA -->. Trust only the GitHub App or a repository owner, member, or collaborator, as the review contract requires.REVIEWINGandharlan-agent-review-requiredmean Review has not finished.harlan-agent-review-skippeddoes not satisfy an Agent-submitted pull request. Confirm the Review request was recorded and wait for Review. The service may consume the request label before it posts the outcome. If Review isQUEUED, or no current-head Task appears, check capacity and elapsed time before waiting again. Respect a trustedPAUSED, stopped, or cancelled Review. Do not start another review for that head. - Read every finding in the terminal comment, plus other review and inline comments:
gh pr view NUMBER --json reviews,comments --jq '.reviews[].body, .comments[].body' gh api repos/OWNER/REPO/pulls/NUMBER/comments --paginate --jq '.[].body' - Read each scored finding from
/api/reviews?repository=OWNER%2FREPO&pull_request=NUMBER. Leave findings at 80/100 or below Logged. They do not require a code change. Mention them as optional follow-ups. Keep authorized Repair work moving until fixed or blocked by an exact boundary. If the resolution isDismissal, report theBLOCKEDoutcome and ask Harlan to decide whether to Dismiss the pull request. Do not repair or request another Review for a Dismissal finding. Act on findings with resolutionRepair. If the service owns a current-head Repair Task, let it finish before editing. This includesQueued,Running, andPublishingTasks. If its Queue is saturated, hand off to that durable Task. Otherwise reproduce the finding, fix it in this task's worktree, run focused checks, commit, and push. If a finding is false positive or not applicable, post one self-identified Agent comment naming the finding, its classification, and concrete evidence. That comment cannot change the service outcome. Ask Harlan to decide whether to dismiss or rerun the Review. Do not change the marked comment or Review outcome label yourself. ABLOCKEDoutcome remains blocked until the service publishes a new outcome. - After a push by the submitting Agent, check the targeted Service Item endpoint for Dismissal again.
If dismissed, report it and stop. Otherwise add
harlan-agent-reviewfor the new head and record a new Review request time. The Service consumes that label per head in Manual Selection mode. Then restart at step 1. A Service Repair commit keeps its own Approval; do not add the label for that commit. Never reuse CI or Review evidence from the old head SHA. Report success only when current-head CI passes or is correctly absent, the current-head Service Review isREADYor a stopped Service Review has a completed subagent assessment, and other material comments are handled. If a finding remainsBLOCKEDafter an evidence-backed false positive or not applicable comment, report that outcome and the comment link.
Count review-driven repair pushes by this submitting Agent across the entire pull request. After three, stop Agent-authored refinements and report remaining findings above 80/100 to Harlan. Do not reset the count because a new head commit starts a new Review. CI repair attempts keep their separate limit below. At that limit, do not start another fallback subagent Review. If an active Service Review Task owns the current head, hand off to that Task. If its Review is stopped, report the stopped Review and outstanding human decision. Never wait for a cancelled Task.
Review queue capacity
If Review is queued or its current-head Task is missing, read and follow Review queue capacity.
That Reference owns the capacity snapshot, fallback thresholds, exact-head stop, and independent subagent assessment.
Never delegate fallback Review before its stop and authority checks pass.
A stopped exact-head Review stays stopped. Report the independent assessment separately from Service READY.
Fix CI failures from the failing check logs (gh run view RUN_ID --log-failed).
Use new commits, never amend published commits. After three failed repairs for one cause, ask the user for guidance.
If the service cannot publish Review, report the exact blocker and keep the pull request open.
For a repository the service does not track, use CI and the available reviewers; state that automated Review was unavailable.
Do not post replies to other reviewers without approval. Draft a reply for a question or non-actionable comment and show it to the user.
Hand back the ready pull request
An active Service implementation Task returns to its controller instead of waiting here.
After current-head CI and Review pass, resolve the merge path using the Auto merge contract.
Check enabled policy, labels, and the current-head Merge risk verdict against that contract.
If the current head qualifies for automatic merge, use pull request watching in the foreground.
Keep the turn active until merge, actionable work, closure, or Dismissal.
On Merged, apply ../take-ownership/SKILL.md in Completion mode for the returned target and merge commit.
Verify required delivery and smoke stages before cleanup.
On ActionRequired, follow existing repair authority, then reassess the current head and merge path.
If automatic merge cannot progress, report the exact blocker. Preserve the target and unintegrated work.
After current-head CI and Review pass, check whether only Harlan's merge decision remains. If so, hand the pull request back. Record the repository, number, URL, head SHA, branch, and absolute worktree path in the session scratchpad. Retain current-head CI and Review evidence, remaining findings, and required delivery stages with that target. Report readiness and the pull request link, then end the turn. Preserve unintegrated work. Release this task's live worktree claim while no mutation is active. Ownership of later delivery remains with the submitting Agent. Do not start a background watch or promise an automatic chat wake-up.
If Harlan requests an active merge wait, use pull request watching in the foreground. Keep that turn active while the watch runs. Stop the watch if Harlan ends the wait.
When Harlan reports a merge or requests follow-up, resume the recorded target and read its current remote state.
Confirm the merge commit before applying ../take-ownership/SKILL.md in Completion mode for this exact pull request.
Verify required delivery, reconcile records, clean task-owned Git state, and report remaining work.
If it remains open, compare the current head with the recorded head before reusing evidence.
If the head changed, restart Step 6. Acquire the worktree claim before any mutation.
If actionable work remains, use the existing repair and publication rules.
If it is closed or dismissed, report that outcome and preserve unintegrated work.
Step 7: Cleanup (after merge or user says "finish")
If the PR was created from a worktree (Step 0), clean up:
wt remove BRANCH_NAMEwt remove removes the worktree. It deletes the local branch only when the branch is integrated. Never use --force or --force-delete to bypass this check.
Related review skill
This skill owns PR creation, metadata, CI monitoring, and review feedback repair.
../adversarial-review/SKILL.md exclusively owns the automated adversarial review outcome and marked bot status. Do not create or update that status here.
../take-ownership/SKILL.md wraps this workflow when one agent owns the current work through delivery verification.