That's it. No long description, no checklist. The channel is high-signal/low-noise.
-
Resolve PR
- If URL given, parse
owner/repo/pull/N.
- Else:
gh pr view --json url,title,number,body,headRefName,isDraft (in the current repo).
- Extract
title, url, number, isDraft.
-
Pre-flight checks — run all three before touching Slack. The goal is simple: don't waste the SC team's attention on a PR that obviously isn't ready. We surface problems to the executor and let them decide what to fix — this skill does NOT auto-create fix PRs (a sibling skill, planned as address-pr-review-comments, owns that separate concern).
a) Unresolved review threads — especially CodeRabbit, but any unresolved thread counts. REST doesn't expose isResolved, so use GraphQL:
gh api graphql -f query='
query($owner:String!,$repo:String!,$num:Int!){
repository(owner:$owner,name:$repo){
pullRequest(number:$num){
reviewThreads(first:100){
nodes{
isResolved
isOutdated
comments(first:1){ nodes{ author{login} body url path } }
}
}
}
}
}' -f owner=<owner> -f repo=<repo> -F num=<N> \
--jq '.data.repository.pullRequest.reviewThreads.nodes
| map(select(.isResolved == false and .isOutdated == false))'
Group results by author. CodeRabbit appears as coderabbitai / coderabbitai[bot].
b) CI status
gh pr checks <N>
Treat as blockers: non-success terminal states (FAILURE, CANCELLED, TIMED_OUT, ACTION_REQUIRED) except for review-gated checks (see allowlist below). IN_PROGRESS/QUEUED/PENDING/SKIPPED is informational, not a blocker on its own.
Review-triggered check allowlist — workflows wired to GitHub's pull_request_review event only fire after a reviewer submits a review. Pre-review they sit in SKIPPED/PENDING/ACTION_REQUIRED by design — they haven't been triggered yet. GitHub renders these in the checks list with a (pull_request_review) suffix on the check name. Posting to #dev-sc-review is literally how we trigger them, so blocking on them would be circular.
Rule: ignore (don't block, don't mention) any check whose name ends in (pull_request_review). This is the only allowlist criterion — it's a workflow-trigger fact, not a name-match.
Important: the same workflow often appears twice in the checks list — once push-triggered (runs on every commit, expected to pass) and once pull_request_review-triggered (runs only on review). E.g., in lifinance/contracts the names version-control, audit-verification, and a few protect-* checks appear in both forms. The push-triggered instance is a real blocker if it fails; the (pull_request_review) instance is not. Match on the suffix, not the bare name.
Some checks (e.g. SC Core Dev Approval Check, Protect security-critical code/system) only exist as pull_request_review workflows — they'll still match the suffix rule and be ignored automatically.
When in doubt about an unfamiliar check, surface it to the user and ask — don't silently allowlist anything beyond the (pull_request_review) rule.
c) Draft status — already captured from step 1 (isDraft).
-
Decide based on pre-flight
-
Unresolved comments OR failing CI → do NOT post. Summarize to the executor and stop:
Not posting to #dev-sc-review yet — please resolve these first:
Unresolved review threads (N total):
• coderabbitai (X): <url>, <url>, ...
• <other> (Y): <url>, ...
Failing CI checks:
• <check name>: <conclusion> — <details_url>
Once addressed (push fixes, mark CodeRabbit threads resolved), re-run this skill.
A separate skill (`address-pr-review-comments`, planned) will help draft a fix PR
that closes review comments — keeping that concern out of this skill.
Do not prompt to post anyway. The executor owns the call to fix vs. override.
-
CI in progress, nothing failing yet → tell the user, ask whether to wait or post anyway. Default: wait.
-
Draft + everything else clean → offer to mark ready via gh pr ready <N> before posting. Confirm first (visible to watchers). If user declines, ask whether to post anyway — drafts can be reviewed, but it's unusual.
-
Everything clean and PR is ready → proceed to step 4.
-
Confirm with user before posting — but skip the confirmation if the user's invoking message already constitutes consent.
Skip confirmation when the request includes an explicit imperative to post, e.g. "post for review", "push for review", "send it", "ship it", "post to dev-sc-review", "move to ready and push", or similar. In that case, post immediately and report what was posted afterward — re-asking is friction the user has already cleared.
Otherwise (the user only named the PR, asked to "prepare" a post, or the intent is ambiguous), confirm first. Slack posts are visible to others and reversible only by deletion, so when in doubt, ask:
About to post to #dev-sc-review:
<url> << <title>
Then reply in thread: "<!subteam^S096X6MCB0C> please review 🙏"
Proceed? (y/n)
If user says yes/y/go/ship, proceed. Otherwise wait for edits.
Note: the pre-flight gate in step 3 is the real safety net — it blocks accidental posts of broken PRs regardless of whether step 4 confirms. Step 4 is just about content/wording, which is fixed and predictable here.
-
Enable auto-merge (default; do this before posting to Slack).
Why: the SC team's review is the last gate. Once they approve and CI is green, the PR should merge itself — no second round-trip to the author. The reviewer's approval doubles as the merge signal.
Command:
gh pr merge <N> --repo <owner>/<repo> --auto --squash
Squash is the LI.FI default merge method for lifinance/contracts. If a future repo uses a different default, mirror it (--merge or --rebase); when unsure, surface to the user.
Handle these outcomes silently (just log a one-line note, then continue):
- Already enabled → no-op, move on.
- "Pull request is already in clean status" / mergeable now → it would merge immediately. Do NOT auto-merge before posting — disable and surface to user: "PR is already mergeable; not enabling auto-merge so the SC team can still review. Want me to merge now instead?"
- "Auto-merge is not enabled for this repository" → skip with a note: "Auto-merge isn't enabled on this repo; posting without it." Don't ask.
- Any other gh error → surface verbatim, ask whether to post anyway.
Opt-out: if the user's invoking message includes "without auto-merge", "no auto-merge", "don't auto-merge", or "manual merge", skip this step entirely.
-
Resolve channel ID via slack_search_channels (query: dev-sc-review). Pick the exact-name match.
-
Post top-level via slack_send_message:
channel_id: resolved ID
text: <url> << <title>
- Capture the returned
ts (message timestamp) — needed for threading.
-
Post thread reply via slack_send_message:
channel_id: same
thread_ts: the ts from step 7
text: <!subteam^S096X6MCB0C> please review 🙏
-
Confirm to user — include both the Slack permalink (if returned) and the auto-merge state (enabled / skipped / already-mergeable), e.g.:
Posted ✓ — auto-merge (squash) enabled