DEV Community

Cover image for Ghost in My Code: an open-weight code archaeologist for code nobody documented
Komal Harshita
Komal Harshita

Posted on AI-assisted

Ghost in My Code: an open-weight code archaeologist for code nobody documented

Hacktoberfest Open-Source AI Challenge: Ghost in the Machine Submission ๐Ÿ‘ป๐ŸŒผ

This is a submission for the Hacktoberfest Open-Source AI Challenge Week 4: Ghost in the Machine

What I Built

Ghost in My Code is a code archaeologist. You paste in a snippet you inherited โ€” the Python 2 file nobody will admit to writing, the callback pyramid from before async/await, the C string handling that still compiles โ€” and it returns an autopsy: what the code actually does, which patterns are outdated, a suggested modern rewrite, line-by-line notes, an honest list of uncertainties, and a short fictional "Ghost Diary" written in the voice of the code itself.

I read "Ghost in the Machine" literally and kindly. The ghost isn't a monster โ€” it's the previous developer, who is usually a slightly younger version of you, and who did their best with the idioms they had. Dรญa de los Muertos is about keeping the dead in the room with you, not exorcising them, so the whole interface is a warm terminal you set a relic on and examine. The narrative voice is clearly labeled fiction; the technical findings are grounded in the actual snippet.

The rule I held myself to while building it: the app may only claim what it actually did. It never executes your code, never says a rewrite is verified equivalent, and never shows a pre-written report without stamping it DEMO REPORT.

Demo

Live app: ghost-in-my-code.lovable.app
Public archive: ghost-in-my-code.lovable.app/gallery

Try this in about twenty seconds: open the app, pick a sample relic from the four bundled ones, and read the four report tabs โ€” Overview, Code Autopsy, Modernization Studio, and Ghost's Diary. The Autopsy separates deterministic findings (regex checks the app ran itself) from model observations, so you can always tell which is which. Save a relic and it lands in the shared archive, visible to every other visitor, which is why the save dialog says so out loud.

If the model can't answer, the header tells you which provider is wired up and why the run failed, instead of quietly handing you something else.

Code

The full source is at: https://github.com/komalharshita/ghost-in-my-code.git

What's in there:

src/lib/ghost/
  types.ts               typed report + input models
  validate.ts            JSON extraction, report schema validation
  deterministic.ts       regex static checks (never runs the code)
  samples.ts             four bundled sample relics + demo reports
  analyze.functions.ts   server function: provider, prompt, retry, errors
  storage.ts             shared relic archive (list, save, rename, delete)
src/routes/
  index.tsx              workspace: relic panel + findings panel
  gallery.tsx            public archive with language filters
src/test/                12 tests: validation, extraction, static checks, routing
Enter fullscreen mode Exit fullscreen mode

How I Built It

React + TypeScript + Tailwind on TanStack Start, deployed as a Cloudflare Worker.

The open-weight model. Analysis runs through an OpenAI-compatible chat endpoint, and the preferred provider is google/gemma-3-27b-it served by Hugging Face Inference Providers, selected purely by a server-side key. Nothing about the app is Gemma-specific: OPEN_MODEL_BASE_URL and OPEN_MODEL_ID point it at any OpenAI-compatible host serving any open model, so swapping in a smaller Gemma for local use is an environment variable, not a refactor.

The model is the smallest part of the pipeline. Around it sits a deliberately boring harness:

  1. Validate input server-side โ€” language whitelist, 8,000-character cap, title length.
  2. Best-effort rate limit (8/min per worker instance).
  3. Run deterministic regex checks so the report has claims the app proved itself.
  4. Send the snippet to the model inside <relic> tags, with a system prompt that declares the code untrusted data, forbids following instructions embedded in it, forbids claiming execution, and forbids inventing APIs, authors, dates or benchmarks.
  5. Extract and validate the JSON against a report schema; on failure, one corrective retry asking for only the corrected object; on second failure, return a real error.
  6. Return a typed report โ€” the client renders model output as text, never as HTML.

Honesty is a schema, not a vibe. The report type carries source (ai or demo), provider, model, and an openWeight flag, and the UI prints them. Demo reports are pre-written for the four bundled samples and are stamped DEMO REPORT ยท PRE-WRITTEN, NOT A LIVE AI ANALYSIS. There is no path where a demo report reaches the screen unlabelled.

The shared archive. Saved relics live in a Postgres table, not in your browser, so the gallery is a real artifact other people can add to. Anyone can read and insert; rename and delete go through SECURITY DEFINER RPCs that check a per-relic edit token handed out at insert time and kept only in the creator's browser. No accounts, no passwords, and still no way for a stranger to rewrite your relic.

A caveat I'd rather state than have you find. My Hugging Face account is out of inference credits today, so live Gemma runs currently return 402 and the app shows exactly that message. The wiring is in place and the header names the provider; a clean live run needs credits on the account. I don't want to imply a run I haven't done.

Why Does Open Innovation Matter?

Because a code archaeologist that only works while a paid key is valid isn't an archaeologist, it's a subscription.

Three things open weights made possible that a closed API wouldn't have:

The model is replaceable by design. Gemma is the target, but the app only knows "an OpenAI-compatible endpoint and a model id." That's the whole integration surface, and it exists because I started from an open model rather than a vendor SDK. A closed API would have quietly become the product's architecture.

Legacy code is the worst possible thing to send to a vendor. The snippets people paste in are exactly the code they shouldn't be shipping to a third party โ€” internal systems, unmaintained in-house tools, a university assignment from someone who never consented to being ingested. Open weights mean "run this on your own machine" is a real instruction, not a marketing line, and the app says plainly which provider your code is going to before you send it.

The license story stays honest. My code is MIT. Gemma's weights are under Google's Gemma Terms of Use, and the README says so instead of pretending one license covers both. A project that ships model output as its core feature should be able to name the terms behind every byte of it.

Open also made the fallback design possible. When no open-weight key is configured, the app will use a proprietary model โ€” but it prints proprietary fallback, never open-weight. You only build that distinction if the open model is the default you're trying to reach.

The Spirit of It

The first time the diary generator ran on the Python 2 sample, it produced a line about hoping someone had finally written the documentation. It sat there in the panel, a few lines of invented feeling attached to eleven lines of real code that had genuinely outlived every person who understood it, and I understood the pitch better than any spec I had written.

The archive is what made it stick. It currently holds one relic โ€” a throwaway test entry I never cleaned up โ€” so the gallery is honestly a beginning, not a collection. But the shape is right: strangers dropping in fragments of code that outlived their context, each with a report and a short fictional voice attached, the way you'd leave something on an ofrenda. Nobody has to be the last person who remembers what a piece of code was for.

Prize Categories

  • Best Use of Gemma โ€” the analysis is built around google/gemma-3-27b-it via Hugging Face Inference Providers, with the provider layer written so any OpenAI-compatible open-weight host can be swapped in by environment variable.

Top comments (0)