.agents/skills/pr-gardening/SKILL.md
Actively garden pull requests referenced by Paperclip issues active in a recent window. Candidate discovery and readiness checking are scripts, not LLM analysis. GitHub access is read-only throughout this workflow.
gh commands or mutating GitHub API requests. The scripts only use gh pr view and read-only gh api GET requests.--dry-run suppresses all Paperclip mutations, including gardening comments and inbox archives. Discovery and GitHub inspection remain read-only in every mode.--days <N>: issue activity window, default 30.--repo <owner/repo>: GitHub repository, default detected by gh repo view.--dry-run: discover, verify, and report without posting comments or archiving inbox entries.--archive-inbox: after GitHub confirms a candidate PR is merged at its current head, archive the originating issue from the responsible user's inbox in Stage D.--cooldown-hours <N>: repeat-comment cooldown, default 48.--max-rounds <N>: maximum gardening rounds per PR, default 3.Use a run-owned directory such as $PAPERCLIP_RUN_SCRATCH_DIR/pr-gardening for generated files.
Run the extract-search path. It scans every result page, rejects truncated match sets, normalizes PR URLs, deduplicates PR numbers, records every mentioning issue, checks issue work products to identify the origin, and drops PRs that GitHub says are merged or closed.
node .agents/skills/pr-gardening/scripts/find-candidates.mjs \
--days 30 \
--dry-run \
--output "$RUN_DIR/candidates.json"
The script calls GET /api/companies/:companyId/search/extract with kind=url, scope=all, and updatedWithin=<N>d. Do not replace it with full issue-list fetching or LLM scanning.
node .agents/skills/pr-gardening/scripts/check-readiness.mjs \
--input "$RUN_DIR/candidates.json" \
--output "$RUN_DIR/readiness.json" \
--dry-run
For every candidate, the script re-fetches the current head SHA and records:
statusCheckRollup check-run and legacy status inventory;success or neutral;reviewDecision;Verdicts are ready, needs_gardening, or report_only for drafts. Always rerun this stage after any wake or claim that a PR was fixed. Never trust issue comments as proof of readiness.
If gardening decides a branch needs a follow-up task to create a single pull request, deduplicate before creating anything.
For each branch, process one branch at a time and do this serially:
backlog, todo, in_progress, in_review, and blocked.Never fan out follow-up task creation in parallel. Do not issue concurrent POST /api/companies/:companyId/issues calls for create-PR tasks. After P1's issue-create idempotency support is available, every create-PR follow-up task creation must include idempotencyKey: "pr-gardening:create-pr:{branch}", where {branch} is the exact branch name.
Skip this stage in --dry-run mode and for ready or report_only entries.
For each needs_gardening PR, use originatingIssue from candidates.json. Selection priority is:
pull_request work product;Before commenting, fetch the issue comments and search for this marker:
<!-- pr-gardening:<owner/repo>#<number> -->
Do not comment if the latest matching marker is newer than the cooldown. Track rounds from matching markers; after three rounds, stop nagging and report not converging; recommend close or human decision. This is a recommendation for human disposition, not an instruction to close the PR.
When a comment is allowed, mention the originating issue assignee, instruct them to run /prepare-pr, include the current head SHA, and copy the exact machine-detected reasons[]. Use POST /api/issues/:issueId/comments with X-Paperclip-Run-Id. Include resume: true when the issue is terminal so the comment creates a live continuation.
Suggested body:
<!-- pr-gardening:paperclipai/paperclip#1234 -->
@Assignee please run `/prepare-pr` for https://github.com/paperclipai/paperclip/pull/1234.
Current-head verification at `abc123` found:
- failing check: test
- Greptile missing at current head
Gardening round 1/3. Re-verification is required after changes; do not merge based on this comment.
Run this stage only when the caller explicitly supplied --archive-inbox. --dry-run always suppresses inbox mutations, even when --archive-inbox is also present. Without the flag, do not archive anything.
Stage D applies to a previously monitored candidate that transitions to merged. Rerun Stage B immediately before this stage and require GitHub to report state: merged for the same current head SHA recorded by that verification. Fresh Stage A discovery intentionally drops PRs that were already merged or closed.
For each qualifying candidate, archive its originatingIssue from the responsible user's inbox with POST /api/issues/:issueId/inbox-archive and an empty JSON body. Do not pass userId; the Paperclip API resolves the responsible user from the gardener's run context and enforces that user's inbox-agent policy. GitHub access remains read-only.
Do not archive PRs that are merely ready, closed without merging, draft, pending, or merged at an unverified or stale head. Never archive an originating issue while the user is still awaiting review, a decision, approval, or other action on it. If Paperclip denies the mutation because the responsible user is unresolved, inbox management is disabled, the gardener is not allowlisted, or a trust boundary applies, report the denial and continue without retrying around policy.
After a successful archive, leave a standard gardening marker comment on the originating issue that names the archived issue and merged PR:
<!-- pr-gardening:paperclipai/paperclip#1234 -->
Inbox tidy-up: archived [PAP-310](/PAP/issues/PAP-310) from the responsible user's inbox after confirming https://github.com/paperclipai/paperclip/pull/1234 merged at current head `abc123`.
This archive is audited and reversible; later issue activity may resurface the item.
Use POST /api/issues/:issueId/comments and include X-Paperclip-Run-Id on both the archive and comment requests. In --dry-run, report the archive and marker comment that would have been written, but perform neither mutation.
Set the gardening run issue's blockedByIssueIds to the non-terminal issues commented in Stage C so blocker resolution wakes the gardener. A scheduled or manual rerun is the fallback.
On every wake, rerun Stage B first. A PR terminates from active gardening only when one of these is mechanically observed:
ready at the current head;Do not leave the gardening issue blocked on terminal issues. Do not poll agents or long-running sessions.
node .agents/skills/pr-gardening/scripts/render-report.mjs \
--input "$RUN_DIR/readiness.json" \
--output "$RUN_DIR/gardening-report.md"
The report groups open PRs by confidence:
Upload candidates.json, readiness.json, and gardening-report.md to the gardening issue, create/update the gardening-report issue document with the Markdown body, and leave a summary comment linking the artifacts. The report is the deliverable; it is never authorization to merge.
Run focused script tests:
node --test .agents/skills/pr-gardening/scripts/pr-gardening.test.mjs
For a live dry run, execute Stages A, B, and F with --dry-run, then sanity-check named PRs only if they are still open. Merged or closed examples should appear under droppedClosedPullRequests, not in readiness results. If also exercising --archive-inbox, confirm the report describes the suppressed Stage D action and that no Paperclip archive or marker-comment mutation occurred.