Graphyti: How a Deterministic Code Graph Eliminates AI's Structural Hallucination Problem
The $2B Problem Nobody Talks About
Every AI coding tool — Cursor, Copilot, Aider, all of them — has a dirty secret. They don't just hallucinate facts about the world. They hallucinate the shape of your own codebase.
The model invents a field that doesn't exist on a Prisma model. It forgets a relation it created two prompts ago. It renames something without knowing three other files depend on it. It "helpfully" restructures code nobody asked it to touch.
This isn't regular hallucination. It's structural hallucination — and it's the silent killer of AI coding tools.
Why Existing Solutions Fall Short
The industry's answer has been better context retrieval. Embeddings. Repo maps. RAG pipelines that fetch smarter context before feeding it to the model.
That helps. But it only makes the model's input better. It does nothing to verify the model's output.
You can give the model a perfect picture of your codebase. It still might get the output wrong. And if you trust that output without verification, you're one bad generation away from a partial write that silently breaks production.
Enter Graphyti
Graphyti is a CLI coding agent built on a different core claim: the model never has to be trusted to remember your codebase correctly, because a deterministic code graph checks its work before anything is written to disk.
The key insight: the graph is used twice. Once to ground generation (smarter context), and again, independently, to verify the result before it's trusted.
How It Works
Step 1: Deterministic Extraction
A static parser — Prisma schema parser + TypeScript AST analysis via ts-morph, never an LLM guess — builds a graph of your codebase. Models. Fields. API routes. Components. And the real edges between them: which route queries which model, which component renders which field, which file imports which.
No LLM guessing. No embedding similarity. Just deterministic parsing.
Step 2: Scoped, Structured Edits
The LLM never rewrites whole files. It first proposes a narrow, structured operation — something like rename_field User.name -> username — which gets applied as a deterministic edit. A targeted schema mutation. A search/replace snippet the model must anchor to the exact current file content.
This alone eliminates an entire class of bugs. The model physically cannot silently delete or restructure code it wasn't asked to touch, because the edit mechanism doesn't give it the surface area to do so.
Step 3: Blast Radius, Computed Before Anything Is Written
Before applying a breaking change, Graphyti walks the graph to answer: what actually depends on this?
Which routes query this model? Which components render this field? Which files would silently break?
You see this before a single file is written. Not after.
Step 4: Two Independent Verification Layers
This is where Graphyti diverges from everything else on the market.
Local structural check: After generation, the same deterministic parser re-parses the generated content and confirms every file in the blast radius was genuinely addressed — not just touched.
HydraDB graph check: The generated change is also re-ingested into HydraDB and cross-checked against the graph's own stored relations. This catches a failure class local parsing can't see: stale or orphaned graph nodes left behind by an incomplete update.
Both must agree before anything is written. If either fails, Graphyti retries once with the specific gap called out. If that still fails, it writes nothing and tells you exactly what's unresolved.
No partial writes. No silent completions. No "it looks like it worked" when it didn't.
Step 5: A Real Safety Boundary on Execution
Any shell command the agent wants to run — npm install, prisma generate, prisma migrate dev — is matched against a strict allowlist and shown to you before it runs. Nothing outside that allowlist executes, ever, regardless of what the model proposes.
The Verification Flow in Action
Here's what happens when you run graphyti "remove the bio field from the User model":
- Context retrieval pulls the graph context from HydraDB
- Classification determines this is a single-step operation
- Intent extraction produces
remove_field on User.bio - Code generation creates the schema edit + migration commands
- Blast radius identifies 4 affected files: 2 API routes, 2 components
- Re-generation attempts to update affected files
- Structural verification checks if all blast-radius files were properly updated
- If verification passes, write proceeds and graph index updates
- If verification fails, one retry, then clean failure, nothing written
The verification is the critical gate. It's not a suggestion. It's a hard boundary.
Why This Is Different
| RAG-only tools | Graphyti | |
|---|---|---|
| Context retrieval | Similarity search | Graph traversal + hybrid search |
| Edit mechanism | Full-file regeneration | Scoped structural edits only |
| Pre-write safety check | None, or model self-report | Blast radius computed from the graph |
| Post-generation verification | None (trust the output) | Two independent checks: local re-parse + graph cross-check |
| Failure behavior | Writes whatever was generated | Blocks the write entirely if verification fails |
| Shell command execution | Often unrestricted | Strict allowlist + explicit confirmation |
The Tech Stack
- CLI: TypeScript, Commander, Ora/Chalk for terminal UX
- Static analysis: ts-morph (TypeScript AST), dedicated Prisma schema parser
- Graph store: HydraDB — knowledge ingestion, forceful relations, hybrid graph-aware retrieval
- LLM: OpenRouter (model-agnostic, no hardcoded provider dependency)
- Target stack: Next.js (App Router + Pages Router) + Prisma
Safety by Design
Every design decision in Graphyti is motivated by the same principle: never trust the model's output without verification.
- Blast radius confirmation — breaking changes shown with reasons before you're asked to confirm
- Two-layer verification — nothing writes unless both the local parser and the independent graph check agree
- One bounded retry — a verification miss gets one automatic retry; a second miss is a hard, clean failure
- Command allowlist — only approved shell commands can ever execute
- Clean exit codes — 0 success, 1 verification blocked, 2 unexpected error — safe for CI and scripts
What's Next
Graphyti's core pipeline — extraction, scoped edits, blast radius, dual verification — is live and working. Actively in progress:
- Plan & Create mode — decomposing broad requests into ordered, independently-verified structural steps, including net-new file creation
- Persistent terminal chat mode — a long-lived conversational session layered on the same verified pipeline
- Hosted mode — account-based setup where users bring their own OpenRouter key
The Bottom Line
Most AI coding tools trust the model. Graphyti verifies it.
That's not a feature. It's a safety boundary. And in a world where AI coding agents are increasingly trusted with production codebases, it's the difference between "it probably works" and "we know it works."
Graphyti is open source under the MIT license. Try it:
# Point Graphyti at your project
graphyti init-graph
# Make a scoped, verified change
graphyti "rename Post.title to headline"
# Preview without writing anything
graphyti "add a priority field to Post" --dry-run