FixForward
Incident-to-PR autopilot powered by GitHub Copilot CLI.
One command to go from broken build to ready-to-merge PR.
pip install fixforward
When builds or tests fail, most devs lose time figuring out root cause and writing the fix. FixForward turns one command into a full recovery workflow:
fixforward run --open-pr
It detects failures, classifies the issue, asks GitHub Copilot CLI to generate a minimal patch, applies it on a safe branch, re-runs tests to verify, pushes the branch, and opens a ready-to-merge pull request โ locally or automatically in CI.
New in v0.2.0 โ it finally opens the PR
FixForward was always called an "incident-to-PR autopilot" โ but until now it stopped one step short: it printed a PR description and made you push and open the PR by hand. v0.2.0 closes the loop.
v0.1 (before) v0.2 (now) Generate the fix โ โ Verify it passes โ โ Write the PR body โ โ Push the branch โ manual โ automatic Open the PR โ manual โ gh pr createLabel by confidence โ โ high / needs-review / low Run in CI โ laptop only โ GitHub Action The result: a red CI build can now become a labelled, verified fix PR without you touching your keyboard โ see GitHub Action.
Demo
Diagnose: detect and classify the failing tests.
Ship: Copilot's fix, verified green, opened as a labelled PR โ automatically.
How It Works
tests fail โ parse output โ classify failure โ Copilot generates fix โ apply on branch โ verify โ PR report
โ โ โ โ โ โ โ
pytest extract regex gh copilot -p git branch re-run markdown
npm test failures heuristics "fix this bug..." safe commit tests PR body
cargo test diff
- Detect โ finds
pytest.ini,package.json, orCargo.tomlto identify your ecosystem - Run tests โ executes the test suite and captures the raw output
- Parse โ extracts individual test failures with file paths, line numbers, and error messages
- Classify โ categorizes failures (dependency, syntax, assertion, API change, env mismatch, lint, flaky)
- Generate patch โ sends failure context to GitHub Copilot CLI (
gh copilot -p) for a minimal fix - Apply โ creates a
fixforward/auto-*branch, writes the fix, commits - Verify โ re-runs the test suite, shows before/after comparison with confidence score
- Report โ generates PR title and body with what changed and why
- Ship (new in v0.2.0, with
--open-pr) โ pushes the branch and opens a real pull request viagh pr create, labelled by its confidence score
Screenshots
| Full autopilot run |
Diagnose mode |
| Dependency detection |
Node.js / Jest support |
Supported Ecosystems
| Ecosystem | Test Command | Parser |
|---|---|---|
| Python | pytest --tb=long -v |
Extracts failures, tracebacks, assertion details |
| Node.js | npm test |
Supports Jest and Mocha output formats |
| Rust | cargo test |
Parses panics, assert_eq! failures, test summaries |
Features
| Feature | Description |
|---|---|
| Auto-detect | Identifies Python, Node, or Rust projects automatically |
| Smart classification | Categorizes failures: dependency, syntax, assertion, API change, env, lint, flaky |
| Copilot-powered fixes | Uses gh copilot -p to generate minimal patches |
| Safe branches | Always applies fixes on a fixforward/auto-* branch, never touches your working branch |
| Before/after verification | Re-runs tests and shows what changed |
| Confidence scoring | 0-100% score based on how many failures were fixed |
| PR report generation | Ready-to-use PR title and body in Markdown |
| Opens the PR for you โจ | --open-pr pushes the branch and runs gh pr create automatically |
| Confidence labels โจ | Tags each PR high-confidence / needs-review / low-confidence |
| Confidence gate โจ | --min-confidence refuses to open a PR for low-trust fixes |
| Auto-merge โจ | --auto-merge enables squash auto-merge for high-confidence fixes |
| GitHub Action โจ | Drop into CI so failing builds open fix PRs by themselves |
| Dry-run mode | Preview the diagnosis without applying any changes |
| Rollback | One command to undo everything: fixforward rollback |
| Patch preview | See the exact diff before confirming |
Quick Start
pip install fixforward
Or install from source:
git clone https://github.com/stackmasteraliza/fixforward.git
cd fixforward
pip install -e .
Prerequisites
- Python 3.9+
- GitHub CLI (
gh) installed and authenticated - GitHub Copilot CLI โ
gh copilotmust be available - Git installed and in PATH
Usage
# Full autopilot: detect, fix, verify, report
fixforward run
# Full autopilot AND open a pull request automatically
fixforward run --open-pr
# Non-interactive end-to-end + PR (great for CI / GitHub Actions)
fixforward ship --min-confidence 0.6
# Only open the PR when the verified fix is at least 70% confident
fixforward run --open-pr --min-confidence 0.7
# Open the PR as a draft, and enable auto-merge for high-confidence fixes
fixforward run --open-pr --draft-pr --auto-merge
# Specify a project path
fixforward run --path ~/projects/my-broken-app
# Dry run: see diagnosis without applying fixes
fixforward run --dry-run
# Diagnose only: detect and classify failures
fixforward diagnose --json
# Undo the last fix
fixforward rollback
You can also run it as a Python module:
python -m fixforward run --path ./my-project
CLI Options
fixforward run
| Flag | Description |
|---|---|
--path, -p |
Path to the project (default: .) |
--dry-run, -n |
Show diagnosis without applying fixes |
--no-confirm |
Skip the patch confirmation prompt |
--open-pr |
Push the fix branch and open a real pull request |
--draft-pr |
Open the pull request as a draft |
--auto-merge |
Enable squash auto-merge for high-confidence fixes |
--min-confidence |
Only open a PR when fix confidence โฅ this (0.0โ1.0) |
--no-animate |
Disable loading animations |
--verbose |
Show raw Copilot CLI output |
fixforward ship
Non-interactive autopilot that always opens a PR โ built for CI. Same flags as run --open-pr --no-confirm.
| Flag | Description |
|---|---|
--path, -p |
Path to the project (default: .) |
--min-confidence |
Only open a PR when fix confidence โฅ this (0.0โ1.0) |
--draft-pr |
Open the pull request as a draft |
--auto-merge |
Enable squash auto-merge for high-confidence fixes |
--no-animate |
Disable loading animations |
fixforward diagnose
| Flag | Description |
|---|---|
--path, -p |
Path to the project (default: .) |
--json |
Output classification as JSON |
--no-animate |
Disable loading animations |
fixforward rollback
| Flag | Description |
|---|---|
--path, -p |
Path to the project (default: .) |
Try It Yourself
The repo includes ready-made broken demo projects you can test with:
Python demo (division bug)
# Clone the repo
git clone https://github.com/stackmasteraliza/fixforward.git
cd fixforward
# 1. See the bug โ test_divide expects integer division but gets float
cat demo/broken_python/app.py
# 2. Diagnose the failure
fixforward diagnose --path demo/broken_python
# 3. Full autopilot โ Copilot fixes a / b โ a // b
fixforward run --path demo/broken_python
# 4. Undo and restore the broken state
fixforward rollback --path demo/broken_python
Node.js demo (truncation bug)
# truncate() produces ".." instead of "..."
fixforward diagnose --path demo/broken_node
Rust demo (off-by-one in clamp)
# clamp() uses >= instead of > for the max boundary
fixforward diagnose --path demo/broken_rust
Dry-run mode (safe, no changes)
fixforward run --path demo/broken_python --dry-run
This runs detection, test execution, and classification but stops before calling Copilot or modifying any files.
JSON output (for scripting)
fixforward diagnose --path demo/broken_python --json
Returns structured JSON with test name, file, line, category, confidence, and error message for each failure.
Run It in CI (GitHub Action)
This is what v0.2.0 was really about: FixForward no longer needs you at the keyboard. Add it to any repo and a failing build will open its own fix PR.
# .github/workflows/fixforward.yml
name: FixForward
on: [push, pull_request]
permissions:
contents: write # push the fix branch
pull-requests: write # open the PR
jobs:
test-and-autofix:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with: { python-version: "3.x" }
- run: pip install -r requirements.txt
- id: tests
run: pytest
continue-on-error: true # hand the failure to FixForward
- name: FixForward
if: steps.tests.outcome == 'failure'
uses: stackmasteraliza/fixforward@v1
with:
min-confidence: "0.6"
github-token: ${{ secrets.GITHUB_TOKEN }}
Action inputs
| Input | Default | Description |
|---|---|---|
path |
. |
Project directory to analyse |
min-confidence |
0.5 |
Only open a PR when the verified fix is at least this confident |
auto-merge |
false |
Enable squash auto-merge for high-confidence fixes |
draft |
false |
Open the PR as a draft |
github-token |
โ | Token used to push the branch and open the PR (required) |
Note on Copilot in CI: generating fixes calls
gh copilot, which needs an account with GitHub Copilot access. In CI, provide a token for such an account (e.g. aCOPILOT_GH_TOKENsecret) โ the defaultGITHUB_TOKENcan push and open PRs but cannot call Copilot. A ready-to-run example lives inexamples/fixforward-on-failure.ymland a live in-repo demo in.github/workflows/demo-autofix.yml.
Failure Categories
FixForward classifies failures using regex heuristics for instant, deterministic results:
| Category | Examples | Confidence |
|---|---|---|
| syntax_error | SyntaxError, IndentationError, Unexpected token |
95% |
| dependency | ModuleNotFoundError, Cannot find module, ImportError |
90% |
| api_change | AttributeError, TypeError (wrong args), has no member |
85% |
| assertion | AssertionError, assert_eq!, expect().toEqual() |
85% |
| env_mismatch | Version conflicts, missing commands, engine incompatible | 80% |
| lint | Flake8, ESLint, Clippy warnings | 75% |
| flaky_test | Timeouts, connection refused, intermittent | 60% |
Safety
FixForward is designed to be safe by default:
- Never modifies your working branch โ all fixes go on
fixforward/auto-*branches - Stashes dirty state โ if you have uncommitted changes, they're stashed and restored on rollback
- Patch preview โ see the exact diff before confirming
- Dry-run mode โ diagnose without touching anything
- One-command rollback โ
fixforward rollbackrestores everything - State persistence โ rollback info stored at
~/.fixforward/state.json
Built With GitHub Copilot CLI
This project was built using GitHub Copilot CLI as part of the GitHub Copilot CLI Challenge on DEV. Copilot CLI is central to the tool โ it powers the actual fix generation via gh copilot -p:
# How FixForward uses Copilot CLI internally:
gh copilot -- -p "I have a python project with failing tests.
The test test_divide in test_app.py fails with AssertionError:
assert 3.333 == 3. Generate a minimal fix..." \
--allow-all-tools --add-dir ./project --silent
Copilot CLI reads the source files, understands the context, and generates the smallest possible code change. FixForward then applies it, verifies it, and reports the result.
Copilot CLI prompts used
Fix generation prompt (sent via gh copilot -- -p):
I have a {ecosystem} project with failing tests. Generate a minimal fix.
FAILURES:
- [assertion] test_divide
File: test_app.py
Error: assert 3.3333333333333335 == 3
SOURCE FILES:
--- app.py ---
{file contents}
Generate the smallest possible code change to fix these failures.
Show the complete corrected file content for each file that needs changes.
Format each fix as:
FILE: <filepath>
```<complete corrected file content>```
Then explain what you changed and why.
Failure explanation prompt (used by fixforward diagnose):
Explain this test failure concisely:
Test: test_divide
File: test_app.py
Error: assert 3.3333333333333335 == 3
Category: assertion
What is the likely root cause and how should it be fixed?
Architecture
fixforward/
โโโ cli.py # argparse CLI with run/ship/diagnose/rollback commands
โโโ detector.py # Ecosystem detection + test runner (subprocess)
โโโ classifier.py # Regex heuristic failure classification
โโโ copilot.py # GitHub Copilot CLI integration (gh copilot -p)
โโโ patcher.py # Safe branch creation + file patching
โโโ verifier.py # Test re-run + confidence scoring
โโโ reporter.py # PR title/body generation
โโโ shipper.py # โจ Push branch + gh pr create + confidence labels (the last mile)
โโโ display.py # Rich-based terminal UI
โโโ state.py # Rollback state persistence
โโโ parsers/
โโโ pytest_parser.py # pytest output parser
โโโ npm_parser.py # Jest/Mocha output parser
โโโ cargo_parser.py # cargo test output parser
action.yml # โจ Composite GitHub Action
.github/workflows/ # โจ CI self-tests + live auto-fix demo
tests/ # โจ Unit tests for shipping policy + PR reporting
Only dependency: rich โ everything else is Python stdlib.
Requirements
- Python 3.9+
- Git installed and in PATH
- GitHub CLI (
gh) with Copilot access - Terminal with color support
MIT License โ see LICENSE for details.
If you like this project, give it a star!
Metadata
Release files for fixforward 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| fixforward-0.2.0.tar.gz | 38.2 kB | Without provenance | Details for fixforward-0.2.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| fixforward-0.2.0-py3-none-any.whl | Python 3 | none | any | Details for fixforward-0.2.0-py3-none-any.whl |
Total release size: 75.4 kB
Release files / fixforward-0.2.0.tar.gz
| Download URL | fixforward-0.2.0.tar.gz |
|---|---|
| Size | 38.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
59c19ece4ab7fa4f9c93161dbe378e5cf705d769205a07d659b1eef06dd44da5
|
|
BLAKE2b-256 checksum How to use checksums |
9a2bd881b264be8f00de9049237ac06467048002d6594449aa2202c8662eba39
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.2
|
Release files / fixforward-0.2.0-py3-none-any.whl
| Download URL | fixforward-0.2.0-py3-none-any.whl |
|---|---|
| Size | 37.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
8fc1ec6f1491872fa94608698eb2dcac32ea8165519b4fd18fd5ff81b93936f9
|
|
BLAKE2b-256 checksum How to use checksums |
b267c7c27e2d262a7aa98d1820374056ac7d217eb6c2a9eb6efb6a9d7a14aaa4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.2
|
Security for fixforward 0.2.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.