Skip to main content
Claurst is a complete standalone rewrite of the Claude Code CLI in async Rust. It shares no runtime code with the original TypeScript implementation and re-implements the same tool names, permission model, CLAUDE.md discovery, auto-compact logic, MCP client, and bridge protocol — all in idiomatic Rust on the Tokio async runtime.

Workspace structure

The workspace lives under claude-code-rust/ and is organized as a Cargo workspace with resolver = "2", edition 2021.
claude-code-rust/
├── Cargo.toml                  # Workspace root
└── crates/
    ├── core/       (cc-core)       # Shared types, config, permissions, history, hooks
    ├── api/        (cc-api)        # API client + SSE streaming
    ├── tools/      (cc-tools)      # All tool implementations (33 tools)
    ├── query/      (cc-query)      # Agentic query loop, compact, cron scheduler
    ├── tui/        (cc-tui)        # ratatui terminal UI
    ├── commands/   (cc-commands)   # Slash command implementations
    ├── mcp/        (cc-mcp)        # MCP (Model Context Protocol) client
    ├── bridge/     (cc-bridge)     # Bridge to claude.ai web UI
    └── cli/        (claude-code)   # Binary entry point (produces `claude` executable)
PackageTypePurpose
cc-coreLibraryShared types, error enum, config, permissions, history, cost tracking, hooks
cc-apiLibraryAnthropic Messages API client with SSE streaming and retry logic
cc-toolsLibraryAll 33 built-in tool implementations
cc-queryLibraryAgentic query loop, auto-compact, sub-agent tool, cron scheduler
cc-tuiLibraryTerminal UI (ratatui + crossterm)
cc-commandsLibrarySlash command registry and implementations
cc-mcpLibraryJSON-RPC 2.0 MCP client over stdio subprocess transport
cc-bridgeLibraryBridge protocol for claude.ai remote control
claude-codeBinaryCLI entry point; binary named claude

Dependency flow

cli → query → tools → core
         ↓         ↗
        api  →  core

       commands → core

        tui   → core

        mcp   → core

       bridge → core
cc-core is the only crate with no upstream dependencies within the workspace. Every other crate depends on it for shared types, error handling, and configuration. The CLI binary wires everything together.

Agentic query loop

The core of Claurst is the agentic loop implemented in cc-query. A single user turn follows this flow:
1

Receive user input

The TUI or headless runner receives a user prompt and appends it to the in-process message history as a Message::user(...).
2

Build the API request

run_query_loop() converts the message history to Vec<ApiMessage>, converts available tools to Vec<ApiToolDefinition>, and assembles a CreateMessageRequest with the system prompt and optional thinking budget.
3

Stream the response

AnthropicClient::create_message_stream() spawns a background Tokio task that reads the SSE response body line by line and sends StreamEvent values over an mpsc channel (buffer: 256). A StreamAccumulator collects deltas into a complete Message.
4

Execute tools

When stop_reason is tool_use, the loop iterates over every ContentBlock::ToolUse in the response. For each block it fires PreToolUse hooks, calls execute_tool(), fires PostToolUse hooks, and collects ToolResult values into a Message::user_blocks(result_blocks) appended to the history.
5

Loop or return

If tool results were appended, the loop continues from step 2. The loop terminates when stop_reason is end_turn or stop_sequence (returns QueryOutcome::EndTurn), max_tokens (returns QueryOutcome::MaxTokens), the turn counter exceeds max_turns (default: 10), or the CancellationToken fires.
Auto-compact runs between turns. When token usage exceeds 90% of the model’s context window, the loop summarises the head of the conversation and replaces it with a <compact-summary> block, keeping the last 10 messages intact.

TUI layer

cc-tui replaces the TypeScript Ink/React rendering layer with an immediate-mode terminal UI:
  • Backend: ratatui + crossterm. The terminal is placed in raw mode with crossterm::terminal::enable_raw_mode() and switched to the alternate screen buffer.
  • Layout: Three vertical chunks — messages area (flex fill), input box (3 rows), status bar (1 row).
  • Rendering: User messages render in Cyan, assistant messages in Green. Streaming text in progress renders in Yellow italic. The status bar shows the active model and current session cost.
  • Input: App::handle_key_event() processes KeyEvent values. Ctrl+C cancels a streaming response; if the input is empty it quits. Up/Down navigates input history. F1 or ? toggles the help overlay.
  • Widgets: A centered render_permission_dialog() popup handles user permission prompts. A braille spinner (⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏) animates during tool execution.
For headless (non-interactive) use, run_headless() streams QueryEvent values to stdout in text, json, or stream-json output formats without starting the TUI.

Async runtime

All async code uses Tokio with the full feature set. The #[tokio::main] macro is applied to main() in crates/cli/src/main.rs. Every tool’s execute() method is async via async_trait. Cancellation is propagated through tokio_util::sync::CancellationToken.

Key shared dependencies

CrateVersionRole
tokio1.44Async runtime (full features)
reqwest0.12HTTP client (rustls-tls, streaming)
ratatui0.29Terminal UI framework
crossterm0.28Cross-platform terminal backend
clap4CLI argument parsing
serde / serde_json1Serialization
schemars0.8JSON Schema generation for tool inputs
async-trait0.1Async trait support
dashmap6Concurrent hash maps for global state
parking_lot0.12Faster mutexes

Tool system

How the Tool trait works, the 33 built-in tools, and input schema validation.

Permissions

Permission modes, categories, layered settings, and protected files.

Memory

Short-term session history, the memdir long-term store, and the AutoDream consolidation system.

Back to overview

Return to the documentation home.

Build docs developers (and LLMs) love