From b4efe3f97847c10f81a6db8c3cfc505457afcf21 Mon Sep 17 00:00:00 2001 From: John Vandenberg Date: Wed, 6 May 2026 06:41:42 +0800 Subject: [PATCH] Add CLAUDE.md --- .mise.toml | 5 ++- CLAUDE.md | 120 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 123 insertions(+), 2 deletions(-) create mode 100644 CLAUDE.md diff --git a/.mise.toml b/.mise.toml index f7a1dd9..0547868 100644 --- a/.mise.toml +++ b/.mise.toml @@ -5,6 +5,7 @@ cargo-binstall = "latest" "cargo:taplo-cli" = "latest" "cargo:wasm-pack" = "latest" "chromedriver" = "146" +claude = "latest" cmake = "latest" codex = "latest" dart = { version = "latest", url = "https://storage.googleapis.com/dart-archive/channels/stable/release/{{ version }}/sdk/dartsdk-{{ os() }}-{{ arch() }}-release.zip", version_expr = 'fromJSON(body).prefixes | filter({ # matches "^channels/stable/release/(\\d+\\.\\d+\\.\\d+)/$" }) | map({split(#, "/")[3]}) | sortVersions()', version_list_url = "https://storage.googleapis.com/storage/v1/b/dart-archive/o?prefix=channels/stable/release/&delimiter=/" } @@ -325,9 +326,9 @@ depends = ["fetch-face1-rclone", "fetch-har-motion1-rclone"] run = "cargo test --workspace" [tasks.test-pyface1] -run = "uv run pytest" dir = "services/ws-modules/pyface1" +run = "uv run pytest" [tasks.test] -depends = ["test-pyface1", "cargo-test"] +depends = ["cargo-test", "test-pyface1"] description = "Run all tests" diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..a34166d --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,120 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Prerequisites + +Install [`mise`](https://mise.jdx.dev/) with shell integration, then configure: + +```bash +mise settings experimental=true +mise settings set cargo.binstall true +mise install +``` + +## Common Commands + +All tasks run through `mise run `. + +| Task | Command | +| ---------------------------------- | ----------------------------- | +| Format all | `mise run fmt` | +| Check all (lint, format, security) | `mise run check` | +| Run all tests | `mise run test` | +| Build all WASM modules | `mise run build-modules` | +| Run Rust tests only | `mise run cargo-test` | +| Run Python tests only | `mise run test-pyface1` | +| Run WebSocket server | `mise run ws-server` | +| Start OpenObserve (Docker) | `mise run o2` | +| Download ONNX models | `mise run download-models` | +| E2E tests (Chrome) | `mise run ws-e2e-chrome` | +| Regenerate verification outputs | `mise run regen-verification` | + +**Rust formatting uses nightly:** `cargo +nightly fmt` + +**Build a single module:** `mise run build-ws--module` (e.g., `build-ws-face-detection-module`) + +## Architecture + +This is a WebSocket-based edge computing framework. + +The server is a hub: it maintains an agent registry, routes messages between agents, provides agents with storage, +and serves node module packages as static files to browsers. + +### Services (`services/`) + +- **ws-server** — Actix-web entry point; wires together the four concerns below. Loads registry from + `registry.yaml` on startup and saves it on shutdown. Run with `mise run ws-server`. +- **ws** (`et-ws-service`) — Agent registry and WebSocket hub. The registry tracks agent state and + queues pending direct messages. Registry is persisted to `registry.yaml`. +- **storage** (`et-storage-service`) — File storage for agents, mounted into the app as configured by `StorageConfig`. +- **modules** (`et-modules-service`) — Scans configured paths for directories containing `package.json`, + then serves those files statically. The root module (default UI) is the package named by `ModulesConfig::root`. +- **ws-wasm-agent** — Browser-side WASM client that connects back to the server over WebSocket. + +### Modules (`services/ws-modules/`) + +Node module packages served as static files by `et-modules-service`. Each module has a `package.json` +with a `main` JS entry point. Built artifacts land in `pkg/`. The browser loads and runs these. +The server only serves them from disk. + +Languages: + +- **Rust → WASM** (wasm-pack): audio1, bluetooth, comm1, data1, face-detection, geolocation, graphics-info, har1, nfc, + sensor1, speech-recognition, video1 +- **Dart → JS**: dart-comm1 +- **Python (Pyodide)**: pydata1, pyface1 +- **C# (.NET WASM)**: dotnet-data1 +- **Java (TeaVM → JS)**: java-data1 +- **Zig → WASM**: zig-data1 + +### Libraries (`libs/`) + +- **edge-toolkit** — Common utilities, config, serialization (shared across services) +- **web** — WASM web helpers (Canvas, MediaStream, WebSocket bindings for browser modules) + +### Utilities (`utilities/`) + +- **cli** (`et-cli`) — Deployment generator: reads scenario YAML, outputs `mise.toml` or `compose.yaml` +- **onnx** — ONNX model utilities +- **module-manifest-to-package-json** — Generates `pkg/package.json` from module metadata. + Reads `pyproject.toml` (Python modules, via `[tool.ws-module]`) + or `Cargo.toml` (Rust modules, via `[package.metadata.ws-module]`). + +### Verification (`verification/`) + +Scenario YAML inputs live in `verification/*/input/`. Expected outputs are checked into `verification/*/output/` +and must stay in sync — `mise run check` will fail if they drift. Regenerate with `mise run regen-verification`. + +## Module Build Details + +- Most Rust modules: `wasm-pack build . --target web` from the module directory +- WASM agent (nightly, MVP target): uses `RUSTFLAGS="-C target-cpu=mvp ..."` and `RUSTUP_TOOLCHAIN=nightly` +- `har1` and `face-detection`: after wasm-pack, merge extra `package.json` fields with `yq` +- Python modules: `uv build --wheel` then `cargo run -p module-manifest-to-package-json` +- Rust modules needing dependency injection: `cargo run -p module-manifest-to-package-json` + merges `[package.metadata.ws-module.dependencies]` from `Cargo.toml` into `pkg/package.json` +- Java: `mvn package` from repo root (uses `pom.xml`) + +## Observability + +The ws-server sends OpenTelemetry traces/logs via OTLP. In development, OpenObserve runs locally: + +```bash +mise run o2 # starts Docker container on :5080 +mise run open-o2 # opens browser UI +``` + +Dev credentials: `root@example.com` / `1234` (set in `[tasks.ws-server.env]`). + +## Testing + +Tests must live in a `tests/` directory or in source files prefixed `test_`. +Do not use inline `#[cfg(test)]` modules. +If a function is private but needs testing, add a `[lib]` target to the crate and export it so `tests/` can reach it. + +## Rust Workspace + +Single Cargo workspace (`Cargo.toml`). +Shared dependency versions are declared in `[workspace.dependencies]`. +Add new deps there, not in individual crate `[dependencies]`.