# Claw-Web Developer Guide **Complete documentation for the Claw-Web project — a web-based port of Claude Code (Rust CLI) to a full-stack TypeScript web application.** **Total codebase:** ~32,700 lines of TypeScript/TSX across 126 source files. --- ## Table of Contents 1. [Architecture Overview](#architecture-overview) 2. [Project Structure](#project-structure) 3. [Tech Stack](#tech-stack) 4. [Getting Started](#getting-started) 5. [Server Runtime Modules](#server-runtime-modules) 6. [Client Components](#client-components) 7. [Buddy Companion Pet System](#buddy-companion-pet-system) 8. [Tools and Executor](#tools-and-executor) 9. [MCP Integration](#mcp-integration) 10. [Configuration System](#configuration-system) 11. [Permissions System](#permissions-system) 12. [Plugin System](#plugin-system) 13. [Deployment](#deployment) 14. [Parity Status with Original](#parity-status-with-original) 15. [Known Issues and TODOs](#known-issues-and-todos) --- ## Architecture Overview Claw-Web is a **full-stack TypeScript application** that ports the original Claude Code Rust CLI to a web interface. It uses a client-server architecture where: - **Client** (React + Vite + TailwindCSS) provides the chat UI, settings, file manager, terminal, and buddy companion - **Server** (Express + tRPC + esbuild) runs the agent loop, tool executor, LLM API calls, and all runtime modules - **Database** (MySQL/TiDB via Drizzle ORM) stores sessions, messages, settings, and user data - **LLM** (HuggingFace Router API, OpenAI-compatible) powers the AI agent with tool calling The agent loop in `server/runtime/agent.ts` is a direct port of the original `conversation.rs` Rust module, implementing the same iteration model with `Number.MAX_SAFE_INTEGER` max iterations (matching Rust's `usize::MAX`). --- ## Project Structure ``` claw-web/ ├── client/ # Frontend (React + Vite) │ └── src/ │ ├── buddy/ # Companion pet system (6 modules) │ │ ├── types.ts # Type definitions (BuddyState, BuddyStats, etc.) │ │ ├── sprites.ts # Sprite configs (6 stages x 10 moods) │ │ ├── companion.ts # State management, XP, leveling, evolution │ │ ├── prompt.ts # Personality, messages, achievements │ │ ├── useBuddyNotification.tsx # React hook for buddy state │ │ └── index.ts # Barrel export │ ├── components/ # UI components │ │ ├── BuddySprite.tsx # Companion pet UI (stats panel, interactions) │ │ ├── ChatInput.tsx # Message input with slash commands │ │ ├── FileManagerPanel.tsx # File browser │ │ ├── MessageBubble.tsx # Chat message rendering │ │ ├── PluginMarketplace.tsx # Plugin management UI │ │ ├── SettingsPanel.tsx # Settings (Model, Parameters, Permissions, MCP, etc.) │ │ ├── Sidebar.tsx # Session sidebar │ │ ├── TaskManagerPanel.tsx # Task/todo management │ │ ├── TerminalPanel.tsx # Embedded terminal │ │ ├── ThinkingBlock.tsx # AI thinking display │ │ ├── ToolCallCard.tsx # Tool call visualization │ │ └── ui/ # shadcn/ui components (70+ files) │ ├── contexts/ # React contexts │ ├── hooks/ # Custom hooks (useChat, useMobile, etc.) │ ├── pages/ # Page components (Home, NotFound, etc.) │ └── lib/ # Utilities (trpc client, utils) ├── server/ # Backend │ ├── _core/ # Framework core (tRPC, auth, LLM, etc.) │ │ ├── llm.ts # LLM API client (OpenAI-compatible) │ │ ├── oauth.ts # OAuth handling │ │ └── ... # Other core modules │ ├── runtime/ # Agent runtime (ported from Rust) │ │ ├── agent.ts # Main agent loop (← conversation.rs) │ │ ├── bootstrap.ts # Project bootstrap/onboarding │ │ ├── chat-endpoint.ts # Chat SSE endpoint + slash commands │ │ ├── compact.ts # Context compaction (527 lines) │ │ ├── config.ts # Config loading + deep merge │ │ ├── lsp-client.ts # LSP client for diagnostics │ │ ├── mcp-client.ts # MCP server manager │ │ ├── permissions.ts # Permission policy system │ │ ├── plugins.ts # Plugin manager │ │ ├── remote.ts # Remote/proxy configuration │ │ ├── sandbox.ts # Container sandbox detection │ │ ├── session.ts # Session serialization/validation │ │ ├── system-prompt.ts # System prompt + TOOL_DEFINITIONS │ │ └── usage.ts # Token/cost tracking │ ├── tools/ # Tool implementations │ │ ├── executor.ts # 30+ tool implementations (1600+ lines) │ │ └── file-ops.ts # File operation utilities │ ├── db.ts # Database schema (Drizzle) │ ├── routers.ts # tRPC routers │ └── storage.ts # File storage ├── shared/ # Shared types between client/server │ ├── claw-types.ts # Core shared types │ └── types.ts # Additional types ├── drizzle/ # Database migrations ├── package.json ├── vite.config.ts └── tsconfig.json ``` --- ## Tech Stack | Layer | Technology | |-------|-----------| | Frontend | React 18, Vite, TailwindCSS, shadcn/ui | | Backend | Express, tRPC, esbuild | | Database | MySQL/TiDB via Drizzle ORM | | Auth | Manus OAuth (session-based) | | LLM | HuggingFace Router API (OpenAI-compatible) | | Deployment | HuggingFace Spaces (Docker) | | Language | TypeScript throughout | --- ## Getting Started ### Prerequisites - Node.js 22+ - pnpm - MySQL/TiDB database ### Development ```bash cd claw-web pnpm install pnpm dev # Starts both client (Vite) and server (esbuild) ``` ### Build ```bash pnpm build # Builds client (Vite) + server (esbuild) ``` ### Environment Variables | Variable | Description | |----------|-------------| | `DATABASE_URL` | MySQL/TiDB connection string | | `HF_TOKEN` | HuggingFace API token for LLM | | `SESSION_SECRET` | Session encryption key | --- ## Server Runtime Modules ### agent.ts — Main Agent Loop **Original:** `conversation.rs` (Rust) **Parity:** ~95% The core agent loop that: 1. Builds system prompt with `TOOL_DEFINITIONS` + dynamically injected MCP tools 2. Calls LLM API with streaming 3. Processes tool calls from LLM response 4. Executes tools via `executor.ts` 5. Runs pre/post-tool hooks 6. Appends results to conversation 7. Loops until LLM stops calling tools or max iterations reached Key constants: - `MAX_ITERATIONS = Number.MAX_SAFE_INTEGER` (matches Rust `usize::MAX`) - Tools are dynamically merged: `TOOL_DEFINITIONS + mcpTools` ### compact.ts — Context Compaction **Original:** `compact.rs` (Rust) **Parity:** ~99% Full implementation (527 lines) of context window compaction: - `shouldCompact()` — checks if conversation exceeds token threshold - `compactSession()` — summarizes old messages, preserves recent context - Triggered manually via `/compact` slash command ### config.ts — Configuration System **Original:** `config.rs` (Rust) **Parity:** ~90% Loads configuration from multiple sources with deep merge: - `.claw/settings.json` (project-level) - `~/.claw/settings.json` (user-level) - `deepMergeObjects()` — recursive merge for nested configs - `extendUnique()` / `pushUnique()` — deduplicated array merging for hooks - `mergeHooksConfig()` — proper PreToolUse/PostToolUse hook merging ### permissions.ts — Permission Policy **Original:** `permissions.rs` (Rust) **Parity:** ~85% Permission modes (ordered by severity, matching Rust `derive(PartialOrd, Ord)`): ```typescript ReadOnly = 0 // Can only read files WorkspaceWrite = 1 // Can write within workspace DangerFullAccess = 2 // Can execute dangerous operations Prompt = 3 // Must prompt user for approval Allow = 4 // Auto-approve everything ``` ### mcp-client.ts — MCP Server Manager **Original:** `mcp.rs` (Rust) **Parity:** ~80% Model Context Protocol integration: - `McpServerManager` — manages multiple MCP server connections - `connectAndListAllTools()` — discovers tools from all configured servers - `normalizeNameForMcp()` — name normalization (preserves case, handles `claude.ai` prefix) - `callTool()` — executes MCP tool calls via JSON-RPC - Dynamic tool injection into agent's `TOOL_DEFINITIONS` ### sandbox.ts — Container Sandbox Detection **Original:** `sandbox.rs` (Rust) **Parity:** ~85% Detects container environments: - Docker (`.dockerenv`, cgroup) - Podman (`/run/.containerenv`) - Kubernetes (`KUBERNETES_SERVICE_HOST`) - containerd (cgroup) - libpod (cgroup) ### session.ts — Session Serialization **Original:** Session handling in Rust **Parity:** ~90% Validated deserialization with `SessionError` class: - `validateSessionData()` — validates all required fields - `deserializeSession()` — safe JSON parsing with error handling - `serializeSession()` — serialization with validation ### usage.ts — Token/Cost Tracking **Original:** `usage.rs` (Rust) **Parity:** ~85% Tracks API usage: - `UsageTracker` — accumulates token counts and costs - `formatUsd()` — formats costs with 4 decimal places (matches Rust `format!("${:.4}")`) - `summaryLines()` — generates usage summary --- ## Client Components ### Home.tsx — Main Page (~1020 lines) The primary page component containing: - Chat interface with message bubbles - Sidebar with session management - Settings panel - File manager, terminal, task manager panels - Buddy companion pet integration - Plan mode with step visualization - Ask-user dialog for agent questions - Export/import session functionality ### SettingsPanel.tsx — Settings UI Tabs: **Model, Parameters, Permissions, MCP, Costs, Memory** Note: API tab was intentionally removed (built-in HuggingFace Router). ### BuddySprite.tsx — Companion Pet UI Full companion pet with: - Evolution-stage sprites (egg → baby → junior → senior → master → legendary) - Interactive stats panel (XP, happiness, energy, hunger) - Achievement system (17 achievements) - Notification system (level-ups, evolutions, achievements) - Feed and Pet interactions - Rename functionality --- ## Buddy Companion Pet System The buddy system is a **6-module subsystem** matching the original Claude Code architecture: | Module | Lines | Description | |--------|-------|-------------| | `types.ts` | 95 | Full type system: BuddyState, BuddyStats, evolution stages, XP rewards | | `sprites.ts` | 160 | Sprite configs for 6 evolution stages x 10 moods, colors, animations | | `companion.ts` | 250 | State management, XP/leveling, evolution, persistence, time decay | | `prompt.ts` | 210 | Personality messages, stage greetings, 17 achievements, stats formatting | | `useBuddyNotification.tsx` | 140 | React hook: state loading, event handlers, mood calculation, decay timer | | `BuddySprite.tsx` | 300 | Full UI: sprite, speech bubbles, stats panel, achievements, notifications | ### Evolution Stages | Stage | Level Range | Description | |-------|------------|-------------| | Egg | 0-2 | Just hatched, minimal interaction | | Baby | 3-5 | Learning, simple faces | | Junior | 6-10 | Growing, more expressive | | Senior | 11-20 | Experienced, accessories | | Master | 21-50 | Expert, special effects | | Legendary | 51+ | Transcended, full effects | ### XP Rewards | Action | XP | |--------|-----| | Tool call | 5 | | File created | 10 | | File edited | 3 | | Bug fixed | 25 | | Test passed | 15 | | Session completed | 20 | | Streak day | 50 | | First session | 100 | --- ## Tools and Executor `server/tools/executor.ts` implements **30+ tools** (1600+ lines): | Tool | Description | |------|-------------| | `bash` | Shell command execution with sandbox support | | `read_file` | Read file contents with line ranges | | `write_file` | Create/overwrite files | | `edit_file` | Surgical file edits (find/replace) | | `multi_edit` | Multiple edits in one call | | `grep_search` | Regex search across files | | `glob_search` | File path pattern matching | | `list_dir` | Directory listing | | `TodoRead` / `TodoWrite` | Task management | | `NotebookRead` / `NotebookEdit` | Jupyter notebook support | | `Agent` | Sub-agent spawning with presets | | `WebSearch` / `WebFetch` | Web browsing | | `REPL` | Python REPL execution | | `mcp__*` | Dynamic MCP tool routing | ### MCP Tool Routing When the LLM calls a tool with prefix `mcp__`, the executor: 1. Splits the name: `mcp__servername__toolname` 2. Finds the MCP server by name 3. Calls `McpServerManager.callTool(serverName, toolName, args)` 4. Returns the result to the LLM --- ## MCP Integration ### Configuration MCP servers are configured in `.claw/settings.json`: ```json { "mcpServers": { "my-server": { "command": "node", "args": ["./mcp-server.js"], "env": {} } } } ``` ### Dynamic Tool Injection At agent loop start: 1. `initializeMcpFromConfig(workDir)` loads MCP config 2. `connectAndListAllTools()` discovers tools from all servers 3. MCP tools are converted to OpenAI function calling format 4. Merged with static `TOOL_DEFINITIONS` 5. Full tool list sent to LLM --- ## Configuration System ### Config Loading Order 1. `.claw/settings.json` (project-level) 2. `~/.claw/settings.json` (user-level) 3. Database settings (per-session) 4. Environment variables ### Deep Merge Uses `deepMergeObjects()` for recursive merging. Arrays in hooks use `extendUnique()` for deduplication (matching original Rust `extend_unique`). --- ## Permissions System ### Permission Modes ``` ReadOnly (0) < WorkspaceWrite (1) < DangerFullAccess (2) < Prompt (3) < Allow (4) ``` This ordering matches the original Rust `derive(PartialOrd, Ord)` enum ordering. ### Tool Permission Mapping Each tool has a required permission level. The agent checks `modeGte(toolPermission, currentMode)` before executing. --- ## Plugin System ### Plugin Structure ``` .claw-plugins/ └── my-plugin/ ├── .claw-plugin/ │ └── plugin.json # Manifest └── hooks/ ├── pre.sh # Pre-tool hook └── post.sh # Post-tool hook ``` ### Hook Environment Variables Pre-tool hooks receive: - `HOOK_EVENT_NAME` — "PreToolUse" - `HOOK_TOOL_NAME` — tool name - `HOOK_TOOL_INPUT` — tool input (first 10KB) - `HOOK_TOOL_INPUT_JSON` — full JSON input - `HOOK_SESSION_ID` — session identifier - `HOOK_WORKING_DIR` — working directory Post-tool hooks additionally receive: - `HOOK_TOOL_OUTPUT` — tool output (first 10KB) - `HOOK_TOOL_RESULT_IS_ERROR` — "true" or "false" --- ## Deployment ### HuggingFace Spaces The project deploys to HuggingFace Spaces via git push: ```bash git remote add space https://huggingface.co/spaces/drt2221143/claw-web git push space main ``` The Space uses a Docker container with Node.js 22. ### Live URL https://drt2221143-claw-web.hf.space/ --- ## Parity Status with Original ### Overall: ~92% | Module | Parity | Notes | |--------|--------|-------| | agent.ts (conversation.rs) | 95% | Full loop, unlimited iterations, MCP injection | | compact.ts | 99% | Full implementation | | config.ts | 90% | Deep merge + extendUnique for hooks | | permissions.ts | 85% | Correct ordering, authorize logic | | mcp-client.ts | 80% | Full normalize, dynamic injection, callTool | | session.ts | 90% | Validated deserialization | | sandbox.ts | 85% | Full container detection | | remote.ts | 85% | All 8 proxy env keys | | usage.ts | 85% | formatUsd matches original | | executor.ts | 85% | 30+ tools, MCP routing, hook payloads | | lsp-client.ts | 85% | stderr drain, graceful shutdown | | plugins.ts | 70% | Install/execute work, update/uninstall basic | | bootstrap.ts | 100% | Full implementation | | buddy system | 90% | 6/6 modules implemented | ### Not Ported (CLI-specific, not needed for web) - `coordinator mode` — multi-agent CLI coordination - `vim mode` — terminal vim keybindings - `voice mode` — microphone input (CLI-specific) - `auto updater` — self-update (not applicable to web) - `magic docs` — auto-documentation (future enhancement) - `prompt suggestion` — smart suggestions (future enhancement) --- ## Known Issues and TODOs ### High Priority 1. **Duplicate `/context` case** in `chat-endpoint.ts` (line 645 and 2070) — causes build warning 2. **Plugin update/uninstall** — basic stubs, need full implementation 3. **LSP diagnostics enrichment** — LSP works but doesn't enrich agent context ### Medium Priority 4. **Session history/resume** — no conversation resume across page reloads 5. **Cost tracker hooks** — real-time cost tracking not integrated 6. **Agent summary** — no session summary generation 7. **Output styles** — basic implementation, needs loadOutputStylesDir ### Low Priority 8. **OAuth PKCE/refresh** — web app uses session auth, not needed 9. **Sandbox OverlayFS** — mount isolation not enforced 10. **Keybindings** — minimal, original has 14 modules --- ## Contributing ### Code Style - TypeScript strict mode - ESLint + Prettier - Functional components with hooks (React) - tRPC for type-safe API calls ### Adding a New Tool 1. Add tool definition to `TOOL_DEFINITIONS` in `system-prompt.ts` 2. Add case handler in `executor.ts` switch statement 3. Set required permission level 4. Add pre/post hook support if needed ### Adding an MCP Server 1. Configure in `.claw/settings.json` under `mcpServers` 2. Tools are automatically discovered and injected 3. No code changes needed --- *Last updated: April 2026* *Maintained by: drt2221143*