AI Coding Guides Deep Dives
Hash-Anchored • AST-Native • No MCP • 64.8% cheaper

Dirac — Accurate & Highly Token Efficient

Dirac is a TypeScript coding agent that reduces API costs by 64.8% while achieving better accuracy — using hash-anchored parallel edits, AST manipulation, and a suite of context curation optimizations. Explicitly no MCP. Built on a fork of Cline.

(Alright, ad over. Back to the serious technical analysis.)

What makes Dirac different

Most coding agents treat file editing as a text manipulation problem: find line N, replace with new content. This breaks the moment the file shifts — even a single inserted line deranges every downstream line number. Dirac takes a different approach: it anchors edits to stable line hashes, uses AST-aware tools for structural code operations, and batches multiple file operations into a single LLM roundtrip. The result is an agent that is measurably more accurate on complex multi-file refactoring tasks and significantly cheaper to run.

The eval results are striking. On 8 real-world refactoring tasks against transformers, vscode, and django repos, Dirac achieved 8/8 correct at an average cost of $0.18 — versus the competition's $0.38–$0.73 range. That is a 2.8x cost reduction with better outcomes.

📊

TerminalBench 2.0 Results

Dirac scored 65.2% on TerminalBench 2.0, beating Google's coding agent at 47.6% and Junie CLI at 64.3%. The eval tests complex, real-world refactoring tasks against public GitHub repos.

Hash-Anchored File Editing

The core innovation in Dirac is its hash-anchored editing system. When Dirac reads a file, it computes a deterministic hash for each line. Edits are then specified as anchor + end_anchor + replacement text rather than start_line + end_line + text. This means:

The EditExecutor in src/core/task/tools/handlers/edit-file/EditExecutor.ts resolves anchors by checking that the anchor name starts with a capital letter, exists in the file's line hash list, and that the provided content line matches the actual file content at that hash. If any check fails, the edit fails with a diagnostic explaining exactly what went wrong.

The batch processor (BatchProcessor.ts) applies multiple edits in reverse line order — highest line index first — so that earlier edits don't shift the coordinates of later ones.

📌

Key files

src/core/task/tools/handlers/edit-file/EditExecutor.ts (anchor resolution, content matching), src/core/task/tools/handlers/edit-file/BatchProcessor.ts (reverse-order batch application), src/core/task/tools/handlers/edit-file/types.ts (AppliedEdit, FailedEdit, ResolvedEdit types), src/utils/line-hashing.ts (splitAnchor, stripHashes, getDelimiter)

AST-Native Precision

Beyond hash-anchored text edits, Dirac has AST-aware tools that target specific symbols — classes, functions, interfaces — directly rather than by text position. This means:

This is the structural equivalent of the hash-anchored system: both prevent the "friction" of coordinate-based editing. Where line numbers drift when the file changes, and raw text matching drifts when the surrounding code changes, AST targeting drifts only when the target symbol itself changes.

Token Efficiency Architecture

Dirac's token efficiency is not an accident — it is a deliberate engineering target backed by multiple mechanisms:

Mechanism How it works Effect
Hash-anchored multi-file batching Multiple files edited in single LLM roundtrip One roundtrip instead of N sequential requests
get_file_skeleton Maps project structure without reading every line "Just-in-time" code loading keeps context tight
ContextManager truncation Half-strategy and quarter-strategy for long context Always relevant context in window
Concurrent tool calling Parallel tool execution in single turn Reduces turn count for complex tasks
Minimal system prompt PRIME DIRECTIVES focus on efficiency, not boilerplate Fewer tokens per turn

The ContextManager (src/core/context/context-management/ContextManager.ts) manages truncation with two strategies: half truncation (remove the middle 50% of conversation) and quarter truncation (remove the middle 25%). The choice depends on context length and model limits.

State Mutex — Thread-Safe Concurrent State

Dirac uses a state mutex (implemented via the p-mutex package) to serialize all state modifications in the main Task loop. This is critical because the concurrent tool calling system can produce multiple tool results simultaneously — without a mutex, two tool completions could corrupt state simultaneously.

// From src/core/task/index.ts (line ~140)
private stateMutex = new Mutex()

private async withStateLock<T>(fn: () => T | Promise<T>): Promise<T> {
  return await this.stateMutex.withLock(fn)
}

