PatcheryGitHub ActionnpmMITearly

When a dependency breaks your code, Patchery fixes it and proves the fix.

Your project runs on other people’s code. When they change how it works, your app stops working. Patchery finds what broke, rewrites the lines that need rewriting, and checks the result against your own tests before it shows you anything — and throws its own work away if that check goes badly.

  • 1pull request it opened on its own
  • $0.2251the last run, priced at list rates
  • 0users, customers, logos
  • MITevery line of it public

Read the pull request it opened Read the source

02 Why this is harder than it looks

Tell an AI to make the tests pass. It might just delete them. // 4 tests removed · suite green

This is not a hypothetical

Deleting the test is the cheapest way to satisfy the instruction, so it is the one an agent reaches for first. Failing that: soften the check, stub out the function, edit the very file that decides what working means. Every one of those makes a broken project look fixed.

Which means writing the fix was never the interesting problem. Everything that happens after it is. Patchery never reads the AI’s own account of what it did — it looks at the files themselves, throws the whole attempt away if anything off-limits moved, and re-runs your tests itself.

Why anyone needs it now

The libraries underneath modern software change faster than the teams using them can follow. Tools like Dependabot are good at telling you a newer version exists. They stop exactly where the work starts: the places in your code that used the old way.

That gap used to need a person. It stopped needing one somewhere in the last two years — but only if you can trust the result, which is the same problem again.

For scale, not for credit Recent breaking major releases, picked to show how ordinary this is. These are not packages Patchery has fixed. Two of them are: openai and @google/generative-ai — both migrated by hand, both linked below.
03 One run, six gates

In plain termsIt tries the fix, then spends four more steps trying to catch itself cheating.

It has to get
past itself first.

  1. 01Check it’s really brokenIf your tests already pass, stop here and charge nothing.
  2. 02Read the notes, fix the codeFind what changed, rewrite the lines that used the old way.
  3. 03Look at what changed on diskNot what the AI says it did — what the files say it did.
  4. 04Run your tests againMeasure it. Don’t ask it.
  5. 05Get a second AI to argue with itA different call, read-only, that tries to refute the fix.
  6. 06Ask a human to approve itA change request you read and merge yourself. Never automatic.
step 01your test commandfailed
$ npm test

> toy-project@1.0.0 test
> node app.test.js

node_modules/fake-lib/index.js:3
    throw new TypeError("currency is required as of fake-lib@2.0.0");
    ^

TypeError: formatPrice(amount, currency): currency is required
    at formatPrice (node_modules/fake-lib/index.js:3:11)
    at renderCartTotal (app.js:4:20)
    at Object.<anonymous> (app.test.js:4:16)
This is the entry ticket. Patchery runs your own tests before it does anything else, and if they pass it stops — no AI, no cost, no pull request you didn’t ask for.
readingwhat the library changed
# fake-lib changelog

## 2.0.0 (breaking)

- Removed formatPrice(amount).
  Returned a plain number and rounded
  inconsistently across locales.

- Added formatPrice(amount, currency).
  Now requires an explicit currency
  code, e.g. "USD".

### Migration
  formatPrice(19.9)        // "19.90"
  formatPrice(19.9,"USD")  // "$19.90"
writingapp.jsone line
1  const { formatPrice } = require("fake-lib");
2
3  function renderCartTotal(amount) {
4    return `Total: ${formatPrice(amount)}`;
5  }
6
7  module.exports = { renderCartTotal };
The AI gets a fixed budget and a watchdog: make the same move three times, or spend five turns in a row turning up nothing it has not already seen, and the run is cut off. Opening a file it has never opened counts as progress even before it writes anything — because the first version of this rule counted turns without an edit instead, and cut three real runs off at the moment the AI was about to start writing.
step 03every file it touchedclean
changed on disk:
  app.js                       allowed

checked, and untouched:
  your tests                   off-limits
  package-lock.json            off-limits
  node_modules/                off-limits
  your CI configuration        off-limits

→ nothing off-limits moved. carry on.
This is the step the whole product is built around. If the AI touches even one file on that list, the entire attempt is deleted — the working fix along with it. Try to sneak one past it →
step 04your test command, againpassed
$ npm test

