PatchPilot is an agentic software-engineering loop for taking a GitHub issue, mapping the repository, making the smallest safe change, generating a regression test, running verification commands, and preparing a pull request with a transparent trace.
The project is intentionally dependency-light. It can run locally without API
keys, and it upgrades to GitHub/Docker flows when GITHUB_TOKEN, gh, or Docker
are available. It also upgrades its repair step when an LLM API key is set (see
LLM Repair Tier).
python -m pip install -e ".[dev]"
patchpilot run https://github.com/OWNER/REPO/issues/123 --repo .For offline development, pass a text file instead of a GitHub URL:
patchpilot run examples/issue.md --repo . --no-pr- A dependency map of Python and JavaScript/TypeScript files.
- A trace directory under
.patchpilot/traces/. - A regression test scaffold when the issue has enough signal.
- A command log with stdout, stderr, exit code, and duration.
- A PR body containing the final diff, failed hypotheses, confidence score, and verification results.
PatchPilot runs the same sequence for local fixture issues and real GitHub issues:
- Normalize the issue into title, body, source URL, labels, and issue number.
- Build a dependency map with imports, exported symbols, and reverse edges.
- Rank likely files from direct path mentions and symbol overlap.
- Generate a pytest regression test from runnable issue snippets.
- Run verification once to reproduce the failure.
- Try minimal repair candidates, including explicit issue diffs, small Python
return-expression fixes such as unwrapping
str(...)or correcting a simple arithmetic operator, and — only if an LLM API key is configured — a single model-drafted diff as a last resort. - Keep only the first candidate that passes verification locally or through
Docker when a
Dockerfileis present. - Write a trace summary and optionally create a branch, commit, push, and PR
through
gh.
This conservative edit policy is deliberate. PatchPilot records failed hypotheses and rejected candidates instead of silently making broad implementation changes.
When the explicit-diff editor and the AST heuristics in PythonRepairEngine
don't produce a passing candidate, PatchPilot can ask a hosted model for one
patch as a last resort. This tier is entirely optional and off by default in
effect: with no API key set, PatchPilot skips it and behaves exactly as
before.
Currently supported: Kimi (Moonshot AI), via its OpenAI-compatible chat completions API. Qwen and Gemini are planned but not implemented yet.
export MOONSHOT_API_KEY=sk-... # required to enable this tier
# optional overrides:
export PATCHPILOT_LLM_MODEL=kimi-k2-0711-preview
export PATCHPILOT_LLM_BASE_URL=https://api.moonshot.ai/v1
export PATCHPILOT_LLM_TIMEOUT=120
patchpilot run https://github.com/OWNER/REPO/issues/123 --repo .Pass --no-llm-repair to skip this tier even when a key is configured. The
model receives the issue text and the contents of up to 6 likely target files,
and must respond with exactly one unified diff (or NO_PATCH). PatchPilot
applies it with git apply, runs the same verification commands used
everywhere else, and rolls back to the original file bytes if verification
fails — the model never gets a second attempt or partial credit.
patchpilot map --repo .
patchpilot map --repo . --json
patchpilot run examples/issue.md --repo . --no-pr
patchpilot run owner/repo#123 --repo /path/to/repo --test-command "npm test"Each run creates:
events.jsonlwith every issue, hypothesis, command, editor, testgen, and PR event.dependency-map.mdwith the files PatchPilot considered.candidate-N.patchfiles for explicit diffs found in the issue.llm-candidate-1.patchfor the LLM repair tier's attempt, when it runs.summary.mdwith changed files, verification results, failed hypotheses, confidence reasons, PR URL, and final diff.