agent-harness-anatomy

3. Hauptkomponenten

Dieses Kapitel beschreibt die zentralen Bausteine von Claude Code im Detail. Kapitel 2 zeigte wie sie zusammenhängen — hier geht es um was jede Komponente intern tut.

3.1 QueryEngine — Der Konversations-Manager

Die QueryEngine (Datei: src/QueryEngine.ts, ~1.296 Zeilen) besitzt den gesamten Lebenszyklus einer Konversation. Pro Konversation existiert genau eine Instanz; jeder submitMessage()-Aufruf startet einen neuen Turn innerhalb derselben Session.

Verantwortlichkeiten

┌──────────────────────────────────────────────────────────┐
│                      QueryEngine                         │
│                                                          │
│  ┌────────────────┐  ┌─────────────┐  ┌──────────────┐   │
│  │  submitMessage │─►│  Vorverarbei-│─►│   query()    │   │
│  │  (Eingang)     │  │  tung       │  │   (Schleife) │   │
│  └────────────────┘  └─────────────┘  └──────┬───────┘   │
│                                              │           │
│  ┌────────────────┐  ┌─────────────┐         │           │
│  │  Ergebnis      │◄─│  Persistenz │◄────────┘           │
│  │  (SDKMessage)  │  │  & Tracking │                     │
│  └────────────────┘  └─────────────┘                     │
└──────────────────────────────────────────────────────────┘

Konfiguration (QueryEngineConfig)

Die QueryEngine wird über ein umfangreiches Config-Objekt initialisiert:

Feld Typ Beschreibung
cwd string Arbeitsverzeichnis für Dateisystem-Operationen
tools Tools Verfügbare Werkzeuge (Built-in + MCP)
commands Command[] Registrierte Slash-Commands
mcpClients MCPServerConnection[] Verbundene MCP-Server
agents AgentDefinition[] Verfügbare Agenten-Definitionen
canUseTool CanUseToolFn Permission-Callback für Tool-Aufrufe
customSystemPrompt string? Ersetzt den Default-System-Prompt
appendSystemPrompt string? Wird nach dem Haupt-System-Prompt angehängt
maxTurns number? Maximale Agentic-Turns pro Nachricht
maxBudgetUsd number? Kosten-Limit in USD
taskBudget {total}? API-seitiges Token-Budget für den gesamten Turn
jsonSchema Record? Erzwingt Structured Output über SyntheticOutputTool
snipReplay fn? Callback für Snip-Komprimierung (feature-gated)

Turn-Ablauf in submitMessage()

Jeder Aufruf von submitMessage() durchläuft folgende Phasen:

submitMessage(prompt)
│
├─ 1. Input-Verarbeitung
│     processUserInput() → Slash-Commands erkennen und verarbeiten
│     Ergebnis: messages[], shouldQuery, allowedTools, model
│
├─ 2. Persistenz (vor API-Aufruf)
│     recordTranscript() → Transkript schreiben, damit --resume funktioniert
│
├─ 3. System-Init
│     fetchSystemPromptParts() → System-Prompt + User-Context + System-Context
│     yield buildSystemInitMessage() → SDK erhält Tool-Liste, Modell, Mode
│
├─ 4. Query-Schleife delegieren
│     yield* query({messages, systemPrompt, ...})
│     → siehe Abschnitt 3.2
│
├─ 5. Ergebnis-Nachrichten yieldden
│     Jede assistant/user/compact_boundary-Nachricht → SDK-Format konvertieren
│     Permission-Denials tracken
│     Usage akkumulieren
│
└─ 6. Ergebnis
      yield {type: 'result', subtype: 'success', usage, cost, ...}

Interner State

Die QueryEngine verwaltet über ihre Lebensdauer hinweg:


3.2 Die Query-Schleife — Das Herzstück

Die Funktion query() (Datei: src/query.ts, ~1.730 Zeilen) ist die Agentic Loop: eine while(true)-Schleife, die erst terminiert, wenn das Modell keine weiteren Tool-Aufrufe mehr erzeugt — oder ein Abbruchgrund eintritt.

Gesamtarchitektur der Schleife

