The vuln resolve pipeline orchestrates four AI agents in an iterative feedback loop to scan, fix, verify, and report on vulnerable dependencies.
┌──────────────────────┐
│ run_pipeline(cfg) │
└──────────┬───────────┘
│
v
┌──────────────────────┐
│ ensure_local_clone │
│ - Auto-detect CWD? │
│ - Configured paths? │
│ - Common dirs? │
│ - CWD remote match? │
│ - Clone to tempdir │
└──────────┬───────────┘
│
v
┌──────────────────────┐
│ setup_branch │
│ git checkout -b │
│ <branch> <base> │
└──────────┬───────────┘
│
v
┌────────────────────────────────────┐
│ scan_summary_override set? │
└────────────────┬───────────────────┘
yes | │ no
│ v
│ ┌────────────────────────────────┐
│ │ SCAN AGENT │
│ │ prompt: build_scan_prompt() │
│ │ tools: BASE_TOOLS + MCP │
│ │ output: JSON -> AlertGroups │
│ │ post: build_scan_summary() │
│ └────────────────┬───────────────┘
│ │
v v
┌────────────────────────────────────┐
│ scan_summary ready │
└────────────────┬───────────────────┘
│
┌─────┴──────┐
│ dry_run? │
└─────┬──────┘
yes | | no
v │
Return scan │
report only │
│
┌──────────────┘
│ iteration = 1
│ feedback = ""
v
┌───> ┌────────────────────────────────────┐
│ │ FIX AGENT │
│ │ prompt: build_fix_prompt( │
│ │ local_path, scan_summary, │
│ │ feedback) │
│ │ tools: FIX_TOOLS + MCP │
│ │ rules: PATCH/MINOR only, │
│ │ update lockfiles, │
│ │ skip if no safe fix │
│ │ output: JSON -> FixResult │
│ └────────────────┬───────────────────┘
│ │
│ v
│ ┌────────────────────────────────────┐
│ │ commit_fixes │
│ │ git add -A && git commit │
│ └────────────────┬───────────────────┘
│ │
│ ┌─────┴──────┐
│ │ Commit │
│ │ created? │
│ └─────┬──────┘
│ yes | | no
│ │ v
│ │ converged = true
│ │ (no changes to fix)
│ │ skip to REPORT
│ │
│ ┌─────┴──────┐
│ │ skip_ │
│ │ verify? │
│ └─────┬──────┘
│ yes | | no
│ v │
│ converged │
│ = true │
│ skip to │
│ REPORT │
│ v
│ ┌────────────────────────────────────┐
│ │ VERIFY AGENT │
│ │ prompt: build_verify_prompt( │
│ │ local_path, branch, base_branch) │
│ │ tools: VERIFY_TOOLS │
│ │ checks: git diff, breaking changes, │
│ │ test suite, lockfile sync │
│ │ output: JSON -> VerifyResult │
│ └────────────────┬───────────────────┘
│ │
│ ┌─────┴──────┐
│ │ passed? │
│ └─────┬──────┘
│ yes | | no
│ │ │
│ │ │
│ │ ┌────┴────────────────┐
│ │ │ iteration < │
│ │ │ max_iterations? │
│ │ └────┬────────────────┘
│ │ yes | | no
│ │ │ │
│ │ v │
│ │ ┌──────────────────┐
│ │ │ revert_to_base │
│ │ │ git reset │
│ │ │ --hard <base> │
│ │ │ on <branch> │
│ │ └────────┬─────────┘
│ │ │
│ │ feedback = verify.feedback
│ │ iteration += 1
│ converged │ │
│ = true │ │
│ │ │
│ v │
│ skip to REPORT │
│ │
└──────────────────────────────┘
┌──────────────────────┐
│ REPORT AGENT │
│ prompt: │
│ build_report_prompt │
│ tools: [Read] │
│ output: text summary │
│ (< 500 words) │
└──────────┬───────────┘
│
┌─────┴────────────┐
│ converged AND │
│ not cfg.no_pr? │
└─────┬────────────┘
yes | | no
v v
┌────────────┐ Return
│ create_pr │ report
│ gh pr │ only
│ create │
└────────────┘
Purpose: Fetch and triage Dependabot alerts.
Prompt template: SCAN_PROMPT_TEMPLATE - instructs Claude to fetch alerts for the repo, analyze each one for actual code path usage, and return structured JSON with risk levels.
Tool allowlist: [Bash, Read, Grep, Glob] + GitHub MCP if available. The scan agent can read files to check import paths but cannot modify anything.
Output: JSON parsed into AlertGroup objects containing TriageResult entries. Post-processed by _build_scan_summary() into a human-readable summary passed to the fix agent.
Pre-computed scan override: When PipelineConfig.scan_summary_override is set (via --from-scan), the scan agent is bypassed entirely. The pre-computed summary string is injected at the same point where _build_scan_summary() would produce it, so all downstream agents (fix, verify, report) receive identical input. This is produced by scan_summary_from_repo_result() which converts a RepoResult model to the same text format.
Purpose: Apply safe dependency upgrades.
Prompt template: FIX_PROMPT_TEMPLATE - receives the scan summary and any feedback from a prior failed verification. Rules: only PATCH/MINOR bumps, update lockfiles, skip if no safe fix, don’t modify application code.
Tool allowlist: [Bash, Read, Grep, Glob, Edit, Write] + GitHub MCP. The fix agent is the only agent with write permissions.
Output: JSON parsed into FixResult with per-package fix actions and skipped packages with reasons.
Purpose: Validate that the fixes don’t break anything.
Prompt template: VERIFY_PROMPT_TEMPLATE - instructs Claude to review the git diff, check for breaking changes, run the test suite, and verify lockfile consistency.
Tool allowlist: [Bash, Read, Grep, Glob]. The verify agent can run tests via Bash but cannot edit files, ensuring independence from the fix agent.
Output: JSON parsed into VerifyResult with passed boolean, categorized issues, test output, and a feedback string that gets fed to the next fix iteration.
Purpose: Summarize the pipeline run.
Prompt template: REPORT_PROMPT_TEMPLATE - receives repo name, iteration count, convergence status, scan summary, and iteration details.
Tool allowlist: [Read]. Minimal permissions - report agent only needs to read to produce its summary.
Output: Plain text executive summary (< 500 words).
The pipeline uses feedback propagation to converge:
Iteration 1: fix_agent(scan_summary, feedback="")
verify_agent -> fails with feedback
Iteration 2: fix_agent(scan_summary, feedback=verify.feedback)
verify_agent -> fails with new feedback
Iteration 3: fix_agent(scan_summary, feedback=verify.feedback)
verify_agent -> passes
-> converged!
The verify agent’s feedback field contains specific instructions for the fix agent: which tests failed, what broke, and suggested approaches. This creates a conversation-like loop where each iteration benefits from prior failures.
| Operation | Implementation | When |
|---|---|---|
| CWD detect | git remote get-url origin |
No flags given, or –repo slug match |
| Clone | git clone --depth 1 |
Repo not found locally |
| Branch | git checkout -b <branch> <base> |
Start of pipeline |
| Commit | git add -A && git commit -m <msg> |
After fix agent |
| Revert | git reset --hard <base> on branch |
After failed verify |
| Push | git push -u origin <branch> |
Before PR creation |
| PR | gh pr create --title --body |
If converged |
All git operations use a 60-second timeout. Failures raise GitError.
When running with --org or --user, batch_resolve.py orchestrates:
run_pipeline() sequentially for each repoBatchResolveReportSequential execution (not parallel) is intentional - each pipeline run creates branches and PRs, and parallel execution could cause rate limiting or resource contention.