Skip to content
Development
Skill

/loop-bb-pr

Compose a /loop that monitors a Bitbucket PR for activity (new comments, review state changes, merge, decline) via the bb-api wrapper. Use when the user says "watch bitbucket PR", "monitor BB PR", "loop-bb-pr", "слідкуй за PR", "поллі bb pr", or pastes a

From plugin
lets-workflow
1718 skills15 agents23 commands
Install
$ npx -y skills add restarter/lets-workflow --skill loop-bb-pr --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/loop-bb-pr

Context preview

The summary Claude sees to decide when to auto-load this skill.

Compose a /loop that monitors a Bitbucket PR for activity (new comments, review state changes, merge, decline) via the bb-api wrapper. Use when the user says "watch bitbucket PR", "monitor BB PR", "loop-bb-pr", "слідкуй за PR", "поллі bb pr", or pastes a

SKILL.md

loop-bb-pr.SKILL.md
name: loop-bb-pr
description: Compose a /loop that monitors a Bitbucket PR for activity (new comments, review state changes, merge, decline) via the bb-api wrapper. Use when the user says "watch bitbucket PR", "monitor BB PR", "loop-bb-pr", "слідкуй за PR", "поллі bb pr", or pastes a bitbucket.org/<workspace>/<repo>/pull-requests/<id> URL and wants periodic check-ins. Composes a paste-ready /loop block — does NOT invoke /loop (UI command). Local test skill.

loop-bb-pr

Compose a `/loop` that periodically polls a Bitbucket PR via the `bb-api` wrapper and surfaces changes (new comments, review state, merge, decline).

The skill **never invokes `/loop` itself** at initial start — Claude Code's `/loop` is a UI command. It composes the prompt and presents for paste; once active, the autonomous run uses `ScheduleWakeup` directly per tick (that part is model-callable).

> **IMPORTANT:** If the spec below invokes any deferred tool (e.g. `AskUserQuestion`), you MUST load and call it as specified.

Step 1: Resolve PR URL

Parse `args` parameter for URL. If not provided, AskUserQuestion:

AskUserQuestion(
  questions=[{
    question: "Bitbucket PR URL to watch?",
    header: "PR URL",
    options: [
      { label: "I'll paste it", description: "Send the bitbucket.org/.../pull-requests/N URL in your next message" },
      { label: "Cancel", description: "Abort composition" }
    ],
    multiSelect: false
  }]
)

If user picks "I'll paste it", wait for URL in their next message.

**Normalize then validate** — real BB URLs often have query strings (`?at=branch&type=...`) or trailing slashes. Strip before regex match:

URL="<from input>"
URL="${URL%%\?*}"   # strip query string (everything from ? onward)
URL="${URL%#*}"     # strip fragment (everything from # onward)
URL="${URL%/}"      # strip trailing slash

Then **strict validation** — normalized URL must match exactly:

^https://bitbucket\.org/[a-zA-Z0-9_-]+/[a-zA-Z0-9_.-]+/pull-requests/[0-9]+$

If validation fails: surface error, exit. Do NOT proceed with malformed URL — the composed prompt may persist (if user switches to interval mode in v1.1) and we don't want arbitrary input in `.claude/scheduled_tasks.json`.

Extract via regex or sed (from normalized URL):

  • `WORKSPACE` — first segment after `bitbucket.org/`
  • `REPO` — second segment
  • `PR_ID` — final numeric segment

Step 2: Verify bb-api availability

which bb-api 2>/dev/null

If `bb-api` not found in PATH:

┌─ LETS ─────────────────────────────────┐
│  bb-api not available.                 │
│  Install bb-api wrapper first.         │
│  (curl fallback planned for v1.1.)     │
└────────────────────────────────────────┘

Exit. v0 hard-requires bb-api.

Step 3: Verify access (always run)

Default-on pre-flight: confirm bb-api auth + URL points at a real PR before composing a 1200s loop. Cheaper to fail here than to ship a /loop the autonomous run immediately rejects.

bb-api get "/repositories/$WORKSPACE/$REPO/pullrequests/$PR_ID" 2>&1 | head -20

Always surface the result to the user as a short summary (title, state, comment count) — confirms what they're about to watch.

If error:

  • **401/403 (auth)** → surface "Bitbucket auth failed — check bb-api credentials" and exit
  • **404** → surface "PR not found at <URL> — check URL" and exit
  • **other errors** → surface verbatim error and exit

Never proceed to compose a /loop if Step 3 fails.

Step 4: Compose /loop

Substitute slots:

  • `<URL>` — validated URL from Step 1
  • `<WS>` `<REPO>` `<ID>` — parsed components
  • `<STATE_FILE>` — `.lets/loop-state/bb-pr-<ID>.json` (relative to project root)

Template (dynamic mode — model self-paces via ScheduleWakeup):

/loop check Bitbucket PR <URL> for activity since baseline.

State file: .lets/loop-state/bb-pr-<ID>.json (workspace=<WS>, repo=<REPO>, id=<ID>)

Use bb-api to fetch (READ-ONLY):
- `bb-api get /repositories/<WS>/<REPO>/pullrequests/<ID>` → state, title, participants
- `bb-api get /repositories/<WS>/<REPO>/pullrequests/<ID>/comments` → count, latest activity timestamp

On FIRST tick (state file does not exist):
- Create .lets/loop-state/ directory if missing
- Write baseline to .lets/loop-state/bb-pr-<ID>.json as JSON: {state, comment_count, latest_activity, approver_count, title, captured_at}
- Report "baseline established for PR #<ID> (<title>): state=<X>, comments=<N>, approvers=<M>"
- Reschedule via ScheduleWakeup(delaySeconds=1200, prompt=<this entire /loop prompt verbatim>, reason="watching BB PR <ID> — baseline")

On SUBSEQUENT ticks (state file exists):
- Read baseline from .lets/loop-state/bb-pr-<ID>.json
- Fetch current state via bb-api (both endpoints above)
- Compare:
  - If state changed to DECLINED or MERGED → report final state and STOP (do NOT call ScheduleWakeup)
  - If comment_count increased → report "N new comments since last check, latest from <user> at <time>" and STOP
  - If approver_count increased → report "approver added: <username>" and STOP
  - If nothing changed → report "no change (T+<minutes>m since baseline)" and reschedule via ScheduleWakeup(1200, verbatim, "watching BB PR <ID> — no change")

Hard constraints (READ-ONLY enforcement):
- Loop must NOT call bb-api with POST/PUT/DELETE
- Loop must NOT comment, approve, decline, merge, or change PR state
- Loop must NOT push to the PR's branch
- On bb-api auth error (401/403): report "Bitbucket auth failed" and STOP (do NOT retry blind — user must investigate)
- On 404 (PR not found / deleted): report "PR not accessible" and STOP
- On other transient errors (timeout, 5xx): log error and reschedule ONCE. If second consecutive error of same type, STOP and surface.
- Never re-baseline silently — the baseline is captured ONCE on first tick

Termination (each STOP surfaces a single-paragraph summary in assistant text):
- state-change-final: PR closed/merged/declined
- comment-detected: new comments since baseline
- approver-change: app
Read more
Ships withlets-workflow

A development workflow plugin for Claude Code Stop babysitting your AI. Start shipping with it.

Get the whole plugin

Other skills on lets-workflow.