| name | ship-pr |
| description | Babysit a PR: iterate with AI reviewers and CI until green, get it ready, optionally squash-merge as Kody and watch the deploy, then send a Discord summary. Medium risk waits for AI reviewer(s) and addresses valid feedback. Use when a pull request needs to be shepherded to done.
|
Ship PR
Risk → merge authority
Self-assess; user policy overrides.
- Low — green CI; nits ignorable; squash-merge when policy allows.
- Medium — wait for AI reviewer(s); address valid feedback (ignore
insignificant nits / already-fixed / wrong); then merge when policy allows.
- High — leave ready-for-review unless the user granted merge authority.
Loop
- Mark ready —
kody:@kentcdodds/github/pr/set-review-status
{ prUrl, status: 'ready' } (or owner/repo/prNumber).
- Wait for CI —
gh pr checks (or compose loop-on-ci / fix-ci).
- Fix failures; for medium+, wait on AI reviewer(s) and address valid
feedback. Rebase only when actually unmergeable. For medium+, also run
npm run preview:manual-test as the seeded user with data for this
change (--request / session cookie; see
preview-manual-test skill).
- Green + (medium+: valid feedback cleared) → break.
- Push → repeat.
Gates ≠ CI
Blocked on soak / parity CHECK / calendar gate → end the run and schedule a
wake (execute + workflows.create({ runAt, idempotencyKey }) calling
createRun). Don't sleep-poll or code-thrash an intentional time window.
Leftovers that wait on that gate need a GitHub issue (Cleanup: title); see
cleanup-after-migrations.
Batch related expand steps into fewer PRs when risk posture allows.
Merge / deploy
When policy + risk allow: squash-merge via kody:@kentcdodds/github/pr/merge
{ prUrl, mergeMethod: 'squash' }, watch deploy. Useful: pr/get-checks,
request, graphql on the same package.
Done → Discord
Always summarize (merged or not) by calling
kody:@kentcdodds/discord/send-shipped-pr with structured fields. Do not
use raw post-message and do not invent token cost or model id — the export
fetches billed Cursor usage for cost, and you pass model from metadata.
agentId (required):
model (deterministic — never infer):
- In a Cursor Cloud Agent VM, read the model that served this turn:
curl -fsS --unix-socket "${CURSOR_AGENT_SOCKET:-/run/cursor/api.sock}" http://cursor-agent/v1/meta-data/turn/model.
Auto resolves to the concrete model that served, not Auto. See
https://cursor.com/docs/cloud-agent/metadata
- Outside a managed VM, pass the model.id used at create/launch if recorded.
- If missing, omit model so the export posts Model pending — do not invent one.
import sendShippedPr from 'kody:@kentcdodds/discord/send-shipped-pr'
export default async function main() {
return sendShippedPr({
agentId,
model,
title: 'PR title',
summary: 'What shipped / parked / blocked and why.',
prUrl: 'https://github.com/owner/repo/pull/1',
repo: 'owner/repo',
extras: ['CI green', 'preview verified'],
status: 'Shipped',
})
}