query(params) → queryLoop()
│
│  while (true) {
│  ┌─────────────────────────────────────────────────┐
│  │ Phase 1: Kontext-Komprimierung                  │
│  │   applyToolResultBudget()   → Ergebnis-Budgets  │
│  │   snipCompactIfNeeded()     → Snip-Komprimierung │
│  │   microcompact()            → Microcompact       │
│  │   applyCollapsesIfNeeded()  → Context Collapse   │
│  │   autocompact()             → Auto-Compact       │
│  ├─────────────────────────────────────────────────┤
│  │ Phase 2: API-Aufruf (Streaming)                 │
│  │   callModel({messages, systemPrompt, tools})    │
│  │   for await (message of stream) {               │
│  │     yield message  → an UI/SDK durchreichen     │
│  │     Tool-Blöcke erkennen → StreamingToolExecutor│
│  │   }                                             │
│  ├─────────────────────────────────────────────────┤
│  │ Phase 3: Fehler-Recovery                        │
│  │   prompt-too-long → Context Collapse / Reactive │
│  │   max_output_tokens → Escalate / Recovery-Loop  │
│  │   Modell-Fallback → anderes Modell, Retry       │
│  ├─────────────────────────────────────────────────┤
│  │ Phase 4: Tool-Ausführung                        │
│  │   StreamingToolExecutor.getRemainingResults()   │
│  │   oder runTools() (Legacy-Pfad)                 │
│  │   → yield tool_result Nachrichten               │
│  ├─────────────────────────────────────────────────┤
│  │ Phase 5: Post-Processing                        │
│  │   Stop-Hooks ausführen                          │
│  │   Token-Budget prüfen                           │
│  │   Attachments laden (Memory, Skills, Queue)     │
│  │   state = {messages + assistantMessages +       │
│  │            toolResults, ...}                    │
│  │   continue  ← nächste Iteration                 │
│  └─────────────────────────────────────────────────┘
│  } // while (true)

Schleifen-State

Der gesamte veränderliche Zustand einer Iteration steckt in einem einzigen State-Objekt:

type State = {
  messages: Message[]              // Kumulierte Konversation
  toolUseContext: ToolUseContext    // Kontext für Tool-Aufrufe
  autoCompactTracking              // Tracking für Auto-Compact-Zyklen
  maxOutputTokensRecoveryCount     // Wie oft max_output_tokens Recovery lief
  hasAttemptedReactiveCompact      // Guard gegen Endlos-Compact-Schleifen
  maxOutputTokensOverride          // Einmaliger Override (Escalate: 8k → 64k)
  pendingToolUseSummary            // Haiku-Summary des vorherigen Turns (Promise)
  stopHookActive                   // Ob gerade ein Stop-Hook läuft
  turnCount                        // Aktuelle Turn-Nummer
  transition                       // Warum die vorherige Iteration fortfuhr
}

Kontext-Komprimierungspipeline (Phase 1)

Vor jedem API-Aufruf durchlaufen die Nachrichten eine 6-stufige Pipeline. Jede Stufe operiert auf dem Ergebnis der vorherigen:

Stufe Modul Feature Flag Wann aktiv Was es tut
1 applyToolResultBudget() — Immer Kürzt überlange Tool-Ergebnisse per Token-Budget
2 snipCompactIfNeeded() HISTORY_SNIP Wenn aktiviert Entfernt alte Turns, behält einen „Tail”
3 microcompact() (immer) Nach Snip Entfernt redundante Tool-Ergebnisse aus dem Cache
4 applyCollapsesIfNeeded() CONTEXT_COLLAPSE Wenn aktiviert Fasst Gruppen von Nachrichten zu Zusammenfassungen zusammen
5 autocompact() (konfigurierbar) Wenn Token-Threshold erreicht Sendet gesamten Kontext an ein Modell zur Zusammenfassung
6 Reactive Compact REACTIVE_COMPACT Bei prompt-too-long Fehlern Emergency-Compact nach 413-Antwort

Die Stufen 4 und 5 können sich gegenseitig ersetzen: Context Collapse läuft vor Auto-Compact — wenn Collapse den Kontext genug reduziert, wird Auto-Compact zum No-Op.

API-Streaming und Tool-Erkennung (Phase 2)

for await (message of callModel(...)) {
  │
  ├─ message.type === 'assistant'?
  │    ├─ Tool-Use-Blöcke extrahieren
  │    ├─ StreamingToolExecutor.addTool(block)  ← sofort starten!
  │    └─ assistantMessages.push(message)
  │
  ├─ Withheld?  (prompt-too-long / max_output_tokens / media-error)
  │    └─ Nicht yielden, sondern Recovery abwarten
  │
  └─ yield message  → an UI/SDK
}

