What I Built
The Unmerged reads a public repository's history, finds the work that was abandoned in it, and has an open-weight model β running inside your browser tab β say what each piece of that work was trying to do.
A repository is read as a record of what got built. It is equally a record of what didn't, and that half never gets read. There is a pull request somebody wrote, pushed, and watched go quiet until it was closed. A branch nobody ever deleted. A commit that shipped and then got taken back. All of it is in the history right now and none of it was looked at again.
So it reads that half back to you, in four passes:
| The Unmerged | Pull requests closed without ever being merged β finished work that went nowhere |
| The Forsaken | Branches still standing, never merged back into the main line |
| Revenants | Commits shipped and then reverted β the only ghosts a history admits to making |
| The Erased | Commits whose whole purpose was to delete something |
Point it at facebook/react and it finds eighteen of them, including branches named 0.3-stable through 0.9-stable β each still pointing at a commit, each still waiting. Nobody deleted them. Somebody just stopped.
How I read the theme: a sΓ©ance is a room where you ask the dead to account for themselves. The dead here aren't deleted files, they're decisions β the quiet ones nobody announced. A closed pull request is the most human artifact in a repository. Someone finished something and it didn't matter.
Demo
amankumarsahani.github.io/the-unmerged
Type any public repository as owner/name. Nothing to install, no account. The model downloads into the tab on first visit (~260 MB on WebGPU, ~370 MB on the WASM fallback) and is cached after.
Unauthenticated GitHub allows 60 API requests an hour and one reading costs four, so there's an optional token field if you hit the wall.
Code
amankumarsahani
/
the-unmerged
Every repo is a record of what got built β and equally of what didn't. Finds abandoned PRs, forsaken branches and reverted commits, and has an open-weight model running in your browser speak for them.
The Unmerged π―οΈ
A repository is read as a record of what got built. It is equally a record of what didn't β and that half never gets read.
The Unmerged reads any public repository's history, finds the work that was abandoned in it, and has an open-weight language model restate what each one was trying to do β running entirely inside your browser tab. No install, no server, no API key, no account.
What it finds
| Rite | What it exhumes |
|---|---|
| The Unmerged | Pull requests closed without ever being merged β finished work that went nowhere |
| The Forsaken | Branches still standing, never merged back into the main line |
| Revenants | Commits shipped and then reverted β the only ghosts a history admits to making |
| The Erased | Commits whose whole purpose was to delete something |
Point it at facebook/react and it finds branches named 0.3-stable through 0.9-stable, eachβ¦
Three static files and a licence. No build step, no dependencies, no backend.
How I Built It
The model is SmolLM2-360M-Instruct β Apache-2.0 weights, openly published training data β running through Transformers.js on WebGPU where the browser offers it and WASM where it doesn't.
Reading is four calls to the GitHub REST API: repository metadata, the last hundred commits, the last hundred closed pull requests, the branch list. The Unmerged are closed PRs with a null merged_at. The Forsaken are every branch that isn't the default. Revenants are commits whose first line starts with revert. The Erased match a verb of destruction. Four calls, no pagination, no server.
Then the part I got wrong twice.
My first design asked the model to write an epitaph in the voice of the dead code. It is a lovely idea and it does not work. Here is SmolLM2-135M on a real closed React pull request:
Repository: twitter/1170753516 - never merged into the main feed
Reply this in one short sentence, in its own voice, as an epitaph.
It leaked my instruction back into its own output and invented a repository that does not exist. I added few-shot examples, which made it worse β "The Stallion did a great job of it getting through this... issue", "Ummmph". So I went up to 360M, and got fluent, confident, completely generic mysticism with no connection to the input at all:
Echoes of lost time. Somewhere long ago, a firestorm burst forth
with unyielding force. They'll eventually join you: in whispers
and smoke you feel it
That is the actual failure mode of a small model asked to be evocative. It doesn't write badly β it writes beautifully about nothing.
What a 360M model can do is restate a sentence. So I stopped asking for a voice and asked only for intent: two worked examples, temperature 0.3, under eight words. Same model, same page, real rows from facebook/react:
#38019 for test only docs: fix typo in README
-> Correct the typo in the README.
#37818 [ci] bump CI Node.js version to 24.22.0
-> Upgrade Node.js to the latest version.
#37947 [Experiment] Flight Result: expand into a model for the serializer
-> Expand the flight result into a regular serializer measurement.
The mood is now carried by the page β the typography, the four names, the order they appear in β and the model only does the one job it is actually capable of. That reads to me as the real lesson of building on small open weights: they are not tiny versions of large models with worse prose. They are good at different work, and the design has to go find that work.
It still gets things wrong, and it is guessing from a title alone. The page says so.
Why Does Open Innovation Matter?
I want to make a narrower claim than "open is good."
This project could not exist on a closed API. Not "would be worse" β could not exist.
Three static files on GitHub Pages, served to an unknown number of strangers, each typing repository names in and getting generated text back. On a hosted API that's a key I have to protect, a bill that scales with other people's curiosity, and a rate limiter I must build before I dare post the link. The honest version of this on closed infrastructure is a signup form and a free tier. Almost nobody would use it, and whoever did would hand a third party a log of which repositories they were curious about.
Open weights move the computation to where the data already is. Your browser reads the history; your browser reasons about it. Nothing is uploaded because there is nowhere to upload it to. That privacy isn't a feature I implemented carefully β it's a property of having no server, which I got for free by running an open model locally.
There's a second thing, and the failure above is the evidence for it. I swapped the model twice and rewrote the prompt three times in an afternoon, because the weights were sitting on disk and nothing was metered. On a closed API I'd have been iterating against someone else's rate limit and someone else's idea of what the model should refuse. Being able to fail cheaply and specifically is most of what open weights buy you, and it never shows up in the benchmark tables.
And it doesn't rot. The weights are downloadable and Apache-2.0. No deprecation email switches this off. In five years someone can clone the repo and it still runs.
The theme this year is that AI belongs to everyone. The test I'd apply is whether a person with no budget, no key and no account can run the thing and keep changing it. Open weights are what make that answer yes.
The Spirit of It
The uncomfortable thing I found is that the busiest, healthiest repositories have the most unmerged pull requests. React has dozens. That isn't dysfunction β it's what a project looks like when lots of people care enough to try. Every one of them is somebody's finished work, with review comments on it, that went nowhere.
We measure repositories by what merged. The unmerged half is a record of effort that was real, and spent, and is now only visible if you go looking. This started as a Halloween joke and turned into the only part I actually care about.
Prize Categories
- Best Use of Open Weights β SmolLM2-360M-Instruct (Apache-2.0) is the only inference anywhere in the project. There is no closed model in it, and the post documents what the open model could and could not do.
- Best Local-First / On-Device AI β all inference runs in the visitor's browser via WebGPU or WASM. No server exists.
AI disclosure
Built in an agent session with Claude (Opus 5). I set the direction β the four passes, the decision to stop asking for a voice after seeing the output above, and the local-first argument β and I reviewed and ran the code before publishing.
What was actually verified, rather than assumed: the GitHub mining was run against live data (18 abandoned things in facebook/react, across all four passes); the page was driven end to end in a real headless browser, which rendered every pass correctly; and the generation step was run against the deployed prompt and real repository rows, which is where the quoted outputs above come from β both the failures and the working ones.
Top comments (0)