System Design Arena

System Design: Windsurf / Codex

Provide on-device + cloud-assisted code completions, chat explanations, and repo context for millions of developers.

Functional RequirementsNon-Functional RequirementsAPI Endpoints

Case Study

AI Pair Programming

Same conversation, diagrams, and wrap-up you expectβ€”now framed with clearer scaffolding and iconography.

Prompt

Build an AI pair-programming assistant. Requirements: context-aware completions, repo-wide search, chat explanations, offline fallback, telemetry, and privacy guardrails.

Interview snapshot

  • β€’ Topic: AI Pair Programming
  • β€’ Expected depth: 45 - 60 minutes
  • β€’ Focus areas: APIs, scale estimation, resilient architecture
  • β€’ Wrap-up: risk, monitoring, disaster recovery

Key takeaways

  • β€’ IDE plugins for VSCode/IntelliJ/etc. Provide completions, inline chat, test generation, doc lookup.
  • β€’ Latency: simple completion < 200 ms; chat < 1 s.
  • β€’ POST /api/context/upload - IDE posts context bundle (files, git diff, metadata).

πŸŽ™οΈ Interview mode

Practice this like a real interview

Don't read the answer first. Work the framework against the bare prompt, then compare against what the interviewer expected at each step.

🎯 Start guided practice (free)

Scorecard

What the interviewer is evaluating

Requirements8/10
Scale estimation7/10
API design7/10
Architecture9/10
Trade-offs9/10
Failure handling6/10

Staff-level signal

Does the candidate design for the 200ms completion budget β€” context assembly, caching, and speculative inference β€” rather than treating it like a chatbot?

🧠 Staff engineer judgment

Every millisecond of context assembly is stolen from inference. If your retrieval pipeline is clever but slow, the product is worse than a dumb fast one.

Calibration

The common (bad) answer

IDE β†’ API β†’ LLM β†’ completion

❌ Why this scores poorly: Misses the defining constraint: completions race the user’s next keystroke. 2-second chatbot latencies are product death; the design is really a context+cache+latency system.

βœ“ What a strong answer adds

  • Context engine: what fits in the prompt (open file, imports, repo map, recent edits) under a token budget.
  • Two-tier models: tiny fast model for inline completions, big model for chat/edits.
  • Prefix caching β€” the file prefix barely changes between keystrokes; reuse KV cache.
  • Debounce + cancellation: most requests die before inference finishes; make that free.
  • Privacy tiers: on-prem/local inference for code that cannot leave the machine.

Build it up

Step-by-Step Walkthrough

An AI pair programmer lives or dies on a ~200ms budget: slower than a keystroke feels broken. The design journey is about what you can afford to compute per keystroke versus per session β€” context assembly, model tiers, and a ranking loop that learns from every accept and reject.

1

Naive: ship the current file to a big model

Version one is an IDE plugin that sends the active file to a large LLM on every pause in typing and inlines whatever comes back. It produces impressive demos and three immediate failures: round-trips to a large model take seconds against a ~200ms feel-threshold; the model suggests functions that do not exist because it cannot see the rest of the repo; and at ~2M daily developers triggering ~200 completions each β€” on the order of 400M requests/day β€” the GPU bill is ruinous.

Each failure names a subsystem: a latency budget forces model tiers, missing context forces repo indexing, and cost forces caching and ranking. The rest of the design is those three, in order.

2

Context assembly is the real product

Completion quality is mostly retrieval quality. A repo indexer parses the codebase into an AST and symbol graph and embeds code chunks into a sharded vector index β€” this runs per commit, off the hot path. Per keystroke, the plugin assembles a cheap local bundle (active file, cursor window, recent edits, open buffers, git diff) and ships it to a context service that merges in retrieved snippets: the callee's signature from another file, the matching test, a similar usage elsewhere.

A prompt builder ranks all of it into the model's context window under a hard token budget β€” nearest-scope first, retrieval filling the remainder. The split to narrate: indexing is expensive and asynchronous, assembly is cheap and synchronous, and the ~200ms budget is spent almost entirely on assembly plus inference.

?The question interviewers reach for

'Context window is full β€” what do you drop?' Rank by proximity to the cursor: enclosing function, then siblings and imports, then retrieved cross-file snippets, then docs. A small model with the right 2K tokens beats a large model with the wrong 8K β€” that sentence reframes the whole design as a retrieval problem.

3

Tier the models to fit the latency budget

One model cannot serve both a ghost-text suggestion (needs <200ms) and 'explain this module' (can take ~1s). Split the fleet: a small distilled model handles inline completions from warm pools with streaming output, a large model serves chat and multi-file edits, and a compact on-device model provides last-mile suggestions when the network disappears β€” the resilience answer interviewers ask for by name.

Caching attacks the volume: identical context prefixes recur constantly (every developer in a repo shares its skeleton), so completion caching on context hashes and server-side prefix reuse cut both latency and GPU cost. At ~20K requests/s peak, every cached hit is a GPU-second saved.

4

Rank completions with the feedback you already get

Users grade every suggestion for free: accepted, rejected, accepted-then-immediately-edited. That telemetry (~400M events/day, ~5K/s) flows into a pipeline feeding a ranking service β€” generate a handful of candidates, score them with a lightweight learned ranker on context features and historical acceptance, and show the winner. Acceptance rate becomes the platform's north-star metric, and ranker updates ship through offline eval against logged sessions before touching production.

This loop is what separates a product from an API wrapper: the model may be a commodity, but the ranking signal β€” which suggestions this codebase's developers actually keep β€” compounds and is yours alone.