Every state modification — tool results, message updates, task history writes — goes through withStateLock. This prevents race conditions between the concurrent tool executor and the main task loop without sacrificing the performance benefit of parallel tool calls.

Hook System

Dirac has an extensive hook system with 8 event types that scripts can intercept:

Hook When it fires Purpose
onTaskStart Before agent starts a task Setup, environment validation
onTaskComplete After task finishes successfully Cleanup, notification, artifact publishing
onTaskCancel When task is cancelled Graceful shutdown, partial result handling
onTaskResume When a paused task resumes State reconstruction
preToolUse Before any tool executes Validation, blocking, input modification
postToolUse After any tool completes Logging, result inspection, side effects
preCompact Before context compaction Protect sensitive content from truncation
preRequest Before sending LLM request System prompt modification, context augmentation

Hooks are discovered via auto-discovery in .claude/, .agents/, or explicitly configured in AGENTS.md. The hook executor (src/core/hooks/hook-executor.ts) runs hooks with structured JSON via stdin and supports cancellation via AbortController. Hooks can return a cancel decision, a contextModification to alter behavior, or an errorMessage.

📌

Key files

src/core/hooks/hook-executor.ts (executeHook, streaming callback, cancellation), src/core/hooks/hook-factory.ts (HookFactory, hasHook, getHookInfo), src/core/hooks/HookManager.ts (active hook execution tracking), src/core/hooks/PreToolUseHookCancellationError.ts

Git Checkpoint System

Dirac includes a git checkpoint system that creates commits before risky operations, enabling revert if something goes wrong. This is built into the Task lifecycle and managed by CheckpointManager.

The checkpoint manager is initialized per workspace (not supported in multi-root workspaces yet). If a checkpoint operation fails, a warning is displayed but doesn't block task execution. The system uses buildCheckpointManager from src/integrations/checkpoints/factory.ts.

Plan/Act Mode Separation

Dirac separates Plan mode and Act mode as first-class execution modes. In Plan mode, Dirac gathers information, asks clarifying questions, and presents a strategy before asking for user approval to switch to Act mode. This mirrors Claude Code's approach but with Dirac's own implementation.

The PlanModeRespondHandler handles plan-mode responses, producing a structured plan that users can approve or modify before any code is written.

YOLO Mode

YOLO mode (dirac -y "prompt") runs fully autonomously with auto-approval of all actions. This is useful for simple, well-understood tasks where the overhead of per-action approval isn't worth it. YOLO mode forces plain text output and exits automatically on task completion.

When YOLO mode is enabled, the DiracIgnoreController also sets yoloMode = true, which may affect how certain tools behave.

Command Permissions — DIRAC_COMMAND_PERMISSIONS

Shell command validation in Dirac is configured via the DIRAC_COMMAND_PERMISSIONS environment variable — a JSON object that defines allow/deny glob patterns for shell commands. This is more flexible than a simple ban list: you can allow npm * and git * while denying rm -rf * and sudo *.

The validation flow: check for dangerous characters → parse into segments (splitting on &&, ||, |, ;) → check deny rules first → check allow rules → verify redirects if applicable. Subshell contents ($(...) and (...)) are recursively validated.

# Allow only npm and git commands
export DIRAC_COMMAND_PERMISSIONS='{"allow": ["npm *", "git *"]}'

# Allow dev commands but deny dangerous ones
export DIRAC_COMMAND_PERMISSIONS='{"allow": ["npm *", "git *", "node *"], "deny": ["rm -rf *", "sudo *"]}'

Subagent System

Dirac has a SubagentToolHandler (src/core/task/tools/handlers/SubagentToolHandler.ts) that spawns isolated child agents with their own configuration. Subagents can be configured with specific tool scopes, model selections, and execution parameters.

The SubagentRunner and SubagentBuilder handle the lifecycle. The AgentConfigLoader loads agent configurations. Subagent results are streamed back to the parent, which can then synthesize or act on the child's output.

Skills System — Auto-Discovery

Dirac's skills system uses auto-discovery from three locations: AGENTS.md, .claude/, and .agents/ directories. Skills are injected into the system prompt at runtime.

