# 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](/docs/install-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`.

| Directory | Stack | Role |
|---|---|---|
| `chengflow/` | Rust (Cargo workspace) | Core backend: engine, REST + WebSocket API, node system |
| `chengflow-ui/` | React 18 + TS + Vite | Primary frontend: visual editor, runtime page renderer |
| `chengflow-sdk/` | React 18 + TS + Vite | Channel-gateway frontend |
| `chengapp/` | Rust + React + Tauri | Chat product |
| `deploy/` | Shell + Docker Compose | Deployment 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:

```bash
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

- **Rust** — the workspace is on edition 2024, so a recent stable toolchain.
- **Node.js ≥ 18** and **pnpm ≥ 9** for the frontends.
- **PostgreSQL** — the only source of business truth.
- **Redis** — optional for the core, required for agent memory nodes and the scheduler.
- **Qdrant** — optional, needed for RAG.

## Backend setup

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

Key settings in `.env`:

| Variable | Purpose |
|---|---|
| `DATABASE_URL` | PostgreSQL connection |
| `TEST_DATABASE_URL` | Separate database for tests |
| `DB_HOST` / `DB_PORT` / `DB_NAME` / `DB_USER` / `DB_PASSWORD` | Connection details for agent memory nodes |
| `RUN_MIGRATIONS` | `true` runs migrations on startup |
| `CREDENTIAL_MASTER_KEY_1` | 64-character hex (32 bytes) for AES-256-GCM credential encryption |
| `REDIS_URL` or `REDIS_HOST`/`REDIS_PORT` | Redis |
| `PUBLIC_BASE_URL` | Public HTTPS base used to compute webhook callbacks |
| `CORS_PERMISSIVE` / `CORS_ALLOWED_ORIGINS` | CORS |
| `RUST_LOG` | Log level (`info` by default) |
| `CHENG_DEMO_MODE` | Fail-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

```bash
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

```bash
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/`):

```bash
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/`):

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

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

## i18n tooling

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

```bash
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

```bash
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

- **Do not create documentation or `*.md` files unless explicitly asked.** This is a hard rule
  in the backend's own guidance and applies across the workspace.
- Confine a change to one subproject when you can.
- Read the subproject's own `CLAUDE.md` or `README.md` — the root file covers only what spans
  projects.

## Next steps

- [Architecture Deep Dive](/docs/dev-architecture) — how the layers fit together.
- [Crate Structure](/docs/dev-crate-structure) — what lives where.
- [Writing a Custom Node](/docs/dev-custom-node) — the most common first contribution.
