Inspiration

Open source maintainers are drowning in issue backlogs, and most of the pile is not what it looks like. The same bug gets reported over and over by different people in completely different words, and the duplicates stay invisible because nothing links them. Search does not help, because two people describing the same crash rarely use the same vocabulary. So the backlog keeps growing, and the real number of distinct problems stays unknown.

I wanted to see what a backlog looks like when you count problems instead of counting issues.

What it does

You paste a public GitHub repo URL. Same Issue pulls the open issues through the GitHub API and clusters them by meaning rather than by keyword. The headline is the whole point: a repo with 312 open issues might only have 47 actual problems in it.

Each cluster shows the issues that belong together, picks a canonical one to consolidate into, and drafts a comment a maintainer can paste onto the duplicates. Every cluster carries a confidence level, and low confidence clusters are shown at reduced prominence rather than hidden, so it is clear where the model is guessing and a human should look.

How I built it

Next.js 14 with the App Router, TypeScript and Tailwind, deployed on Vercel.

Issues come from the GitHub REST API, paginated and capped at 300, then reduced to a compact payload of number, title, truncated body and labels. That payload goes to a provider adapter that calls Gemini by default and falls back automatically to Groq if Gemini errors or rate limits. The model returns structured JSON: clusters, canonical issue, shared symptom, draft comment, confidence.

All keys are server-side in a route handler. Nothing touches the client. The three sample repos are pre-analysed and served as static JSON, so the most common path costs no API calls at all.

Challenges I ran into

The GitHub issues endpoint returns pull requests alongside issues. Nothing errors, nothing looks wrong, and the clusters are quietly polluted with PRs until you filter on the pull_request field. It was invisible until we checked the raw response.

Free tier token limits shaped the architecture more than anything else. Groq's free tier caps at 12,000 tokens per minute, well below a full backlog payload, so the fallback had to chunk the issues and merge cluster results rather than retry the same oversized call.

The other real decision was what to do when the model is unsure. Hiding low confidence clusters would have made the output look cleaner and more impressive. Showing them, demoted and labelled, is more honest and more useful to someone who has to act on it.

Accomplishments that I'm proud of

A maintainer can point it at their own repo and find duplicates they did not know were there, in under a minute, with no signup and no install. It runs entirely on free tier infrastructure with a working fallback path, and it tells you when it is not sure instead of presenting every guess as fact.

What I learned

Semantic clustering catches what keyword search structurally cannot. "App crashes on startup" and "won't open when I launch it" share not a single word and describe the same bug. That gap is exactly where an LLM earns its place, and it is not a gap you can close with better search.

We also learned that free tier constraints are worth designing around rather than around apologising for. The chunked fallback exists because of a token limit, and it is a better piece of engineering than a single call would have been.

What's next for SAME ISSUE

A gitHub action that runs on every newly opened issue and comments if it looks like a duplicate of something already in the backlog, so the pile stops growing in the first place.

Built With

Share this project:

Updates