Files
OutBack Dingo 6d9dbbb3b9 fork: rename IronClaw → OptimClaw
Full rename of all identifiers, filenames, and references:
  ironclaw → optimclaw
  IronClaw → OptimClaw
  IRONCLAW → OPTIMCLAW
  ironclaw_common → optimclaw_common
  ironclaw_safety → optimclaw_safety

Upstream: nearai/ironclaw
2026-03-29 06:27:52 +07:00

10 KiB

description, disable-model-invocation, allowed-tools, argument-hint
description disable-model-invocation allowed-tools argument-hint
Full PR lifecycle — review, fix findings, address comments, quality gate, push, CI fix loop, merge true Bash(gh pr view:*), Bash(gh pr diff:*), Bash(gh pr comment:*), Bash(gh pr merge:*), Bash(gh pr checks:*), Bash(gh pr edit:*), Bash(gh pr list:*), Bash(gh pr checkout:*), Bash(gh api:*), Bash(gh repo view:*), Bash(gh run view:*), Bash(gh run watch:*), Bash(git diff:*), Bash(git log:*), Bash(git fetch:*), Bash(git checkout:*), Bash(git status:*), Bash(git branch:*), Bash(git add:*), Bash(git commit:*), Bash(git push:*), Bash(git merge:*), Bash(git rebase:*), Bash(cargo fmt:*), Bash(cargo clippy:*), Bash(cargo test:*), Bash(cargo check:*), Read, Edit, Write, Grep, Glob, Agent <pr-number or url> [--fix] [--merge] [--review-only]

PR Shepherd

Full PR lifecycle: review → fix → quality gate → push → CI → merge.

