* chore: uppercase PR template (summary, problem, solution) Made-with: Cursor * chore: uppercase PR template (testing, impact) Made-with: Cursor * chore: uppercase PR template (breaking changes, related) Made-with: Cursor * chore: intermediate rename for pull request template path Made-with: Cursor * chore: use uppercase PULL_REQUEST_TEMPLATE.md Made-with: Cursor * docs: point agent docs at PULL_REQUEST_TEMPLATE.md Made-with: Cursor * chore: update pull request and feature issue templates for clarity and consistency - Standardized section headings to title case for uniformity. - Enhanced descriptions for each section to improve guidance for contributors. - Introduced a new feature issue template to streamline feature proposals and documentation requirements. * docs: enhance issue and pull request templates for better guidance - Added a new bug issue template to standardize bug reporting. - Updated the feature issue template to clarify the problem and solution sections. - Revised the pull request template to include a submission checklist for testing and documentation requirements. * chore: comment out E2E macOS workflow steps in test.yml - Temporarily disabled the E2E (macOS / Appium) job in the GitHub Actions workflow by commenting out all related steps for future reference.
19 KiB
OpenHuman
AI-powered assistant for communities — React + Tauri v2 desktop app with a Rust core (JSON-RPC / CLI) and sandboxed QuickJS skills.
This file orients contributors and coding agents. Authoritative narrative architecture: docs/ARCHITECTURE.md. Frontend layout: docs/src/README.md. Tauri shell: docs/src-tauri/README.md.
Repository layout
| 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 entrypoint (src/main.rs) — core_server, openhuman::* domains, skills runtime (QuickJS / rquickjs), MCP routing in the core process |
| Skills registry | 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/) |
Commands in documentation assume the repo root unless noted: yarn dev runs the app workspace.
Skills registry: Skill sources and the bundler live in github.com/tinyhumansai/openhuman-skills. Clone that repository to author or change skills (yarn install, yarn build). The desktop app’s skills catalog defaults to that GitHub slug; override with VITE_SKILLS_GITHUB_REPO (see app/src/utils/config.ts).
Runtime scope
- Shipped product: desktop — Windows, macOS, Linux (see
docs/ARCHITECTURE.md“Platform reach”). - Tauri host (
app/src-tauri): desktop-only (compile_error!for non-desktop targets). Do not add Android/iOS branches insideapp/src-tauri. - Core binary (
openhuman): spawned/staged as a sidecar; the Web UI talks to it over HTTP (core_rpc_relay+core_rpcclient), not by re-implementing domain logic in the shell.
Where logic lives
- Rust (
openhuman/ repo rootsrc/): Business logic and execution—domains, skills runtime, RPC, persistence, and CLI behavior. This is the authoritative place for rules and side effects. - Tauri + React (
app/): Interaction and UX—screens, navigation, input, accessibility, windowing, and bridging to the core. The shell presents and orchestrates; it does not duplicate core business rules.
Commands (from repository root)
# Frontend + Tauri dev (workspace delegates to app/)
yarn dev
# Desktop with Tauri (loads env via scripts/load-dotenv.sh)
yarn tauri dev
# Production UI build (app workspace)
yarn build
# Typecheck / lint / format (app workspace)
yarn typecheck
yarn lint
yarn format
yarn format:check
# Stage openhuman core binary next to Tauri resources (required for core RPC)
cd app && yarn core:stage
# Skills — develop in the GitHub registry repo, then build (see tinyhumansai/openhuman-skills).
# If you keep a local clone path wired in app scripts, you can also run:
yarn workspace openhuman-app skills:build
yarn workspace openhuman-app skills:watch
# Rust — core library + CLI (repo root)
cargo check --manifest-path Cargo.toml
cargo build --manifest-path Cargo.toml --bin openhuman
# Rust — Tauri shell only
cargo check --manifest-path app/src-tauri/Cargo.toml
Tests: Vitest in app/ (yarn test, yarn test:coverage). Rust tests via cargo test at repo root as wired in app/package.json.
Quality: ESLint + Prettier + Husky in the app workspace.
Testing Guide (Unit + E2E)
Unit tests (Vitest)
- Where tests live: co-locate as
*.test.ts/*.test.tsxunderapp/src/**. - Runner/config: Vitest with
app/test/vitest.config.tsand shared setup inapp/src/test/setup.ts. - Run:
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.tsstarts the shared mock server by default onhttp://127.0.0.1:5005.
Key admin endpoints:
GET /__admin/healthPOST /__admin/resetPOST /__admin/behaviorGET /__admin/requests
Run manually:
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
- Helpers:
-
Build + run:
# 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:
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_WORKSPACEredirects 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).
- Rebuild/stage sidecar once per E2E run (
Rust tests with mock backend
Use the shared mock backend runner so Rust unit/integration tests get deterministic API behavior:
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:
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)
Order matters for auth and realtime:
Redux Provider → PersistGate → UserProvider → SocketProvider → AIProvider → SkillProvider → HashRouter → AppRoutes.
There is no TelegramProvider in the current tree; Telegram may appear in UI copy or legacy settings, but MTProto is not an active provider here.
State (app/src/store/)
Redux Toolkit slices include auth, user, socket, ai, skills, team, and related modules. Prefer Redux (and persist where configured) over ad hoc localStorage for app state; see project rules for exceptions.
Services (app/src/services/)
Singleton-style modules include apiClient, socketService, coreRpcClient (HTTP bridge to the core process), and domain api/* clients. There is no mtprotoService in this tree.
MCP (app/src/lib/mcp/)
Transport, validation, and types for JSON-RPC-style messaging over Socket.io — not a large Telegram tool pack. Tooling for agents is driven by the skills system and backend; see agentToolRegistry.ts and core RPC.
Routing (app/src/AppRoutes.tsx)
Hash routes include /, /onboarding, /mnemonic, /home, /intelligence, /skills, /conversations, /invites, /agents, /settings/*, plus DefaultRedirect. No dedicated /login route in AppRoutes (auth flows use the welcome/onboarding paths).
AI configuration
Bundled prompts live under src/openhuman/agent/prompts/ at the repository root (also bundled via app/src-tauri/tauri.conf.json resources). Loaders under app/src/lib/ai/ use ?raw imports, optional remote fetch, and in Tauri ai_get_config / ai_refresh_config for packaged content.
Tauri shell (app/src-tauri/)
Thin desktop host: window management, daemon health bridging, core process lifecycle (core_process, CoreProcessHandle), and JSON-RPC relay to the openhuman sidecar (core_rpc_relay, core_rpc).
Registered IPC commands (see docs/src-tauri/02-commands.md) include greet, write_ai_config_file, ai_get_config, ai_refresh_config, core_rpc_relay, window commands, and OpenHuman service / daemon host helpers (openhuman_*).
Deep link plugin is registered where supported; behavior is platform-specific (see platform notes below).
Rust core (repo root src/)
openhuman/— Domain logic (skills, memory, channels, config, …). RPC controllers live inrpc.rsfiles per domain; useRpcOutcome<T>pattern perAGENTS.md/ internal rules.src/openhuman/module layout: New functionality must live in a dedicated subdirectory (its own folder/module, e.g.openhuman/my_domain/mod.rsplus related files, or a new subfolder under an existing domain). Do not add new standalone*.rsfiles directly atsrc/openhuman/root; place new code in a module directory and declare it frommod.rs(or merge into an existing domain folder).- Controller schema contract: Shared controller metadata types live in
src/core/mod.rs(ControllerSchema,FieldSchema,TypeSchema) and are consumed by adapters (RPC/CLI) in different ways. - Domain schema files: For each domain, define controller schema metadata in a dedicated module inside the domain folder (example:
src/openhuman/cron/schemas.rs) and export from the domainmod.rs. - Light
mod.rsrule: Keep domainmod.rsfiles light and export-focused. Put operational code in sibling files (example:ops.rs,store.rs,schedule.rs,types.rs), then re-export the public API frommod.rs. core_server/— Transport only: Axum/HTTP, JSON-RPC envelope, CLI parsing, dispatch (core_server::dispatch) — no heavy business logic here.- Layering: Implementation in
openhuman::<domain>/, controllers inopenhuman::<domain>/rpc.rs, routes incore_server/.
Skills runtime uses QuickJS (rquickjs) in src/openhuman/skills/ (e.g. qjs_skill_instance.rs, qjs_engine.rs), not V8/deno_core in this repository.
Controller migration checklist
src/openhuman/<domain>/mod.rs: keep export-focused, addmod schemas;and re-export:all_controller_schemas as all_<domain>_controller_schemasall_registered_controllers as all_<domain>_registered_controllers
src/openhuman/<domain>/schemas.rsmust define:schemas(function: &str) -> ControllerSchemaall_controller_schemas() -> Vec<ControllerSchema>all_registered_controllers() -> Vec<RegisteredController>- domain handler fns
fn handle_*(_: Map<String, Value>) -> ControllerFuture
- Handlers should delegate to existing domain
rpc.rsfunctions during migration. - Wire domain exports into
src/core/all.rsfor both declared schemas and registered handlers. - Keep adapters generic: do not add domain-specific logic to
src/core/cli.rsorsrc/core/jsonrpc.rs. - Remove migrated method branches from
src/rpc/dispatch.rsonce registry coverage is in place.
App theme & design system
Design intent: Premium, calm visual language — ocean primary (#4A83DD), sage / amber / coral semantic colors, Inter + Cabinet Grotesk + JetBrains Mono, Tailwind with custom radii/spacing/shadows. Details: docs/DESIGN_GUIDELINES.md.
Git workflow
- GitHub issues on upstream — File and track issues on tinyhumansai/openhuman (Issues), not only a fork’s tracker, unless the workflow explicitly says otherwise.
- GitHub issue templates — Use
.github/ISSUE_TEMPLATE/feature.mdfor new features and.github/ISSUE_TEMPLATE/bug.mdfor bugs; keep the same section structure and fill every required part. AI-authored issues should follow those templates verbatim. - Open pull requests on upstream — Always create PRs against tinyhumansai/openhuman (pull requests), not only a fork’s default remote, unless the workflow explicitly says otherwise.
- Public repo; push to your working branch; PRs target
main. - Use
.github/PULL_REQUEST_TEMPLATE.md; AI-generated PR text should follow its sections and checklist.
Coding philosophy
- Unix-style modules: Prefer individual modules with a single, sharp responsibility—each should do one thing really well. Compose behavior through small, well-named units and clear boundaries instead of monolithic code.
- Tests before the next layer: Ship enough unit tests and coverage for the behavior you are adding or changing before building additional features on top of it. Treat untested code as incomplete; do not accumulate depth on a shaky base.
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.
- Specify against the current codebase — Ground the design in existing domains, controller/registry patterns, and JSON-RPC naming (
openhuman.<namespace>_<function>). Reuse or extend documented flows indocs/ARCHITECTURE.mdand sibling guides; avoid parallel architectures. - Implement in Rust — Add domain logic under
src/openhuman/<domain>/, 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. - JSON-RPC E2E — Add or extend integration-style tests that call the real HTTP JSON-RPC surface (e.g.
tests/json_rpc_e2e.rs, mock backend /scripts/test-rust-with-mock.shas appropriate) so methods, params, and outcomes match what the UI will call. - UI in the Tauri app — Build React screens, state, and
core_rpc_relay/coreRpcClientusage inapp/; keep business rules in the core, not duplicated in the shell. - App unit tests — Cover components, hooks, and clients with Vitest (
yarn test/yarn test:unitinapp/). - App E2E — Add desktop E2E specs where the feature is user-visible (
yarn test:e2e*, isolated workspace — see 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 namespaceddebug/ dev logs (app/) on new flows so sidecar + WebView output is easy to grep; see Feature design workflow. Never log secrets or raw tokens. src/openhuman/: New features go in a folder/module, not new root-levelsrc/openhuman/*.rsfiles (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 --noEmitinapp/;cargo fmt+cargo checkfor changed Rust (Cargo.tomlat root and/orapp/src-tauri/Cargo.tomlas appropriate). - No dynamic imports in app code (static
importonly); use try/catch around Tauri APIs where needed. - Type-only imports:
import typewhere appropriate. - Dual socket / tool sync: If you change realtime protocol, keep frontend (
socketService/ MCP transport) and core socket behavior aligned (seedocs/ARCHITECTURE.mddual-socket section).
Platform notes
- macOS deep links: Often require a built
.appbundle; not onlytauri dev. Seedocs/telegram-login-desktop.mdif applicable. window.__TAURI__: Not assumed at module load; guard Tauri usage accordingly.- Core sidecar: Must be staged/built so
core_rpccan reach theopenhumanbinary (seescripts/stage-core-sidecar.mjs).
Last aligned with monorepo layout (app/ + root src/), QuickJS skills in openhuman_core, skills catalog on GitHub (tinyhumansai/openhuman-skills), and Tauri shell IPC as of repo state.