|
1 | 1 | # Crab Code Architecture |
2 | 2 |
|
3 | | -> Version: v2.1 |
4 | | -> Updated: 2026-04-06 |
| 3 | +> Version: v2.2 |
| 4 | +> Updated: 2026-04-14 |
5 | 5 |
|
6 | 6 | --- |
7 | 7 |
|
|
13 | 13 | |-------|-------|----------------| |
14 | 14 | | **Layer 4** Entry Layer | `crates/cli` `crates/daemon` | CLI entry point (clap), background daemon | |
15 | 15 | | **Layer 3** Engine Layer | `agent` `session` | Multi-Agent orchestration, session management, context compaction | |
16 | | -| **Layer 2** Service Layer | `tools` `mcp` `api` `fs` `process` `plugin` `skill` `telemetry` `tui` | Tool system, MCP protocol stack, multi-model API client, file/process operations, skill system, TUI components | |
| 16 | +| **Layer 2** Service Layer | `tools` `mcp` `api` `fs` `process` `plugin` `skill` `memory` `telemetry` `tui` | Tool system, MCP protocol stack, multi-model API client, file/process operations, skill system, persistent memory, TUI components | |
17 | 17 | | **Layer 1** Foundation Layer | `core` `common` `config` `auth` | Domain model, config hot reload, authentication | |
18 | 18 |
|
19 | 19 | > Dependency direction: upper layers depend on lower layers; reverse dependencies are prohibited. `core` defines the `Tool` trait to avoid circular dependencies between tools/agent. |
|
45 | 45 | │ │in │ │ │ │ │ │ │ │ │ │ |
46 | 46 | │ └┬────┬─┘ └───────┘ └────┘ └──────────┘ └────────────┘ │ |
47 | 47 | │ │ │ │ |
48 | | -│ ┌▼──┐ ┌▼──────┐ ┌──────┐ ┌──────┐ │ |
49 | | -│ │fs │ │process │ │plugin│ │skill │ │ |
50 | | -│ │glob│ │sub- │ │hooks │ │regis-│ │ |
51 | | -│ │grep│ │process│ │WASM │ │try + │ │ |
52 | | -│ │ │ │signal │ │MCP↔ │ │built-│ │ |
53 | | -│ └───┘ └───────┘ └──────┘ └──────┘ │ |
| 48 | +│ ┌▼──┐ ┌▼──────┐ ┌──────┐ ┌──────┐ ┌──────┐ │ |
| 49 | +│ │fs │ │process │ │plugin│ │skill │ │memory│ │ |
| 50 | +│ │glob│ │sub- │ │hooks │ │regis-│ │store │ │ |
| 51 | +│ │grep│ │process│ │WASM │ │try + │ │rank │ │ |
| 52 | +│ │ │ │signal │ │MCP↔ │ │built-│ │age │ │ |
| 53 | +│ └───┘ └───────┘ └──────┘ └──────┘ └──────┘ │ |
54 | 54 | ├───────────────────────────────────────────────────────────────────┤ |
55 | 55 | │ Layer 1: Foundation Layer │ |
56 | 56 | │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ |
|
70 | 70 | | **Entry Layer** entrypoints/ | `cli.tsx` `main.tsx` | `crates/cli` `crates/daemon` | CC uses React/Ink for rendering, Crab uses ratatui | |
71 | 71 | | **Command Layer** commands/ | `query.ts` `QueryEngine.ts` | `agent` + `session` | CC's query loop maps to agent orchestration | |
72 | 72 | | **Tool Layer** tools/ | 52 Tool directories | `tools` + `mcp` | CC mixes tools and MCP in services/; Crab separates them | |
73 | | -| **Service Layer** services/ | `api/` `mcp/` `oauth/` `compact/` | `api` `mcp` `auth` `skill` `plugin` `telemetry` | CC's service layer is flat; Crab splits by responsibility | |
| 73 | +| **Service Layer** services/ | `api/` `mcp/` `oauth/` `compact/` `memdir/` | `api` `mcp` `auth` `skill` `plugin` `memory` `telemetry` | CC's service layer is flat; Crab splits by responsibility. CC's `memdir/` maps to `memory` | |
74 | 74 | | **Foundation Layer** utils/ types/ | `Tool.ts` `context.ts` | `core` `common` `config` | CC scatters types across files; Crab centralizes them in core | |
75 | 75 |
|
76 | 76 | ### Core Design Philosophy |
77 | 77 |
|
78 | 78 | 1. **core has zero I/O** -- Pure data structures and trait definitions, reusable by any frontend (CLI/GUI/WASM) |
79 | 79 | 2. **Message loop driven** -- Everything revolves around the query loop: user input -> API call -> tool execution -> result return |
80 | | -3. **Workspace isolation** -- 16 library crates with orthogonal responsibilities (~190 modules); incremental compilation only triggers on changed parts |
| 80 | +3. **Workspace isolation** -- 17 library crates with orthogonal responsibilities; incremental compilation only triggers on changed parts |
81 | 81 | 4. **Feature flags control dependencies** -- No Bedrock? AWS SDK is not compiled. No WASM? wasmtime is not compiled. |
82 | 82 |
|
83 | 83 | --- |
@@ -2337,20 +2337,21 @@ impl ToolExecutor { |
2337 | 2337 |
|
2338 | 2338 | ### 6.10 `crates/session/` -- Session Management |
2339 | 2339 |
|
2340 | | -**Responsibility**: State management for multi-turn conversations (corresponds to CC `src/services/compact/` + `src/services/SessionMemory/` + `src/services/sessionTranscript/`) |
| 2340 | +**Responsibility**: State management for multi-turn conversations (corresponds to CC `src/services/compact/` + `src/services/SessionMemory/` + `src/services/sessionTranscript/`). Memory system extracted to `crates/memory/`; session re-exports core memory types. |
2341 | 2341 |
|
2342 | 2342 | **Directory Structure** |
2343 | 2343 |
|
2344 | 2344 | ``` |
2345 | 2345 | src/ |
2346 | 2346 | ├── lib.rs |
2347 | | -├── conversation.rs // Conversation state machine, multi-turn management |
2348 | | -├── context.rs // Context window management, auto-compaction trigger |
2349 | | -├── compaction.rs // Message compaction strategies (5 levels: Snip/Microcompact/Summarize/Hybrid/Truncate) |
2350 | | -├── history.rs // Session persistence, recovery, search, export, statistics |
2351 | | -├── memory.rs // Memory system (file persistence) |
2352 | | -├── cost.rs // Token counting, cost tracking |
2353 | | -└── template.rs // Session template + quick recovery |
| 2347 | +├── conversation.rs // Conversation state machine, multi-turn management |
| 2348 | +├── context.rs // Context window management, auto-compaction trigger |
| 2349 | +├── compaction.rs // Message compaction strategies (5 levels: Snip/Microcompact/Summarize/Hybrid/Truncate) |
| 2350 | +├── history.rs // Session persistence, recovery, search, export, statistics |
| 2351 | +├── memory.rs // Re-exports from crab-memory (MemoryStore, MemoryFile, etc.) |
| 2352 | +├── memory_extract.rs // Conversation → memory extraction (heuristic, depends on crab-core::Message) |
| 2353 | +├── cost.rs // Token counting, cost tracking |
| 2354 | +└── template.rs // Session template + quick recovery |
2354 | 2355 | ``` |
2355 | 2356 |
|
2356 | 2357 | **Core Types** |
@@ -3193,7 +3194,42 @@ wasm = ["wasmtime"] |
3193 | 3194 |
|
3194 | 3195 | --- |
3195 | 3196 |
|
3196 | | -### 6.15 `crates/telemetry/` -- Observability |
| 3197 | +### 6.15 `crates/memory/` -- Persistent Memory System |
| 3198 | + |
| 3199 | +**Responsibility**: File-based cross-session memory storage — user preferences, feedback, project context, external references (corresponds to CC `src/memdir/`) |
| 3200 | + |
| 3201 | +**Directory Structure** |
| 3202 | + |
| 3203 | +``` |
| 3204 | +src/ |
| 3205 | +├── lib.rs // Public API re-exports |
| 3206 | +├── types.rs // MemoryType enum, MemoryMetadata, frontmatter parsing |
| 3207 | +├── store.rs // MemoryStore — file CRUD + mtime-sorted scan |
| 3208 | +├── index.rs // MEMORY.md index read/write + truncation (200 lines / 25KB) |
| 3209 | +├── relevance.rs // MemorySelector keyword scoring + MemoryRanker trait |
| 3210 | +├── age.rs // Exponential decay scoring (30-day half-life, SystemTime) |
| 3211 | +├── paths.rs // Per-project / global / team memory directory resolution |
| 3212 | +├── security.rs // Path traversal / symlink / null byte validation |
| 3213 | +├── prompt.rs // MemoryPromptBuilder — system prompt injection |
| 3214 | +├── team.rs // TeamMemoryStore — shared team memory with slugified filenames |
| 3215 | +└── ranker.rs // LlmMemoryRanker — Sonnet sidequery (feature = "mem-ranker") |
| 3216 | +``` |
| 3217 | + |
| 3218 | +**External Dependencies**: `crab-common`, `serde`, `serde_json`, `serde_yml`, `dunce`. Optional: `crab-api`, `crab-core`, `tokio` (with `mem-ranker` feature) |
| 3219 | + |
| 3220 | +**Feature Flags** |
| 3221 | + |
| 3222 | +```toml |
| 3223 | +[features] |
| 3224 | +default = [] |
| 3225 | +mem-ranker = ["dep:crab-api", "dep:crab-core", "dep:tokio"] # LLM-driven memory selection |
| 3226 | +``` |
| 3227 | + |
| 3228 | +**Key Types**: `MemoryType` (User/Feedback/Project/Reference), `MemoryMetadata`, `MemoryFile`, `MemoryStore`, `MemorySelector`, `MemoryRanker` (trait), `LlmMemoryRanker` (impl, feature-gated), `MemoryPromptBuilder`, `TeamMemoryStore` |
| 3229 | + |
| 3230 | +--- |
| 3231 | + |
| 3232 | +### 6.16 `crates/telemetry/` -- Observability |
3197 | 3233 |
|
3198 | 3234 | **Responsibility**: Distributed tracing and metrics collection (corresponds to CC `src/services/analytics/` + `src/services/diagnosticTracking.ts`) |
3199 | 3235 |
|
@@ -3264,7 +3300,7 @@ otlp = [ # OpenTelemetry O |
3264 | 3300 |
|
3265 | 3301 | --- |
3266 | 3302 |
|
3267 | | -### 6.15 `crates/cli/` -- Terminal Entry Point |
| 3303 | +### 6.17 `crates/cli/` -- Terminal Entry Point |
3268 | 3304 |
|
3269 | 3305 | **Responsibility**: An extremely thin binary entry point that only does assembly with no business logic (corresponds to CC `src/entrypoints/cli.tsx`) |
3270 | 3306 |
|
@@ -3402,7 +3438,7 @@ full = ["tui", "crab-plugin/wasm", "crab-api/bedrock", "crab-api/vertex"] |
3402 | 3438 |
|
3403 | 3439 | --- |
3404 | 3440 |
|
3405 | | -### 6.16 `crates/daemon/` -- Background Daemon |
| 3441 | +### 6.18 `crates/daemon/` -- Background Daemon |
3406 | 3442 |
|
3407 | 3443 | **Responsibility**: A persistently running background daemon that manages multiple sessions (corresponds to CC `src/daemon/`) |
3408 | 3444 |
|
@@ -3528,7 +3564,7 @@ async fn main() -> anyhow::Result<()> { |
3528 | 3564 |
|
3529 | 3565 | --- |
3530 | 3566 |
|
3531 | | -### 6.17 Global State Split: AppConfig / AppRuntime |
| 3567 | +### 6.19 Global State Split: AppConfig / AppRuntime |
3532 | 3568 |
|
3533 | 3569 | Global state shared by CLI and Daemon is split into **immutable configuration** and **mutable runtime** halves, |
3534 | 3570 | avoiding a single `Arc<RwLock<AppState>>` where read paths get blocked by write locks. |
|
0 commit comments