Schlüssel-Insight: Der StreamingToolExecutor startet concurrent-safe Tools (Grep, Glob, FileRead) bereits während der API noch streamt. Das spart Latenz, weil read-only Tools oft schneller fertig sind als die vollständige API-Antwort.

Terminierung

Die Schleife endet durch einen von 10 return-Pfaden:

Return-Reason Auslöser
completed Modell hat keine Tool-Aufrufe mehr → natürliches Ende
blocking_limit Token-Limit erreicht (Auto-Compact aus)
prompt_too_long 413-Fehler, Recovery fehlgeschlagen
image_error Bild zu groß, Recovery fehlgeschlagen
model_error API-Fehler (nicht-retryable)
aborted_streaming User-Interrupt während Streaming
aborted_tools User-Interrupt während Tool-Ausführung
hook_stopped Stop-Hook hat Fortsetzung verhindert
stop_hook_prevented Stop-Hook mit preventContinuation
max_turns maxTurns-Limit erreicht

3.3 Tool-System

Das Tool-System besteht aus drei Schichten: Definition (was ein Tool ist), Registry (welche Tools verfügbar sind) und Ausführung (wie Tools laufen).

3.3.1 Tool-Interface (Tool.ts)

Die Datei src/Tool.ts (~793 Zeilen) definiert das zentrale Tool-Interface. Jedes Tool — ob Built-in, MCP oder Plugin — muss dieses Interface implementieren.

Die wichtigsten Methoden:

Methode Signatur Beschreibung
call() (args, context, canUseTool, parentMsg, onProgress?) → ToolResult Hauptlogik — führt das Tool aus
prompt() (options) → string Erzeugt den Prompt-Text, den das Modell sieht
description() (input, options) → string Dynamische Beschreibung (kontextabhängig)
checkPermissions() (input, context) → PermissionResult Tool-eigene Berechtigungsprüfung
validateInput() (input, context) → ValidationResult Input-Validierung vor Ausführung
inputSchema z.ZodType Zod-v4-Schema für Input-Validierung

Concurrency-relevante Properties:

Property Typ Beschreibung
isConcurrencySafe(input) boolean Darf parallel laufen? (Default: false)
isReadOnly(input) boolean Verändert nichts? (Default: false)
isDestructive(input) boolean Kann irreversiblen Schaden anrichten?
interruptBehavior() 'cancel' \| 'block' Was bei User-Interrupt passiert

Rendering-Methoden (für Terminal-UI):

Das Tool-Interface enthält über 10 render*-Methoden, die steuern, wie ein Tool-Aufruf in der Ink-UI dargestellt wird: renderToolUseMessage, renderToolResultMessage, renderToolUseProgressMessage, renderToolUseRejectedMessage, renderToolUseErrorMessage, renderGroupedToolUse u.v.m.

buildTool() — Die Factory-Funktion

Statt das vollständige Interface zu implementieren, verwenden Tools die buildTool()-Funktion. Sie füllt sichere Defaults ein:

buildTool(def) → { ...TOOL_DEFAULTS, ...def }

TOOL_DEFAULTS:
  isEnabled       → () => true
  isConcurrencySafe → () => false     (konservativ: nicht parallel)
  isReadOnly      → () => false       (konservativ: nimmt Schreibzugriff an)
  isDestructive   → () => false
  checkPermissions → allow (delegiert an Permission-System)
  toAutoClassifierInput → '' (Security-relevante Tools müssen überschreiben)
  userFacingName  → name

ToolUseContext — Der Kontext für jeden Tool-Aufruf

ToolUseContext ist der zentrale Kontext, der bei jedem Tool-Aufruf mitgegeben wird. Er enthält:

