con un clic
process-prs
Process PRs
Instalar con Codex o Claude Copia este prompt, pégalo en Codex, Claude u otro asistente, y deja que revise la página de la skill y la instale por ti.
Menú
Process PRs
Instalar con Codex o Claude Copia este prompt, pégalo en Codex, Claude u otro asistente, y deja que revise la página de la skill y la instale por ti.
Basado en la clasificación ocupacional SOC
Canonical turn protocol for agents writing to Neotoma. Bounded retrieval on the user message, store user message PART_OF conversation with REFERS_TO edges to retrieved entities, store assistant reply the same way. Use this skill in any agent loop that should persist conversation state to Neotoma.
Session-end audit. Files remaining work as task entities and lists them as bullets, verifies all data intended for Neotoma storage from this session is actually stored, and persists what's missing. Invoke at the natural close of a working session, before context is lost.
Mid-session status report. Summarizes what's been achieved so far this session and what work remains, in succinct qualitative prose and bullets with only light technical detail. Read-only — stores nothing, files nothing. Invoke any time to take stock without closing the session.
Close a Neotoma working session — store the assistant reply and a session-close summary.
Retrieve the bounded context for the current session — recent interactions and relevant entities.
Begin a Neotoma working session — open a conversation and record the opening interaction.
| name | process_prs |
| description | Process PRs |
Use this skill to work the open PR queue end-to-end: assess merge readiness, run security gates, selectively request Claude Opus review on substantial PRs, merge eligible PRs, and hand off release PRs to /release.
When you want to triage and advance open PRs on the repository — checking CI status, running security checks, merging what is ready, and surfacing what is blocked.
Trigger with /process_prs, or naturally ("work the PR queue", "triage open PRs").
gh pr list --state open --json number,title,headRefName,baseRefName,isDraft,reviewDecision,statusCheckRollup,labels,mergeable,author
Exclude draft PRs from automated merge actions. Include them in the summary report.
The per-PR audit (Steps 1b, 1c, 2, 3-discovery) is read-only gh/git work with no cross-PR dependencies. It is the right shape for parallel subagent delegation: each subagent audits a disjoint batch, returns a structured verdict, and the main thread synthesizes and takes all merge/comment/review actions itself. This keeps mutation single-threaded (no two agents racing to merge) while collapsing the wall-clock cost of a large queue.
Partition first — do not audit every PR at full depth. From the Step 1 JSON, bucket PRs before spending audit budget:
mergeable: CONFLICTING → blocked-needs-rebase. These cannot merge regardless of any other signal. Do not deep-audit; list them in the report's rebase bucket. (Verify the bucket isn't masking a base-branch issue, but a conflicting PR is never merge-eligible this run.)baseRefName is not main/dev but another open PR's head) → blocked on parent. Note the parent; do not deep-audit until the parent lands.mergeable: MERGEABLE → the real audit candidates. These get the full Step 1b/1c/2/3 fan-out.When to fan out vs. inline: if the MERGEABLE candidate set is > 6 PRs, fan out. At or below that, audit inline on the main thread (subagent spin-up overhead isn't worth it). Scale the subagent count so each handles 3–5 PRs: ceil(candidates / 4) subagents, capped at 8.
Dispatch (single message, multiple Agent calls so they run concurrently):
subagent_type: "Explore" for the audit batches — it is read-only by construction (cannot merge, comment, or push), which is exactly the guarantee you want for a discovery agent. Give each one a disjoint list of PR numbers and the full per-PR audit checklist (CI status + mechanical-vs-substantive failure classification, base-branch/stacked detection, security-adjacency with triggering files, diff size + contract-surface flag, Step 1c review-blocker verdict with quoted blocking findings, linked-issue detection including the auto-close gap, and reviewDecision/mergeable). Require a terminal one-line verdict per PR: MERGE-ELIGIBLE | BLOCKED(<reason>) | STACKED(base=<branch>) | REVIEW-BLOCKED | SECURITY-GATE-NEEDED.code-reviewer subagent on that single PR. Use this sparingly — it is for the PRs where a holistic human-grade review matters, not routine triage.Synthesis is mandatory and adversarial — never act on a subagent verdict alone. Subagents read excerpts, not whole files, and will miss things. Before any merge, the main thread MUST independently re-confirm the load-bearing facts for that specific PR:
gh pr checks <n> and confirm the green run is against the current head SHA, not a months-old run. A subagent reporting "CI passed" may be quoting a stale run; main moving (or the baseline gate's openapi-drift check) can invalidate it. This is the single most common synthesis correction.gh pr diff <n> --name-only. Subagents have under-counted security-adjacency and contract-surface by trusting a PR's self-description or a stale rebase view. Verify src/actions.ts, openapi.yaml, and the security-adjacency file set directly.mergeStateStatus — CLEAN is required to merge; UNKNOWN means GitHub is still computing mergeability (wait/re-poll), BEHIND/DIRTY means rebase needed.Treat the subagent report as a prioritized worklist with evidence, not a decision. The main thread owns every gh pr merge, gh pr comment, gh issue comment/close, and @claude review call.
Before classifying for merge, check whether each PR needs (or needs another) automated Opus review. The claude_pr_review.yml workflow runs on synchronize events but deliberately skips claude/* branches to avoid runaway agent loops. This step compensates by explicitly posting @claude review on PRs that are worth a holistic look.
Skip review-requesting for:
claude/ — the workflow already runs on opened for theseFor newly opened PRs (state was just opened, no review comment yet):
gh pr diff <number> --stat
Parse the stat output to get: files changed, insertions, deletions. Also check whether the diff touches both src/ and openapi.yaml simultaneously:
gh pr diff <number> --name-only
Post @claude review if any of the following are true:
src/ and openapi.yaml (contract surface change)gh pr comment <number> --body "@claude review"
For PRs with new commits since last review was requested:
Find the most recent @claude review comment:
gh pr view <number> --json comments --jq '[.comments[] | select(.body | contains("@claude review"))] | last | .createdAt // empty'
If a prior review comment exists, count commits that landed after that timestamp:
gh api repos/{owner}/{repo}/pulls/<number>/commits --jq '[.[] | select(.commit.committer.date > "<last_review_iso_timestamp>")] | length'
Post another @claude review if new commits since last review ≥ 3.
Never post @claude review more than once per batch run on the same PR. If you already posted in this run, do not post again.
Reviews posted asynchronously by the Opus review job can land after the author pushed the final commit. The agent that merges later must not assume "review happened, so review was addressed." This step blocks merge on unaddressed substantive findings.
For each PR, fetch the most recent review comment from github-actions[bot]:
gh api repos/{owner}/{repo}/issues/<number>/comments \
--jq '[.[] | select(.user.login == "github-actions[bot]" and (.body | test("PR Review|Recommended|Blocker|Blocking|MUST|Findings"; "i")) and (.body | length > 300))] | last | {created_at, body}'
Detect and skip placeholder reviews that never completed:
I'll analyze this and get back to you. (no substantive content)usage.output_tokens was 0 (the action timed out or errored)If the most recent review is a placeholder, treat the PR as "review requested but not delivered" and re-post @claude review (subject to the once-per-batch cap in Step 1b).
For substantive reviews, classify findings by scanning the body for:
Blocker, Blocking, MUST, must fix, Required:, request changes, Verdict: request changes**1.**, ### 1., 1. **) that are not in a "Resolved" or "Verified" section## Approve, Verdict: approve, Resolved, or Non-blocking sectionIf the review has any Blocking items, the PR is review-blocked until either:
Waiver: <reason> on a per-finding basis acknowledging the deferral, or@claude review is requested and the new review's verdict is approve / approve in substance.Detecting "housekeeping commits" that do not count as addressing findings:
A commit is housekeeping (and does not clear a Blocking finding) if its message matches any of:
^chore: regenerate test catalog^chore: regenerate openapi types^chore: apply prettier formatting^chore: fix prettier formatting^Merge branch 'main' / ^Merge pull request^chore: rebase onto mainCounting these as "post-review work" is the exact pattern that caused PRs #152, #222, #223, #224, #178, #233, #232, #151 to merge with unaddressed findings on 2026-05-18.
Use this check to compute pending_review_blockers for each PR:
# Count substantive (non-housekeeping) commits after the latest substantive review
last_review_iso=$(gh api repos/{owner}/{repo}/issues/<number>/comments \
--jq '[.[] | select(.user.login == "github-actions[bot]" and (.body | length > 300) and (.body | test("PR Review|Recommended|Blocker|MUST|Findings"; "i")))] | last | .created_at // empty')
if [ -n "$last_review_iso" ]; then
gh api repos/{owner}/{repo}/pulls/<number>/commits \
--jq "[.[] | select(.commit.committer.date > \"$last_review_iso\") | select(.commit.message | test(\"^chore: (regenerate|apply|fix) prettier|^chore: regenerate test catalog|^chore: regenerate openapi types|^Merge branch|^Merge pull request|^chore: rebase\"; \"\") | not) | .sha[:8]]"
fi
If the review had Blocking items and zero substantive (non-housekeeping) commits landed after it, the PR is review-blocked. Post a summary comment listing the unaddressed findings and request fixes; do not merge.
A PR that changes agentic behavior — the instructions agents receive, the tools they can call, or the flows they execute — must demonstrate eval coverage before it can be merged.
Detect agentic behavior changes. A PR is agentic-behavior-adjacent if its diff touches any of:
docs/developer/mcp/instructions.mdsrc/tool_definitions.tssrc/server.ts.cursor/skills/*/SKILL.md.claude/skills/*/SKILL.mdagent_instructionssrc/services/ whose name contains agent or instructionDetection command:
gh pr diff <number> --name-only | grep -E \
'docs/developer/mcp/instructions\.md|src/tool_definitions\.ts|src/server\.ts|\.cursor/skills/.*/SKILL\.md|\.claude/skills/.*/SKILL\.md|agent_instructions'
If the command produces any output, the PR is agentic-behavior-adjacent.
Check for eval evidence. A PR satisfies the eval requirement if at least one of the following is true:
PR body references evals. The PR description body (not just title) contains at least one of: eval, agentic eval, agentic_eval, scenario, tier 1, tier 2.
gh pr view <number> --json body --jq '.body' | grep -iE 'eval|agentic_eval|scenario|tier 1|tier 2'
Linked issue references evals. Any issue closed by the PR (from gh pr view <number> --json closingIssuesReferences) has a body or comment referencing eval coverage.
New or modified eval fixture. The diff includes a file under tests/fixtures/agentic_eval/.
gh pr diff <number> --name-only | grep 'tests/fixtures/agentic_eval/'
Human reviewer confirmed evals pass. A human reviewer (non-bot) posted a comment containing eval coverage confirmed, evals pass, or evals verified (case-insensitive).
gh pr view <number> --json comments --jq '.comments[] | select(.author.login != "github-actions[bot]") | select(.body | test("eval coverage confirmed|evals pass|evals verified"; "i")) | .body'
If no eval evidence is found, the PR is eval-blocked. Post a comment on the PR:
This PR modifies agentic behavior (agent instructions, MCP tool definitions, skill files, or related paths) and does not yet have eval coverage.
**Before this PR can be merged, please provide at least one of:**
1. Update the PR description to reference passing evals (mention `eval`, `agentic eval`, `scenario`, or `tier 1`/`tier 2`).
2. Add or update an eval fixture in `tests/fixtures/agentic_eval/` that covers the changed behavior.
3. Post a comment confirming evals pass: `eval coverage confirmed` or `evals pass`.
See [docs/developer/eval_requirements.md](../docs/developer/eval_requirements.md) for how to write an eval fixture and what counts as eval evidence.
If eval evidence is found, continue to Step 2. Note this in the per-PR summary as "Eval coverage: ✓".
Note: a commit message referencing evals (e.g. test: add eval fixture for …) is not by itself eval evidence unless the commit also adds/modifies a fixture file under tests/fixtures/agentic_eval/.
For each PR that adds or modifies user-facing surfaces (CLI commands, flags, API endpoints, MCP tools, config knobs), verify that documentation was updated in the same PR.
Surfaces that require documentation updates:
docs/developer/cli_reference.md and docs/developer/cli_agent_instructions.mddocs/developer/mcp/tool_descriptions.yaml and docs/developer/mcp/instructions.mdopenapi.yamldocs/developer/cli_reference.md Runtime overrides tableCheck for missing docs coverage:
gh pr diff <number> --name-only
If the diff contains files under src/cli/ (new CLI surface), src/services/ (new tool behavior), or openapi.yaml — cross-check that the PR also modifies the corresponding doc files listed above.
If a documented surface was added or modified but the corresponding doc file was not changed:
Waiver: <reason> explaining why no doc update is neededA Waiver: comment on the PR is sufficient to clear a docs-blocked status.
For each PR that adds or modifies user-facing surfaces, verify that tests covering the new behavior were added or updated in the same PR.
Surfaces that require test coverage per change_guardrails_rules.md rules 19–21:
tests/cli/ exercising the command end-to-enddetectSource)Check for missing test coverage:
gh pr diff <number> --name-only
If the diff adds files in src/cli/ (new CLI command), src/services/ (new service behavior), or touches migration scripts — cross-check that the PR also adds or modifies test files in tests/ or co-located *.test.ts files.
For transcript/file-import surfaces specifically: verify that tests assert POST body structure (field names and values), not just the count of POST calls. A test that only counts calls will not catch a broken parser that sends {} instead of { file_path, observation_source }.
If a testable surface was added but no test covers it:
Test-waiver: <reason> explaining why coverage is not feasibleA Test-waiver: comment (distinct from Waiver: used for docs and review findings) is sufficient to clear a test-blocked status.
For each open PR, determine:
Is it a release PR? Criteria: base branch is main, head branch is dev (or configured integration branch), and package.json version bump is present in the diff.
/release to handle it. Do not inline release steps.Is it security-adjacent? A PR is security-adjacent if its diff touches any of:
src/actions.ts, src/services/local_auth.ts, src/middleware/, any route handlerprotected_routes_manifest.json, scripts/security/, docs/security/*auth*, *token*, *session*, *credential*, *permission*What is the CI status? Read statusCheckRollup from the PR JSON. Classify as: passed, failed, pending, or missing.
Is it mergeable? A PR is merge-eligible when:
passed (all checks green)reviewDecision is APPROVED or review is not required by branch protectionmergeable is MERGEABLEgithub-actions[bot] review and no substantive (non-housekeeping) commits or Waiver: comments since is review-blocked and must not be merged.Waiver: comment explains the omission.Test-waiver: comment explains why coverage is not feasible.gh pr merge.For security-adjacent PRs — mandatory before merge:
npm run security:lint
Errors are blocking. Warnings are noted but do not block. If errors are found, report them on the PR and do not merge until resolved.
npm run security:manifest:check
npm run test:security:auth-matrix
Both must pass. If security:manifest:check fails due to an out-of-date manifest (not a code error), run:
npm run security:manifest:write
and confirm the manifest change is staged in the PR branch before re-running the check.
For all other PRs — advisory:
Run npm run security:lint and report results. Do not block merge on warnings, but surface any errors for the PR author.
Do not run security:classify-diff, security:ai-review, or the deployed probes (deployed_probes.sh) — those are release-scoped gates that run in /release Step 3.5 and Step 5.
For each PR that passes all merge-eligibility criteria, before running gh pr merge, walk every issue the PR claims to close and post a closure-narrative comment on it. This memorializes the work and forces a final verification that every original ask was addressed.
The auto-close behavior of GitHub (Closes #N in PR body) only posts a generic merge-link comment. That is not sufficient: it does not verify that each bullet of the issue body was addressed, does not reconcile review-thread follow-ups, and does not call out explicit deferrals.
Detect the linked issues:
# Issues GitHub auto-tracks (must be in body via "Closes/Fixes/Resolves #N")
gh pr view <number> --json closingIssuesReferences --jq '[.closingIssuesReferences[].number]'
# Also scan the PR body and commit messages for bare references that GitHub did
# not parse (e.g. "fix bugs #168 #170 #171 #172" — only #168 auto-closes).
gh pr view <number> --json body,commits --jq '.body, (.commits[].messageHeadline), (.commits[].messageBody // "")' \
| grep -oE '(closes|close|fixes|fix|resolves|resolve)\s+#[0-9]+' -i | sort -u
# Any issue listed here that is NOT in closingIssuesReferences will not be
# auto-closed at merge time — flag it for manual `gh issue close` after merge.
Closure comment shape (uniform across PRs):
Resolved by PR #<pr> (merged <yyyy-mm-dd>). Shipping in **v<version>**.
## What the issue asked for
<bullets quoted from the issue's Expected / Proposed fix / Acceptance / Problem section>
## How it was addressed
<concrete description of the fix: bullets from the PR's Summary section,
ideally referencing file:line or commit SHA for each ask. If the PR closes
multiple issues, include only the bullet that pertains to *this* issue.>
<If review-thread follow-ups for this PR landed in a separate cleanup PR,
note that explicitly: "Review-thread follow-ups for PR #X were addressed in
cleanup batch PR #Y.">
## Verification
<bullets from the PR's Verification / Test plan section, with checkboxes
ticked since the PR has merged.>
## Deferred / out of scope (if applicable)
<bullets describing any original-issue ask or review-comment ask that was
NOT addressed by this PR, with a link to the follow-up issue or a written
reason for the deferral.>
Operationally:
For each linked issue, read the issue body (gh issue view <iss>) and the PR body (gh pr view <pr>).
Build the comment per the shape above. Quote the issue's original asks verbatim where possible.
Verify that every original ask appears in the "How it was addressed" or "Deferred" section. If any ask is unaccounted for, do not merge — push back on the PR author or file a follow-up issue.
Post the comment:
gh issue comment <iss> --body-file <draft.md>
If the issue is in the "auto-close gap" list from the detection step (closure verb in body/commit but not in closingIssuesReferences), close it manually after merge:
gh issue close <iss> --reason completed
Skip the closure comment for:
For each PR that passes all merge-eligibility criteria AND has closure comments posted on every linked issue:
gh pr merge <number> --merge --delete-branch
Use --merge (no-ff merge) to preserve PR history. Use --squash only if the PR branch has a single logical commit and the repo convention allows it. Do not rebase-merge.
After merging, confirm the merge succeeded and manually close any auto-close-gap issues identified in Step 4:
gh pr view <number> --json state,mergedAt
# For each issue in the auto-close gap list:
gh issue close <iss> --reason completed
For each PR that cannot be merged, take the appropriate action:
security:lint errors or manifest/auth-matrix failures. Do not merge.Waiver: <reason> comments per finding, or re-request @claude review after the fixes. Do not merge.Waiver: <reason> explaining why no doc change is needed. Do not merge.Test-waiver: <reason> explaining why coverage is not feasible. Do not merge./release.Produce a comprehensive summary covering:
@claude review was posted and why (new substantial PR, or N new commits since last review)/release to ship these" callout| Gate | Command | When to run | Blocks merge? |
|---|---|---|---|
| G2 static lint | npm run security:lint | All PRs | Yes, on errors |
| G3a manifest check | npm run security:manifest:check | All PRs | Yes, on failure |
| G3b auth matrix | npm run test:security:auth-matrix | All PRs | Yes, on failure |
Gates not run here (release-only):
| Gate | Reason |
|---|---|
G1 security:classify-diff | Requires --base <last-tag>; release-scoped semantic |
G4 security:ai-review | Requires tag, writes to release supplement path |
| G5 deployed probes | Requires live deployed environment |
The /release Step 3.5 re-runs G2 and G3 against the exact release commit as a hard gate. The duplication is intentional: PRs merged to dev weeks before release may be followed by commits that break the gates.
main directly. Merges to main only happen via /release./release.--no-verify.github-actions[bot] review with Blocking findings followed only by housekeeping commits is not a green light. The author must either (a) land non-housekeeping fix commits, (b) post Waiver: <reason> comments per deferred finding, or (c) trigger a re-review whose verdict is approve.Waiver: comment explains the omission.Test-waiver: comment explains why coverage is not feasible.gh pr merge for every PR that closes a linked issue. Auto-close alone does not produce a resolution trail.closingIssuesReferences).@claude review on a claude/* branch PR — the workflow already runs on opened for those.@claude review more than once per batch run on the same PR.@claude review on trivially small PRs (≤5 files, ≤150 lines, no contract surface changes, not security-adjacent).I'll analyze this and get back to you. with 0 tokens) as "review not delivered," not "review approved." Re-trigger once per batch.Explore (read-only) for audit-batch subagents so they structurally cannot merge, comment, or push. Keep every mutating action (gh pr merge, gh pr comment, gh issue comment/close, @claude review) on the main thread.mergeStateStatus on the main thread before merging — never merge on a subagent's verdict alone./release@claude review on every push — only request when the diff genuinely warrants a holistic re-review (≥3 new commits since last request)chore: regenerate test catalog / prettier / rebase-merge commits as "post-review fixes." They are housekeeping and do not clear review blockers.I'll analyze this and get back to you. with 0 output tokens) as completed reviews. Re-trigger and wait for a substantive review.closingIssuesReferences), close the issue manually after merge with gh issue close <iss> --reason completed and a comment linking the resolving PR.Waiver: comment as clearing a test-blocked status. Docs waivers and test waivers are distinct; only Test-waiver: clears a test-blocked status.