Skip to content

Architecture ​

code-assist is structured as a layered system: a CLI shell wraps a QueryEngine, which orchestrates the core agent loop — sending messages to the Anthropic API, streaming responses, dispatching tool calls, and looping until the model signals completion.

System Architecture ​

Module Overview ​

ModulePathResponsibility
clisrc/code_assist/cli/Click-based entry point, argument parsing
configsrc/code_assist/config/Settings loading/merging, CLAUDE.md discovery, constants
coresrc/code_assist/core/QueryEngine, query() loop, streaming, input processing
memorysrc/code_assist/memory/Memory file scanning, frontmatter parsing, type definitions
servicessrc/code_assist/services/Anthropic API client, tool execution dispatch, error classification
taskssrc/code_assist/tasks/Background task types (local shell, local agent, remote agent)
toolssrc/code_assist/tools/All built-in tools, tool registry, base protocol/class
tuisrc/code_assist/tui/Terminal UI widgets and themes (Textual framework)
typessrc/code_assist/types/Shared types: messages, permissions, hooks, commands, plugins
utilssrc/code_assist/utils/Auth, cost tracking, logging, token counting, bash parsing

Data Flow: Single Turn ​

The following sequence diagram shows what happens when the user submits a single message:

Key Abstractions ​

Tool Protocol ​

Every tool implements the Tool protocol defined in tools/base.py. The protocol mandates:

MethodPurpose
nameUnique identifier string
input_schemaPydantic BaseModel subclass for input validation
call()Async execution — receives validated args, context, and progress callback
description()Human-readable description for the model's system prompt
is_read_only()Whether this invocation mutates state (affects permission logic)
is_concurrency_safe()Whether the tool can safely run in parallel

The concrete ToolDef base class provides sensible defaults so most tools only need to implement call() and input_schema.

QueryEngine ​

QueryEngine is the primary API surface. It accepts a QueryEngineConfig and exposes:

  • submit_message(prompt) — async generator that yields QueryEvent objects.
  • messages — the full conversation history.
  • clear_messages() — reset the conversation.
  • total_turns — cumulative turn count across all queries.

Internally it builds the system prompt from CLAUDE.md files, filters enabled tools, and delegates to the query() loop.

Settings Merge ​

Settings are loaded and merged in priority order:

defaults < global (~/.claude/settings.json)
         < project (.claude/settings.json)
         < local (.claude/settings.local.json)

Deep merge is used — nested dicts are merged recursively, while scalar values are replaced by the higher-priority source.

Permission Engine ​

Permissions are resolved through a pipeline:

  1. Mode check — the current PermissionMode (default, plan, acceptEdits, bypassPermissions, dontAsk, auto).
  2. Rule matching — allow/deny rules from settings are matched against tool_name and rule_content.
  3. Hook override — PreToolUse hooks can approve, deny, or modify tool input.
  4. Classifier — optional safety classifier for high-risk bash commands.
  5. User prompt — if no rule matches and mode is default, the user is asked.

Message Types ​

The internal message format uses dataclasses (UserMessage, AssistantMessage) with typed content blocks:

  • TextBlock — plain text content.
  • ToolUseBlock — a tool call with id, name, and input.
  • ToolResultBlock — the result of a tool call with tool_use_id, content, and is_error.

These are converted to Anthropic API format before each request.

Research and educational use only. Inspired by Claude Code by Anthropic. All original rights reserved by Anthropic.