Skip to content

Dirac architecture

Dirac is not a custom model. It is the Claude API — called directly from the app with the user’s own Anthropic key — wrapped in a tutor system prompt, a context-injection pipeline, and tool definitions. There is no Nuclei server in the loop.

  • Entered in Settings → Dirac AI (validated against the sk-ant- prefix), stored in WebView localStorage under nuclei-dirac-api-key — details and the keychain caveat are on the configuration page.
  • A build-time VITE_CLAUDE_API_KEY env var is an optional fallback for development. Because Vite inlines it statically, a key set at build time is baked into the shipped JS bundle — never set it for distribution builds.
  • The key is sent to exactly one place: api.anthropic.com, as the x-api-key header on each call. (“Never leaves your machine” would be imprecise — it leaves with every request, to Anthropic only.)

All five Anthropic call sites POST to https://api.anthropic.com/v1/messages with anthropic-version: 2023-06-01 and anthropic-dangerous-direct-browser-access: 'true'. No proxy, no Nuclei server, no logging of prompts in transit.

Model IDs live in src/config/dirac.ts — plus two duplicated local constants (claudeClient.ts:3-4, ghostCompletions.ts:14-15), so a model bump touches three files. OPUS_MODEL is exported but never used; routing is Haiku/Sonnet only.

SurfaceModelmax_tokensSource
Chat — short, simple Q&Aclaude-haiku-4-5-202510014096diracRouting.ts:52-84
Chat — >100 chars, explain-keywords, or action-keywords (tools)claude-sonnet-4-64096diracRouting.ts:38-84
Chat — /think or reasoning keywordsclaude-sonnet-4-6 + thinking: {budget_tokens: 10000}16000diracRouting.ts:23-35,87-126
Compose (/compose or intent-classified)claude-sonnet-4-62048compose.ts:94-95
Cmd+K inline editclaude-sonnet-4-62048InlineEditWidget.tsx:92-94
Ghost completionsclaude-haiku-4-5-20251001 (local constant)150ghostCompletions.ts:15,109
Narration (ambient one-liners)Haiku (claudeClient default)120narration.ts:44,66
Error rewriteHaiku (claudeClient default)500errorRewrite.ts:42

The chat rows describe the default settings. Chat routing is a keyword/length heuristic, not a strict rule: common verbs like “make”, “check”, “try” escalate to Sonnet with tools. Two Settings → Dirac AI knobs adjust the chat rows only — the other surfaces in the table are fixed by design (ghost completions, narration, and error rewrite stay on Haiku for latency; compose and Cmd+K stay on Sonnet for generation quality):

  • Preferred Model (auto, default): haiku/sonnet force that model for chat Q&A. Tool-use and /think turns still run Sonnet even with a Haiku preference — capability wins.
  • Extended Thinking (default on): when off, reasoning keywords no longer auto-escalate to the thinking variant; an explicit /think always does.

Context injection — what each surface sends

Section titled “Context injection — what each surface sends”

This table doubles as the privacy statement: per surface, exactly this data accompanies the request to Anthropic.

SurfaceData sentSource
ChatFull editor code, circuit summary (framework, qubits, classical bits, depth, gate types), top-8 probabilities + per-qubit Bloch coords + exec time, active exercise metadata, last 3 stderr lines, selected hardware backend + last completed hardware-job probabilities, active challenge metadata — wrapped in <ide_context> around the last user message; full conversation history including prior tool callsuseDirac.ts:216-280,484-510
Chat system promptTutor persona + student model (skill level, mastered/struggling concepts, common errors — only after first code execution), Learn Mode track/lesson progress, active capstone milestone, selected backend specsuseDirac.ts:53-95
ComposeFramework, the request, full editor code (language-aware fence)compose.ts:71-81
Cmd+KFramework, snapshot qubits/depth, full file, selected code (or current line), the instructionInlineEditWidget.tsx:75-81
Ghost completionsFramework, circuit summary, last 2 stderr lines, the entire buffer split around a [CURSOR] markerghostCompletions.ts:69-86
NarrationFramework, qubit/depth/gate-type summary, top-3 probabilities (result), code sliced to 1500 charsnarration.ts:34-66
Error rewriteFramework, code sliced to 2000 chars, traceback sliced to 2500 charserrorRewrite.ts:32-40

The Chat row describes Context Depth: Standard (the default). The third Settings knob, Context Depth, trims what chat sends — code and the circuit summary are always included:

  • Minimal: code + circuit summary + recent errors only (no simulation results, Bloch coords, exercise, hardware, or challenge context).
  • Standard (default): everything in the Chat row above.
  • Full: same sections with deeper detail — top-16 probabilities and the last 10 stderr lines.

Per-feature toggles: narration and autoExplainErrors default on, ghostCompletions defaults off (beginner default). With no API key, every surface silently no-ops.

Compose never asks Claude to “reply with code” — it forces a tool call: tool_choice: { type: 'tool', name: 'insert_code' }, and the tool’s contract is a complete, runnable file (the full next editor buffer, never a diff). The prompt embeds the current code in a language-aware fence (python or qsharp), and the one-sentence explanation rides along as a separate text block. Cmd+K uses the same complete-file contract without the tool wrapper.

When the framework is Q#, every generating surface (compose, Cmd+K) appends QSHARP_STYLE_GUIDE to its system prompt so output is modern QDK 1.x rather than legacy Microsoft.Quantum dialect; ghost completions carry a manually-synced distilled subset to fit Haiku’s budget.

Verified against the codebase (not just asserted):

  1. Dirac calls — to api.anthropic.com only, with your key and the context listed above. The only AI endpoint in the app.
  2. Hardware submissions — circuit source/QIR and credentials go to the provider you connect (IBM/IonQ/Azure/…); credentials persist in the OS keyring, not in browser storage. See hardware overview.
  3. Auto-updater — the desktop shell polls github.com/calelamb/nuclei/releases/latest/download/latest.json.
  4. App telemetry: none is sent. The Settings toggle “Anonymous Telemetry” (default off) writes a flag that no code reads; the TelemetryService in src/services/telemetry.ts has zero importers and its flush() clears the queue without any network call. The Rust shell makes no HTTP requests beyond the updater. (Vercel analytics run on the marketing website, not in the app.)

Chat passes nine tool definitions when action keywords are detected: insert_code, run_simulation, highlight_gate, step_to, create_exercise, verify_solution, submit_hardware, challenge_hint, glossary_lookup. Read-only/teaching tools (highlight_gate, step_to, create_exercise, verify_solution) auto-execute; everything that touches the editor, kernel, or hardware stays pending until the user accepts. Tools are omitted in reasoning mode.

Adding tools and prompt fragments is covered in Extending Dirac.