AI-Editor Systems & Design
Context retrieval, agents, latency and eval at scale
Context retrieval for LLM prompts
After this you can design how the right code reaches the model
The model only knows what you put in front of it. Everything Cursor does well starts with one quiet, brutal engineering problem: which bytes of a million-line repo go into a few-thousand-token window.
An interviewer who works on the editor will probe this fast, because it's the unglamorous core of the product. A completion that ignores the helper you wrote two files over feels broken even when the model is fine. The model wasn't wrong, it was blind. Context retrieval is the part of the system that decides what it gets to see.
Frame the prompt as a budget you spend deliberately. You have a fixed token window, you want to fill it with the snippets most likely to make the next edit correct and you have milliseconds to decide.
What goes into the contextranked, not dumped
Strong answers name concrete sources and the order you'd try them, not a vague "relevant code." Lead with what's cheapest and most certainly useful, then spend the rest of the budget on retrieval.
Interactive diagram. Tab through its regions; each focused region shows its detail in the panel below.
Spend the token budget top-down: cheap, certain signals first, then retrieval fills the rest.
- Current file + cursor
- The text around the cursor is the strongest signal for what the user wants next. Cheapest, always included.
- Recent edits
- The last few changes reveal intent - renaming a field, threading a new arg - that the static file can't show.
- Open tabs / viewport
- What the user has open is a free, high-precision relevance signal they gave you for free.
- Imports + direct dependencies
- The symbols this file references resolve via the call graph, so types and signatures are exact, not guessed.
- Retrieved snippets
- Semantic or lexical search over the repo for code the file doesn't reference but probably needs.
- Project conventions
- Lint config, a style file or rules the user set, so output matches the house style.
Three retrieval strategies and when to combine
Candidates who only say "embeddings" undersell themselves. The honest answer is that each approach fails in a way the others cover, so production systems blend them and re-rank.
- Approach
- Lexical (grep/BM25)
- Good at
- Exact identifiers, error strings, rare tokens
- Fails at
- Synonyms and conceptual matches - "auth" vs "login"
- Approach
- Semantic (embeddings)
- Good at
- Conceptual similarity, "code that does X"
- Fails at
- Exact symbols; stale vectors after edits; index cost
- Approach
- Structural (graph/imports)
- Good at
- Precise types, callers, definitions
- Fails at
- Code that's relevant but not statically linked
| Approach | Good at | Fails at |
|---|---|---|
| Lexical (grep/BM25) | Exact identifiers, error strings, rare tokens | Synonyms and conceptual matches - "auth" vs "login" |
| Semantic (embeddings) | Conceptual similarity, "code that does X" | Exact symbols; stale vectors after edits; index cost |
| Structural (graph/imports) | Precise types, callers, definitions | Code that's relevant but not statically linked |
Each column's weakness is another column's strength - hence hybrid retrieval plus a re-rank.
Run lexical and semantic in parallel, union the candidates, then re-rank with cheap structural signals: is this symbol actually imported here, is it in an open tab, how recently was it edited. A small re-ranker over a fused candidate set beats any single retriever and it's the answer that reads as someone who has built one.
Indexing a large repo and keeping it fresh
A repo with hundreds of thousands of files can't be re-embedded on every keystroke. The interview wants to hear that you index incrementally and treat freshness as a first-class problem.
- 1Initial build. Walk the tree, chunk by syntactic unit (function, class, block) rather than fixed lines so a chunk is a meaningful retrieval target. Embed and store, keyed by a content hash.
- 2Incremental update. On save or file-watch event, re-chunk only the changed files. The content hash skips re-embedding chunks whose text didn't move.
- 3Edit-time freshness. Between index updates, the live buffer is the source of truth - read recent edits from the editor, not the stale index, so the model sees what the user just typed.
- 4Eviction. Drop vectors for deleted files and prune by access recency so the index doesn't grow without bound.
Ranking and truncation when context overflows
The window will overflow on any real repo, so truncation policy is where you show judgment. Don't drop uniformly. Rank by an estimate of marginal usefulness and cut the tail.
- Score each candidate by a blend of retrieval score, structural proximity (is it imported, is it open) and recency of edit.
- Pack greedily down the ranked list until the budget is spent, reserving headroom for the model's output.
- Prefer signatures and types over full bodies for distant code - a function's interface is often enough and costs a fraction of the tokens.
- Always keep the cursor's immediate surroundings and recent edits whole; never let retrieved noise crowd out the one thing you know is relevant.
More context is not free and not always better. Past a point, extra tokens add latency and cost and irrelevant snippets actively distract the model and lower acceptance. The cost/latency tradeoff is the whole reason ranking exists - say that out loud instead of proposing to "just send more."
When asked "how would Cursor know which files to send?", don't pick one retriever. Sketch the budget, name two or three sources, then describe the fuse-and-re-rank step and the freshness problem. Naming the failure mode of embeddings (exact symbols, staleness) signals you've shipped retrieval rather than read about it.
Takeaway. Context retrieval is budget allocation: rank a fused set of lexical, semantic and structural candidates, keep the cursor and recent edits whole and index incrementally so the model never reads stale code.
Self-check
QAn interviewer asks why Cursor wouldn't just use embedding search to pick context for a completion. What's the strongest answer?
Agent loops and applying edits
After this you can reason about how the agent acts on a codebase
A completion suggests. An agent acts. The jump from autocomplete to an agent that reads files, runs tools and rewrites five files in one turn is where most of the hard product decisions live.
Cursor builds the surfaces for AI-native workflows - reviewing PRs of AI-generated code, coordinating multi-file edits - so an interviewer will want you to reason about the loop itself, not just the model behind it. The loop is a control system wrapped around a probabilistic core.
The plan, act, observe loop
An agent turn is a cycle, not a single call. It plans an action, takes it, reads what happened and decides whether it's done. Each pass through the loop is one tool call plus its result fed back into context.
Interactive diagram. Tab through its regions; each focused region shows its detail in the panel below.
Verify is the gate that turns a probabilistic core into a system people trust.
- 1Plan. From the user's request and current context, the model decides the next action - read a file, search or propose an edit. Keep the plan small; over-planning ahead of evidence is where agents drift.
- 2Act. Execute the tool call. Reading a file, running a search or applying an edit are all just tools the model can invoke, each with a typed result.
- 3Observe. Feed the result back: file contents, search hits, a compiler error. This grounds the next step in reality instead of the model's guess.
- 4Verify and decide. Check progress against the goal - did the test pass, did the type-check clear - then loop or stop. A turn that never verifies is the classic confidently-wrong agent.
The difference between a demo agent and one people trust is whether it reads the result of its own actions. An agent that proposes an edit and moves on is guessing. One that applies the edit, runs the type-check, sees the error and fixes it is closing the loop - and that loop is what makes a probabilistic system behave reliably.
Streaming edits and the review surface
Multi-file edits raise a UX problem before a systems one: the user has to stay in control of changes they didn't type. The answer is to stream edits into a diff the user reviews, not silently overwrite the buffer.
- Stream, don't batch
- Render edits as they generate so the user sees progress and can stop a run that's going wrong, instead of waiting for a wall of changes.
- Diff as the unit of trust
- Every change lands as a reviewable diff - accept, reject or accept-per-hunk - so AI output is a proposal, not a fait accompli.
- Keep the buffer authoritative
- Apply against the live document with conflict checks; if the user typed since generation started, reconcile rather than clobber.
- Per-file granularity
- A five-file edit shouldn't be all-or-nothing. Let the user keep the three good files and redo the two that missed.
Guardrails: scope, confirmation, rollback
An agent that can edit anything is a liability. Constrain its blast radiusHow much breaks if a change goes wrong; the scope of potential damage. up front and make every action reversible.
Bound what the agent can touch: the workspace, an allowlist of paths, no writes outside the repo.
Gate destructive tools (shell, delete) behind explicit permission.
Cheap, reversible edits can apply optimistically into a diff.
Side effects that leave the editor - running commands, network - ask first.
Checkpoint before a multi-step run so one click undoes the whole turn.
Treat the agent's changes as a transaction, not scattered keystrokes.
Failure handling
Edits fail in specific, recurring ways and naming them is what separates a careful systems answer from a hopeful one.
- Failure
- Partial application
- What goes wrong
- Edit applies to 3 of 5 files, then a tool errors
- Recovery
- Atomic-per-turn checkpoint; roll back to a consistent state, surface what landed
- Failure
- Conflicting edit
- What goes wrong
- User typed in a region the agent is rewriting
- Recovery
- Detect on apply, re-anchor the hunk or re-generate against the new buffer
- Failure
- Stale anchor
- What goes wrong
- The diff targets line numbers that have shifted
- Recovery
- Anchor edits to content/AST nodes, not raw line offsets
- Failure
- Doom loop
- What goes wrong
- Agent retries the same broken fix forever
- Recovery
- Cap iterations, detect repetition, hand back to the user with what it learned
| Failure | What goes wrong | Recovery |
|---|---|---|
| Partial application | Edit applies to 3 of 5 files, then a tool errors | Atomic-per-turn checkpoint; roll back to a consistent state, surface what landed |
| Conflicting edit | User typed in a region the agent is rewriting | Detect on apply, re-anchor the hunk or re-generate against the new buffer |
| Stale anchor | The diff targets line numbers that have shifted | Anchor edits to content/AST nodes, not raw line offsets |
| Doom loop | Agent retries the same broken fix forever | Cap iterations, detect repetition, hand back to the user with what it learned |
When you describe an agent, always say how it stays in control: the diff is the contract, edits are a transaction, the loop verifies before it stops. Cursor's bar is "powerful tools without compromising ease-of-use," so an answer that pairs capability with a rollback story and a review surface lands far better than raw autonomy.
Takeaway. An agent is a plan-act-observe loop that must verify its own actions; apply edits as a streamed, reviewable diff with scope limits and a one-click rollback so the user stays in control.
Self-check
Latency, cost and inference at product scale
After this you can design for sub-100ms across millions of users
Tab prediction has to land before the user's next keystroke. That single constraint - sub-100ms, every keystroke, millions of users - is one of the most common design prompts for this role and it rewards engineers who think in tail latency and unit economics.
“Design Cursor's tab prediction system: sub-100ms latency, on every keystroke, across millions of users.”
Don't jump to a model. Start by sizing the problem out loud, because the numbers dictate the architecture. Every keystroke at millions of users is a torrent of requests, most of which the user will never see - so the cheapest request is the one you never make.
Frame the budget first
Interactive diagram. Tab through its regions; each focused region shows its detail in the panel below.
Network and client overhead are fixed taxes; what's left is all the inference you get.
- Network round trip
- 20–50ms depending on edge proximity - this alone forces you toward regional inference, not one datacenter.
- Inference
- What's left, ~40–70ms - only achievable with a small model and short output, not a latest-generation model.
- Client overhead
- Debounce, serialize, render - keep it single-digit ms and off the hot path.
The budget proves the design: a big model over a far network can't fit, so the levers below are forced, not optional.
The latency levers
- Lever
- Debounce + cancel in-flight
- What it buys
- Kills most requests before they're sent - the user is still typing
- Cost / catch
- Tune the window: too long feels laggy, too short wastes calls
- Lever
- Small, specialized model
- What it buys
- The only way inference fits the budget at this volume
- Cost / catch
- Lower ceiling on hard completions - route those elsewhere
- Lever
- Speculative / early decoding
- What it buys
- Start emitting before the full sequence is decoded
- Cost / catch
- Wasted compute on speculations that don't pan out
- Lever
- Caching
- What it buys
- Repeat prefixes and contexts skip inference entirely
- Cost / catch
- Cache keys must include enough context to stay correct
- Lever
- Prefetch on pause
- What it buys
- Compute likely completions during a typing pause, serve instantly
- Cost / catch
- Speculative spend; bound it so it doesn't dominate cost
- Lever
- Edge proximity
- What it buys
- Cuts the fixed network tax that no model trick can recover
- Cost / catch
- Operational complexity of regional inference
| Lever | What it buys | Cost / catch |
|---|---|---|
| Debounce + cancel in-flight | Kills most requests before they're sent - the user is still typing | Tune the window: too long feels laggy, too short wastes calls |
| Small, specialized model | The only way inference fits the budget at this volume | Lower ceiling on hard completions - route those elsewhere |
| Speculative / early decoding | Start emitting before the full sequence is decoded | Wasted compute on speculations that don't pan out |
| Caching | Repeat prefixes and contexts skip inference entirely | Cache keys must include enough context to stay correct |
| Prefetch on pause | Compute likely completions during a typing pause, serve instantly | Speculative spend; bound it so it doesn't dominate cost |
| Edge proximity | Cuts the fixed network tax that no model trick can recover | Operational complexity of regional inference |
Cost control: route by difficulty
At this scale, cost and latency are the same conversation. You can't afford a big model on every keystroke and you don't need one. Most completions are trivial.
- 1Default to small. Send the overwhelming majority of completions to a fast, cheap model that handles the easy 90%.
- 2Detect difficulty. Use signals - low model confidence, a complex multi-line context, an explicit larger request - to flag the cases the small model will fumble.
- 3Escalate selectively. Route only the hard minority to a larger model, accepting its latency where the user expects a beat to think.
- 4Cache the wins. Memoize completions keyed on context so a repeated situation never pays inference twice.
A small-model-first cascade with selective escalation is the answer that shows you understand product economics. It keeps p50 latency tiny and per-completion cost near zero and it spends the expensive model only where it changes the outcome. "Use a smaller model" is a fragment; "route easy to small, escalate hard, cache both" is a system.
p50 is a vanity metric; p99 is the product
A great median with a bad tail still feels broken, because the user remembers the stall, not the 200 fast completions before it. Tab prediction has a hard UX cliff: past roughly 100–150ms the suggestion arrives after the user has already typed past it and a late suggestion is worse than none - it's a distraction.
- Set the SLO on the tail (p99), not the median and treat a p99 regression as a product bug, not a perf nicety.
- Shed load gracefully: under pressure, drop to the small model or skip the completion rather than serving it late.
- A timed-out completion should silently no-op; never show a stale suggestion two keystrokes after it was relevant.
Don't optimize average latency and call it done. The interviewer is listening for whether you distinguish p50 from p99 and whether you know the typing-flow cliff exists. An answer that names the cliff - "a late tab completion is negative value" - separates product engineers from people who've only read the benchmark.
Takeaway. Size the 100ms budget first; it forces edge inference and a small-first model cascade. Kill most requests with debounce, escalate only hard cases and set the SLO on p99 because a late tab completion is worse than none.
Self-check
QIn a tab-prediction design, why is optimizing p99 latency more important than optimizing the median?
Privacy-preserving inference
After this you can handle confidential user code in the architecture
You're asking enterprises to send their proprietary source code to a model over the network. The entire product is a trust transaction and privacy is not a compliance checkbox - it's a feature you can lose deals without.
“Design the privacy-preserving inference architecture that keeps user code confidential.”
Lead with the default that earns trust: don't train on user code. Then layer the standard protections and be honest about the tradeoffs, because a confident "it's all encrypted" with no nuance reads as someone who hasn't thought about where code actually flows.
The protection layers
- No training on code by default
- Customer code is used to serve the request, not to improve models, unless they opt in. This is the headline trust promise.
- Encryption in transit and at rest
- TLS everywhere; any persisted artifact (logs, caches, indexes) encrypted. Table stakes, but say it.
- Minimize retention
- Process the request, return the result, keep as little as possible for as short as possible. The code you never store can't leak.
- Scoped access + audit
- Least-privilege service access to code, with an audit trail an enterprise security team can review.
Local vs server-side: the central tradeoff
Where computation happens is the real design fork. Server-side gives you latest-generation models and shared indexes; local keeps code on the user's machine but caps capability. The interview wants you to reason about the spectrum, not pick a dogma.
- Concern
- Model power
- Server-side
- Full latest-generation models, big context
- Local / on-prem
- Limited by the user's hardware
- Concern
- Code exposure
- Server-side
- Code leaves the machine (encrypted, not retained)
- Local / on-prem
- Code never leaves; strongest privacy story
- Concern
- Indexing
- Server-side
- Fast shared index, but vectors derived from code live remotely
- Local / on-prem
- Index stays local; slower, heavier on the client
- Concern
- Fit
- Server-side
- Most users; the default product
- Local / on-prem
- Regulated, air-gapped or zero-egress customers
| Concern | Server-side | Local / on-prem |
|---|---|---|
| Model power | Full latest-generation models, big context | Limited by the user's hardware |
| Code exposure | Code leaves the machine (encrypted, not retained) | Code never leaves; strongest privacy story |
| Indexing | Fast shared index, but vectors derived from code live remotely | Index stays local; slower, heavier on the client |
| Fit | Most users; the default product | Regulated, air-gapped or zero-egress customers |
A subtle point that scores well: a remote vector index isn't "not the code." Embeddings can leak structure and can sometimes be partially inverted, so a privacy-sensitive customer cares where the index lives, not just where the raw files live. Treating derived artifacts as sensitive too is the kind of rigor Cursor's truth-seeking culture rewards.
Privacy as a product tier
Frame this as a differentiator, not just a constraint. A privacy mode - no retention, no training, optionally local indexing - is exactly the thing that lets a security-conscious enterprise say yes when a competitor can't give the same guarantee.
- A "privacy mode" that hardens defaults (zero retention, no training, restricted egress) and is contractually verifiable, not just toggled.
- Clear data-flow documentation, since enterprise buyers need to show their own security team exactly where code goes.
- Be ready to position this against Copilot, Windsurf and Claude Code - "who do you trust with the repo" is a real buying axis and an opinion here signals you understand the market.
Don't promise "fully local, fully private, fully powerful" - that combination doesn't exist with today's latest-generation models. State the tradeoff plainly: local maximizes privacy at the cost of capability, server-side maximizes capability with strong but non-zero exposure. Naming the tension is more credible than pretending it away.
Takeaway. Lead with no-training-by-default plus encryption and minimal retention; then reason about the local-vs-server tradeoff honestly, treat the remote index as sensitive too and pitch privacy mode as a deal-winning product tier.
Self-check
QWhy does a remote vector index complicate the claim that server-side inference "keeps code confidential"?
Evaluation and A/B testing at scale
After this you can measure code-suggestion quality and ship from data
Cursor runs experiments on millions of users to advance the agent. That sentence is in the job description and it means you'll be asked: how do you actually know one model or prompt is better than another?
The trap is measuring what's easy instead of what matters. Acceptance rate is trivial to log and dangerously misleading on its own. The skill is building a metric stack that catches the gap between "the user clicked accept" and "the code was good."
Metrics for suggestion quality
- Metric
- Acceptance rate
- What it captures
- Did the user take the suggestion
- Where it lies
- Users accept then immediately delete; rewards flashy, not correct
- Metric
- Edit-distance after accept
- What it captures
- How much they had to fix it
- Where it lies
- Some edits are intended follow-on work, not corrections
- Metric
- Retention of accepted code
- What it captures
- Is the code still there minutes/hours later
- Where it lies
- The truest signal that a suggestion was actually useful
- Metric
- Task success
- What it captures
- Did the user finish what they set out to do
- Where it lies
- Hardest to attribute, but closest to real value
| Metric | What it captures | Where it lies |
|---|---|---|
| Acceptance rate | Did the user take the suggestion | Users accept then immediately delete; rewards flashy, not correct |
| Edit-distance after accept | How much they had to fix it | Some edits are intended follow-on work, not corrections |
| Retention of accepted code | Is the code still there minutes/hours later | The truest signal that a suggestion was actually useful |
| Task success | Did the user finish what they set out to do | Hardest to attribute, but closest to real value |
Retention and edit-distance are the antidote to acceptance-rate gaming.
The single most important eval insight for this product: a change can raise acceptance while lowering quality, if it makes suggestions longer or more eager. You catch that by pairing acceptance with retention (was the code still there after a few minutes) and edit-distance (how much did they rewrite). When acceptance and retention diverge, retention is telling the truth.
Offline evals before you risk production
You don't A/B test a change you haven't sanity-checked, because exposing millions of users to a regression is expensive and erodes trust. Gate on offline evals first.
- 1Build a held-out task set. Real tasks with known-good outcomes - this refactor should compile, this completion should match the accepted ground truth.
- 2Grade automatically where you can. Compile, type-check and test-pass are deterministic, fast and trustworthy; reserve an LLM-judge for taste a test can't express.
- 3Set a gate. A candidate has to clear the offline threshold before it earns a live experiment. Regressions die here, cheaply.
- 4Watch for overfitting. A set you tune against stops measuring; refresh tasks and hold some fully blind.
A/B testing on millions of users
Once a change clears offline, it earns a slice of live traffic. At Cursor's scale the statistics are easy; the discipline is in guardrails and honest readouts.
- Primary metric
- Pick one quality metric to win on (e.g. retention-weighted acceptance), decided before launch, not after.
- Guardrail metrics
- Latency p99, cost per completion, error rate - a win on quality that tanks latency is not a win.
- Ramp
- Start at 1%, watch guardrails, expand. A bad change should hurt thousands, not millions.
- Significance + duration
- Run long enough for novelty effects to fade and for the sample to be real, not until the number looks good.
The acceptance-vs-quality divergence is the failure that catches good teams. A model that suggests bigger, bolder completions can win acceptance and lose retention and if acceptance is your only metric you'll ship a regression that feels like progress. Always name the guardrail metric that would catch it.
Tie this straight back to the JD. When asked how you'd improve a completion model, answer in the loop the role actually runs: define a quality metric, gate on offline evals, ramp an A/B from 1% with latency and cost guardrails and read retention alongside acceptance. That's the literal job described as a method.
Takeaway. Acceptance rate alone is gameable; pair it with retention and edit-distance, gate every change on offline evals first, then ramp an A/B from 1% with p99-latency and cost guardrails and a pre-declared primary metric.
Self-check
Taming hallucination and bad output
After this you can design for correctness in a probabilistic system
The model will sometimes invent an API that doesn't exist, call a function with the wrong signature or confidently delete the wrong block. You can't make a probabilistic system deterministic, so you design the system around it being wrong sometimes.
Onsite prompts in this loop have included addressing hallucinations in deployed models, so a vague "we'd improve the prompt" won't survive. Come with a layered playbook that reduces wrong output, catches what slips through and makes the rest cheap to reject.
Three lines of defense
Interactive diagram. Tab through its regions; each focused region shows its detail in the panel below.
You can't reach zero - so reduce it, mechanically catch what slips and make the rest one keystroke to reject.
Ground in retrieved context so the model edits real symbols, not invented ones.
Constrain outputs - schemas, valid edit formats - so malformed proposals can't form.
Give it tools to look things up instead of guessing.
Validate before or after applying: compile, type-check, run tests.
An edit that doesn't type-check is auto-suspect; loop the agent to fix it or hold it back.
Surface every change as a diff that's one keystroke to reject.
Show uncertainty so the user knows when to look harder.
Grounding is the biggest lever
Most code hallucination is the model filling a gap in its context with a plausible guess. Give it the real signature of the function it's calling and the guess has nowhere to go. This is why retrieval (section one) and hallucination control are the same problem viewed from two ends.
- Feed exact symbol definitions and types so the model references reality, not its training-data memory of a similar library.
- Constrain to a structured edit format the system can parse and validate, rejecting anything malformed before it reaches the buffer.
- Prefer tool calls (read the file, search the docs) over the model recalling an API from memory.
Verification: the loop that earns trust
The cheapest, most reliable hallucination filter is the compiler. Code is special among LLM outputs: you can often check it mechanically. Lean on that hard.
- 1Type-check / compile the proposed edit. A change that doesn't build is wrong, full stop, no model judgment required.
- 2Run relevant tests where they exist; a passing suite is strong evidence the edit preserved behavior.
- 3Feed failures back into the agent loop so it fixes its own mistake before the user ever sees it.
- 4Escalate the unverifiable. When nothing mechanical can check it, mark it uncertain and lean on the review UX rather than pretending it's verified.
You will never get to zero hallucination, so the product goal shifts: make a wrong suggestion cost the user almost nothing. A clear diff, an obvious reject and surfaced uncertainty turn a hallucination from a trust-breaking incident into a half-second "no thanks." The review surface isn't polish; it's the safety system.
If you get "how would you address hallucinations in a deployed model," answer in three moves and name them: reduce with grounding and constrained outputs, catch with compile/type-check/test in the loop and make residual errors cheap to reject with a diff and surfaced uncertainty. Calling the compiler your most reliable grader signals you know code is checkable in ways prose isn't.
“I assume the model will be wrong sometimes, so I design three layers. I ground it in retrieved symbols so it has less to invent, I verify edits with the compiler and tests in the agent loop so wrong ones get caught and retried and I make whatever survives land as a diff the user can reject in one keystroke. Correctness in a probabilistic system is an architecture, not a better prompt.”
Takeaway. You can't eliminate hallucination, so layer it: ground with retrieved symbols, catch with compile/type-check/test in the loop and surface the rest as a diff that's one keystroke to reject - the compiler is your most reliable grader.
Self-check
QWhy is code an unusually favorable output to defend against hallucination and how do you exploit that in the agent loop?