DEV Community

Cover image for TraceForge: I Built This for the Friend Who Sends Screenshots Instead of Logs
Rahul Roy
Rahul Roy Subscriber

Posted on

TraceForge: I Built This for the Friend Who Sends Screenshots Instead of Logs

Hacktoberfest Weekend Challenge: Build for a Friend Submission 🀝

This is a submission for the Hacktoberfest Weekend Challenge: Build for a Friend

What I Built

I have a friend who ships frontend for a living, and he has one debugging habit that used to drive me a little insane.

He does not paste the stack trace.

He sends a screenshot.

Sometimes it is the GitHub Actions page with a red Build failed. Sometimes it is the browser with a CORS overlay he did not notice. Sometimes it is his editor, zoomed in on a squiggle, with the actual error cut off at the edge of the frame. Then a message: β€œany idea?”

I do not mind helping. What bothered me is what happens after. The answer lives in chat for ten minutes and then dies. Next week the same class of bug shows up, he sends another screenshot, and we do the whole thing again. No notes. No checklist. No β€œhere is how we proved it last time.”

TraceForge is the thing I built for him this weekend.

You give it the evidence he already has:

a screenshot of the broken UI, CI job, or terminal
the log, if he remembered to copy it
a short note about what he was doing (β€œI moved the Button component and production started failing”)
Gemma 4 reads the image and the text together, then TraceForge returns a structured diagnosis: what is actually visible, what is only a likely cause, how to reproduce it, a small fix plan, and a validation checklist. After that it turns the incident into a reusable Agent Skill (SKILL.md + a troubleshooting note) so the next time this kind of failure shows up, an agent - or he, at 1am - does not start from zero.

The loop I wanted for him is simple:

see β†’ understand β†’ explain β†’ reproduce β†’ fix β†’ encode β†’ reuse

Most tools stop at β€œhere is probably why it broke.” I wanted the leftover knowledge to survive the chat thread.

Demo

Code: github.com/Rahul-Roy-Hub/traceforge

Code

Run it locally:

npm install
copy .env.example .env.local
set GEMINI_API_KEY from Google AI Studio
npm run dev
Then open http://localhost:3000, go to New Analysis, drop a screenshot, paste a log, and hit analyze.

There is also a Chrome extension in extension/. Load it unpacked, open a page that is actually failing, click Trace This Issue, and it grabs the visible tab, console errors, and failed network requests. That was the β€œhand it over” part. I did not want him filling a form. I wanted him to click one button on the broken page.

The Gemini key stays on the Next.js server. It never goes in the extension.

If you want a smoke test without the UI:

curl.exe http://localhost:3000/api/health
curl.exe -X POST http://localhost:3000/api/analyze
-F "image=@public/demo/placeholder.png"

