Development Setup

Applies to: ChengOS v0.1.0+ | Last verified: 2026-08-12 | Source: chengflow/CLAUDE.md, chengflow-ui/CLAUDE.md, chengflow/.env.example, chengflow/Cargo.toml, root CLAUDE.md

This page is for people who want to build ChengOS itself. If you only want to run it, use Installing ChengOS instead — whole-system installs go through deploy/chengos.sh, not the commands here.

Repository layout

chengos is a meta-workspace, not a single repository. There is a trap in it worth knowing before your first git status.

DirectoryStackRole
chengflow/Rust (Cargo workspace)Core backend: engine, REST + WebSocket API, node system
chengflow-ui/React 18 + TS + VitePrimary frontend: visual editor, runtime page renderer
chengflow-sdk/React 18 + TS + ViteChannel-gateway frontend
chengapp/Rust + React + TauriChat product
deploy/Shell + Docker ComposeDeployment tooling

Product names and directory names diverge. The channel gateway is called chengflow-app in docs and deployment configs but lives in chengflow-sdk/.

Git topology

chengflow/, chengflow-ui/, chengapp/, and chengflow-sdk/ are independent repositories, each with its own .git. The root .gitignore ignores the first three so their source is not uploaded to the public mirror. chengflow-sdk/ is recorded as a bare gitlink with no .gitmodules, so root git status shows m chengflow-sdk whenever its worktree moves — that is expected, not a dirty worktree.

Root-level git status and git diff will not show file-level changes inside any subproject. Run git from inside it:

cd chengflow && git status --short && git diff

The root repo is not empty: it owns deploy/, scripts/, .github/, and the release metadata (VERSION, CHANGELOG.md, README.md, release.sh).

A cross-cutting change — a node's schema, say — means editing Rust in chengflow/ and the corresponding handling in a frontend, and committing in each affected repository separately.

Three related projects are not in this tree at all. chenghub, skill-registry, and skill-package-spec live under /home/cheng/works/chengrouter/community/. They are standalone Rust projects, not members of the chengflow Cargo workspace, and must not depend on cheng-* crates.

Prerequisites

Backend setup

cd chengflow
cp .env.example .env
cargo run -p cheng-api        # listens on :19225

Key settings in .env:

VariablePurpose
DATABASE_URLPostgreSQL connection
TEST_DATABASE_URLSeparate database for tests
DB_HOST / DB_PORT / DB_NAME / DB_USER / DB_PASSWORDConnection details for agent memory nodes
RUN_MIGRATIONStrue runs migrations on startup
CREDENTIAL_MASTER_KEY_164-character hex (32 bytes) for AES-256-GCM credential encryption
REDIS_URL or REDIS_HOST/REDIS_PORTRedis
PUBLIC_BASE_URLPublic HTTPS base used to compute webhook callbacks
CORS_PERMISSIVE / CORS_ALLOWED_ORIGINSCORS
RUST_LOGLog level (info by default)
CHENG_DEMO_MODEFail-closed public demo API — denies saves, executions, and WebSockets

Use TEST_DATABASE_URL for a separate test database. Tests are destructive against whatever they point at.

A bare cargo build or cargo run targets the default-members — cheng-api and chengctl — not the whole workspace. Build everything with cargo build --workspace.

Frontend setup

cd chengflow-ui
pnpm install
pnpm dev                      # :5173, proxies /api and /ws to :3000

The Vite dev server proxies /api, /ws, and related paths to the backend on http://localhost:19225 (see vite.config.ts). The old Express server on :4000 is deprecated.

Environment variables for the frontend must be prefixed VITE_.

pnpm build needs the backend running. It runs gen:pages, which calls the backend to render static pages; without a backend that step fails or skips. Run pnpm gen:pages standalone to regenerate pages.

Database

cd crates/cheng-storage
diesel migration run          # apply
diesel migration revert       # undo the last one
diesel print-schema > src/schema.rs

Or set RUN_MIGRATIONS=true and let the server apply them on startup.

Common commands

Rust (chengflow/, chengapp/):

cargo build                   # default-members only
cargo build -p cheng-core     # one crate
cargo test                    # whole workspace
cargo test -p cheng-engine    # one crate
cargo test test_workflow_creation
cargo test -- --nocapture
cargo check                   # no codegen — the fast loop
cargo fmt
cargo clippy

Frontends (chengflow-ui/, chengflow-sdk/, chengapp/):

pnpm dev / build / preview
pnpm test                     # Vitest, watch mode
pnpm test -- src/path/file.test.ts
pnpm test -- -t "test name"
pnpm test:integration         # Vitest integration config
pnpm test:e2e                 # Playwright
pnpm test:coverage
pnpm lint / lint:fix / format / type-check

chengapp is a mixed workspace whose Rust side excludes the Tauri client (src-tauri), because it links webkit2gtk, which is not present on every dev host. Build it separately:

cargo build --manifest-path src-tauri/Cargo.toml

i18n tooling

Node UI strings are translated offline by chengctl — no database or server required:

cargo run -p chengctl -- missing-i18n [--fail-if-missing]
cargo run -p chengctl -- dump-i18n-keys [--package builtin] [--output keys.json]
cargo run -p chengctl -- translate-missing [--engine baidu|llm] [--dry-run]
cargo run -p chengctl -- merge-i18n --base PATH --patch PATH

Base en-US keys are extracted from the registered builtin nodes; zh-CN lives in an overrides file, with untranslated entries marked [TODO-zh]. Bundles live under config/i18n.

API docs and packaging

make openapi      # generate openapi.yaml from code
make docs         # OpenAPI, Swagger, Redoc, Postman, SDKs, Markdown
make dev          # API server plus docs server
make test-api     # API contract tests
./build.sh        # release binary + Docker / hybrid bundles (--help for options)

Working conventions

Next steps