From pr-jangler
PR Jangler final-call workflow. Use when the orchestrator dispatches the decision phase for a reviewed PR or when the user runs 'prj-decision' to label, comment, and log a ready-to-merge / request-changes / close-as-not-now verdict.
How this skill is triggered — by the user, by Claude, or both
Slash command
/pr-jangler:prj-decisionThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
This skill closes the loop on a reviewed PR. One invocation aggregates the per-PR cache (review, verification, fix-plan, adversarial, implementation, overlap, decisions log), applies a deterministic rubric over the structural gates, optionally consults LLM judgement for ambiguous cases, then applies the `prj/decision:{class}` GitHub label, posts a structured summary comment from the template at...
assets/template-decision-comment.mdscripts/__pycache__/aggregate.cpython-314.pycscripts/__pycache__/decision_io.cpython-314.pycscripts/__pycache__/rubric.cpython-314.pycscripts/__pycache__/run.cpython-314.pycscripts/aggregate.pyscripts/decision_io.pyscripts/rubric.pyscripts/run.pyscripts/tests/__init__.pyscripts/tests/__pycache__/test_aggregate.cpython-314.pycscripts/tests/__pycache__/test_decision_io.cpython-314.pycscripts/tests/__pycache__/test_rubric.cpython-314.pycscripts/tests/__pycache__/test_run.cpython-314.pycscripts/tests/test_aggregate.pyscripts/tests/test_decision_io.pyscripts/tests/test_rubric.pyscripts/tests/test_run.pyThis skill closes the loop on a reviewed PR. One invocation aggregates the per-PR cache (review, verification, fix-plan, adversarial, implementation, overlap, decisions log), applies a deterministic rubric over the structural gates, optionally consults LLM judgement for ambiguous cases, then applies the prj/decision:{class} GitHub label, posts a structured summary comment from the template at assets/template-decision-comment.md, appends a JSONL entry to prs/{n}/decisions.log, and transitions the PR's phase in state.json.
Act as a senior reviewer making a defensible call. The cache is the evidence. The rubric is the law. Never decide on "vibes." Every output must trace back to a cache artifact.
scripts/run.py) resolve from the skill root.{project-root}/... resolves from the project working directory.[modules.prj] in {project-root}/_bmad/config.toml.prj-orchestrator's state_io module (imported via sys.path); this skill never touches state.json directly.Load configuration from {project-root}/_bmad/config.toml. The required key is prj_repo (owner/name). The PR number is supplied via --pr <number> (the orchestrator passes the highest-priority PR; CLI users supply it explicitly). If prj_repo is missing, exit early with status misconfigured; if --pr is missing, exit with status bad-args.
Execute the decision:
python3 scripts/run.py --pr <number>
That single script handles aggregation, rubric application, label, comment, decisions.log append, state transition, and run-log entry. Flags:
--pr <N> (required) the PR number to decide on--dry-run compute the decision and log the intent, but do not apply label, post comment, or transition state--verbose emit diagnostics to stderr--project-root <path> override autodetectSee python3 scripts/run.py --help for full detail.
Three classes, evaluated in order. The first class whose gates all pass wins.
All three must hold:
last_maintainer_activity_at field on the PR state entry (set by prj-discover when comments are reconciled). Absent or older than 30 days → gate (a) passes.triage.md classification is definite-no, ORoverlap.md verdict is redundant, ORdecisions.log shows 2 or more entries with kind: "adversarial-escalation".If all three hold, decision is close-as-not-now. The label is applied. The comment makes explicit that the PR is NOT auto-closed; the maintainer closes manually.
All four must hold:
review.md has no severity: "blocker" findings, OR all blocker findings have a corresponding entry in implementation.md with addresses_finding: <id>.implementation.md shows tests: "pass" AND regressions: "none". If no fix was needed (no implementation.md), the review's tests_status must be pass or absent (PR is doc-only / chore).overlap.md is absent OR verdict is independent or complementary. conflicting or redundant block this class.adversarial.md exists, its verdict is pass. reject or escalate block this class.Default fallback when neither close-as-not-now nor ready-to-merge apply. Requires at least one actionable signal:
blocker or major finding in review.md, ORverification.md exists with verdict verified AND no fix-plan.md follow-through, ORadversarial.md verdict is reject (single rejection — escalation is the close gate).If none of those hold either, the rubric returns request-changes with confidence: "low" and the LLM activation context is responsible for either confirming or escalating to please-advise (not a decision class, but a phase). In practice the orchestrator should not have dispatched decision in this case; this branch is a safety net.
| Decision | From phase | To phase | Notes |
|---|---|---|---|
ready-to-merge | Reviewed, FixImpl | ReadyToMerge | Terminal. Maintainer merges manually. |
request-changes | Reviewed | Reviewed | No transition; PR stays for next round. next_action clears. |
close-as-not-now | Reviewed, Blocked | Rejected | Terminal. PR is NOT auto-closed on GitHub. |
A PR already in a terminal phase (ReadyToMerge, Rejected, Archived, Blocked — except moving from Blocked to Rejected) is treated as no-op: status: "already-decided".
The deterministic rubric handles the structural gates. Where the cache contains qualitative signals the rubric cannot reduce (e.g. "review found a major issue but the fix-plan claims it is out-of-scope") the rubric returns decision: "request-changes" with confidence: "low" and a list of ambiguity_signals. In normal cron-driven operation that result is taken at face value (conservative default). When the orchestrator routes the activation to a model context, the model may override using the comment-template's "Notes" section to record the override rationale. Overrides are written to the decisions.log with kind: "llm-override" so the audit trail is preserved.
This skill reads:
{project-root}/_bmad/config.toml{project-root}/_bmad-output/pr-workflow/state.json{project-root}/_bmad-output/pr-workflow/prs/{n}/review.md{project-root}/_bmad-output/pr-workflow/prs/{n}/verification.md{project-root}/_bmad-output/pr-workflow/prs/{n}/fix-plan.md{project-root}/_bmad-output/pr-workflow/prs/{n}/adversarial.md{project-root}/_bmad-output/pr-workflow/prs/{n}/implementation.md{project-root}/_bmad-output/pr-workflow/prs/{n}/overlap.md{project-root}/_bmad-output/pr-workflow/prs/{n}/triage.md{project-root}/_bmad-output/pr-workflow/prs/{n}/decisions.logassets/template-decision-comment.mdThis skill writes:
{project-root}/_bmad-output/pr-workflow/state.json (via state_io.save_state, atomic){project-root}/_bmad-output/pr-workflow/prs/{n}/decisions.log (append-only JSONL){project-root}/_bmad-output/pr-workflow/logs/{YYYY-MM-DD}.jsonl (append-only run-log)gh pr edit --add-label prj/decision:{class}gh pr comment <n> --body-file <tmp>The comment posted to GitHub uses assets/template-decision-comment.md. The placeholders are simple {name} tokens substituted by decision_io.render_comment:
{decision_class} one of ready-to-merge, request-changes, close-as-not-now{summary} one-line summary of the call{findings_block} bulleted list of outstanding findings (or "None."){outstanding_items} bulleted list of action items for the maintainer (or "None."){recommendation} next-step recommendation in plain prose{cache_paths} newline-joined list of cache artifacts the decision drew from{run_id} correlation id with the run-log entryFor close-as-not-now, the comment explicitly states: "This PR has not been auto-closed. If you agree with this assessment, close it manually."
close-as-not-now is non-negotiable. Two-of-three is request-changes, not close.close-as-not-now labels and comments; user closes manually.state_io.save_state.Smoke-test with a populated per-PR cache (no gh required if --dry-run):
python3 scripts/run.py --pr 42 --dry-run --verbose
Run the unit tests (all subprocess invocations mocked):
python3 -m unittest discover scripts/tests
npx claudepluginhub delorenj/pr-jangler --plugin pr-janglerGuides creation, editing, and verification of skills for AI coding agents using test-driven development with subagent scenarios. Use when authoring or debugging skills.