Parse $ARGUMENTS:

  • Extract PR number from bare number or https://github.com/owner/repo/pull/123 URL.
  • Flags: --fix (auto-fix without asking), --merge (merge when CI green), --review-only (stop after review, don't fix).
  • If no PR number, detect from current branch: gh pr list --head $(git branch --show-current) --json number --jq '.[0].number'
  • If still nothing, stop and ask the user.

Phase 1: Situational Awareness

Gather everything in parallel:

PR metadata:

gh pr view {number} --json number,title,body,author,baseRefName,headRefName,headRefOid,state,isDraft,mergeable,mergeStateStatus,files,additions,deletions,labels,reviewRequests

Diff:

gh pr diff {number}
gh pr diff {number} --name-only

CI status:

gh pr checks {number} --json name,status,conclusion,detailsUrl

Review comments (human + bot):

gh api --paginate repos/{owner}/{repo}/pulls/{number}/comments
gh api --paginate repos/{owner}/{repo}/pulls/{number}/reviews

Resolve {owner}/{repo}:

gh repo view --json owner,name --jq '"\(.owner.login)/\(.name)"'

Save headRefOid — needed for posting line comments later.

Assess the situation and print a status card:

PR #{number}: {title}
Author: {author}    Base: {base} ← {head}
Size: +{additions} -{deletions} across {file_count} files
CI: {PASS|FAIL|PENDING|NONE}    Mergeable: {yes|no|conflict}
Reviews: {N approved, N changes_requested, N comments-only, N bot-only}
Unresolved comments: {N}
Draft: {yes|no}

Decide the mode based on situation:

  • Has unresolved review comments → Phase 2a (address comments first, then review remaining)
  • No reviews yet / bot-only reviews → Phase 2b (full deep review)
  • CI failing, no review issues → Phase 4 (jump to CI fix)
  • Everything green + approved → Phase 6 (ready to merge)

Phase 2a: Address Existing Review Comments

For each unresolved review comment or review with CHANGES_REQUESTED:

  1. Read the referenced code at the file and line mentioned. Never assess without reading.

  2. Classify each comment:

    • Valid & unresolved — needs a code fix
    • Already fixed — a later commit addressed it
    • False positive — explain why the code is correct
    • 🔧 Nit — optional improvement, not blocking
  3. Deduplicate — bots (Copilot, Gemini) often post the same finding. Group by actual issue.

Present a table:

# Source File:Line Issue Status Planned Fix

Wait for user confirmation (unless --fix flag set), then proceed to Phase 3.


Phase 2b: Deep Review (6 Lenses)

Read EVERY changed file in full (not just diff hunks). For PRs touching >20 files, prioritize: service logic > handlers > types > tests > docs. Batch reads in parallel via Agent tool.

OptimClaw-specific checks (always)

  • No .unwrap() or .expect() in production code
  • Prefer crate:: for cross-module imports (super:: OK in tests/intra-module)
  • Error types use thiserror
  • If persistence touched, both backends updated (postgres.rs AND libsql/)
  • New tools implement Tool trait correctly and registered
  • External tool output passes through safety layer
  • Tool parameters redacted before logging/SSE
  • No byte-index slicing on external strings
  • Case-insensitive comparisons where needed

Correctness

Off-by-one, wrong operators, inverted conditions, unreachable code, type confusion, error propagation, broken invariants, TOCTOU races.

Edge cases & failure handling

Empty/None/zero-length input, external service failures, integer boundaries, malformed/adversarial input, partial failure handling.

Security (assume adversarial actors)

Auth/authz bypass, IDOR, injection (SQL/command/log/header), data leakage in logs/errors/API responses, resource exhaustion, replay/race conditions.

Test coverage

New public functions tested? Error paths tested? Edge cases covered? Existing tests still valid?

Architecture

Follows existing patterns? Unnecessary abstractions? Duplicated logic? Clean module dependencies?

Present findings as a table:

# Severity Category File:Line Finding Suggested Fix

Severity: Critical > High > Medium > Low > Nit

If --review-only flag is set, post findings as GitHub comments (see Phase 2c) and STOP.

Otherwise, ask which findings to fix (default: all Critical + High + Medium). Then proceed to Phase 3.


Phase 2c: Post Review Comments on GitHub

For each finding the user approved (or all Critical/High/Medium if --fix):

Line-specific findings — post as PR review comments:

gh api repos/{owner}/{repo}/pulls/{number}/comments \
  -f body="**{Severity}**: {finding}\n\n{explanation}\n\n**Suggested fix:** {suggestion}" \
  -f path="{file}" \
  -f commit_id="{headRefOid}" \
  -F line={line} \
  -f side="RIGHT"

Cross-cutting/architectural findings — post as regular PR comment:

gh pr comment {number} --body "..."

Phase 3: Fix

Checkout the PR branch if not already on it (handles fork PRs automatically):

gh pr checkout {number}

Implement fixes for:

  1. All approved review comment fixes (from Phase 2a)
  2. All approved review findings (from Phase 2b)

Follow OptimClaw conventions:

  • thiserror for errors
  • crate:: imports
  • No .unwrap() in production
  • Both DB backends if persistence touched
  • Regression test for every bug fix (enforced by commit-msg hook; bypass only with [skip-regression-check] if genuinely not feasible)

After all fixes implemented, proceed to Phase 4.


Phase 4: Quality Gate

Run the full OptimClaw shipping checklist:

cargo fmt
cargo clippy --all --benches --tests --examples --all-features
cargo test --lib

If persistence changes are present, also verify feature isolation:

cargo check --no-default-features --features libsql
cargo check --all-features

If any step fails: fix the issue and re-run. Do NOT proceed past a failing step. Loop up to 3 times per step. If still failing after 3 attempts, report the failure and stop.


Phase 5: Commit & Push

Stage changed files by name (never git add -A — it can include unintended files):

git add path/to/changed/file1 path/to/changed/file2
git commit -m "{message}"

Commit message format:

  • For review fixes: fix: address review findings on PR #{number}
  • For comment responses: fix: address review comments on PR #{number}
  • For CI fixes: fix: resolve CI failures on PR #{number}
  • Include specifics in the body (which findings/comments were addressed)

Push:

git push origin {headRefName}

Reply to addressed review comments on GitHub. For each comment that was fixed, reply with the commit SHA and a brief description of what was done. For false positives, reply explaining why no change was needed.


Phase 6: CI Monitor & Fix Loop

Wait briefly for CI to start, then poll (do NOT use --watch as it can hang indefinitely):

gh pr checks {number} --json name,status,conclusion

Re-check every 30 seconds, up to 10 minutes. If still pending after 10 minutes, report status and ask the user whether to keep waiting.

If CI passes → proceed to Phase 7.

If CI fails (up to 3 fix attempts):

  1. Identify the failing check:

    gh run view {run_id} --log-failed
    

    If --log-failed shows nothing useful:

    gh run view {run_id} --log | tail -100
    
  2. Diagnose and fix the failure.

  3. Re-run Phase 4 (quality gate).

  4. Commit and push (Phase 5).

  5. Go back to top of Phase 6.

After 3 failed CI fix attempts: Report what's failing and why, then stop. Don't keep looping.


Phase 7: Merge Decision

Print final status:

PR #{number}: {title}
CI: ✅ PASS
Reviews: {summary}
Findings fixed: {N}
Comments addressed: {N}
Commits added: {N}

Auto-merge conditions (if --merge flag or user confirms):

  • CI is passing
  • No unresolved CHANGES_REQUESTED reviews
  • PR is not draft
  • PR is mergeable (no conflicts)

If all conditions met, ask the user for merge strategy:

"CI is green. Merge this PR? [squash/rebase/merge/no]"

Then execute:

gh pr merge {number} --{strategy} --delete-branch

If any condition NOT met, report what's blocking and let the user decide.


Rules

  • Read before judging. Never comment on code you haven't read in full. Verify line numbers.
  • Be specific. "Line 42 returns 404 but should return 400 because X" not "this might have issues."
  • Fix the pattern, not just the instance. When fixing a bug, grep for the same pattern across src/.
  • Respect the commit-msg hook. Bug fixes need regression tests. Use [skip-regression-check] only if genuinely not feasible.
  • Don't over-fix. Only change what was flagged. Don't refactor surrounding code or add improvements beyond the review scope.
  • Credit original authors. If taking over someone else's PR, credit them in commits and comments.
  • No secrets in comments. Never include customer data, credentials, or PII in GitHub comments.
  • Distinguish certainty. "This IS a bug" vs "This COULD be a bug if X." Be honest.
  • Round up severity when uncertain. Cheaper to dismiss a false alarm than miss a real bug.
  • Parallel where possible. Use Agent tool for parallel file reads on large PRs. Batch gh api calls.