The getOrDiscoverSkills function in src/core/context/instructions/user-instructions/skills.ts handles discovery and loading. Skills can be enabled or disabled via the refreshDiracRulesToggles and refreshExternalRulesToggles functions, allowing users to toggle rules at runtime without restarting.

Exponential Backoff Retry

Dirac's retry system uses exponential backoff with 2s, 4s, and 8s delays between attempts. When an API request fails, the retry logic in src/core/api/retry.ts automatically schedules re-attempts with increasing delays to avoid hammering rate-limited endpoints.

The retry system also handles streaming failures — if the stream breaks mid-response, Dirac can recover and resume without losing the full conversation context.

Provider Support — 40+ APIs

Dirac is explicitly not tied to one model family. It ships with a large provider catalog in src/core/api/providers/ covering 40+ APIs including Anthropic, OpenAI, Google (Gemini), AWS Bedrock, Azure, and many OpenAI-compatible gateways. Each provider is a separate handler file following the ApiHandler interface.

The src/core/api/index.ts contains createHandlerForProvider which instantiates the correct handler from configuration. Model metadata — IDs, pricing, capability flags like supportsTools and supportsThinking — is centralized in src/shared/api.ts.

📌

Key files

src/core/api/index.ts (createHandlerForProvider), src/shared/api.ts (model metadata, pricing, capability flags), src/core/api/providers/ (individual provider implementations), src/core/api/transform/ (stream normalization across providers)

No MCP — Explicit Design Decision

Unlike virtually every other agent in this directory set, Dirac does not implement MCP support. This is an explicit design decision, not an oversight. The team chose to focus on its own tool surface rather than maintaining a protocol bridge.

This puts Dirac in a unique position: it is the most accurate on structural code manipulation tasks among the TypeScript-based agents, but it cannot connect to external MCP servers. For users who need MCP integration, this is a significant gap. For users who want a tightly integrated, self-contained agent, this is a feature.

Architecture Overview

Extension entry point → webview → controller → task. The core modules:

Dirac is a fork of Cline, and the architecture reflects that lineage. The core task loop, tool system, and context management are all built on Cline's foundation, with Dirac's innovations layered on top.

CLI Quick Reference

Command Description
dirac "prompt" Run a task interactively
dirac -p "prompt" Run in Plan mode
dirac -y "prompt" Run in YOLO mode (auto-approve)
dirac -T taskId "follow-up" Resume an existing task
dirac --continue Resume most recent task
dirac history List task history
dirac auth Authenticate with a provider
git diff | dirac "Review" Pipe context directly to Dirac

How Dirac compares

Most accurate on structural edits

Hash-anchored editing and AST-native precision make Dirac the most reliable agent for complex multi-file refactoring. On eval tasks, Dirac achieves 8/8 correct while competitors fail 1-3 tasks.

Best for refactoring

Cheapest to run

At $0.18 average cost per task vs $0.38–$0.73 for competitors, Dirac is 2.8x cheaper. For teams running hundreds of tasks daily, this compounds significantly.

Best for cost-conscious teams

No MCP integration

The tradeoff for tight integration is the absence of MCP support. If you need to connect to external MCP servers, Dirac is not the right choice.

Gap vs other agents

Fork of Cline

Dirac builds on Cline's architecture, inheriting its strong tool surface and VS Code extension foundation. The innovations (hash anchors, AST, batching) are layered on top.

Cline-based

Key files

File Role
src/core/task/index.ts Main Task class (1,868 lines) — agent loop, state mutex, tool orchestration
src/core/task/tools/handlers/edit-file/EditExecutor.ts Hash-anchor resolution and edit application
src/core/task/tools/handlers/edit-file/BatchProcessor.ts Reverse-order batch edit processor
src/core/context/context-management/ContextManager.ts Context truncation with half/quarter strategies
src/core/hooks/hook-executor.ts Hook execution with streaming and cancellation
src/core/prompts/system-prompt/template.ts System prompt with PRIME DIRECTIVES
src/core/api/providers/ 40+ provider implementations
src/core/api/retry.ts Exponential backoff retry (2s, 4s, 8s)
cli/man/dirac.1.md Full CLI reference (man page)
walkthrough/step1-4.md Feature showcases (AST precision, minimal roundtrips, hash anchors, speed)