ToolUseContext
├── options
│   ├── commands[]         Verfügbare Slash-Commands
│   ├── tools[]            Alle registrierten Tools
│   ├── mainLoopModel      Aktuelles Modell (z.B. "claude-sonnet-4")
│   ├── mcpClients[]       MCP-Server-Verbindungen
│   ├── agentDefinitions   Verfügbare Agenten
│   └── thinkingConfig     Thinking-Modus (adaptive/disabled)
│
├── State-Zugriff
│   ├── getAppState()      Globalen App-State lesen
│   ├── setAppState()      Globalen App-State ändern
│   └── readFileState      LRU-Cache gelesener Dateien
│
├── Steuerung
│   ├── abortController    Für User-Interrupts
│   ├── messages[]         Aktuelle Konversation
│   └── agentId?           Falls Sub-Agent: seine ID
│
├── UI-Callbacks
│   ├── setToolJSX()       Tool-UI im Terminal anzeigen
│   ├── addNotification()  Benachrichtigungen anzeigen
│   └── sendOSNotification()  OS-Benachrichtigungen
│
└── Tracking
    ├── queryTracking      Chain-ID + Tiefe
    ├── updateFileHistoryState()  Datei-Änderungen tracken
    └── updateAttributionState()  Attribution für Commits

3.3.2 Tool-Registry (tools.ts)

Die Datei src/tools.ts (~390 Zeilen) ist die zentrale Quelle der Wahrheit für alle verfügbaren Tools. Drei Funktionen bilden die Tool-Assemblierung:

getAllBaseTools()                    // Alle Built-in Tools (ungefiltert)
    │
    ▼
getTools(permissionContext)          // Gefiltert nach Deny-Rules + isEnabled()
    │
    ▼
assembleToolPool(permCtx, mcpTools)  // + MCP-Tools, dedupliziert, sortiert

getAllBaseTools() — Alle Built-in Tools

Diese Funktion listet alle Tools, die in der aktuellen Build-Konfiguration verfügbar sind:

Kategorie Tools Concurrency
Dateisystem FileRead, FileEdit, FileWrite, NotebookEdit Read: parallel, Write: seriell
Shell Bash, PowerShell (optional) Seriell
Suche Glob, Grep (wenn kein eingebettetes bfs/ugrep) Parallel
Web WebFetch, WebSearch, WebBrowser (feature-gated) Parallel
Agenten Agent, TaskStop, TaskOutput, SendMessage Seriell
Tasks (v2) TaskCreate, TaskGet, TaskUpdate, TaskList —
Planung EnterPlanMode, ExitPlanModeV2 —
MCP ListMcpResources, ReadMcpResource Parallel
Sonstige TodoWrite, AskUserQuestion, SkillTool, Brief, Config, ToolSearch, … Variabel

Viele Tools werden Feature-gated importiert — sie existieren nur, wenn das entsprechende Flag zur Build-Zeit aktiv ist:

feature('COORDINATOR_MODE')   → Coordinator-spezifische Tools
feature('WEB_BROWSER_TOOL')   → WebBrowserTool
feature('HISTORY_SNIP')       → SnipTool
feature('WORKFLOW_SCRIPTS')   → WorkflowTool
feature('TERMINAL_PANEL')     → TerminalCaptureTool
feature('UDS_INBOX')          → ListPeersTool

getTools() — Gefilterter Tool-Pool

getTools() wendet drei Filter an:

  1. Deny-Rules: Tools mit blanket-deny (alwaysDenyRules ohne ruleContent) werden entfernt, bevor das Modell sie sieht
  2. REPL-Mode: Wenn REPLTool aktiv ist, werden die darin gekapselten Primitiv-Tools (Bash, FileRead, etc.) ausgeblendet
  3. isEnabled(): Jedes Tool kann sich dynamisch deaktivieren

assembleToolPool() — Die finale Tool-Liste

assembleToolPool(permissionContext, mcpTools):
  builtInTools = getTools(permCtx)     // sortiert nach Name
  allowedMcp = filterByDenyRules(mcp)  // sortiert nach Name
  return uniqBy([...builtIn, ...mcp], 'name')
         ↑ Built-in gewinnen bei Namenskonflikten

Die Sortierung ist nicht kosmetisch — sie dient der Prompt-Cache-Stabilität: Die API legt Cache-Breakpoints nach dem letzten Built-in-Tool. Wenn MCP-Tools zwischen Built-ins sortiert würden, würde jede MCP-Änderung alle Cache-Keys invalidieren.

3.3.3 Tool-Ausführung

Die Tool-Ausführung verteilt sich auf drei Dateien:

toolOrchestration.ts        Partitionierung + Ablaufsteuerung
StreamingToolExecutor.ts    Streaming-Ausführung während API-Response
toolExecution.ts            Einzelnes Tool: Validierung → Permission → Call

