Architecture Overview
Wayland Core is a Cargo workspace of ~53 crates under crates/. Each crate owns a single domain; dependencies flow strictly downward through four layers. Nothing in the tree except wcore-cli depends on everything else, so individual crates compile and test in isolation.
Crate layers
Section titled “Crate layers”Bottom layer (zero internal deps)
Section titled “Bottom layer (zero internal deps)”| Crate | Purpose |
|---|---|
wcore-types | Provider-neutral data types: LlmRequest, LlmEvent, Message, ContentBlock. Every higher layer speaks this vocabulary. |
wcore-compact | Context compression algorithms: token folding, sanitization, CompactionLevel (Off / Safe / Full). |
Mid layer
Section titled “Mid layer”| Crate | Purpose |
|---|---|
wcore-config | Configuration cascade (WAYLAND_HOME / XDG / project-local .wayland-core.toml), ProviderCompat declarative-quirks table, credential vault, cross-platform shell helpers (shell_command_argv / shell_command). |
wcore-protocol | JSON-Lines host protocol: ProtocolCommand enum (10 inbound commands), ProtocolEvent enum (~25 event types), ToolApprovalManager. |
wcore-plugin-api | Plugin trait, PluginContext, scoped registries. Isolation boundary: plugins have no dependency on wcore-browser, wcore-cua, or wcore-agent. |
wcore-egress | Single outbound-HTTP chokepoint (EgressClient). A clippy.toml disallowed-methods lint bans reqwest::Client::new/builder everywhere else in the workspace so no network call can bypass the egress policy. |
wcore-providers | LlmProvider trait and all provider implementations. |
wcore-pricing | Bundled pricing.toml with Q2-2026 list prices; token accounting types. |
wcore-budget | ExecutionBudget (7-axis tree), per-session and per-user-daily caps, CapWarn (80%) / CapBlock enforcement. |
wcore-tools | ~75 built-in tools registered through bootstrap.rs. Tools absent their required env credentials are not registered at all (the NO-STUBS contract). |
wcore-mcp | MCP client (stdio / SSE / streamable-HTTP) and mcp-serve server. |
wcore-skills | Skill front-matter parsing, variable substitution, shell expansion, conditional activation, per-skill permissions, SkillRouter, SkillWatcher. |
wcore-memory | 5-partition x 3-tier SQLite store, auto-memorize, pluggable embedders, background decay. |
wcore-sandbox | SandboxBackend trait with platform backends: BubblewrapBackend (Linux), SandboxExecBackend (macOS), AppContainerBackend (Windows), DockerBackend (opt-in). Fail-closed default. |
wcore-browser | 18-op ARIA-tree-first browser surface over Camoufox (default), chromiumoxide (opt-in chromium feature), or Browserbase (env-gated). |
wcore-cua | Computer-use actions on macOS (CGEvent), Linux X11 (XTest), Linux Wayland (wlrctl/grim), Windows (UI Automation). First-time-per-app approval gate. |
wcore-permissions | ACL, bearer tokens, learned approval policy. See the status matrix for current wiring state. |
wcore-observability | Trace schema, span sinks, PII scrubber (28 patterns), OTLP exporter (off by default; enable with the otlp cargo feature). |
wcore-safety | Pre-exec content scan, URL safety checks, path validation, OSV dependency check. |
wcore-repomap | Aider-style light symbol extractor and codebase index. No internal wcore-* deps by design. |
wcore-user-model | User preference and expertise backend abstraction (UserModelBackend). LocalBackend ships by default; wcore-honcho-adapter wires an alternative persistent backend. |
wcore-compact | (see bottom layer) |
wcore-eval | Deterministic skill-quality gate: 60-case corpus, precision/recall thresholds, gates GEPA evolution. |
wcore-eval-scenarios | Scenario-level E2E harness: drives the real binary in --json-stream mode against real LLM APIs, asserts outcomes via LLM-as-judge. |
wcore-evolve | GEPA offline evolutionary optimizer: 4 mutators, plateau termination, graveyard, CuratorPort, PromptStore. Runs as a separate binary, not in-session. |
wcore-replay | Session-trace replay and diff for debugging. |
wcore-dispatch | Internal task dispatch primitives used by the agent loop. |
wcore-cron | Cron scheduler: 5-field expressions, 3 target types (slash command / channel message / skill), CLI integration, cronjob LLM tool. |
wcore-acp | Agent Client Protocol: HTTP/SSE + stdio + WebSocket JSON-RPC 2.0, session CRUD, message/send. See the status matrix for completeness notes. |
wcore-channels | Channel trait and shared channel types. |
wcore-channels-registry | Auto-registers channel adapters from ~/.wayland/channels/*.toml. |
wcore-channel-slack | Slack adapter. |
wcore-channel-discord | Discord adapter. |
wcore-channel-telegram | Telegram adapter. |
wcore-channel-signal | Signal adapter. |
wcore-channel-whatsapp | WhatsApp adapter. |
wcore-channel-sms | SMS adapter. |
wcore-channel-email | Email adapter. |
wcore-channel-matrix | Matrix adapter. |
wcore-channel-msteams | MS Teams adapter (send-only; inbound deferred to v0.8.3). |
wcore-channel-imessage | iMessage adapter (macOS only). |
wcore-fixture-harness | Shared test fixture utilities. |
wcore-swarm | Worktree-isolated multi-agent dispatch. 4 topologies: Spawn (5), Swarm (20), Mesh (50), Fleet (100). Consensus and Debate overlays. |
wcore-plugin-subprocess | Subprocess plugin host (JSON-RPC/stdio). |
wcore-plugin-wasm | WASM Component Model plugin host (wasmtime + WASI). |
wcore-honcho-adapter | Bridges UserModelBackend to a Honcho client for persistent cross-device user state. |
Top layer
Section titled “Top layer”| Crate | Purpose |
|---|---|
wcore-agent | The agent engine: AgentEngine::run, session management, tool dispatch, ForgeFlows workflow runner (RON DSL to GraphConfig IR to WorkflowRunner), plan mode, sub-agent spawning, self-evolution drafter, HITL approval. |
wcore-cli | Binary entry point. Three run modes: interactive TUI, one-shot positional prompt, --json-stream headless. 13 top-level subcommands. |
Plugin crates (extend via wcore-plugin-api, no upward deps)
Section titled “Plugin crates (extend via wcore-plugin-api, no upward deps)”| Crate | Purpose |
|---|---|
wayland-ollama | Ollama local-inference provider. Registers via register_providers only. |
wayland-browser | Plugin packaging of wcore-browser via mirror types in wcore-plugin-api. |
wayland-cua | Plugin packaging of wcore-cua via mirror types in wcore-plugin-api. |
wayland-ijfw | IJFW anchor plugin exercising every register_* surface. |
wayland-honcho | Honcho client library used by wcore-honcho-adapter. |
Core trait seams
Section titled “Core trait seams”Four traits define the primary extension boundaries. Provider, channel, tool, and routing implementations are registered by name and resolved at runtime; adding a new variant does not require modifying the engine.
LlmProvider
Section titled “LlmProvider”Defined in wcore-providers. Every provider implementation converts between LlmRequest / LlmEvent (the provider-neutral types from wcore-types) and the wire format of its target API. Provider quirks (field naming, token-count field, schema sanitization, streaming shape) are declared in ProviderCompat rather than as conditionals in engine code. The engine calls provider.complete(request) and never inspects the provider type.
// wcore-types: what the engine seespub struct LlmRequest { /* model, messages, tools, params */ }pub enum LlmEvent { TextDelta, ToolRequest, StreamEnd, /* ... */ }
// ProviderCompat (wcore-config/src/compat.rs:10): declares quirks as datapub struct ProviderCompat { pub max_tokens_field: Option<String>, // "max_tokens" vs "max_completion_tokens" pub sanitize_schema: Option<bool>, // some providers reject unknown schema keys // ~18 more fields}Channel
Section titled “Channel”Defined in wcore-channels. Each of the 10 channel adapter crates implements Channel and is auto-registered at startup from ~/.wayland/channels/*.toml. The engine dispatches outbound messages through the registry by channel name; adding a new adapter is a new crate, not an engine change.
Tool (via wcore-tools and wcore-plugin-api)
Section titled “Tool (via wcore-tools and wcore-plugin-api)”Built-in tools are registered in wcore-agent/src/bootstrap.rs. The NO-STUBS rule applies here: tools whose required environment credentials or system dependencies are absent are not registered. A tool that is registered is expected to be fully functional. Plugins register additional tools through PluginContext::register_tool using the mirror types in wcore-plugin-api, with no dependency on wcore-agent or wcore-tools.
SandboxBackend
Section titled “SandboxBackend”Defined in wcore-sandbox. Platform backends implement SandboxBackend::execute(manifest, command) -> SandboxOutput. The dispatcher in default_for_platform() selects the strongest available backend at spawn time. If no real backend is available and WAYLAND_ALLOW_NO_SANDBOX=1 is not set, the engine refuses execution rather than falling back to unsandboxed host execution.
Core vs. Wayland Desktop boundary
Section titled “Core vs. Wayland Desktop boundary”Wayland Desktop is an Electron application. It embeds Wayland Core as a subprocess and communicates exclusively through the wcore-protocol JSON-Lines protocol (--json-stream). Desktop renders the conversation, approval UI, and sub-agent monitors. The engine does the agent loop, tool dispatch, provider routing, and security enforcement.
The protocol commands include ToolApprove, ToolDeny, ApprovalResume, AddMcpServer, and others. The engine’s contract is complete on its side. One known gap exists in Desktop: WCoreCommand is currently missing the ApprovalResume arm, which means HITL-gated tool calls dispatched from the Desktop GUI can hang until the app-side fix lands. The engine contract itself is correct; the fix is entirely in the Desktop codebase.
This boundary also means Wayland Core is fully usable without Desktop. The same binary runs as a terminal agent, as a headless subprocess behind any host, or as an MCP server.
Dependency rule
Section titled “Dependency rule”Dependencies flow downward. wcore-types has no internal deps. wcore-cli may depend on anything. Plugin crates in the wayland-* namespace may depend on wcore-plugin-api and wcore-types but not on wcore-agent, wcore-tools, wcore-browser, or wcore-cua directly. The build enforces this via build.rs lint checks in wcore-plugin-api. Circular or upward references break the build.