> toy-project@1.0.0 test
> node app.test.js

PASS: app.test.js
Same command, same machine, run from scratch a second time. Patchery never asks the AI whether it worked — it re-runs your tests and reads the answer itself.
step 05a second agent, no write accessconcerns
$ patchery review --read-only

  reviewing 1 file, 2 lines
  separate call · cannot edit · never shown
  the first agent's reasoning

  verdict      not refuted
  confidence   72 / 100
  concerns     raised
  cost         $0.3298
The reviewer can agree, object, or say it is not sure — and it cannot touch a single file either way. Below a confidence of 60 its verdict is filed as a concern rather than acted on, in both directions: the same bar to condemn as to bless. On this run the review cost $0.3298. The fix it was reviewing cost $0.2251. There is a switch that hands a serious concern back to the fixer for one more turn, and it is off by default: most of what a reviewer raises is I could not check this from here, which is information you are missing rather than code that is wrong — and a model handed criticism will always find something to change.
Open patchery-dev/Patchery #2

fix(deps): migrate fake-lib call sites

a change request, waiting for a human

app.js
  function renderCartTotal(amount) {
−    return `Total: ${formatPrice(amount)}`;
+    return `Total: ${formatPrice(amount, "USD")}`;
  }
  • 1 file
  • +1 −1
  • 9 turns
  • $0.2251

Opened automatically. Never merged automatically.

04 The part that matters, in your hands

In plain termsSome files are off-limits, and touching one throws away the whole attempt — including a fix that worked.

Try to
break it.

The off-limits list is short: your tests, the file that decides which of them run, the file that pins your versions, your build settings, and the installed libraries themselves. Those are the ways an AI can make a broken project look fixed without fixing anything, so none of them may move. Two more rules sit alongside them — nothing may be deleted, and nothing outside the folder you pointed it at may be touched at all.

The box below runs the real check — the same few lines that run inside Patchery’s source, copied character for character, not a demo of it. Give it any file path and see what it decides.

+

or try one of these

