Crate Structure
Applies to: ChengOS v0.2.0+ | Last verified: 2026-09-25 | Source:
chengflow/Cargo.toml,chengflow/CLAUDE.md,crates/
The backend is a Cargo workspace. This page is the map: what each crate owns, and the naming traps that cost time when you first go looking for something.
Workspace members
members = [
"crates/cheng-vector", "crates/cheng-common", "crates/cheng-core",
"crates/cheng-storage", "crates/cheng-engine", "crates/cheng-file-ops",
"crates/cheng-code-index","crates/cheng-local-executor",
"crates/cheng-workspace-tools", "crates/cheng-nodes", "crates/cheng-llm",
"crates/cheng-adapters", "benches/cheng-engine-benchmarks",
"crates/cheng-api", "crates/cheng-cli", "crates/cheng-mcp",
"crates/chengctl",
]
default-members = ["crates/cheng-api", "crates/chengctl"]
default-members matters. A bare cargo build or cargo run targets only cheng-api and
chengctl. Use --workspace to build everything, or -p <crate> for one.
The workspace is on edition 2024, with dependency versions pinned centrally in
[workspace.dependencies] — add a dependency there, not in the member crate, when more than one
crate needs it.
The crates
Foundation
| Crate | Owns |
|---|---|
cheng-common | Basic types, error handling, shared utilities, and version.rs — the single release version every component reads |
cheng-core | Domain models, ports (traits), domain services, domain events. No infrastructure dependencies. |
cheng-core is the crate to protect. If something you are adding needs a database connection,
an HTTP client, or a filesystem path, it does not belong there.
Infrastructure
| Crate | Owns |
|---|---|
cheng-storage | PostgreSQL persistence with Diesel; migrations; DieselWorkflowRepository, DieselExecutionRepository; domain ↔ row conversion |
cheng-vector | Vector database abstraction — Qdrant integration, named vectors, BM25 full-text |
cheng-llm | LLM provider abstraction layer, plus the separate decision layer: typed-choice providers (TypeSafe Jev, Laya, the LLM baseline), decision_config and decision_calibration loading, and the DecisionService behind ai/decision_branch |
cheng-adapters | First-party channel adapters (WhatsApp, Telegram, Slack, DingTalk, WeCom, ChengApp), registered in create_default_registry() |
cheng-mcp | MCP integration: a static app-level server at /mcp (MCP_ENABLED=true) plus per-workflow dynamic servers on ephemeral ports |
Execution
| Crate | Owns |
|---|---|
cheng-engine | DAG-based executor with streaming; scheduling; lifecycle |
cheng-nodes | Builtin nodes and the registry |
cheng-runtime | Script execution: LightRuntime (QuickJS / Python sandbox) and HeavyRuntime (Docker), used by the tools/code_* nodes |
cheng-code-index | Tree-sitter code intelligence: indexing, symbols, go-to-definition, find-references, workspace symbols |
cheng-runtime is not a top-level workspace member — it is a path dependency of
cheng-nodes. Looking for it in the members list will not find it.
cheng-code-index is storage-agnostic at its core, with an optional durable PostgreSQL store and
Redis coordination behind cargo features: redis-state, lang-typescript, lang-javascript,
lang-python. Rust support is built in, the other languages are feature-gated.
The shared client-local trio
These three exist because the same operations must run server-side and client-side with identical semantics:
| Crate | Owns |
|---|---|
cheng-file-ops | Pure file-operation core — logic plus JSON-compatible I/O types, no node/engine/API code |
cheng-workspace-tools | The same split for non-file workspace tools: process, shell, git, tests, markdown, preview |
cheng-local-executor | UI-independent client-local execution shell: request classification, read-only policy, mutation/process serialisation, cancellation |
cheng-file-ops is shared by both backends of tools/file_ops_hub — the server-local shims
in cheng-nodes and the client-local executor. cheng-local-executor is reused by every local
client: the cheng CLI, its TUI and headless shells, and the desktop client. That is the whole
point: file semantics cannot drift between "the server did it" and "your machine did it".
Interfaces
| Crate | Owns |
|---|---|
cheng-api | Axum REST API, WebSocket via WsManager, dependency injection in main.rs |
cheng-cli | Terminal workflow client — builds the cheng binary; contains the TUI (tui/, tui.rs) and headless mode |
chengctl | Offline CLI: i18n tooling, and gen-node-docs, which renders the node-reference articles from the live registry and fails when a registered node is missing from log/node-docs-map.toml. No database or server needed |
cheng-cli's lib.rs exposes the API client, event stream, and session cache so integration
tests can drive them; main.rs is a thin composition over that. The binary is named cheng,
not cheng-cli.
Macros
cheng-macros is the crate directory, but the Cargo package is cheng-workflow-macros
and the Rust import path is cheng_workflow_macros. It provides #[derive(Node)] and
#[derive(FieldOrder)].
This is the naming trap that costs the most time. use cheng_macros::Node does not compile.
Archived: the Spatial Design Platform
The spatial crates — cheng-spatial, cheng-plan, cheng-quantity, cheng-scene,
cheng-spatial-conformance — together with their storage, API handlers, and contracts were
removed in commit 909662be. That was a product decision, not a technical failure. The last
green state is preserved at the tag spatial-phase-1-archived, which carries the revival
instructions; the design documents are under docs/archive/spatial-*.md.
Do not build on spatial APIs: nothing in the current tree provides them. The commented
Phase 2-4 placeholders in the workspace members list are notes, not crates. A revival must
re-add its database migration under a current date so it sorts after migrations added since.
Non-Rust directories in chengflow/
| Directory | Contents |
|---|---|
node_skills/ | Per-node usage docs / skill definitions consumed by agent and LLM features, one directory per node type |
skills/ | Higher-level workflow-building skills: workflow-helper, workflow-json-builder, skill-importer |
config/i18n | Node translation bundles |
docs/ | Internal design docs |
node_skills/ and skills/ are LLM-facing assets, not Rust code. Adding a node usually
means adding a node_skills/<node>/ entry too, or the agent will not know how to use it.
Node implementation directories
Under cheng-nodes/src/nodes/builtin/:
agent ai chat document io rag table tools translation ui utils workspace
The category value in the #[node(...)] macro — trigger, control, webui, and so on — is
a logical grouping for the UI and may differ from the directory name. Do not assume
category = "Utils" means the file is in utils/, or vice versa.
Finding your way
| You are looking for | Start at |
|---|---|
| A business rule | cheng-core/src/domain/ |
| An interface definition | cheng-core/src/ports/ |
| A database query | cheng-storage/src/repos/ |
| Scheduling or DAG logic | cheng-engine/src/executor/, .../dag/ |
| A node | cheng-nodes/src/nodes/builtin/<category>/ |
| An HTTP endpoint | cheng-api/src/rest/handlers/, routes in rest/routes.rs |
| A WebSocket message | cheng-api/src/ws/protocol.rs |
| Wiring / DI | cheng-api/src/main.rs |
Docs and packaging
Node reference docs are generated, not hand-written:
cargo run -p chengctl -- gen-node-docs --locale en --dry-run # coverage check only
cargo run -p chengctl -- gen-node-docs --locale zh # write log/docs-content/zh
Adding a node without placing it in log/node-docs-map.toml (or its [skip] table, with a
reason) fails both this command and cargo test -p chengctl. The source headers stamp the
workspace version; override with --applies-to vX.Y.Z.
The Makefile generates API documentation from code — make openapi, make docs, make dev,
make test-api; run make help for the full list. ./build.sh builds the release binary and
packages Docker and hybrid bundles, defaulting to single-user mode and the
x86_64-unknown-linux-musl target.
Next steps
- Architecture Deep Dive — how these crates relate.
- Writing a Custom Node — working inside
cheng-nodes. - Development Setup — getting a build running.