Skip to main content

Incident-to-PR autopilot: detect failures, generate fixes with GitHub Copilot CLI, and open ready-to-merge PRs — locally or in CI.

Project description

FixForward — incident-to-PR autopilot powered by GitHub Copilot CLI

FixForward

Incident-to-PR autopilot powered by GitHub Copilot CLI.

PyPI version Python License: MIT Downloads

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 create
Label 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.

FixForward diagnosing failing tests

Ship: Copilot's fix, verified green, opened as a labelled PR — automatically.

FixForward opening a verified pull request
FixForward Demo

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
  1. Detect — finds pytest.ini, package.json, or Cargo.toml to identify your ecosystem
  2. Run tests — executes the test suite and captures the raw output
  3. Parse — extracts individual test failures with file paths, line numbers, and error messages
  4. Classify — categorizes failures (dependency, syntax, assertion, API change, env mismatch, lint, flaky)
  5. Generate patch — sends failure context to GitHub Copilot CLI (gh copilot -p) for a minimal fix
  6. Apply — creates a fixforward/auto-* branch, writes the fix, commits
  7. Verify — re-runs the test suite, shows before/after comparison with confidence score
  8. Report — generates PR title and body with what changed and why
  9. Ship (new in v0.2.0, with --open-pr) — pushes the branch and opens a real pull request via gh 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

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. a COPILOT_GH_TOKEN secret) — the default GITHUB_TOKEN can push and open PRs but cannot call Copilot. A ready-to-run example lives in examples/fixforward-on-failure.yml and 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 rollbackfixforward rollback restores 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!

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

fixforward-0.2.0.tar.gz (38.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

fixforward-0.2.0-py3-none-any.whl (37.1 kB view details)

Uploaded Python 3

File details

Details for the file fixforward-0.2.0.tar.gz.

File metadata

  • Download URL: fixforward-0.2.0.tar.gz
  • Upload date:
  • Size: 38.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.2

File hashes

Hashes for fixforward-0.2.0.tar.gz
Algorithm Hash digest
SHA256 59c19ece4ab7fa4f9c93161dbe378e5cf705d769205a07d659b1eef06dd44da5
MD5 fd5e2b72f1035eb49f6788682b6a9712
BLAKE2b-256 9a2bd881b264be8f00de9049237ac06467048002d6594449aa2202c8662eba39

See more details on using hashes here.

File details

Details for the file fixforward-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: fixforward-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 37.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.2

File hashes

Hashes for fixforward-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 8fc1ec6f1491872fa94608698eb2dcac32ea8165519b4fd18fd5ff81b93936f9
MD5 a9b926a045dbe1271db8983f350b6bcf
BLAKE2b-256 b267c7c27e2d262a7aa98d1820374056ac7d217eb6c2a9eb6efb6a9d7a14aaa4

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page