Crate Dependency Graph
ClawDesk's workspace contains 27 crates organized in a directed acyclic graph (DAG). This page documents the full dependency structure, compilation characteristics, and strategies for maintaining build performance.
Full Dependency DAG
Topological Layers
The crates are organized into 7 topological layers (L0–L6). Crates within the same layer can compile in parallel:
| Layer | Crates | Count | Description |
|---|---|---|---|
| L0 | types | 1 | Zero-dependency foundation |
| L1 | storage, infra | 2 | Port definitions, platform abstractions |
| L2 | domain, sochdb, channel, security, memory, plugin, observability, cron, media, autoreply, browser, discovery, tunnel | 13 | Core modules and adapters |
| L3 | channels, agents, providers, skills, runtime, telemetry | 6 | Subsystem integrations |
| L4 | gateway | 1 | Application server (convergence point) |
| L5 | acp | 1 | Agent Communication Protocol |
| L6 | cli, tauri, tui | 3 | Leaf binaries |
Layer 2 contains 13 crates that all compile concurrently. This is where the most parallelism is available. With a 10-core machine, all 13 crates begin compilation as soon as L0 and L1 complete.
Critical Path Analysis
The critical path determines the minimum possible build time, regardless of available CPU cores:
clawdesk-types (L0)
→ clawdesk-storage (L1)
→ clawdesk-domain (L2)
→ clawdesk-channels (L3)
→ clawdesk-gateway (L4)
→ clawdesk-acp (L5)
→ clawdesk-cli (L6)
Critical path depth: 6 edges (7 nodes)
Estimated Critical Path Timing
| Crate | Estimated Compile Time | Cumulative |
|---|---|---|
clawdesk-types | ~2.5s | 2.5s |
clawdesk-storage | ~1.0s (traits only) | 3.5s |
clawdesk-domain | ~3.0s | 6.5s |
clawdesk-channels | ~4.5s | 11.0s |
clawdesk-gateway | ~6.0s | 17.0s |
clawdesk-acp | ~2.0s | 19.0s |
clawdesk-cli | ~1.5s | 20.5s |
The critical path accounts for ~20.5s out of a total ~65s of sequential compile time. With 8+ cores, the wall-clock build time is dominated by this path. Keeping critical-path crates lean directly reduces overall build times.
Compilation Model
Cargo's Parallel Compilation Strategy
Cargo compiles crates in topological order, parallelizing independent crates:
Build Metrics
| Metric | Value | Notes |
|---|---|---|
| Total crates | 27 | Workspace members only |
| Critical path depth | 6 | Edges in longest path |
| Maximum parallelism | 13 | Layer 2 width |
| Average crate size | ~1,200 LOC | Excluding generated code |
| Largest crate | clawdesk-gateway (~4,500 LOC) | Convergence point |
| Smallest crate | clawdesk-storage (~200 LOC) | Trait definitions only |
Dependency Count Analysis
Each crate's direct dependency count within the workspace:
// Dependency fan-in (how many crates depend on this crate)
// Higher fan-in = more impact from changes
clawdesk_types: fan_in = 26 // everything depends on types
clawdesk_storage: fan_in = 8
clawdesk_domain: fan_in = 6
clawdesk_channel: fan_in = 2
clawdesk_security: fan_in = 3
clawdesk_sochdb: fan_in = 3
clawdesk_observability: fan_in = 3
clawdesk_gateway: fan_in = 4
clawdesk_agents: fan_in = 2
clawdesk_acp: fan_in = 2
// All other crates: fan_in ≤ 1
Changes to clawdesk-types trigger recompilation of all 26 downstream crates. Treat this crate as near-frozen. Use feature flags or extension traits in downstream crates instead of modifying clawdesk-types directly.
Graph Invariants
The crate DAG maintains several invariants that are enforced by CI:
1. Acyclicity
The dependency graph must be a DAG. Cargo enforces this at the build level, but we additionally verify it in CI:
# CI check: verify no cycles in workspace
cargo metadata --format-version=1 \
| jq '.resolve.nodes[] | {id: .id, deps: [.deps[].pkg]}' \
| python3 -c "
import json, sys
# Topological sort — exits non-zero on cycle
"
2. No Adapter-to-Adapter Dependencies
Adapter crates must never depend on each other. This rule prevents coupling between concrete implementations:
# FORBIDDEN:
clawdesk-sochdb → clawdesk-channels ✗
clawdesk-channels → clawdesk-sochdb ✗
# ALLOWED:
clawdesk-sochdb → clawdesk-storage ✓ (adapter → port)
clawdesk-channels → clawdesk-channel ✓ (adapter → port)
3. Leaf Binaries Have No Dependents
Binary crates (cli, tauri, tui) are always leaf nodes:
$$ \forall b \in {cli, tauri, tui}: \text{fan_in}(b) = 0 $$
4. Port Crates Have No Adapter Dependencies
Port crates contain only trait definitions and must not depend on any adapter:
$$ \text{deps}(\text{storage}) \cap \text{adapters} = \emptyset $$
Feature Flag Strategy
Feature flags control optional dependencies and reduce compilation scope:
# Cargo.toml (workspace root)
[workspace.features]
default = ["sochdb", "anthropic", "openai"]
# Channel features
slack = ["clawdesk-channels/slack"]
discord = ["clawdesk-channels/discord"]
telegram = ["clawdesk-channels/telegram"]
whatsapp = ["clawdesk-channels/whatsapp"]
matrix = ["clawdesk-channels/matrix"]
irc = ["clawdesk-channels/irc"]
all-channels = ["slack", "discord", "telegram", "whatsapp", "matrix", "irc"]
# Provider features
anthropic = ["clawdesk-providers/anthropic"]
openai = ["clawdesk-providers/openai"]
gemini = ["clawdesk-providers/gemini"]
ollama = ["clawdesk-providers/ollama"]
bedrock = ["clawdesk-providers/bedrock"]
all-providers = ["anthropic", "openai", "gemini", "ollama", "bedrock"]
# Storage features
sochdb = ["clawdesk-sochdb"]
# Desktop features
desktop = ["clawdesk-tauri"]
tui = ["clawdesk-tui"]
Conditional Compilation Impact
Disabling unused features significantly reduces compile time:
| Configuration | Crates Compiled | Approx. Time |
|---|---|---|
| Full workspace | 27 | ~21s |
| Default (SochDB + Anthropic + OpenAI) | 19 | ~16s |
| Minimal (CLI + Ollama only) | 14 | ~12s |
| Library only (no binaries) | 24 | ~18s |
Adding a New Crate
When adding a new crate to the workspace, follow these rules:
- Identify the topological layer — Where does it fit in the DAG?
- Minimize dependencies — Depend only on port crates and
clawdesk-types - Avoid increasing critical path depth — New crates should branch off, not extend the critical path
- Add to workspace
Cargo.toml:
[workspace]
members = [
"crates/clawdesk-new-crate",
# ... existing members
]
- Update CI graph validation to include the new crate
- Document the dependency in this page
Never add a dependency from a Layer 2 crate back to a Layer 3+ crate. This would create a cycle or increase the critical path depth. If you need shared functionality, extract it to a new crate at Layer 1 or 2.
Workspace Configuration
The workspace root Cargo.toml defines shared settings:
[workspace]
resolver = "2"
members = [
"crates/clawdesk-types",
"crates/clawdesk-storage",
"crates/clawdesk-domain",
"crates/clawdesk-sochdb",
"crates/clawdesk-channel",
"crates/clawdesk-channels",
"crates/clawdesk-agents",
"crates/clawdesk-providers",
"crates/clawdesk-gateway",
"crates/clawdesk-cli",
"crates/clawdesk-tauri",
"crates/clawdesk-plugin",
"crates/clawdesk-memory",
"crates/clawdesk-security",
"crates/clawdesk-cron",
"crates/clawdesk-media",
"crates/clawdesk-autoreply",
"crates/clawdesk-infra",
"crates/clawdesk-skills",
"crates/clawdesk-acp",
"crates/clawdesk-tunnel",
"crates/clawdesk-observability",
"crates/clawdesk-telemetry",
"crates/clawdesk-runtime",
"crates/clawdesk-tui",
"crates/clawdesk-browser",
"crates/clawdesk-discovery",
]
[workspace.dependencies]
tokio = { version = "1", features = ["full"] }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
thiserror = "2"
tracing = "0.1"
async-trait = "0.1"
Summary
| Property | Value |
|---|---|
| Workspace crates | 27 |
| Critical path depth | 6 |
| Maximum layer width | 13 (Layer 2) |
| Binary leaf nodes | 3 (cli, tauri, tui) |
| Port-only crates | 2 (storage, channel) |
| Zero-dep foundation | 1 (types) |
| Convergence point | 1 (gateway) |
The crate DAG is designed for maximum parallel compilation, clear dependency boundaries, and minimal change propagation from foundational crates to leaf binaries.