ワンクリックで
prj-detect-overlap
// PR Jangler duplicate and overlap detector. Use when the orchestrator dispatches the overlap check after triage marked a PR as possible-duplicate, or when the user runs 'prj-detect-overlap' for manual debug.
// PR Jangler duplicate and overlap detector. Use when the orchestrator dispatches the overlap check after triage marked a PR as possible-duplicate, or when the user runs 'prj-detect-overlap' for manual debug.
PR Jangler hub. Cron-driven autonomous workflow for triaging, verifying, reviewing, fix-planning, adversarially validating, fix-implementing, deciding, and daily-reporting on a GitHub PR backlog. Use when the user mentions "PR jangler", "pr-jangler", "PR backlog workflow", "PR triage", "autonomous PR review", "fix-plan", "fix-PR", "adversarial validator", "PleaseAdvise", or wants to install, configure, or extend the PR Jangler BMad module. Routes to 12 phase skills, owns the cross-cutting state-file conventions, idempotency rules, GitHub-label vocabulary, and 1Password/SMTP/`gh`/`op` dependency map shared by every phase. Triggers on prj-setup, prj-orchestrator, prj-discover, prj-triage, prj-verify-claim, prj-review, prj-detect-overlap, prj-plan-fix, prj-validate-adversarial, prj-implement-fix, prj-decision, prj-report-daily.
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.
PR Jangler GitHub-to-queue sync. Use when the orchestrator dispatches the discovery sweep (on cadence or empty queue) or when the user runs 'prj-discover' for manual debug.
PR Jangler Tier-2 implementer. Use when prj-validate-adversarial passed for a PR and the orchestrator dispatches FixImpl. Pushes a fix branch and opens a fix-PR into the contributor's branch; falls back to a comment if the contributor's branch refuses PRs.
PR Jangler cron heartbeat dispatcher. Use when cron invokes one heartbeat of the PR backlog workflow or when the user runs 'prj-orchestrator' for manual debug.
PR Jangler fix-planning workflow. Use when a Trello-like comment claim on a PR has been verified by prj-verify-claim and a fix plus failing-test plan must be designed before any implementation. Activated by prj-orchestrator when a PR's phase is FixPlan.
| name | prj-detect-overlap |
| description | PR Jangler duplicate and overlap detector. Use when the orchestrator dispatches the overlap check after triage marked a PR as possible-duplicate, or when the user runs 'prj-detect-overlap' for manual debug. |
This skill is the overlap-and-duplication detector for the PR Jangler module. One invocation scores one target PR's file footprint against every other open PR in the queue, runs a structured semantic comparison on the high-overlap pairs, and writes a verdict that drives the next phase transition. The deterministic plumbing (file overlap scan via gh pr diff --name-only, label application via gh pr edit, overlap report rendering, atomic state I/O) lives in Python scripts. The semantic comparison itself is LLM-driven from assets/prompt-semantic-compare.md; the script accepts the per-pair verdicts on the CLI and persists them.
Act as a careful cross-referencer. Treat any 2-shared-files pair as worth a semantic look, but apply verdicts conservatively: independent is the default when comparison is unclear, redundant requires near-identical intent on near-identical files, and conflicting requires the two diffs to disagree on the same lines or contracts.
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.The orchestrator passes --pr-number N (the target). Load configuration from {project-root}/_bmad/config.toml ([modules.prj]). Required key: prj_repo. If absent, exit early with status misconfigured and a clear run-log entry.
Two-step workflow:
python3 scripts/run.py --pr-number N --scan
This invokes gh pr diff --name-only for the target PR and every other open PR, computes intersections, and emits a JSON pairs report on stdout. Each pair carries the two PR numbers, the shared file list, and the overlap count. Pairs with fewer than 2 shared files are filtered out and listed under skipped.
If pairs is empty, the script writes the overlap report (empty table), transitions the PR to ReviewPending, applies no labels, and exits. No semantic comparison is needed.
For every pair returned in step 1, read assets/prompt-semantic-compare.md, fill in the variables (target PR diff, other PR diff, shared files), and run the comparison. Pick exactly one verdict per pair:
independent — the two diffs touch the same files but address unrelated concernsconflicting — the two diffs disagree on the same lines, the same contracts, or mutually exclusive approachescomplementary — the two diffs work together; the older one logically lands firstredundant — the two diffs do the same thing on the same surface; one of them should be closedThen persist all verdicts in one call:
python3 scripts/run.py --pr-number N --verdicts-json '{"82": "complementary", "75": "independent"}'
The script applies labels, writes the overlap report at prs/{n}/overlap.md, executes the phase transition, and appends a run-log entry. Pass --rationale-json '{"82": "...", "75": "..."}' to surface one-paragraph rationales in the report (optional but strongly recommended; the prompt asks for them).
Flags on scripts/run.py:
--pr-number N (required) — target PR number.--scan — run step 1 only (emit pairs as JSON, do not persist).--verdicts-json STR — JSON object mapping other_pr_number (string) -> verdict.--rationale-json STR — JSON object mapping other_pr_number (string) -> one-paragraph rationale.--dry-run — compute everything, log intent, do not call gh, do not write state, do not write the report.--skip-label — perform state and cache writes but skip the gh label call.--verbose — emit progress diagnostics to stderr.--project-root PATH — override autodetect.See python3 scripts/run.py --help for full detail.
The target PR receives one final phase based on the strongest verdict across all pairs (most-severe wins):
| Strongest pair verdict | Target PR phase | Target PR next_action | Labels applied |
|---|---|---|---|
redundant | Rejected | null | prj/overlap:duplicate, prj/triage:definite-no |
conflicting | Blocked (target is newer) | null | prj/overlap:conflicts-with-{other-pr} (per pair) |
complementary | ReviewPending | {skill: "prj-review", mode: null} | prj/overlap:depends-on-{older-pr} (per pair) |
independent only | ReviewPending | {skill: "prj-review", mode: null} | none |
Severity order: redundant > conflicting > complementary > independent.
If verdict is conflicting and the target PR is older than its counterpart (by phase_entered_at ascending, fallback to PR number ascending), the OTHER PR moves to Blocked instead, with blocking_on set to the target. Either way, the script also sets blocking_on on the blocked PR.
For complementary pairs, older_pr is the lower PR number tiebroken by earlier phase_entered_at. The label encodes the dependency direction: the newer PR carries prj/overlap:depends-on-{older-pr-number}.
complementary verdicts also append a one-line note to the target PR's cache at prs/{n}/overlap-notes.md so the daily report can surface the merge-ordering recommendation.
| Concern | Lives in |
|---|---|
| Shared state I/O (atomic load, save, runlog) | state_io (imported from prj-orchestrator/scripts) |
File overlap computation + gh pr diff --name-only calls | scripts/overlap_scan.py |
| Label application + report rendering + phase transitions | scripts/verdict_io.py |
| Orchestration: config, scan, verdict persist, runlog | scripts/run.py |
| Semantic-compare prompt (LLM input) | assets/prompt-semantic-compare.md |
The script split keeps each module narrow and independently testable. run.py itself is mostly argument routing. The semantic comparison is the LLM's job, not Python's: the prompt asset is the contract.
This skill writes to:
{project-root}/_bmad-output/pr-workflow/state.json (via state_io.save_state, atomic){project-root}/_bmad-output/pr-workflow/prs/{pr_number}/overlap.md (overwritten each run){project-root}/_bmad-output/pr-workflow/prs/{pr_number}/overlap-notes.md (append-only, complementary pairs only){project-root}/_bmad-output/pr-workflow/logs/{YYYY-MM-DD}.jsonl (append-only run-log)prj/overlap:* labels per the verdict aggregation tableThis skill reads from:
{project-root}/_bmad/config.toml (config){project-root}/_bmad-output/pr-workflow/state.json (prior queue state; finds all other open PRs)gh pr diff --name-only (changed-file lists for target and every other open PR)independent. redundant requires near-identical intent on near-identical files.state_io.save_state. Direct file writes to state.json are forbidden.overlap.md is overwritten; overlap-notes.md appends.Smoke-test the scan step (requires gh auth, reads target PR's changed files):
python3 scripts/run.py --pr-number 82 --scan --verbose
Expected: exit 0, JSON on stdout with pairs array, no state changes.
Then exercise verdict persistence in dry-run mode (no gh, no state writes):
python3 scripts/run.py --pr-number 82 --verdicts-json '{"81": "complementary"}' --dry-run --verbose
Expected: exit 0, run-log entry with status: "dry-run", no state changes, no label applied, no overlap.md written.
Run the unit tests (no gh calls; all subprocess invocations mocked):
python3 -m unittest discover scripts/tests