Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,16 @@
**/target/
*.wasm
.env
.env*
.claude/
ui/dist/
*.rs.bk
*.rlib
*.prof*
.idea/
*.log
.DS_Store
Thumbs.db
*.tmp
*.swp
.vscode/
41 changes: 36 additions & 5 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,12 @@ A secure, WASM-sandboxed AI agent runtime written in Rust. The "infrastructure l
cargo check # type-check (fast feedback loop)
cargo build # debug build
cargo build --release # release build (~21MB, LTO + strip)
cargo run -- onboard # first-time setup (secure API key entry)
cargo run -- status # smoke test
cargo run -- gateway --port 7200 # start gateway on loopback (no auth needed)
cargo run -- gateway --bind 0.0.0.0 --token my-secret # non-loopback requires token
cargo run -- plugin load ./path/to/plugin.wasm # load a WASM plugin
cargo test # run tests (none yet)
cargo test # run all tests (134 tests)
cargo clippy # lint (fix all non-dead-code warnings)
cargo fmt # format (canonical style, zero config)
cargo fmt --check # check formatting without modifying
Expand All @@ -27,6 +28,23 @@ RUST_LOG=debug cargo run -- gateway # enable debug logging

Dead-code warnings from `cargo clippy` are expected until modules are wired together. All other clippy warnings should be zero.

### Building the Chat UI (WASM)

```bash
# Prerequisites (one-time)
rustup target add wasm32-unknown-unknown
cargo install trunk

# Build the Leptos frontend
trunk build # dev build (fast, no wasm-opt)
trunk build --release # release build (smaller bundle)

# The output goes to ui/dist/ which is embedded in the server binary via rust-embed.
# After rebuilding the UI, recompile the server: cargo build
```

The Chat UI is a Leptos 0.7 CSR app in `ui/`. It compiles to WASM and is embedded in the server binary. The gateway serves it at `/`.

### Building the echo plugin (WASM)

```bash
Expand All @@ -40,6 +58,8 @@ Plugin crates use `crate-type = ["cdylib"]` and depend on `extism-pdk`.
## Architecture

```
Browser (http://localhost:7200) → ui/ (Leptos WASM, embedded via rust-embed)
↓ WebSocket
Client (WebSocket) → gateway/ (axum, auth, JSON-RPC)
→ router/ (hierarchical session routing)
→ agent/ (LLM streaming: Anthropic + OpenAI SSE)
Expand All @@ -59,8 +79,9 @@ Client (WebSocket) → gateway/ (axum, auth, JSON-RPC)

### Module Relationships

- `main.rs` — CLI entry point (clap). Creates `gateway::Config` and calls `gateway::run()` or `sandbox::load_plugin()`.
- `gateway/server.rs` — Owns `AppState` which holds `SessionRouter` and `Arc<RwLock<PluginHost>>`. Starts axum server, handles WebSocket upgrade, runs auth-then-message-loop per connection.
- `main.rs` — CLI entry point (clap). Handles `onboard` (API key setup via `run_onboard()`), `gateway` (starts server), `plugin` (loads WASM plugins), and `status` commands.
- `gateway/server.rs` — Owns `AppState` which holds `SessionRouter`, `PluginHost`, `SessionStore`, `MemoryEngine`, `ExoclawConfig`, and per-session locks. Starts axum server, handles WebSocket upgrade, runs auth-then-message-loop per connection. Serves embedded UI at `/` via `rust-embed`.
- `secrets.rs` — Credential storage. Stores API keys at `~/.exoclaw/credentials/{provider}.key` with mode 0600. Functions: `store_api_key()`, `load_api_key()`. Provider whitelist prevents path traversal.
- `gateway/protocol.rs` — JSON-RPC dispatch. Accesses `AppState` to query plugins and router. Methods: `ping`, `status`, `chat.send` (stub), `plugin.list`.
- `gateway/auth.rs` — `verify_connect()` parses first WS message for token, compares with `subtle::ConstantTimeEq`. Returns true if no token configured (loopback mode).
- `router/mod.rs` — `SessionRouter` holds `Vec<Binding>` and `HashMap<String, SessionState>`. `resolve()` walks bindings in priority order, creates/updates sessions keyed as `{agent_id}:{channel}:{account}:{peer}`.
Expand All @@ -76,8 +97,11 @@ Client (WebSocket) → gateway/ (axum, auth, JSON-RPC)
- **axum 0.8**: WebSocket `.close()` requires `use futures::SinkExt`.
- **Auth enforcement**: Non-loopback bind requires `--token` or `EXOCLAW_TOKEN` env var. Loopback skips auth entirely (returns true with no token check).
- **Plugin instances**: Created fresh per `call()` invocation for isolation — the `PluginEntry` stores the `Manifest`, not a live `Plugin`.
- **Rust edition 2024**: Both the main crate and echo-plugin use `edition = "2024"`.
- **No tests exist yet**. `dev-dependencies` has `tokio-test` ready.
- **Rust edition 2024**: All workspace crates use `edition = "2024"`.
- **Cargo workspace**: Root crate `exoclaw` (server binary) + `ui/` crate `exoclaw-ui` (Leptos WASM frontend). They share a `Cargo.lock` and `target/` directory.
- **Leptos 0.7 CSR**: The UI crate uses client-side rendering (`features = ["csr"]`). Built with `trunk build` which produces `ui/dist/` (index.html + WASM + JS glue). The server binary embeds these files via `rust-embed`.
- **UI asset embedding**: `rust-embed` embeds `ui/dist/` at compile time. After changing UI code, rebuild with `trunk build` then `cargo build` to re-embed.
- **Credential storage**: API keys stored at `~/.exoclaw/credentials/{provider}.key` (mode 0600). Resolution: env var > credential file > None. Config file never contains the key.

## Design Decisions

Expand All @@ -102,3 +126,10 @@ See `specs/001-core-runtime/` for the full feature specification:
- `data-model.md` — Entity schemas and relationships
- `contracts/jsonrpc-spec.md` — WebSocket JSON-RPC protocol
- `quickstart.md` — Getting started guide

## Active Technologies
- Rust 2024 edition, Leptos 0.7 CSR + axum 0.8, gloo-net (WASM WebSocket client), pulldown-cmark (WASM markdown), rpassword 7, rust-embed (static asset embedding)
- Filesystem only — `~/.exoclaw/credentials/` for keys, `~/.exoclaw/config.toml` for config

## Recent Changes
- 002-onboard-chat-ui: Added Leptos 0.7 CSR chat UI (trunk + rust-embed), onboarding CLI, gloo-net WebSocket client, pulldown-cmark markdown rendering, 14 integration tests
Loading