Partitionierung (partitionToolCalls)

Wenn das Modell mehrere Tools in einer Antwort aufruft, partitioniert partitionToolCalls() sie in Batches:

Eingabe: [Grep, Grep, FileWrite, FileRead, FileRead]
                                  ↓
Batch 1: [Grep, Grep]        isConcurrencySafe: true   → parallel (max 10)
Batch 2: [FileWrite]          isConcurrencySafe: false  → seriell
Batch 3: [FileRead, FileRead] isConcurrencySafe: true   → parallel

Die Regel: Aufeinanderfolgende concurrent-safe Tools werden gebatcht; sobald ein nicht-concurrent-safe Tool kommt, wird es allein ausgeführt; danach kann wieder gebatcht werden.

StreamingToolExecutor

Der StreamingToolExecutor (src/services/tools/StreamingToolExecutor.ts, ~531 Zeilen) startet Tools während die API noch streamt:

API-Stream:
  ──[text]──[tool_use:Grep1]──[text]──[tool_use:Grep2]──[tool_use:FileEdit]──►
                  │                          │                    │
  addTool(Grep1)──┘     addTool(Grep2)───────┘    addTool(Edit)──┘
       │                      │                        │
       ▼                      ▼                        ▼
  ┌─────────┐          ┌─────────┐              ┌──────────┐
  │ execute │          │ execute │              │  queued   │
  │ (sofort)│          │ (sofort)│              │(wartet auf│
  └─────────┘          └─────────┘              │Grep 1+2) │
                                                └──────────┘

Kernlogik der Concurrency-Prüfung:

canExecuteTool(isConcurrencySafe):
  executing = tools.filter(status === 'executing')
  return executing.length === 0
      || (isConcurrencySafe && ALL executing are concurrencySafe)

Besonderes Verhalten bei Fehlern:

runToolUse() — Einzelner Tool-Aufruf

Die Funktion runToolUse() in toolExecution.ts (~1.746 Zeilen) orchestriert einen einzelnen Tool-Aufruf:

runToolUse(toolUse, assistantMessage, canUseTool, context)
│
├─ 1. Tool finden
│     findToolByName() → auch Aliases prüfen (z.B. "KillShell" → "TaskStop")
│
├─ 2. Input validieren
│     tool.inputSchema.safeParse(input)
│     tool.validateInput?()  → tool-spezifische Validierung
│
├─ 3. Permission prüfen
│     tool.checkPermissions(input)  → tool-eigene Prüfung
│     canUseTool(tool, input)       → Permission-Pipeline (5 Stufen)
│     ├─ allow    → weiter
│     ├─ deny     → tool_result mit Fehlermeldung
│     └─ ask      → User-Prompt (interaktiv) / auto-deny (headless)
│
├─ 4. Pre-Tool-Use Hooks
│     runPreToolUseHooks() → benutzerdefinierte Hooks
│
├─ 5. Tool ausführen
│     tool.call(parsedInput, context, canUseTool, assistantMessage)
│     ├─ Timeout/Abort → AbortError
│     ├─ Fehler → formatiertes error tool_result
│     └─ Erfolg → ToolResult
│
├─ 6. Post-Tool-Use Hooks
│     runPostToolUseHooks() → benutzerdefinierte Hooks
│     Stop-Hooks prüfen → können Fortsetzung verhindern
│
└─ 7. Ergebnis aufbereiten
      mapToolResultToToolResultBlockParam()
      processToolResultBlock() → Große Ergebnisse auf Disk auslagern
      yield {message, contextModifier?}

3.4 Command-System (Slash-Commands)

Die Datei src/commands.ts (~755 Zeilen) verwaltet die Slash-Commands, die Benutzer mit / aufrufen können (z.B. /compact, /help, /review).

Command-Typen

Es gibt drei grundlegende Typen (definiert in src/types/command.ts):

Typ Ausführung Beispiele
prompt Wird in Text expandiert und an das Modell gesendet /review, /commit, Skills, Workflows
local Führt lokale Logik aus, gibt Text zurück /cost, /compact, /clear
local-jsx Rendert interaktive Ink-UI-Komponenten /config, /mcp, /install

Command-Zusammensetzung

Commands kommen aus sechs Quellen, die beim Aufruf von getCommands() zusammengeführt werden:

