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.

Dependency flow

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


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.