This is a submission for the Hacktoberfest Open-Source AI Challenge Week 4: Ghost in the Machine
What I Built
"Every codebase has ghos...
For further actions, you may consider blocking this person and/or reporting abuse
๐ Every developer has that one file they're afraid to touch.
You know the one. No documentation, questionable logic, three mysterious comments, and absolutely nobody remembers why it works.
That's the problem I wanted to tackle with GitSรฉance. Instead of blindly refactoring legacy code, what if we could actually ask the original developer why they wrote it that way?
So I built an AI necromancer with specialized agents, Git history analysis, TabPFN, Gemma, and even a voice for the ghosts. ๐ป
Now I need to know: What's the most terrifying
// DO NOT TOUCHfile you've encountered? And more importantly, did you ever dare to touch it? ๐Cool project, reaper part is really useful.
But from my experience, "do not touch" files usually appear not because developer left. Team decided one way, after one month code was written other way, and nobody wrote which decision is current. So sรฉance is more like fixing the result, not the reason.
In our project we keep all decisions in markdown files near the code (ADR and stories), agents also read it and update. We call it ProjectStore. Boring, but later nobody need to call ghosts :)
Question: reaper reads commit messages or PR descriptions? Usually only there you can find "why".
100% agree on ADRs! If every team maintained clean markdown decision records like your ProjectStore near the code, software engineering would be paradise and we wouldn't need code necromancy at all! ๐
GitSรฉance was designed for the messy reality of the other 90% of codebases โ especially ancient open-source fossils from 2010 where no ADRs exist and the original creators moved on a decade ago.
To answer your question: right now, the Reaper reads commit messages, not PR descriptions.
It traverses the Git commit log for each file to:
hack,temporary,black magic,workaround).fix,patch,bug).The main reason I didn't query PR descriptions in v1 was strictly GitHub API rate limits (unauthenticated REST calls cap out at 60 req/hr, and querying PRs per file across a whole repo burns through that instantly).
That said, querying linked PR descriptions and review discussions when an authenticated GitHub PAT is provided is a fantastic idea for v2. Appreciate the great insight! ๐
Also, I'd love to continue this project once its out of judging.
Have A Great Day!
Yes, agree, most of real code is fossils without any docs :) For old projects your way is the only way.
Small tip for v2: in GitHub GraphQL commit has field associatedPullRequests, so you can get PR description together with commit history in one query, not one request per file. It needs token, but limit is much bigger.
Good luck with judging, will follow the project!
Thanks Sir! for the tips and wishes.
Have A Great Day!
The thought-token parsing for Gemma is a really clever fix. I've run into the same issue with reasoning models โ the internal chain-of-thought eats the output budget. Your _extract_text walker is a clean solution. Did you find that the thought tokens were consistent enough to filter reliably, or did you need fallbacks for edge cases?
Great question! The short answer is:
part.thought = Truein thegoogle-genaiSDK is consistent, but token budget starvation was the sneaky edge case.Here is what we ran into:
The Chain-of-Thought Trap: If
max_output_tokenswas set too tight (e.g. ~300 tokens), Gemma would spend its entire budget in internal reasoning mode. The call would returnFINISH_REASON_MAX_TOKENS, but every single part hadthought = True. Filtering them left us with an empty string! Bumping the budget to 1024+ gave it enough runway to conclude its thought and emit dialogue.The Multi-Tiered Fallback: In
_extract_text, we intentionally checkcandidate.content.partsfirst (filteringthought=True), and fall back toresponse.textsecond (in case future SDK versions or other endpoints don't expose separate part objects).App-Level Graceful Degradation: If the model returns empty text anyway (or hits a rate limit / 404 on an obscure repo), the backend catches it and serves a deterministic forensic fallback persona based on the Git commit blame metadata. That way the CRT terminal never crashes with an unhandled exception.
Really appreciate you looking at my code! Did you find a similar workaround with your reasoning models?
The 'token budget starvation' edge case is exactly the kind of thing that only shows up in production. Setting max_output_tokens to 300 seems reasonable until you realize the model spends all of it thinking and never gets to the actual response. Bumping to 1024+ is the right fix, but it's a non-obvious one.
Exactly! When your API call returns
200 OKand charges you for 300 tokens, but the text payload is completely empty, it literally feels like a ghost in the machine. ๐ป๐Hopefully future SDKs decouple the reasoning budget from the completion budget so developers don't have to learn this the hard way. Really glad you found the post-mortem useful! ๐ค
The 'feels like a ghost in the machine' is the perfect description. You pay for 300 tokens, get an empty string, and the only thing haunting you is the API bill. Very on-theme for this project.
Yeah Yeah, different kind of horror and you don't even need halloween to vibe with it.๐
Have A Great Day!
โI left that hack at 2 AM before a release. I promised myself I would refactor it that weekend, but that weekend never cameโ is the most relatable thing a ghost has ever said. Love the shift from fearing legacy code to honoring the person who wrote it. The death certificate is a brilliant touch too.
Thanks!
The whole motive was to bring out ghost of one who wrote file and honor them, and if you want have a voiceover using eleven labs api voice key.
Glad you liked it!
Have A Great Day!
Love that the Reaper walks commit history and fear comments before the Medium speaks โ most โexplain this legacy fileโ tools skip the forensic step and just invent intent. TabPFN as the mortality scorer is a neat non-LLM choice for that risk vector too.
Thanks! Glad you liked it!
And I'm glad that people got the feel of haloween.๐
Have A Great Day!
I have that file. Everyone has that file, and the 'nobody knows why this works' comment is always written by someone who left three years ago. The ghost-chat idea is fun, but the part I'd actually use is the mortality badge โ a README that admits which files are haunted feels more honest than pretending the repo is healthy. Did the TabPFN score surprise you on any file you thought was fine?
Haha completely agree โ the README badge that actually admits the skeletons in the closet is much more honest than a wall of fake green badges! ๐
To answer your question: yes! That was actually the exact reason I used TabPFN over a naive heuristic/linter.
A simple rule-based linter looks at a core mathematical utility (like
crc32.pyorslugify.pyuntouched for 3+ years) and blindly screams "DEAD". But TabPFN evaluated the high test sentinel and near-zero defect churn, correctly predicting it was just stable/frozen (18% mortality).The real surprise in the other direction was files untouched for only ~6 months that looked "alive" on the surface, but had 100% author turnover and a 60%+ bug-fix commit ratio โ TabPFN immediately flagged them with 78%+ mortality risk. It caught silent structural rot before anyone realized the original architect had vanished.
Thanks for checking out the project!
This is such a creative way to tackle one of the most familiar problems in software development. Every codebase seems to have that one file nobody wants to touch because its original logic and history have slowly become a mystery.
I especially like the idea of using AI to bring some of that hidden context back instead of simply trying to rewrite everything. Understanding why a particular piece of code was written that way can be just as important as understanding what it does. Sometimes the biggest challenge isn't fixing legacy code, but figuring out the story behind it. Great concept!
Really like that the pipeline starts from signals most tools ignore โ commit-history orphan detection plus the human traces ('hack', 'do not touch' comments) rather than static analysis alone, because fear comments are genuinely high-signal metadata about where knowledge died. The four-agent split is the right decomposition: finding, predicting, translating and proposing are different jobs that shouldn't share one prompt. In desktop app maintenance I'd point this at the one mysterious native module nobody dares rebuild โ grounding the 'ghost' in git blame and release history makes the revival blueprint auditable instead of hallucinated.
Thanks! That exact point โ that a single mega-prompt hallucinates while 4 grounded agents keep each other honest โ was the core design philosophy behind GitSรฉance. Appreciate you highlighting the architecture! ๐
Have A Great Day!
Extracting historical intent from git blame and PR discussions is surprisingly useful for legacy modules. Most teams just let tribal knowledge evaporate.
Nice bro, I tried it!
AND STOP GRINDING TOO MUCH!!!
Thanks bro
and a what now?๐
๐ Great! see you soon
Cool โ ๏ธ
Thanks di!!!
I'd love if you try it.
Have A Great Day!
The useful output is not a fictional author narrative; it is a traceable map of what makes the file risky to change. Iโd surface the evidence beside every explanationโrecent callers, ownership churn, test coverage, and dependency edgesโso the recommendation can be challenged before anyone treats it as repository truth.
That's actually the exact architecture under the hood!
The ghost persona is the creative interface layer built specifically to honor the Hacktoberfest "Ghost in the Machine" (Halloween & Dรญa de los Muertos) challenge theme. But you can't revive legacy systems on vibes alone.
Underneath the sรฉance altar, that exact traceable evidence is computed across our 7-dimensional forensic feature vector:
unique_authorsbus factor calculation)has_testsbranch presence)bug_fix_commit_ratioandchurn_velocity)days_since_last_commitand lines added/deleted ratio)That's why we added the "๐ Export CSV" button and the native Model Context Protocol (MCP) server โ so engineers can audit the raw telemetry, challenge the Bayesian mortality probability, or feed the tabular distribution directly into their own CI/CD pipelines.
Best of both worlds: grounded forensic telemetry for the codebase, wrapped in an authentic retro persona for the hackathon spirit! ๐Spot on analysis โ and that's actually the exact architecture under the hood!
The ghost persona is the creative interface layer built specifically to honor the Hacktoberfest "Ghost in the Machine" (Halloween & Dรญa de los Muertos) challenge theme. But you can't revive legacy systems on vibes alone.
Underneath the sรฉance altar, that exact traceable evidence is computed across our 7-dimensional forensic feature vector:
unique_authorsbus factor calculation)has_testsbranch presence)bug_fix_commit_ratioandchurn_velocity)days_since_last_commitand lines added/deleted ratio)That's why we added the "๐ Export CSV" button and the native Model Context Protocol (MCP) server โ so engineers can audit the raw telemetry, challenge the Bayesian mortality probability, or feed the tabular distribution directly into their own CI/CD pipelines.
Best of both worlds: grounded forensic telemetry for the codebase, wrapped in an authentic retro persona for the hackathon spirit! ๐
Balancing churn velocity against defect ratios is the right fix for survival analysis on legacy files. Simple staleness heuristics consistently misclassify hardened utilities as dead weight because they treat elapsed time as decay. When test coverage is high and bug-fix frequency is near zero, an untouched module is usually closer to a stable asset than an abandoned liability.
Couldn't have said it better myself! "Stable asset vs. abandoned liability" was the exact principle behind moving to the 7D Bayesian model. Appreciate the great takeaway, Dean! ๐
Have A Great Day!
the Reaper agent flagging files from commit history and fear comments is the useful bit, and the 7 dimension vector feeding TabPFN is where i would push. mortality risk needs a ground truth label, and in most repos the file nobody touched for years is stable, not dying.
we scored staleness on a few repos and the rarely edited files with the most inbound imports were the safe ones, churn plus test coverage told us more than age.
what did you use as the label for calibrating the risk score, or is it unsupervised?
check new repo
dev.to/jovojovi/full-projects-buil...