Auto-fix mechanical CI failures and push fix commits to PR branches.
When CI fails due to lint or formatting violations, Fixup detects the failure class, runs the appropriate fixer, and pushes a chore: fixup <tool> commit directly to the branch.
| Fixer | Detects | Fix Command |
|---|---|---|
eslint |
ESLint errors in CI logs | npx eslint --fix . |
prettier |
Prettier formatting failures | npx prettier --write . |
oxlint |
oxlint errors | npx oxlint --fix . |
oxfmt |
oxfmt formatting failures | npx oxfmt --write . |
lockfile |
Stale lockfiles (pnpm/bun/yarn/npm) | <pm> install |
cargo-fmt |
rustfmt / cargo fmt | cargo fmt --all |
clippy |
clippy warnings | cargo clippy --fix --allow-dirty --allow-staged |
terraform-fmt |
terraform fmt / tofu fmt | terraform fmt -recursive |
ruff |
ruff check / ruff format | ruff check --fix . && ruff format . |
Add .github/workflows/fixup.yml to your repo:
name: Fixup
on:
workflow_run:
workflows: ["CI"] # name of your CI workflow
types: [completed]
permissions:
contents: write
actions: read
jobs:
fixup:
if: github.event.workflow_run.conclusion == 'failure'
runs-on: ubuntu-latest
steps:
- uses: tractorbeamai/fixup@main- uses: tractorbeamai/fixup@main
with:
fixers: "eslint,prettier"Implement the Fixer interface and register in a wrapper action:
import { Fixer, FixResult } from "@tractorbeam/fixup";
export const myFixer: Fixer = {
name: "my-tool",
detect(log: string): boolean {
return /my-tool.*error/i.test(log);
},
async fix(cwd: string): Promise<FixResult> {
// run your fix command
return { summary: "Fixed things", filesChanged: 1 };
},
};Fixup checks if the most recent commit on the branch was authored by github-actions[bot]. If so, it skips to prevent infinite fix loops.
- Only runs on PR branches — never on
mainormaster. - Commits are attributed to
github-actions[bot], making them easy to identify and filter. - Each fixer runs the same deterministic tool the developer would run locally.
- Uses the built-in
GITHUB_TOKEN— no secrets or GitHub App setup required.