getCommands(cwd)
│
├─ loadAllCommands(cwd)  ← memoized nach cwd
│  ├─ getBundledSkills()              Eingebaute Skills (synchron)
│  ├─ getBuiltinPluginSkillCommands() Skills aus Built-in-Plugins
│  ├─ getSkillDirCommands(cwd)        .claude/skills/ Verzeichnisse
│  ├─ getWorkflowCommands(cwd)        Workflow-Scripts (feature-gated)
│  ├─ getPluginCommands()             Plugin-Commands
│  ├─ getPluginSkills()               Plugin-Skills
│  └─ COMMANDS()                      ~80 Built-in Commands (memoized)
│
├─ getDynamicSkills()                 Skills, die während Dateioperationen entdeckt wurden
│
└─ Filter: meetsAvailabilityRequirement() && isCommandEnabled()

Command-Verfügbarkeit

Commands können ihre Sichtbarkeit über zwei unabhängige Mechanismen steuern:

Mechanismus Prüfzeitpunkt Beispiel
availability: ['claude-ai', 'console'] Statisch (Auth/Provider) /extra-usage nur für Claude.ai-Subscriber
isEnabled() Dynamisch (Feature Flags, Env) /voice nur wenn VOICE_MODE aktiv

Besondere Command-Sets

Set Zweck
INTERNAL_ONLY_COMMANDS Nur für Anthropic-interne Builds (USER_TYPE === 'ant')
REMOTE_SAFE_COMMANDS Sicher in --remote-Mode (keine lokale Filesystem-Abhängigkeit)
BRIDGE_SAFE_COMMANDS Dürfen über die Remote-Control-Bridge (Mobile/Web) ausgeführt werden

Skill-Invocation durch das Modell

Nicht alle Commands sind direkt vom Modell aufrufbar. Die Funktion getSkillToolCommands() filtert:

getSkillToolCommands(cwd):
  allCommands.filter(cmd =>
    cmd.type === 'prompt' &&
    !cmd.disableModelInvocation &&
    cmd.source !== 'builtin' &&
    (cmd.loadedFrom in ['bundled', 'skills', 'commands_DEPRECATED']
     || cmd.hasUserSpecifiedDescription
     || cmd.whenToUse)
  )

Das Modell sieht diese Commands über das SkillTool, das sie als auswählbare Skills präsentiert.


3.5 Konkrete Tool-Implementierungen

3.5.1 BashTool

Das mächtigste Tool — es gibt dem Agenten eine Shell. Datei: src/tools/BashTool/BashTool.tsx (~1.144 Zeilen).

Input-Schema:

Feld Typ Beschreibung
command string Der auszuführende Shell-Befehl
timeout number? Timeout in Millisekunden (Default: 120s, Max: 600s)
description string? Beschreibung für Permission-Dialog

Concurrency-Klassifikation:

Das BashTool führt eine semantische Analyse des Befehls durch, um zu entscheiden, ob er parallel laufen darf:

isSearchOrReadBashCommand(command):
  splitCommandWithOperators(command)
  für jedes Teil:
    ├─ BASH_SEARCH_COMMANDS: grep, rg, find, ag, ...  → isSearch
    ├─ BASH_READ_COMMANDS: cat, head, wc, jq, ...     → isRead
    ├─ BASH_LIST_COMMANDS: ls, tree, du               → isList
    ├─ BASH_SEMANTIC_NEUTRAL: echo, printf, true, :   → neutral (ignoriert)
    └─ alles andere                                    → NICHT read-only
  Pipeline: ALLE Teile müssen search/read/list sein

Sicherheits-Features:

3.5.2 AgentTool — Sub-Agenten

Das AgentTool (src/tools/AgentTool/AgentTool.tsx, ~1.398 Zeilen) spawnt Sub-Agenten — vollständige Claude-Instanzen mit eigenem Kontext, eigenen Tools und eigenem Token-Budget.

Agent-Definition (AgentDefinition):

Agenten werden aus Markdown-Dateien in .claude/agents/ geladen (ähnlich wie Skills). Jede Definition enthält:

Feld Beschreibung
name Eindeutiger Name (z.B. "Explore", "Plan")
description Kurzbeschreibung für das Modell
prompt System-Prompt des Agenten
tools Erlaubte Tools (Whitelist)
disallowedTools Verbotene Tools (Blacklist)
model Modell-Override ("sonnet", "opus", "haiku", "inherit")
permissionMode Berechtigungsmodus ("plan", "auto", …)
maxTurns Maximale Turns
mcpServers Agenten-spezifische MCP-Server
hooks Frontmatter-definierte Hooks
isolation "worktree" (Git-Worktree) oder "remote" (Remote-Umgebung)
memory Memory-Scope ("user", "project", "local")

