# 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

```toml
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/`:

```text
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:

```bash
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](/docs/dev-architecture) — how these crates relate.
- [Writing a Custom Node](/docs/dev-custom-node) — working inside `cheng-nodes`.
- [Development Setup](/docs/dev-setup) — getting a build running.
