From 7bcf43314a0f2f63d9e8bc17c6375532e4d69e82 Mon Sep 17 00:00:00 2001
From: Steven Enamakel <31011319+senamakel@users.noreply.github.com>
Date: Sun, 29 Mar 2026 18:14:13 -0700
Subject: [PATCH] Improve service lifecycle E2E coverage and align CI workflows
(#62)
* Add JSON-RPC schema definition and HTTP schema endpoint
- Introduced a new `schema.json` file containing detailed definitions for various JSON-RPC methods, including their inputs, outputs, and descriptions.
- Implemented a new HTTP endpoint `/schema` in the core server to serve the JSON-RPC schema, enhancing API documentation and accessibility.
- Updated the core HTTP router to include the new schema route, improving the overall structure and usability of the API.
- Enhanced error handling and response formatting in the server to ensure consistent feedback for schema requests.
* Update TypeScript configuration and refactor core RPC client
- Changed TypeScript target from ES2020 to ESNext and updated library references in `tsconfig.json` for improved compatibility with modern features.
- Refactored `coreRpcClient.ts` to enhance JSON-RPC request handling, including the introduction of legacy method aliases and improved error handling.
- Updated API service methods in `authApi.ts` and `channelConnectionsApi.ts` to utilize the new core RPC client structure, streamlining authentication and channel connection processes.
- Added new utility functions for managing JSON-RPC requests and responses, improving code organization and maintainability.
- Enhanced test coverage for the new RPC client methods and refactored existing tests to align with the updated structure.
* Enhance Tauri configuration and refactor daemon program arguments
- Updated `tauri.conf.json` to include additional macOS infoPlist settings for better application identification and icon management.
- Refactored the `daemon_program_args` function in `common.rs` to improve clarity by renaming the parameter to `_exe`, indicating it is unused. This change enhances code readability and maintainability.
* Refactor Tauri configuration by removing unused macOS infoPlist settings
- Updated `tauri.conf.json` to streamline macOS configuration by removing unnecessary infoPlist entries while retaining essential settings for the application.
- This change enhances clarity and maintainability of the Tauri configuration file.
* Enhance authentication flow and testing documentation
- Introduced a new `isAuthBootstrapComplete` state in the authentication slice to manage the completion of the authentication bootstrap process.
- Updated the `UserProvider` to set the `isAuthBootstrapComplete` state based on the authentication status, improving session restoration logic.
- Modified route components (`DefaultRedirect`, `ProtectedRoute`, `PublicRoute`) to conditionally render based on the `isAuthBootstrapComplete` state, enhancing user experience during the authentication process.
- Added a comprehensive testing guide in `CLAUDE.md`, detailing unit and E2E testing practices, including setup, authoring rules, and a checklist for test coverage.
- Updated the `SettingsHome` component to redirect to the home page instead of the login page upon logout, streamlining user navigation.
- Enhanced the `LocalModelPanel` to track download progress and manage local AI assets more effectively, improving overall functionality.
* Add resolutions for @tauri-apps/api dependency in package.json
- Introduced a resolutions field in package.json to enforce the use of @tauri-apps/api version 2.10.1, ensuring compatibility across workspaces.
- Updated dependencies in app/package.json to include @tauri-apps/api version 2.10.1, aligning with the new resolution.
- Adjusted yarn.lock to reflect the updated version of @tauri-apps/api, enhancing dependency management and consistency.
* Refactor Tauri configuration and enhance E2E build process
- Updated `tauri.conf.json` to remove unused resource paths, streamlining the configuration for better maintainability.
- Modified `wdio.conf.ts` to improve application path resolution for macOS, allowing for multiple bundle base checks to enhance compatibility.
- Refactored `e2e-build.sh` to disable updater artifacts for E2E builds and introduced a conditional cargo clean mechanism, improving build efficiency and clarity.
* Enhance E2E testing setup and documentation
- Updated `CLAUDE.md` to clarify the default behavior of `OPENHUMAN_WORKSPACE` in `e2e-run-spec.sh`, emphasizing automatic creation and cleanup for reproducible E2E runs.
- Modified `e2e-run-spec.sh` to implement automatic temporary workspace creation when `OPENHUMAN_WORKSPACE` is not set, improving usability for debugging and testing.
- Enhanced cleanup logic in `e2e-run-spec.sh` to ensure proper removal of temporary workspaces after tests, contributing to a cleaner testing environment.
* Implement shared mock backend for testing and enhance documentation
- Introduced a shared mock backend for unit and integration tests, allowing for deterministic API behavior across app and Rust tests.
- Updated `CLAUDE.md` to include detailed instructions on using the shared mock backend, including key admin endpoints and manual run commands.
- Modified `package.json` to add scripts for running the mock API server and Rust tests with the mock backend.
- Refactored test setup to utilize the new mock backend, improving test reliability and isolation.
- Removed obsolete MSW handlers and server setup, streamlining the testing framework.
* Enhance authentication state management and testing coverage
- Introduced `isAuthBootstrapComplete` state in the authentication slice to track the completion of the authentication process.
- Updated `ProtectedRoute` and `PublicRoute` components to utilize the new state, improving user experience during authentication.
- Enhanced test cases for `ProtectedRoute` and `PublicRoute` to reflect the updated authentication state structure.
- Added a new end-to-end test for the authentication flow, ensuring proper handling of OAuth tokens and session management.
- Improved mock setup in tests to better simulate authentication scenarios, enhancing test reliability and coverage.
* Enhance README.md with architecture overview and component roles
- Added detailed descriptions of the OpenHuman architecture, highlighting the separation of business logic and UI components.
- Explained the roles of Rust and the UI in the monorepo, including the use of JSON-RPC, QuickJS, Vite, React, and Tauri.
- Documented the structure of controllers and the RPC surface, emphasizing the shared contract for automation and testing.
- Provided links to further documentation for architecture, frontend structure, and Tauri commands.
* Integrate ServiceBlockingGate component and enhance loading states
- Added the `ServiceBlockingGate` component to manage service availability and display appropriate loading screens.
- Updated `DefaultRedirect`, `ProtectedRoute`, and `PublicRoute` components to show a loading indicator while authentication bootstrap is in progress.
- Implemented timeout handling in `UserProvider` for improved authentication state management.
- Introduced tests for `ServiceBlockingGate` to ensure proper rendering and functionality under various service states.
* Implement core RPC URL resolution and default hash route handling
- Added a function to resolve the core RPC URL based on the environment, improving flexibility for Tauri and non-Tauri contexts.
- Introduced a default hash route handler in the main application entry point to ensure proper navigation behavior.
- Updated the core RPC command to expose the resolved RPC URL, enhancing the integration with the frontend.
- Refactored the core RPC client to utilize the new URL resolution logic, ensuring consistent API calls.
* Refactor backend URL usage to API_BASE_URL
- Replaced all instances of BACKEND_URL with API_BASE_URL across various components and services to standardize API endpoint references.
- Updated OAuth provider configurations, settings panels, hooks, and services to ensure consistent API calls.
- Enhanced test setups to reflect the new API_BASE_URL, improving test reliability and alignment with the updated configuration.
* Implement RouteLoadingScreen for improved loading states
- Introduced a new `RouteLoadingScreen` component to provide a consistent loading experience across various routes.
- Updated `DefaultRedirect`, `ProtectedRoute`, and `PublicRoute` components to utilize `RouteLoadingScreen` while waiting for authentication bootstrap completion.
- Enhanced `MiniSidebar` to hide on additional public/setup routes, improving user navigation experience.
- Refactored `UserProvider` to streamline authentication state management by removing unnecessary references.
* Add feature design workflow section to CLAUDE.md
- Introduced a comprehensive workflow for feature design, outlining steps from specification to UI implementation and testing.
- Emphasized the importance of grounding designs in existing codebases and defined planning rules for E2E scenarios.
- Provided detailed instructions for implementing features in Rust, conducting JSON-RPC tests, and building UI components in the Tauri app.
* Refactor backend URL handling and improve OAuth flow
- Replaced static API_BASE_URL references with dynamic backend URL resolution across various components and services, enhancing flexibility for Tauri and non-Tauri environments.
- Updated OAuth provider configurations to utilize the new backend URL logic, ensuring consistent login URL generation.
- Refactored API client and socket service to fetch the backend URL dynamically, improving reliability in different deployment contexts.
- Introduced a new service for resolving the backend URL, streamlining the configuration and enhancing test setups.
* Add debug logging guidelines to CLAUDE.md
- Introduced comprehensive guidelines for implementing development-oriented debug logging in both Rust and the app.
- Emphasized the importance of logging at appropriate levels (`debug`/`trace`) and following existing patterns for consistency.
- Provided instructions on avoiding sensitive information in logs and ensuring terminal output is grep-friendly for easier debugging during development.
* Enhance service management with new mock functionality and E2E tests
- Added a mock service manager to facilitate deterministic service behavior during end-to-end tests, enabling better simulation of service states.
- Introduced new buttons in the `ServiceBlockingGate` component for restarting and uninstalling services, improving user control over service management.
- Implemented a comprehensive E2E test suite for the service connectivity flow, covering installation, starting, stopping, restarting, and uninstalling services.
- Updated package scripts to include a new E2E test for service connectivity, enhancing testing coverage and reliability.
- Refactored service operations to support mock functionality, ensuring consistent behavior across testing and production environments.
* Enhance ServiceBlockingGate with improved logging and periodic health polling
- Introduced periodic health polling in the `ServiceBlockingGate` component to refresh service status every 3 seconds, enhancing responsiveness to service state changes.
- Added detailed logging for various operations, including service status checks and error handling, to improve traceability and debugging.
- Updated E2E tests to include logging steps for better visibility during service connectivity flow tests.
- Refactored error handling to ensure consistent logging of error messages across service operations.
* Refactor E2E testing scripts and enhance CLAUDE.md documentation
- Updated paths in CLAUDE.md to reflect the new location of the E2E run script, ensuring accurate instructions for running tests.
- Removed outdated E2E test scripts from package.json and migrated relevant functionality to app/package.json for better organization.
- Introduced new E2E testing scripts for specific flows (auth, login, payment, etc.) to streamline testing processes and improve modularity.
- Added a script to run all E2E flows sequentially, enhancing test coverage and simplifying execution.
- Improved documentation for E2E testing procedures in CLAUDE.md, providing clearer guidance for developers.
* Refactor imports and enhance code readability
- Removed duplicate import of `ServiceBlockingGate` in `App.tsx` for cleaner code.
- Improved readability in `MiniSidebar.tsx` by formatting conditional statements.
- Reordered imports in `PublicRoute.tsx` for consistency.
- Enhanced formatting in `ServiceBlockingGate.tsx` for better clarity in asynchronous operations.
- Streamlined import statements in various test files and components for improved organization.
- Updated `LocalModelPanel.tsx` to enhance button disable logic readability.
- Refactored CORS headers in `jsonrpc.rs` for better formatting.
* ci: align build and test workflows with app workspace e2e
* ci: align release and typecheck workflows with current workspace
* Enhance ServiceBlockingGate functionality with improved refresh options
- Introduced a new `RefreshOptions` type to customize the behavior of the `refreshStatus` function, allowing for conditional error clearing and status checking.
- Updated the `refreshStatus` function to utilize the new options, enhancing control over service state updates.
- Modified the button click handler to pass the new options, improving user experience during service refresh operations.
- Adjusted state updates to prevent unnecessary re-renders and maintain consistency in service state management.
* Refactor RefreshOptions type for improved clarity in ServiceBlockingGate
- Consolidated the definition of the `RefreshOptions` type into a single line for better readability.
- Maintained existing functionality while enhancing code clarity in the `ServiceBlockingGate` component.
---
.github/workflows/build.yml | 5 +-
.github/workflows/release.yml | 6 -
.github/workflows/test.yml | 9 +-
.github/workflows/typecheck.yml | 8 +-
CLAUDE.md | 136 +-
README.md | 30 +-
app/package.json | 16 +-
app/schema.json | 1940 +++++++++++++++++
{scripts => app/scripts}/e2e-auth.sh | 2 +-
{scripts => app/scripts}/e2e-build.sh | 18 +-
.../scripts}/e2e-crypto-payment.sh | 2 +-
{scripts => app/scripts}/e2e-gmail.sh | 2 +-
{scripts => app/scripts}/e2e-login.sh | 2 +-
{scripts => app/scripts}/e2e-notion.sh | 2 +-
{scripts => app/scripts}/e2e-payment.sh | 2 +-
.../scripts}/e2e-resolve-node-appium.sh | 0
{scripts => app/scripts}/e2e-run-all-flows.sh | 6 +-
{scripts => app/scripts}/e2e-run-spec.sh | 42 +-
{scripts => app/scripts}/e2e-telegram.sh | 2 +-
app/src-tauri/src/commands/core_relay.rs | 5 +
app/src-tauri/src/core_rpc.rs | 4 +
app/src-tauri/src/lib.rs | 94 +-
app/src-tauri/tauri.conf.json | 2 +-
app/src/App.tsx | 32 +-
app/src/AppRoutes.tsx | 3 +-
app/src/components/DefaultRedirect.tsx | 6 +
app/src/components/MiniSidebar.tsx | 9 +-
app/src/components/ProtectedRoute.tsx | 6 +
app/src/components/PublicRoute.tsx | 6 +
app/src/components/RouteLoadingScreen.tsx | 15 +
.../__tests__/ProtectedRoute.test.tsx | 28 +-
.../components/__tests__/PublicRoute.test.tsx | 21 +-
.../components/daemon/ServiceBlockingGate.tsx | 225 ++
.../__tests__/ServiceBlockingGate.test.tsx | 60 +
.../components/oauth/OAuthProviderButton.tsx | 24 +-
app/src/components/oauth/providerConfigs.tsx | 5 -
app/src/components/settings/SettingsHome.tsx | 4 +-
.../settings/panels/LocalModelPanel.tsx | 98 +-
.../settings/panels/TauriCommandsPanel.tsx | 3 +-
app/src/hooks/useConsciousItems.ts | 4 +-
app/src/lib/ai/__tests__/loader.test.ts | 4 +
app/src/main.tsx | 12 +
app/src/pages/Conversations.tsx | 4 +-
app/src/providers/SkillProvider.tsx | 14 +-
app/src/providers/UserProvider.tsx | 50 +-
.../services/api/__tests__/userApi.test.ts | 30 +-
app/src/services/api/authApi.ts | 72 +-
app/src/services/api/channelConnectionsApi.ts | 187 +-
app/src/services/apiClient.ts | 15 +-
app/src/services/backendUrl.ts | 48 +
app/src/services/coreRpcClient.ts | 124 +-
app/src/services/socketService.ts | 13 +-
app/src/store/authSlice.ts | 7 +
app/src/store/index.ts | 67 +-
app/src/test/handlers.ts | 68 -
app/src/test/server.ts | 8 -
app/src/test/setup.ts | 43 +-
app/src/types/modules.d.ts | 1 +
app/src/types/oauth.ts | 1 -
app/src/utils/__tests__/authFlow.e2e.test.tsx | 113 +
.../__tests__/tauriCoreBridge.e2e.test.ts | 32 +-
app/src/utils/config.ts | 7 +-
app/src/utils/desktopDeepLinkListener.ts | 4 +-
app/src/utils/tauriCommands.ts | 59 +-
app/src/utils/tauriSocket.ts | 43 +-
app/test/e2e/mock-server.ts | 761 +------
.../specs/service-connectivity-flow.spec.ts | 221 ++
app/test/vitest.config.ts | 9 +-
app/test/wdio.conf.ts | 22 +-
app/tsconfig.json | 4 +-
docs/TODO.md | 33 +-
package.json | 12 +-
scripts/mock-api-core.mjs | 705 ++++++
scripts/mock-api-server.mjs | 32 +
scripts/test-rust-with-mock.sh | 49 +
src/core/jsonrpc.rs | 129 +-
src/core/mod.rs | 8 +-
src/openhuman/config/ops.rs | 10 +-
src/openhuman/config/schemas.rs | 21 +
src/openhuman/service/common.rs | 16 +-
src/openhuman/service/core.rs | 20 +
src/openhuman/service/mock.rs | 281 +++
src/openhuman/service/mod.rs | 1 +
tests/json_rpc_e2e.rs | 16 +-
yarn.lock | 2 +-
85 files changed, 4825 insertions(+), 1437 deletions(-)
create mode 100644 app/schema.json
rename {scripts => app/scripts}/e2e-auth.sh (67%)
rename {scripts => app/scripts}/e2e-build.sh (60%)
rename {scripts => app/scripts}/e2e-crypto-payment.sh (69%)
rename {scripts => app/scripts}/e2e-gmail.sh (65%)
rename {scripts => app/scripts}/e2e-login.sh (69%)
rename {scripts => app/scripts}/e2e-notion.sh (65%)
rename {scripts => app/scripts}/e2e-payment.sh (69%)
rename {scripts => app/scripts}/e2e-resolve-node-appium.sh (100%)
rename {scripts => app/scripts}/e2e-run-all-flows.sh (86%)
rename {scripts => app/scripts}/e2e-run-spec.sh (64%)
rename {scripts => app/scripts}/e2e-telegram.sh (65%)
create mode 100644 app/src/components/RouteLoadingScreen.tsx
create mode 100644 app/src/components/daemon/ServiceBlockingGate.tsx
create mode 100644 app/src/components/daemon/__tests__/ServiceBlockingGate.test.tsx
create mode 100644 app/src/services/backendUrl.ts
delete mode 100644 app/src/test/handlers.ts
delete mode 100644 app/src/test/server.ts
create mode 100644 app/src/types/modules.d.ts
create mode 100644 app/src/utils/__tests__/authFlow.e2e.test.tsx
create mode 100644 app/test/e2e/specs/service-connectivity-flow.spec.ts
create mode 100644 scripts/mock-api-core.mjs
create mode 100755 scripts/mock-api-server.mjs
create mode 100755 scripts/test-rust-with-mock.sh
create mode 100644 src/openhuman/service/mock.rs
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 555471715..519deb759 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -27,7 +27,7 @@ jobs:
uses: actions/setup-node@v4
with:
node-version: 24.x
- cache: 'yarn'
+ cache: "yarn"
- name: Install Rust stable
uses: dtolnay/rust-toolchain@1.93.0
@@ -69,9 +69,6 @@ jobs:
if: steps.yarn-cache.outputs.cache-hit != 'true'
run: yarn install --frozen-lockfile
- - name: Install skills dependencies
- run: cd skills && yarn install --frozen-lockfile
-
- name: Build sidecar core binary
run: cargo build --manifest-path Cargo.toml --release --target x86_64-unknown-linux-gnu --bin openhuman
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 277cec2d5..359a0de1b 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -275,12 +275,6 @@ jobs:
- name: Install dependencies
run: yarn install --frozen-lockfile
- - name: Install skills dependencies
- run: cd skills && yarn install --frozen-lockfile
-
- - name: Build skills
- run: cd skills && yarn build
-
- name: Define Tauri configuration overrides
id: config-overrides
uses: actions/github-script@v7
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 2a917b474..c68c96601 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -120,9 +120,6 @@ jobs:
- name: Install dependencies
run: yarn install --frozen-lockfile
- - name: Install skills dependencies
- run: cd skills && yarn install --frozen-lockfile
-
- name: Ensure .env exists for E2E build
run: touch app/.env
@@ -132,9 +129,7 @@ jobs:
appium driver install mac2
- name: Build E2E app bundle
- run: yarn test:e2e:build
- env:
- E2E_SKIP_CARGO_CLEAN: "1"
+ run: yarn workspace openhuman-app test:e2e:build
- name: Run all E2E flows
- run: yarn test:e2e:all:flows
+ run: yarn workspace openhuman-app test:e2e:all:flows
diff --git a/.github/workflows/typecheck.yml b/.github/workflows/typecheck.yml
index 54a17c2ee..46e33b277 100644
--- a/.github/workflows/typecheck.yml
+++ b/.github/workflows/typecheck.yml
@@ -26,7 +26,7 @@ jobs:
uses: actions/setup-node@v4
with:
node-version: 24.x
- cache: 'yarn'
+ cache: "yarn"
- name: Cache node modules
id: yarn-cache
@@ -44,16 +44,16 @@ jobs:
run: yarn install --frozen-lockfile
- name: Type check TypeScript files
- run: yarn typecheck
+ run: yarn workspace openhuman-app compile
env:
NODE_ENV: test
- name: Check Prettier formatting
- run: yarn format:check
+ run: yarn workspace openhuman-app format:check
env:
NODE_ENV: test
- name: Run ESLint
- run: yarn lint
+ run: yarn workspace openhuman-app lint
env:
NODE_ENV: test
diff --git a/CLAUDE.md b/CLAUDE.md
index 914ee103a..5557ea98a 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -11,7 +11,7 @@ This file orients contributors and coding agents. Authoritative narrative archit
| Path | Role |
| ----------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`app/`** | Yarn workspace **`openhuman-app`**: Vite + React (`app/src/`), Tauri desktop host (`app/src-tauri/`), Vitest tests |
-| **Repo root `src/`** | Rust library **`openhuman_core`** and **`openhuman`** CLI binary (`src/bin/openhuman.rs`) — `core_server`, `openhuman::*` domains, skills runtime (QuickJS / `rquickjs`), MCP routing in the core process |
+| **Repo root `src/`** | Rust library **`openhuman_core`** and **`openhuman`** CLI binary entrypoint (`src/main.rs`) — `core_server`, `openhuman::*` domains, skills runtime (QuickJS / `rquickjs`), MCP routing in the core process |
| **Skills registry** | **[`tinyhumansai/openhuman-skills`](https://github.com/tinyhumansai/openhuman-skills)** on GitHub — canonical skill packages and TS build; not vendored in this tree (see blurb below). |
| **`Cargo.toml`** (root) | Core crate; `cargo build --bin openhuman` produces the sidecar the UI stages via `app`’s `core:stage` |
| **`docs/`** | Architecture and module guides (numbered pages under `docs/src/`, `docs/src-tauri/`) |
@@ -75,6 +75,122 @@ cargo check --manifest-path app/src-tauri/Cargo.toml
---
+## Testing Guide (Unit + E2E)
+
+### Unit tests (Vitest)
+
+- **Where tests live**: co-locate as `*.test.ts` / `*.test.tsx` under `app/src/**`.
+- **Runner/config**: Vitest with `app/test/vitest.config.ts` and shared setup in `app/src/test/setup.ts`.
+- **Run**:
+
+```bash
+yarn test:unit
+yarn test:coverage
+```
+
+- **Authoring rules**:
+ - Prefer testing behavior over implementation details.
+ - Use existing helpers from `app/src/test/` (`test-utils.tsx`, shared mock backend) before adding new harness code.
+ - Keep tests deterministic: avoid real network calls, time-sensitive flakes, or hidden global state.
+
+### Shared mock backend (app + Rust tests)
+
+- **Core implementation**: `scripts/mock-api-core.mjs`
+- **Standalone server entrypoint**: `scripts/mock-api-server.mjs`
+- **E2E wrapper**: `app/test/e2e/mock-server.ts`
+- **Vitest unit setup**: `app/src/test/setup.ts` starts the shared mock server by default on `http://127.0.0.1:5005`.
+
+Key admin endpoints:
+
+- `GET /__admin/health`
+- `POST /__admin/reset`
+- `POST /__admin/behavior`
+- `GET /__admin/requests`
+
+Run manually:
+
+```bash
+yarn mock:api
+curl -s http://127.0.0.1:18473/__admin/health
+```
+
+### E2E tests (WDIO + Appium mac2)
+
+- **Where specs live**: `app/test/e2e/specs/*.spec.ts`
+- **Shared harness**:
+ - Helpers: `app/test/e2e/helpers/*`
+ - Mock backend: `app/test/e2e/mock-server.ts`
+ - WDIO config: `app/test/wdio.conf.ts`
+
+- **Build + run**:
+
+```bash
+# Build desktop app bundle + stage core sidecar
+yarn test:e2e:build
+
+# Run one spec
+bash app/scripts/e2e-run-spec.sh test/e2e/specs/smoke.spec.ts smoke
+
+# Run all flow specs
+yarn test:e2e:all:flows
+```
+
+- **Authoring rules**:
+ - Ensure each spec is runnable in isolation.
+ - Use helper waits (`waitForAppReady`, `waitForWebView`, etc.) instead of ad hoc long sleeps.
+ - Assert both UI outcomes and backend/mock effects when relevant.
+ - Add failure diagnostics (request logs, accessibility tree dump) for faster debugging by agents.
+
+### Deterministic core-sidecar reset
+
+By default, `app/scripts/e2e-run-spec.sh` creates and cleans a temp `OPENHUMAN_WORKSPACE`
+automatically when the variable is not provided.
+
+If you need a fixed workspace for debugging, provide one explicitly:
+
+```bash
+export OPENHUMAN_WORKSPACE="$(mktemp -d)"
+yarn test:e2e:build
+bash app/scripts/e2e-run-spec.sh test/e2e/specs/smoke.spec.ts smoke
+rm -rf "$OPENHUMAN_WORKSPACE"
+```
+
+- `OPENHUMAN_WORKSPACE` redirects core config + workspace storage away from `~/.openhuman`.
+- Default reset strategy:
+ - Rebuild/stage sidecar once per E2E run (`yarn test:e2e:build`).
+ - Isolate state per test case with a fresh temp workspace (default behavior in `e2e-run-spec.sh`).
+
+### Rust tests with mock backend
+
+Use the shared mock backend runner so Rust unit/integration tests get deterministic API behavior:
+
+```bash
+yarn test:rust
+# or targeted
+bash scripts/test-rust-with-mock.sh --test json_rpc_e2e
+```
+
+Example per-test-case pattern inside a harness script:
+
+```bash
+run_case() {
+ export OPENHUMAN_WORKSPACE="$(mktemp -d)"
+ bash app/scripts/e2e-run-spec.sh "$1" "$2"
+ rm -rf "$OPENHUMAN_WORKSPACE"
+}
+```
+
+### Test authoring checklist
+
+- Add/update unit tests for logic changes before stacking additional features.
+- Add/update E2E coverage for user-visible flows and cross-process integration behavior.
+- Keep new tests independent, deterministic, and debuggable from logs alone.
+- When touching core/sidecar behavior, validate both:
+ - `yarn test:unit`
+ - targeted E2E spec(s) via `app/scripts/e2e-run-spec.sh`
+
+---
+
## Frontend (`app/src/`)
### Provider chain (`app/src/App.tsx`)
@@ -166,8 +282,26 @@ Skills runtime uses **QuickJS** (`rquickjs`) in **`src/openhuman/skills/`** (e.g
---
+## Feature design workflow (new capabilities)
+
+Follow this order so behavior is **specified**, **proven in Rust**, **proven over RPC**, then **surfaced in the UI** with matching tests.
+
+1. **Specify against the current codebase** — Ground the design in **existing** domains, controller/registry patterns, and JSON-RPC naming (`openhuman._`). Reuse or extend documented flows in [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md) and sibling guides; avoid parallel architectures.
+2. **Implement in Rust** — Add domain logic under `src/openhuman//`, wire **schemas + registered handlers** into the shared registry, and land **unit tests** in the crate (`cargo test -p openhuman`, focused modules) until the feature is correct in isolation.
+3. **JSON-RPC E2E** — Add or extend **integration-style tests** that call the real HTTP JSON-RPC surface (e.g. [`tests/json_rpc_e2e.rs`](tests/json_rpc_e2e.rs), mock backend / [`scripts/test-rust-with-mock.sh`](scripts/test-rust-with-mock.sh) as appropriate) so methods, params, and outcomes match what the UI will call.
+4. **UI in the Tauri app** — Build **React** screens, state, and **`core_rpc_relay` / `coreRpcClient`** usage in `app/`; keep **business rules** in the core, not duplicated in the shell.
+5. **App unit tests** — Cover components, hooks, and clients with **Vitest** (`yarn test` / `yarn test:unit` in `app/`).
+6. **App E2E** — Add **desktop E2E** specs where the feature is user-visible (`yarn test:e2e*`, isolated workspace — see [Testing Guide (Unit + E2E)](#testing-guide-unit--e2e)) so the full stack (UI → Tauri → sidecar) behaves as intended.
+
+**Debug logging (throughout)** — Add **lots of development-oriented logging** as you build, not as an afterthought. In **Rust**, use `log` / `tracing` at **`debug`** or **`trace`** on RPC entry and exit, error paths, state transitions, and any branch that is hard to infer from tests alone. In **`app/`**, follow existing patterns (e.g. the **`debug`** npm package with a **namespace** per area) plus **dev-only** detail where useful. Prefer **grep-friendly prefixes** (`[feature]`, domain name, or JSON-RPC method) so terminal output from **sidecar**, **Tauri**, and **WebView** can be correlated during `yarn dev` / `tauri dev`. **Never** log secrets, raw JWTs, API keys, or full PII—redact or omit.
+
+**Planning rule:** When scoping a feature, define the **E2E scenarios (core RPC + app)** up front. Those scenarios should **cover the full intended scope**—happy paths, failure modes, auth or policy gates, and regressions you care about. If a scenario is not testable end-to-end, the spec is incomplete or the cut is too large; split or add harness support first.
+
+---
+
## Key patterns (concise)
+- **Debug logging**: Ship **heavy `debug`/`trace` (Rust)** and **namespaced `debug` / dev logs (`app/`)** on new flows so sidecar + WebView output is easy to grep; see [Feature design workflow](#feature-design-workflow-new-capabilities). Never log secrets or raw tokens.
- **`src/openhuman/`**: New features go in a **folder/module**, not new root-level `src/openhuman/*.rs` files (see Rust core section).
- **File size**: Prefer ≤ ~500 lines per source file; split modules when growing.
- **Pre-merge checks** (when touching code): Prettier, ESLint, `tsc --noEmit` in `app/`; `cargo fmt` + `cargo check` for changed Rust (`Cargo.toml` at root and/or `app/src-tauri/Cargo.toml` as appropriate).
diff --git a/README.md b/README.md
index d1255c5e0..a1ef3f0a8 100644
--- a/README.md
+++ b/README.md
@@ -25,15 +25,23 @@
"The Tet. What a brilliant machine" — Morgan Freeman as he recalls about alien superintelligence in the movie Oblivion