Built-in Agents:

Ausführungsmodi:

AgentTool.call()
│
├─ Foreground (default)
│   runAgent() → query() mit eigenem Kontext
│   ├─ Eigener AbortController
│   ├─ Eigene readFileState (geklont)
│   ├─ Eingeschränktes Tool-Set (resolveAgentTools)
│   └─ Eigener Transcript (Sidechain)
│
├─ Background (run_in_background: true)
│   Wie Foreground, aber:
│   ├─ Läuft in eigenem Promise (nicht blockierend)
│   └─ Benachrichtigung bei Completion
│
├─ Worktree-Isolation
│   createAgentWorktree() → Git-Worktree erstellen
│   Agent arbeitet auf Kopie des Repos
│
└─ Remote (Anthropic-intern)
    teleportToRemote() → Agent in Cloud-Umgebung

3.5.3 Coordinator-Modus

Der Coordinator-Modus (src/coordinator/coordinatorMode.ts, ~370 Zeilen) verwandelt die Haupt-Instanz in einen Orchestrator, der nur Sub-Agenten spawnt und koordiniert:

Coordinator-Modus:
┌─────────────────────────────────────────────┐
│  Coordinator (Hauptprozess)                 │
│  Tools: Agent, TaskStop, SendMessage        │
│  Aufgabe: Aufgaben zerlegen & delegieren    │
│                                             │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐   │
│  │ Worker 1 │  │ Worker 2 │  │ Worker 3 │   │
│  │ Bash,    │  │ Bash,    │  │ Bash,    │   │
│  │ FileRead,│  │ FileRead,│  │ FileRead,│   │
│  │ FileEdit │  │ FileEdit │  │ FileEdit │   │
│  └──────────┘  └──────────┘  └──────────┘   │
└─────────────────────────────────────────────┘

Aktivierung: CLAUDE_CODE_COORDINATOR_MODE=1

Die Worker erhalten ein eingeschränktes Tool-Set (ASYNC_AGENT_ALLOWED_TOOLS), während der Coordinator selbst nur Agent, TaskStop und SendMessage verwendet.


3.6 Referenz: Alle ~40 Built-in Tools

Die folgende Tabelle listet alle Tools, die getAllBaseTools() registriert:

Tool Kategorie Parallel Feature Gate Beschreibung
Agent Multi-Agent ✗ — Sub-Agent spawnen
TaskOutput Multi-Agent ✗ — Ergebnis eines Task abrufen
TaskStop Multi-Agent ✗ — Laufenden Task/Shell beenden
Bash Shell ✗ — Shell-Befehl ausführen
Glob Suche ✓ ¬embedded Datei-Suche per Glob-Pattern
Grep Suche ✓ ¬embedded Text-Suche per Regex
FileRead Dateisystem ✓ — Datei lesen
FileEdit Dateisystem ✗ — Datei bearbeiten (Search & Replace)
FileWrite Dateisystem ✗ — Datei schreiben/erstellen
NotebookEdit Dateisystem ✗ — Jupyter-Notebook bearbeiten
WebFetch Web ✓ — URL abrufen
WebSearch Web ✓ — Web-Suche
WebBrowser Web ✓ WEB_BROWSER_TOOL Headless Browser
TodoWrite Planung ✗ — Todo-Liste verwalten
EnterPlanMode Planung ✗ — In Plan-Modus wechseln
ExitPlanModeV2 Planung ✗ — Plan-Modus verlassen
SkillTool Skills ✗ — Skill/Command aufrufen
AskUserQuestion Interaktion ✗ — Benutzer eine Frage stellen
Brief Kommunikation ✗ — Kurzzusammenfassung
Config Konfiguration ✗ ant Claude-Code-Config bearbeiten
Tungsten Intern ✗ ant Anthropic-internes Tool
SendMessage Multi-Agent ✗ — Nachricht an anderen Agenten
ListPeers Multi-Agent ✓ UDS_INBOX Peer-Agenten auflisten
TeamCreate Multi-Agent ✗ Agent Swarms Team erstellen
TeamDelete Multi-Agent ✗ Agent Swarms Team löschen
EnterWorktree Isolation ✗ Worktree-Mode Git-Worktree erstellen
ExitWorktree Isolation ✗ Worktree-Mode Git-Worktree verlassen
TaskCreate Tasks v2 ✗ Todo v2 Task erstellen
TaskGet Tasks v2 ✓ Todo v2 Task abrufen
TaskUpdate Tasks v2 ✗ Todo v2 Task aktualisieren
TaskList Tasks v2 ✓ Todo v2 Tasks auflisten
LSP IDE ✓ ENABLE_LSP_TOOL LSP-Server abfragen
ListMcpResources MCP ✓ — MCP-Ressourcen auflisten
ReadMcpResource MCP ✓ — MCP-Ressource lesen
ToolSearch Meta ✓ Tool-Search Verfügbare Tools durchsuchen
SnipTool Kontext ✗ HISTORY_SNIP Manuelles Snipping
TerminalCapture IDE ✓ TERMINAL_PANEL Terminal-Output erfassen
Sleep Async ✗ PROACTIVE/KAIROS Warten auf Events
CronCreate/Delete/List Scheduling ✗ AGENT_TRIGGERS Cron-Aufgaben verwalten
Workflow Workflows ✗ WORKFLOW_SCRIPTS Workflow-Scripts ausführen
CtxInspect Debug ✓ CONTEXT_COLLAPSE Kontext inspizieren
Monitor Monitoring ✗ MONITOR_TOOL File/Process-Monitoring