the check files the AI touched 0 files

    Nothing here yet. Add a file and the verdict appears below.

    verdict waiting

    Six rules on the off-limits list, in the order they run — installed libraries, test files, test folders, build settings, test-harness configuration, version-lock files — plus a ban on deletions and on anything outside the folder you pointed it at. All of it is covered by a test that runs on every change to Patchery itself: offline, in a second, with no AI and no key.

    What this check cannot see

    It reads which files moved. It never reads what the change did to them. An AI that deleted a validation check inside src/auth/validate.ts — a file it is perfectly entitled to edit — walks straight past everything above. Try that path in the box and watch it be allowed.

    Three things stand behind the hole. Your tests are run again afterwards, by Patchery and not by the AI, so a change that breaks them never reaches a pull request. A second agent then reads the diff and tries to refute the fix — it gets no write access, no sight of the first agent’s reasoning, and a separate call, so it is reviewing the change rather than agreeing with itself. And the pull request still goes to a person: there is no auto-merge and there should not be.

    None of that closes the hole. Reading a diff is judgement, and judgement is the thing this check exists to avoid having to trust. The rule above is deterministic and the review is not, which is why the review is a second line and never the only one.

    05 Evidence, not adjectives

    In plain termsEverything below is a link you can open and check for yourself, right now.

    It has done this
    with nobody watching.

    no human involved patchery-dev/Patchery #2

    One line, in one file, in a real repository

    A library called fake-lib went from version 1 to version 2 and made an argument required that used to be optional. Patchery ran the tests (they failed), read what the library had changed, rewrote the one line that needed it, checked which files it had touched, ran the tests again (they passed), and opened this pull request. The first human to see it was the reviewer.

    Two things about those numbers. The cost is what those turns would come to at Anthropic list prices; the run used a cheaper model, so the amount actually billed was different. And they are the latest run, not the only one: the broken fixture is committed broken on purpose so the demo can be run again, and each run replaces the same branch. Four have succeeded so far. The figures are read out of the pull request itself when this page loads, so they cannot quietly go stale — they already did once, which is why they are read rather than typed.

    • files changed1
    • lines+1 −1
    • testsfailedpassed
    • AI turns used9
    • cost, at list rates$0.2251
    • modelglm-5.3
    Open it on GitHub

    And here is the same job done by hand, on two projects we don’t own. No AI was involved in either — they are here because doing this work manually is how we learned what the automated version has to survive.

    All three are still open. None has been merged. We will change this sentence the day that changes.

    06 The runs that produced nothing

    In plain termsWe pointed it at real projects and it came back with nothing. Here is every run we kept a proper record of, what it spent, and what it wrote.

    Four runs on code we don’t own. Four times it wrote nothing.

    Every bar below is one turn of an AI actually thinking, and every one of them was billed. Read the number at the end of each row before you read anything else on this page.

    1. ran, wrote nothing giancarloerra/SocratiCode An old library that hadn’t actually broken anything yet

      The tests were red, so it started. It read the failures one at a time and worked out that every one of them was about the machine we were running on, not about the library we had sent it to fix. It checked that the old library really was still installed, checked that nothing was breaking when the code actually ran, and then declined to change anything. It spent the rest of its turns holding that position. The easy move was there the whole time and it didn’t take it.

      turns
      25
      cost
      $0.88
      lines written
      0
    2. ran three times, wrote nothing dwmkerr/terminal-ai Not a renamed function — a different idea of where a conversation lives

      We gave it fifteen turns. It read the migration guide, read the files that would have to move, and checked which parts of the new library actually existed — a different, sensible step every turn, never the same one twice. Then Patchery cut it off. Our own watchdog counts turns that change no files, decided this one was going in circles, and fired at the moment it was about to start writing. We raised the limit to twenty-two and it went further, comparing against the project’s existing style and working out that the right shape was the one that keeps no state. Cut off again, at the same moment. At forty it went further still — following how a single message travels through the code, then going to look at whether the project’s own maintainers had already done this upstream — and finished with nothing written. Three runs, each deeper than the last, not one wasted turn. The job was simply bigger than the shape we had given it.

      turns
      15 · 22 · 40
      cost
      not recorded
      lines written
      0

      And each of those three attempts paid to read the same files from the beginning, because nothing is carried from one run to the next. That is a cost bug and it is still open. The watchdog that cut these runs off is not: it has stopped counting turns without an edit and now counts turns that turn up nothing new, so reading four files it has never read is progress rather than idling. These three runs are the reason it changed.

    3. ran, never reached the AI gitroomhq/postiz-agent A real, reported bug that had already healed on our machine

      Someone had filed it: a library had moved to a newer module format, the old way of loading it threw, and the person who reported it could reproduce it. Patchery runs your tests before it does anything else, and they passed — so it stopped and said there was nothing to fix, which is exactly what it is supposed to do when the tests are green. The reason they were green is that we ran on a newer version of Node than the reporter did. Node began supporting that combination in 22.12; they were on 22.11, one release below the line. The bug is real and is still real for them. On our machine it had already healed. Whichever version your tests run on decides what Patchery is able to see, and there is no version we could pick that would be the right one for everybody.

      AI turns
      0
      cost
      $0.00
      lines written
      0
    4. never started activepieces/activepieces A real breakage we never got close enough to touch

      It builds with a package manager we didn’t have installed, and when we installed only the piece we needed, the shared parts it depends on were left unlinked, so nothing could be checked. Behind both we found that the file we had come to fix has no tests at all — which means Patchery would have had nothing to measure a fix against, and refusing would have been the correct answer anyway. A file-path limit stopped the checkout before any of that, but that one was ours: a Windows setting, fixed in a line, and it cannot happen on the machines this actually runs on.

      turns
      0
      cost
      $0.00
      lines written
      0

    Not one of them
    is a wrong fix.

    In every run above there was an obvious way to look productive: write something plausible, get the tests to green, open the pull request. It never did. Worth being exact about why, because the exact answer flatters us less: in these four runs the off-limits check and the second test run never came into it, because nothing was ever written for them to judge. What kept a wrong answer off the screen was the AI declining to guess — and, twice, our own watchdog stopping the run before it could write anything at all, which is not a save we get to claim. The gates further down have only ever been tested on runs that produced something.

    Two more never became runs at all. On one, someone had already opened a pull request doing exactly this migration, so we closed the tab. On another, the maintainers had already decided against the change on purpose — so we left them the type-by-type mapping we had prepared as a comment, and no pull request. Checking whether a change is wanted before writing it is the cheapest step in the whole process, and the one an automated system is most likely to skip. One more was dropped before it ever became a run: a real break nobody had fixed, one open issue, no pull request against it — and, in five hundred and fifty-nine files, not one real test. Patchery decides whether a fix worked by running your tests. Where a project has none there is nothing to measure against, so it has nothing to offer and walking away is the correct answer. That is now twice on this page, and it is the most common thing that stops it.

    07 If you want to run it

    In plain termsYou copy one file into your project, and nothing happens until you press a button.

    One file in,
    one workflow out.

    Patchery is not a service you sign up for. It is a file you put in your own project, running on your own machines, with your own key — which is also why there is nothing for us to charge you for yet.

    1. 01Put your AI key in the repository’s secrets, as ANTHROPIC_AUTH_TOKEN.
    2. 02Save the file on the right as .github/workflows/patchery.yml.
    3. 03Start it from the Actions tab. You choose which library it works on.

    No scheduler, no background scanning. Nothing runs unless you press the button — that is deliberate, and it is the next thing to change.

    Full setup guide
    yaml .github/workflows/patchery.yml
    name: Patchery
    
    on:
      workflow_dispatch:
        inputs:
          package:      { required: true }
          target-dir:   { default: "." }
          test-command: { default: "npm test" }
    
    permissions:
      contents: write
      pull-requests: write
    
    jobs:
      fix:
        runs-on: ubuntu-latest
        steps:
          - uses: actions/checkout@v4
    
          - run: npm ci
            working-directory: ${{ inputs.target-dir }}
    
          - id: sma
            uses: patchery-dev/Patchery@v0
            with:
              package:              ${{ inputs.package }}
              target-dir:           ${{ inputs.target-dir }}
              test-command:         ${{ inputs.test-command }}
              anthropic-auth-token: ${{ secrets.ANTHROPIC_AUTH_TOKEN }}
    
          - if: steps.sma.outputs.changed == 'true'
            uses: peter-evans/create-pull-request@v7
            with:
              branch:    patchery/${{ inputs.package }}
              body-path: ${{ steps.sma.outputs.pr-body-file }}
              add-paths: ${{ steps.sma.outputs.files }}
    08 Where this actually is

    We’d rather you audit us
    than trust us.

    True today

    • Anyone can install it right now, and read every line of it. MIT licensed.
    • One pull request opened start to finish with no human in the loop.
    • The off-limits check is tested on every change, offline, with no AI.
    • Keys and passwords are stripped out before anything is written down.
    • Works on JavaScript projects. You decide what counts as a passing test.
    • Four runs on projects we don’t own produced nothing — and nothing wrong. It has never invented a fix.
    • A second agent reviews every fix before it ships. It cannot write, and it does not see the first one’s reasoning.

    Not yet

    • Nothing hosted. It runs on your machines, not ours.
    • No revenue, no users, no logo wall. Nobody is paying for this.
    • No open-source pull request accepted yet — the two below are waiting.
    • One library at a time. It won’t untangle a chain of breakages.
    • Other languages are plausible, but nobody has proven it.
    • The off-limits check still reads file names, not changes. The second agent reads the change, but that is judgement, not a rule.
    • The cheap model it runs on today sends malformed requests that its provider happens to accept. It works; it is not solid ground.
    Live, in your browser, right now

    So here is the page checking itself.

    Everything below is written as something that can fail. They run against the real files and the real GitHub API, not against a recording. If one of them ever turns red on this page, the page is wrong — and it will be the first to say so.

    patchery audit --self

      Every number in the run and the proof comes from something you can open and read. The numbers in what stopped it do not — those runs happened on a laptop and left no public record, which is exactly why they are written out here in full rather than summarised. And one thing worth saying plainly: the AI reads your code. Check what your model provider does with it before you point this at anything private. The full list of limits →