12# Community PR Readiness Check
13
14Given a PR number or branch name, determine whether it is ready for human review and take the right follow-up action.
15
16## Decision tree
17
181. **Bot author** (n8n-cat-bot / aikido-autofix) → cleanup-only, no review. See "Internal automation PRs" below.
192. **Auto-rejection screen matches** (typo-only / unsanctioned new node) → action path **D — close** with the matching template.
203. **All checks pass** (readyForReview === true) → action path **B — triage to team**.
214. **One or more checks fail** → action path **A** (if title is minor-fix only) then **C — post comment**.
22
23## Step 1 — Resolve the PR
24
25If given a branch name, find the PR number first:
26
27```bash
28gh pr view <branch> --repo n8n-io/n8n --json number --jq .number
29```
30
31## Step 2 — Fetch and pre-process
32
33```bash
34gh pr view <number> --repo n8n-io/n8n \
35 --json number,title,body,author,headRefName,headRefOid,files,isDraft,state,labels
36```
37
38### Internal automation PRs (bot authors)
39
40If author.login is one of n8n's internal bots — n8n-cat-bot / app/n8n-cat-bot or aikido-autofix / app/aikido-autofix — skip the PR entirely and perform the cleanup actions below. Do **not** emit any JSON output.
41
421. Relabel the PR (both bots): swap community → n8n team:
43 ```bash
44 gh pr edit <number> --repo n8n-io/n8n --remove-label community --add-label "n8n team"
45 ```
462. Update the linked Linear ticket (extract GHC-XXXX per step 5):
47 - **n8n-cat-bot** — cancel: mcp__linear-server__save_issue with state: "Canceled", no labels.
48 - **aikido-autofix** — route to Dev Platform: mcp__linear-server__save_issue with team: "Developer Platform", state: "Triage", no labels.
49
50When reviewing a batch, omit the skipped PR from the output. For a single PR, emit a one-line note (e.g. Skipped & cleaned up #30591 (n8n-cat-bot): relabeled to n8n team, cancelled GHC-8398.).
51
52### Collision guard
53
54If triage:in-progress is already on the PR, another reviewer is mid-triage — **bail out** to avoid double-processing. Emit a one-line note (e.g. Skipped #30205: already has triage:in-progress) and move on to the next PR. Do not run the checks, do not modify labels, do not touch Linear.
55
56If the user explicitly asks to re-process a PR that's stuck on triage:in-progress (e.g. a previous run crashed), they can clear the label manually and re-invoke.
57
58### Otherwise — mark in-progress
59
60Strip any existing triage:* state label before adding triage:in-progress, so the single-state invariant holds even when re-reviewing a PR that was previously sent back with triage:needs-info or triage:tests-needed:
61
62```bash
63gh pr edit <number> --repo n8n-io/n8n \
64 --remove-label "triage:pending" \
65 --remove-label "triage:needs-info" \
66 --remove-label "triage:tests-needed" \
67 --remove-label "triage:complete" \
68 --add-label "triage:in-progress"
69```
70
71Only one of those triage:* labels will actually be present; --remove-label errors when a label is missing, so run each removal as its own call (or batch and ignore errors) and then do the add. A PR carries exactly one triage:<state> label at a time; the skill replaces triage:in-progress with a terminal state before exit (see reference/label-flow.md).
72
73### Also fetch (in parallel)
74
75```bash
76# cubic-dev-ai PR review comments (for check E)
77gh api --paginate "repos/n8n-io/n8n/pulls/<number>/comments" \
78 --jq '.[] | select(.user.login == "cubic-dev-ai[bot]") | {body: .body, path: .path}'
79
80# n8n-assistant issue comments (for the Linear ticket reference)
81gh api --paginate "repos/n8n-io/n8n/issues/<number>/comments" \
82 --jq '[.[] | select(.user.login == "n8n-assistant[bot]" or .user.login == "n8n-assistant") | .body] | join("\n")'
83```
84
85## Step 2.5 — Auto-rejection screen
86
87Per [CONTRIBUTING.md](../../../../../CONTRIBUTING.md), two PR patterns should be closed outright rather than reviewed:
88
89- **Typo-only PR** — diff is entirely spelling/grammar fixes with no logic or tests.
90- **New-node PR** — adds a brand-new node, unless the n8n team has explicitly agreed to take it.
91
92If either matches, set checks.AutoReject and skip directly to action **D**. Full rules and how to verify each pattern: see reference/checks.md.
93
94## Step 3 — Run the five checks
95
96Run when AutoReject is null. Full rules for each in reference/checks.md:
97
98- **A. CLA** — cla-signed label present.
99- **B. Title** — matches the conventional-commit regex. Authoritative rules in [.github/pull_request_title_conventions.md](../../../../../.github/pull_request_title_conventions.md).
100- **C. Description** — every section heading and checklist item from [.github/pull_request_template.md](../../../../../.github/pull_request_template.md) is present in the PR body. The template is read at check time, so changes to it propagate automatically.
101- **D. Tests** — source logic changes have matching test files. Skip for docs/ci/chore/build PRs.
102- **E. cubic-dev-ai** — no unresolved comments (resolved = "Addressed in commit" marker).
103
104## Step 4 — Identify the responsible team
105
106Run node .github/scripts/owners.mjs against the changed file list and map the winning GitHub team to a Linear team. Full mapping table, sub-agent fallback procedure, and label rules: see reference/teams.md.
107
108## Step 5 — Extract the Linear ticket
109
110n8n-assistant leaves a comment on every community PR containing This PR has been added to our internal tracker as "GHC-XXXX". Search the concatenated n8n-assistant comment body for \bGHC-\d+\b, take the first match.
111
112If no n8n-assistant comment exists (older PRs that predate the automation), linearTicket is null.
113
114## Step 6 — Output JSON
115
116```json
117{
118 "readyForReview": <true if all passing checks allow merge, false otherwise>,
119 "messageForUser": "<Short message to the contributor listing what they need to address. 'N/A' if ready.>",
120 "team": "<Linear team name (from reference/teams.md), or 'Engineering' as fallback>",
121 "linearTicket": "<GHC-XXXX or null>",
122 "checks": {
123 "AutoReject": <"typo-only" | "new-node" | null>,
124 "CLA": <bool>,
125 "Title": <bool>,
126 "Description": <bool>,
127 "TestsNeeded": <bool>,
128 "TestsIncluded": <bool>,
129 "CubicIssues": <true if unresolved cubic issues exist, false otherwise>
130 }
131}
132```
133
134readyForReview is true only when: AutoReject is null; CLA, Title, and Description are all true; CubicIssues is false; and either TestsNeeded is false or TestsIncluded is true. If AutoReject is set, readyForReview is always false.
135
136Emit the JSON first, then take the appropriate action path below.
137
138## Step 7 — Action paths
139
140Use AskUserQuestion for each prompt. Sub-agents called for analysis only should stop after step 6 and let the caller drive step 7.
141
142### A — Minor title fix
143
144A title issue is **minor** if it can be repaired by a deterministic transformation:
145
146- Leading or trailing whitespace.
147- First letter of the summary in the wrong case.
148- Trailing period.
149- Mixed case revert: requiring lowercase (no change needed, just flag).
150
151If the *only* failing check is Title (or Title + CubicIssues) and the issue is minor, propose the fix and ask Apply proposed / Edit before applying / Skip. Apply with:
152
153```bash
154gh pr edit <number> --repo n8n-io/n8n --title "<new title>"
155```
156
157Then re-evaluate Title (now passes) and continue to **B** or **C**. Non-minor title problems (wrong/missing type, no colon, hyphenated scope) need contributor input — skip A and go to **C**.
158
159### B — Triage to team (readyForReview === true)
160
161Ask: *"PR is ready for review. Assign Linear ticket <linearTicket> to team <team> and move to <destination state>?"* Options: Yes, assign and triage / No, leave as-is.
162
163Destination state: Review for NODES, Triage for every other team. Label composition: see reference/teams.md.
164
165On Yes:
166
167```python
168# 1. Linear
169mcp__linear-server__save_issue(
170 id=linearTicket,
171 team=<team>,
172 state=<destination>,
173 labels=<computed labels>,
174)
175# 2. GitHub (only if Linear succeeded) — see reference/label-flow.md
176gh pr edit <number> --repo n8n-io/n8n \
177 --remove-label "triage:in-progress" \
178 --remove-label "status:pending-assignment" \
179 --add-label "team:<slug>" \
180 --add-label "status:team-assigned" \
181 --add-label "triage:complete"
182```
183
184If linearTicket is null, ask whether to create a new Linear ticket before triaging (older PRs predating n8n-assistant). Otherwise skip B and ask the user.
185
186### C — Post contributor comment (readyForReview === false, no auto-reject)
187
188Show messageForUser and ask Post as-is / Edit before posting / Skip. On post:
189
190```bash
191gh pr comment <number> --repo n8n-io/n8n --body "<final message>"
192```
193
194Then apply the right terminal triage label — exactly one, priority triage:tests-needed > triage:needs-info. See reference/label-flow.md. On Skip, leave the PR on triage:in-progress so the next loop picks it up.
195
196Skip C entirely if A already handled the only failing check and the PR is now ready — run B instead.
197
198### D — Close the PR
199
200Used when the PR should be closed rather than reviewed. Three common triggers:
201
2021. **Auto-rejection** (AutoReject set) — typo-only or unsanctioned new node.
2032. **Duplicate** — another open PR addresses the same change.
2043. **Out of scope / bundled** — multiple unrelated fixes that should be split, or scope n8n team has declined.
205
206Ask Close + comment / Edit before closing / Skip. Templates below; pick one and adapt to the contributor and specifics.
207
208**Typo-only:**
209> Thanks for taking the time to send this in! Per our [contributing guide](../blob/master/CONTRIBUTING.md#community-pr-guidelines) we don't accept typo-only PRs — they create review overhead without changing functionality, and our spell-checker rules cover most cases automatically. Closing this for now; please feel free to open a PR that pairs a typo fix with a related logic change. 🙏
210
211**New node:**
212> Thanks for the contribution! n8n no longer accepts new nodes directly into the core monorepo unless the team has explicitly agreed to scope one in. Please publish this as a [community node](https://docs.n8n.io/integrations/creating-nodes/overview/) instead — that gives you full ownership and avoids the long review queue here. Closing this PR per our [contributing guide](../blob/master/CONTRIBUTING.md#community-pr-guidelines).
213
214**Duplicate of another PR:**
215> Thanks for the contribution! This change is already being handled in #<other-pr>, which is further along in review. Closing this in favour of that PR to keep the queue tidy — please feel free to chime in over there if there's anything missing.
216
217**Bundled / out of scope:**
218> Thanks for the contribution! Per our [contributing guide](../blob/master/CONTRIBUTING.md#community-pr-guidelines) we ask for one focused change per PR. This PR bundles <N> unrelated fixes — please reopen them as separate, focused PRs, each with the [template](../blob/master/.github/pull_request_template.md) filled in and a unit test that locks in the regression. Closing this one in the meantime. 🙏
219
220Close action (same for every reason):
221
222```bash
223gh pr comment <number> --repo n8n-io/n8n --body "<final message>"
224gh pr close <number> --repo n8n-io/n8n
225gh pr edit <number> --repo n8n-io/n8n \
226 --remove-label "triage:in-progress" \
227 --remove-label "status:pending-assignment" \
228 --add-label "status:internal-closed" \
229 --add-label "triage:complete"
230```
231
232If linearTicket is set, also cancel it: mcp__linear-server__save_issue(id=linearTicket, state="Canceled"). If gh pr close reports the PR is already closed (contributor beat you to it), proceed with the comment, labels, and ticket cancellation anyway.
233
234## Notes
235
236- **Draft PRs** — report all findings but note the PR is a draft.
237- **Already merged or closed** — say so and skip the checks (don't apply triage labels).
238- **Re-reviewing a PR you've already commented on** — use the GitHub Timeline API to detect contributor activity since the last skill touch. See reference/re-review.md.
239- **Label state machine** — single triage:<state> label at any time; transitions documented in reference/label-flow.md.
240