GitHub stars tell you what the crowd adopted. They do not tell you what fits your project. RepoFinder is my attempt at the second thing: give it a GitHub repo or a public website plus a goal - “production evals”, “auth”, “background jobs” - and it returns three to five open source tools that genuinely complement what you are building. Each pick comes with a What, a project-specific Why, a How to integrate, ease and impact ratings, and live GitHub evidence: stars, contributors, commits in the last 90 days. Then you can interrogate any of them. The tagline is the thesis: build better, focused, and faster - where your taste matters more than the number of stars.
Source at github.com/motozero/repofinder.io. Built entirely with Codex, running on the OpenAI API, deployed as a single Cloudflare Worker.
#Third pass at the same itch
This is the third time I have taken a run at software discovery. RepoRadar was the hackathon version - four hours, generative UI, 2nd place worldwide, an agent that deploys a micro-app for any repo. Repo Recommender was the disciplined Claude Code rebuild with a 23-lesson book. RepoFinder is the sniper version: no generative UI, no deploys, one sharp loop. Search for the right repo, understand why it ranked, ask what else you should consider. It is deliberately lightweight - plain HTML, CSS, and vanilla JavaScript on the front, one TypeScript Worker behind it, D1 for persistence. No frontend framework at all.
The taste thesis is baked into the model’s own instructions: treat stars as a signal of adoption, treat last update as a maintenance signal, never recommend a tutorial or an awesome-list, and prefer the tool a senior engineer would actually install. Stars and recency are signals, not verdicts.
#Exactly two models, one routing table
Every OpenAI call in the codebase goes through one provider boundary, src/openai.ts, and it names exactly two models:
- gpt-5.6-luna does the high-volume, low-stakes work: reading the source repo or website and extracting its purpose, stack, and two or three canonical GitHub search queries. Reasoning effort is literally set to
"none", capped at 500 output tokens. - gpt-5.6-terra does everything customer-facing: picking the 3-5 best complements from the candidate pool and writing the Why and How (effort
"medium", 2,200 tokens), answering the per-repo chat (effort"low", 700 tokens), and acting as the LLM judge in the eval harness.
It all runs on the Responses API via raw fetch - no SDK - with store: false on every call as an explicit data choice, since user goals and README excerpts flow through. Outputs use strict JSON Schema with additionalProperties: false, which is why the parser is intentionally boring: JSON.parse, no fence-stripping, no regex recovery heuristics. A strict schema is a contract; prompting a model to “return JSON” is just a preference.
#How a recommendation actually gets made
- Luna analyzes the source and emits canonical search queries.
- Up to six live GitHub searches run, results merged and deduped, the source repo excluded.
- Three safety-net filters prune the pool: an ecosystem filter (a TypeScript app cannot
npm installa Rust crate), a non-tool regex that kills awesome-lists, interview-question dumps, tutorials, and boilerplates no matter how many stars they have, and an archived-repo filter. - The top 12 by stars go to terra, which picks 3-5 and writes the explanations and ratings.
- Any repo name the model returns that GitHub did not actually supply is silently dropped. A syntactically valid name is not a real repo. That one rule is the anti-hallucination guard.
- Final picks get enriched with objective metrics - contributor counts and 90-day commit velocity - pulled from GitHub in parallel.
If the OpenAI key is missing or any call fails, the app drops to a deterministic GitHub-only ranker and says so with a visible “GitHub fallback” badge. That was a design rule, not an accident: graceful degradation must never masquerade as model reasoning.
The “Ask OpenAI about this repo” chat on each card is the taste-building feature. Ask why it ranked, whether it fits your stack, what the tradeoffs are. The repo’s README goes into the prompt as a JSON block explicitly labeled untrusted data, never into system instructions, so a poisoned README gets no system-level authority. And every reply must end with exactly one forward-moving question - enforced in code, not just requested in the prompt.
The same engine is also a remote MCP tool: recommend_repos at repofinder.io/mcp, stateless over Streamable HTTP. Browser and agents are two surfaces on one engine; neither duplicates a line of logic.
#What the repo teaches about Codex
Daytripper, the app I built the day before, taught me the Codex product loop. RepoFinder is where the deeper machinery came together, and I wrote it down as a 15-lesson course checked into lessons/ - each lesson names a decision, points at the actual code, and ends with an exercise. The parts that changed how I work:
- AGENTS.md is durable context, not a transcript. Architecture rules, runtime facts, safety boundaries, quality gates. The test for a good instruction is whether it is checkable: “write clean code” is vague, “recommendation logic lives only in
src/engine.ts” is enforceable. When Codex misses a constraint, you improve AGENTS.md, not the prompt for one session. - Skills encode judgment, not capability. A tool provides a capability; a skill provides repeatable judgment about when and how to use it. The two Codex skills in
.agents/skills/carry YAML frontmatter with trigger descriptions, because the agent has to know when a skill applies before it can follow the steps. A checked-in.codex/config.tomlpoints Codex at the app’s own MCP server, so the agent that built the product can also use it. - Codex works as a closed loop, not a code generator. The build sequence in lesson 15 is the part I would show anyone: Codex checked current OpenAI and Cloudflare docs before writing code, planned around four user-visible contracts each with a verification path, and - because the sandbox could read the repo but not write to it - made a clone under
/private/tmp, built and tested there, and applied the diff back only after typecheck and tests passed. The useful unit of Codex work is a verified outcome. - Tests and evals answer different questions. Forty-eight deterministic tests cover the exact, easy-to-break plumbing: SSRF guards, rate-limit key hashing, prompt-injection containment, a regression test that pushes secrets through every telemetry channel and asserts none reaches D1. The eval harness handles judgment: seven cases through the real engine, scored by a free structural tier (which fails any output containing an em-dash, since the house style is machine-enforced), a recall tier with concept groups, and a gpt-5.6-terra judge scoring genuine fit on a rubric. The dataset is honest about its own calibration - one case is annotated “Known-weak case: this is the gap the eval set exists to measure,” and three others document mislabels that the recall-versus-judge gap caught.
One more loop worth naming: Codex built it, and my Claude-side gstack tooling reviewed it. The git history shows fix(qa) commits, numbered design findings, and a regression test whose header reads “Found by /qa on 2026-08-03.” Two different agents, one adversarial workflow, and the product came out better than either would have produced alone.
#Try it
Point repofinder.io at your repo and a goal, then argue with the results - that is what the chat is for. Read the lessons if you are learning Codex; they are the artifact I wish I had a week ago. And if it mis-ranks something for your stack, tell me - the eval dataset exists to grow.
Let’s go!