-F "userContext=The deployment started failing after I moved the Button component." `
-F "logText=Error: Cannot find module '@components/Button'"
That JSON can go straight into /api/generate-skill, then /api/validate-skill, then /api/export-skill for a ZIP.

Code

GitHub logo Rahul-Roy-Hub / traceforge

Build a focused multimodal developer tool that uses Gemma 4 as a core intelligence layer and turns a screenshot/error report into a reusable Agent Skill

TraceForge

Visual Evidence β†’ Diagnosis β†’ Reusable Agent Skill

TraceForge is a multimodal developer troubleshooting tool powered by Gemma 4 on the Gemini API. Developers upload a screenshot, paste an error log, and describe what they were doing. TraceForge correlates visual and textual evidence, produces a structured diagnosis with uncertainty, and converts the troubleshooting workflow into a reusable Agent Skill.

Problem

Debugging starts with fragmented evidence: a screenshot, a log, and a short description. Most tools process only one of these well, and the answer disappears after the incident.

Solution

TraceForge compiles one debugging incident into reusable agent knowledge:

SEE β†’ UNDERSTAND β†’ EXPLAIN β†’ REPRODUCE β†’ FIX β†’ ENCODE β†’ REUSE

Demo

  1. POST /api/analyze with a screenshot, user context, and optional log.
  2. POST /api/generate-skill with the analysis JSON.
  3. POST /api/validate-skill to check Agent Skill frontmatter and required sections.
  4. POST /api/export-skill to download a ZIP.

A thin tester is…

The model is not a chatbot bolted onto a form. The system prompt is the product:

  1. Separate observed evidence from hypotheses.
  2. Never present an unverified cause as a confirmed fact.
  3. Prefer the smallest practical fix.
  4. Explain which evidence supports each important conclusion.
  5. Include uncertainty when evidence is incomplete. ...
  6. Causes are likely, not confirmed, unless the evidence is direct and unambiguous. Gemma 4 has to return JSON that matches a Zod schema. Evidence is tagged by source (image, log, user_context) and importance. Causes have confidence. There is an unknowns field on purpose, because a cropped screenshot should be allowed to say β€œI cannot read that.”

If the first pass is not valid JSON, we send it back through a repair prompt instead of pretending the answer was fine. If the image path fails but he still pasted a log, we fall back to text rather than failing the whole request.

After analysis, lib/skill-generator.ts compiles a SKILL.md with Purpose, Workflow, Evidence Rules, and Validation. lib/skill-validator.ts checks the Agent Skills frontmatter (name, description, kebab-case, length limits) and those required sections. npm run harness scores three known fixtures: module resolution, a CI deploy missing DATABASE_URL, and a UI that cannot reach its API.

That last part is the whole point for my friend. The first broken deploy becomes a skill he can keep.

How I Built It

Open-source AI is not a side feature here. Gemma 4 (gemma-4-26b-a4b-it) is the intelligence layer. I am serving it through the Gemini API with @google/genai, thinking set to high, responseMimeType set to JSON, and the screenshot sent as inlineData next to the prompt. The image is not an afterthought. If you only paste the log, you lose the CI job name, the red overlay, the URL in the address bar - the stuff he actually photographed.

Stack:

Next.js 16 App Router + TypeScript
Gemma 4 for multimodal analysis
Zod for the diagnosis shape
js-yaml + a small original validator for Agent Skills
JSZip for export
a Chrome extension that captures the page without opening DevTools
Render as the web service (render.yaml, health check on /api/health, GEMINI_API_KEY only in the dashboard)
Flow:

POST /api/analyze β€” screenshot + context + log β†’ structured diagnosis
POST /api/generate-skill β€” analysis JSON β†’ SKILL.md package
POST /api/validate-skill β€” frontmatter and section checks
POST /api/export-skill β€” ZIP
GET /api/harness β€” fixture coverage
GET /api/health β€” Render
I kept screenshots off disk. They go to Gemma and then they are gone. For a friend who will absolutely photograph a .env someday, that mattered. The UI even warns you to strip keys before upload.

The UI is a small workspace: diagnosis, reproduction, fix plan, validation, generated skill. Templates exist only to prefill New Analysis. Gemma still runs on whatever you actually upload. No mock diagnoses.

I built this over the weekend with an AI coding agent in the loop, then ripped out the fake data path so nothing on screen could pretend to be a live answer. If Gemma is down or the key is missing, it errors. That is the honest behavior.

Why Does Open Innovation Matter?

A closed debugging API would have given him a paragraph in a chat box and a bill. That is not what I needed.

Gemma 4 is open-weight. The model is the product, not a rented mystery. I can swap the model id, turn thinking down to minimal if Render starts timing out, and keep the same schema. The prompt, the evidence rules, and the skill format are mine. If a closed model refused to admit uncertainty, I would be stuck. Here, unknowns is part of the contract.

The output is an open Agent Skill, not a vendor transcript. SKILL.md is markdown with YAML frontmatter. He can read it, diff it, drop it into another agent, or ignore the model later and keep the checklist. A closed API would have trapped the β€œhow we fixed it” inside someone else’s UI.

His screenshots do not have to become training data on a box I cannot inspect. TraceForge does not store the image. The key never leaves the server. For a friend pasting production logs, that is the difference between β€œsure, I’ll try your app” and β€œI am not uploading this.”

I could ship the whole pipeline in a weekend. Open model, open skill spec, Render as a normal Node web service, Apache-2.0 on the repo. No partnership form. No waitlist. The open pieces are what make the product work, not stickers on a README.

If I had used a closed multimodal API as the core, TraceForge would be a thin wrapper around a chat completion. The thing that matters - evidence vs guess, then a skill you can reuse - would still be possible in theory, but it would not be ours. Open innovation is what let me put the rules in the prompt, validate the output, and hand my friend a ZIP instead of a screenshot reply.

Prize Categories

Best Use of Gemma - Gemma 4 is the core intelligence. It reads the screenshot and the log together, thinks through the diagnosis, and the rest of the app is built around that payload.
Best Use of Render - the app is a Render web service (render.yaml, npm start, /api/health). Gemma runs behind that Node process, not on the laptop.

Team Submissions: Lokesh Kumar Singh

Top comments (0)