Skip to main content

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:

LayerCratesCountDescription
L0types1Zero-dependency foundation
L1storage, infra2Port definitions, platform abstractions
L2domain, sochdb, channel, security, memory, plugin, observability, cron, media, autoreply, browser, discovery, tunnel13Core modules and adapters
L3channels, agents, providers, skills, runtime, telemetry6Subsystem integrations
L4gateway1Application server (convergence point)
L5acp1Agent Communication Protocol
L6cli, tauri, tui3Leaf binaries
Maximum Parallelism

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

CrateEstimated Compile TimeCumulative
clawdesk-types~2.5s2.5s
clawdesk-storage~1.0s (traits only)3.5s
clawdesk-domain~3.0s6.5s
clawdesk-channels~4.5s11.0s
clawdesk-gateway~6.0s17.0s
clawdesk-acp~2.0s19.0s
clawdesk-cli~1.5s20.5s
Build Optimization

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

MetricValueNotes
Total crates27Workspace members only
Critical path depth6Edges in longest path
Maximum parallelism13Layer 2 width
Average crate size~1,200 LOCExcluding generated code
Largest crateclawdesk-gateway (~4,500 LOC)Convergence point
Smallest crateclawdesk-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
Change Impact

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:

ConfigurationCrates CompiledApprox. Time
Full workspace27~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:

  1. Identify the topological layer — Where does it fit in the DAG?
  2. Minimize dependencies — Depend only on port crates and clawdesk-types
  3. Avoid increasing critical path depth — New crates should branch off, not extend the critical path
  4. Add to workspace Cargo.toml:
[workspace]
members = [
"crates/clawdesk-new-crate",
# ... existing members
]
  1. Update CI graph validation to include the new crate
  2. Document the dependency in this page
Anti-Pattern

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

PropertyValue
Workspace crates27
Critical path depth6
Maximum layer width13 (Layer 2)
Binary leaf nodes3 (cli, tauri, tui)
Port-only crates2 (storage, channel)
Zero-dep foundation1 (types)
Convergence point1 (gateway)

The crate DAG is designed for maximum parallel compilation, clear dependency boundaries, and minimal change propagation from foundational crates to leaf binaries.