3.7 Skills und Plugins

Skills

Skills sind vom Benutzer definierte Prompt-Erweiterungen — Markdown-Dateien mit optionalem Frontmatter, die das Modell bei Bedarf als Kontext laden kann.

Lade-Hierarchie:

~/.claude/skills/           ← User-global (userSettings)
.claude/skills/             ← Projekt-lokal (projectSettings)
managed/.claude/skills/     ← Policy-verwaltet (policySettings)
plugins/*/skills/           ← Plugin-bereitgestellt
built-in                    ← Eingebaute Skills (bundled)
MCP-Server                  ← MCP-bereitgestellte Skills (feature-gated)

Frontmatter-Felder:

Feld Beschreibung
description Kurzbeschreibung (sichtbar für Modell und Benutzer)
whenToUse Wann das Modell diesen Skill verwenden soll
tools Erlaubte Tools für diesen Skill
model Modell-Override
context 'inline' (expandiert in Konversation) oder 'fork' (als Sub-Agent)
agent Agent-Typ für fork-Kontext
effort Effort-Level
paths Glob-Patterns — Skill wird nur nach Berühren passender Dateien sichtbar
hooks Hooks, die beim Aufruf des Skills registriert werden

Plugins

Plugins sind ein strukturierteres Erweiterungssystem als Skills. Sie werden aus Git-Repositories geladen und können eigene Commands, Skills, Agenten und Hooks bereitstellen. Die Plugin-Architektur ist in src/plugins/ und src/utils/plugins/ implementiert.


3.8 Zusammenfassung: Datenfluss durch die Hauptkomponenten

User-Eingabe
    │
    ▼
QueryEngine.submitMessage()
    │
    ├─ processUserInput()  → Slash-Commands verarbeiten
    │
    ├─ fetchSystemPromptParts()  → System-Prompt aufbauen
    │
    ▼
query() / queryLoop()
    │
    ├─ Kontext-Komprimierung (6 Stufen)
    │
    ├─ callModel()  → API-Streaming
    │   │
    │   └─ StreamingToolExecutor.addTool()  → Parallel-Start
    │
    ├─ runTools() / getRemainingResults()
    │   │
    │   ├─ partitionToolCalls()  → Batching
    │   │
    │   └─ runToolUse()
    │       │
    │       ├─ validateInput()
    │       ├─ checkPermissions()
    │       ├─ canUseTool()  → 5-stufige Pipeline
    │       ├─ tool.call()   → BashTool / FileEditTool / AgentTool / ...
    │       └─ post-Hooks
    │
    ├─ Attachments (Memory, Skills, Queue-Commands)
    │
    └─ state = {...} → continue (nächste Iteration)
         oder
    return {reason: 'completed'}
    │
    ▼
QueryEngine → yield {type: 'result', ...}