Every team I have watched adopt Cursor, Claude Code or Codex hits the same wall in week two.
The agent writes plausible code that does not fit the repo. It invents a test command. It puts a
component in src/components/ when everything else lives in app/ui/. It edits a file that is
generated.
The usual diagnosis is "the model is not smart enough." It usually is not that. The agent was never
told the rules — because nobody wrote them down.
There is a file for this. Cursor reads .cursorrules. Claude Code reads CLAUDE.md. Codex and most
harnesses read AGENTS.md. Copilot reads .github/copilot-instructions.md. If those files do not
exist, the agent improvises, and improvising means guessing.
So: write the file. The problem is that writing a good one takes 30–90 minutes per repo, and it rots
the moment you switch test runners.
ContextForge takes a snapshot of your repo — a file tree, plus
optionally one or two key files like package.json — and drafts those instruction files for you.
The interesting part is not that it calls a model. Everything calls a model. The interesting part is
what runs before the model.
Before any model is involved, a parser reads your tree and extracts facts:
next.config.*, vite.config.*, angular.json…) vitest.config.*, jest.config.*, playwright.config.*…).github/workflows/, .gitlab-ci.yml, Jenkinsfile…) pages/index.tsx and app/page.tsx are both Next.js entry
points, but they are different routers, and a naive regex misses bothscripts in your package.json
None of that needs a model. Which means none of it can fail because a model is down.
The model-assisted pass writes readable conventions from those facts. Its prompt forbids invention:
it may only restate what was supplied, and anything marked as a guess has to be written as a question.
Which brings me to the part I care about most.
This is the failure mode nobody warns you about. If your AGENTS.md confidently states a convention
your repo does not follow, the agent trusts the instruction over the code. An empty file makes the
agent cautious. A wrong file makes it confidently wrong.
So every fact carries a provenance tag:
detected``"scripts.test": "vitest run" is a fact.inferred
Here is a slice of real output:
## Project
- Languages: TypeScript
- Package manager: npm
- Framework: Next.js
- Test runner: Vitest
- CI: GitHub Actions
## Commands
npm run build
npm run lint
- Test command is undetermined
That last line is the product working correctly. It did not know, so it said so.
This is where most AI products quietly cheat, so here is the whole behaviour table:
| Situation | Response |
|---|---|
| Fair-use quota exhausted | 429 — checkedbefore the model call |
| No API key configured | 503 AI_NOT_CONFIGURED |
| Upstream model call fails | 502 AI_UPSTREAM_FAILED |
| You explicitly asked for a demo | 200 +demo: true + "Demo mode — not live AI" |
| Live success | 200 +source: Model-assisted |
| Model unavailable, rule-based draft | 200 +source: Rule-based |
The last two rows are the point. A rule-based draft is never labelled as AI output, and a failed
model call is never disguised as a successful one. If the tool cannot tell you something, it says
so rather than filling the gap with something plausible.
(While building this I actually caught myself violating the fourth row: an explicit demo request was
routing through the model, so an upstream outage turned a demo into a 502. A demo must always
succeed. Fixed.)
Every run returns a Context Score out of 100, built from what it could actually determine — build
command, test command, lint command, entry points, stack, directory conventions, forbidden paths.
A repo where it found everything scores 100. A repo where you pasted three files scores 40 and hands
you a list of what to fill in. The score is not a quality judgement about your project; it is a
statement about how much evidence the tool had.
The honest limitation I would want to know as a user: the fair-use quota is stored in serverless
memory, so it is per-instance rather than a true global limit. A hard global limit needs shared
storage (KV or Edge Config) and that is not shipped yet.
Paste the output of git ls-files into ContextForge and see what
it makes of your repo. The five example outputs are on
GitHub if you want to judge the format before
handing over a tree.
And if the generated file says something your repo does not do — fix it, then re-run. That is the
whole workflow.