5

The policy engine makes it sellable

Source code is the crown jewels, so a policy engine wraps the whole flow: secret scanning redacts keys and tokens from context bundles before they leave the IDE, tenant isolation keeps one company's embeddings out of another's retrieval, context bundles are stored ephemerally (~24h) with zero-retention contracts for enterprises, and every access lands in an audit log.

Close on the converged shape β€” plugin β†’ context service β†’ prompt builder β†’ tiered inference, with the indexer feeding retrieval, telemetry feeding ranking, and policy wrapped around everything. Then name the failure mode you designed away: cloud unreachable degrades to the local model behind a circuit breaker. Never silence, just smaller suggestions.

!The redaction trap

Redact secrets client-side, in the plugin, before upload β€” server-side redaction means the secret already crossed the wire and touched your logs. Interviewers plant this one deliberately; catching it unprompted is worth a level.

Blueprint

Architecture Diagram

The narrated components above, laid out as an actual flow β€” so you can see how a request moves through the system, not just read a list of pieces.

IDE plugin

1

IDE plugin

2

context service

3

storage (object store

storage (object store + metadata DB)

Context retrieval +

1

Context retrieval +

Context retrieval + vector search

2

prompt builder

3

inference service (LLM)

Local model (on-device)

1

Local model (on-device) handles fallback suggestions

Policy/safety engine redacts

1

Policy/safety engine redacts secrets

Policy/safety engine redacts secrets, enforces tenant boundaries

Telemetry pipeline feeds

1

Telemetry pipeline feeds ranking service

2

abuse detection

Flow Diagram

How the API maps to this flow

  1. 1POST /api/context/uploadβ€” IDE posts context bundle (files, git diff, metadata).
  2. 2POST /api/completionsβ€” request completion with prompt/context handles streaming tokens.
  3. 3POST /api/chatβ€” conversational Q&A with code references.
  4. 4GET /api/search?query=β€” repo-wide semantic search.
  5. 5POST /api/feedbackβ€” sends rating + suggestions for completions.

?But why does this actually hold up at scale?

Assume 2M daily active devs, each triggering 200 completions/day β†’ 400M requests/day (~4.6K/s avg, 20K/s peak).

Interview flow

Dialogue timeline

Interviewer

What are the core components?

Candidate

IDE plugin collects context (files, diffs), sends to backend for completions/chat. Backend uses LLMs + vector search. Need policy engine, caching, telemetry.

Interviewer

How do you manage latency?

Candidate

Short completions must return in <200 ms. Use local caches, distill smaller models for simple suggestions, fallback to cloud for complex queries.

Interviewer

Explain context ingestion.

Candidate

Plugin builds context bundle (active file, project graph, tests), redacts secrets, uploads to context service. Vector index stores embeddings for retrieval.

Scoping

Requirements & trade-offs

Functional Requirements

  • β€”IDE plugins for VSCode/IntelliJ/etc. Provide completions, inline chat, test generation, doc lookup.
  • β€”Repo indexing: parse AST, symbol graph, embedding generation.
  • β€”Cloud inference service with multiple model tiers (fast vs smart).
  • β€”Offline mode using smaller local model for last-mile suggestions.
  • β€”Telemetry + feedback loop for ranking improvements.
  • β€”Security: secret scanning, privacy controls per enterprise tenant.

Non-Functional Requirements

  • β€”Latency: simple completion < 200 ms; chat < 1 s.
  • β€”Scalability: millions of active devs, thousands of requests per second.
  • β€”Data privacy: tenant isolation, zero retention options for enterprises.
  • β€”Resilience: degrade gracefully if cloud unreachable (local model fallback).

Blueprint

Architecture modules

Module 1

API Endpoints

  • β€’POST /api/context/upload - IDE posts context bundle (files, git diff, metadata).
  • β€’POST /api/completions - request completion with prompt/context handles streaming tokens.
  • β€’POST /api/chat - conversational Q&A with code references.
  • β€’GET /api/search?query= - repo-wide semantic search.
  • β€’POST /api/feedback - sends rating + suggestions for completions.

Module 2

Back-of-the-Envelope

  • β€’Assume 2M daily active devs, each triggering 200 completions/day β†’ 400M requests/day (~4.6K/s avg, 20K/s peak).
  • β€’Context bundle avg 200 KB β†’ need efficient uploads + dedupe. 2M bundles/day β†’ 400 GB raw; store ephemeral (24h).
  • β€’Vector index: 100K repos * 1M symbols each = 100B embeddings; need sharded ANN (FAISS) with coarse filtering.
  • β€’Telemetry: 400M events/day -> 4.6K/s; store aggregated metrics for ranking updates.

Module 3

System Diagram Notes

  • β€’IDE plugin -> context service -> storage (object store + metadata DB).
  • β€’Context retrieval + vector search -> prompt builder -> inference service (LLM).
  • β€’Local model (on-device) handles fallback suggestions.
  • β€’Policy/safety engine redacts secrets, enforces tenant boundaries.
  • β€’Telemetry pipeline feeds ranking service + abuse detection.

Module 4

Design Playbook

  • β€’Clarify IDE integration, languages supported, offline requirements.
  • β€’Explain context ingestion, indexing, retrieval flow.
  • β€’Discuss inference tiers (fast vs smart), streaming completions, caching.
  • β€’Cover security: secret redaction, tenant isolation, audit logging.
  • β€’Highlight feedback loop: telemetry -> ranking -> deployment.
  • β€’Plan for resilience: circuit breakers, local fallback, feature flags.