mirror of
https://github.com/tinyhumansai/openhuman.git
synced 2026-07-28 05:12:33 +00:00
650 lines
45 KiB
Markdown
650 lines
45 KiB
Markdown
# OpenHuman
|
||
|
||
**AI assistant for communities — React + Tauri v2 desktop app with a Rust core (JSON-RPC / CLI) embedded in-process.**
|
||
|
||
This file orients contributors and coding agents. Authoritative narrative architecture: [`gitbooks/developing/architecture.md`](gitbooks/developing/architecture.md). Frontend layout: [`gitbooks/developing/architecture/frontend.md`](gitbooks/developing/architecture/frontend.md). Tauri shell: [`gitbooks/developing/architecture/tauri-shell.md`](gitbooks/developing/architecture/tauri-shell.md).
|
||
|
||
---
|
||
|
||
## Repository layout
|
||
|
||
| Path | Role |
|
||
| ----------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||
| **`app/`** | pnpm workspace **`openhuman-app`** (v0.53.45): Vite + React (`app/src/`), Tauri desktop host (`app/src-tauri/`), Vitest tests |
|
||
| **Repo root `src/`** | Rust library crate **`openhuman`** (lib name) with **`openhuman-core`** CLI binary entrypoint (`src/main.rs`) — `src/core/` (transport: HTTP/JSON-RPC, CLI, dispatch, auth, event bus), `src/openhuman/*` domains. The QuickJS skills runtime has been removed; `src/openhuman/skills/` is metadata-only now. |
|
||
| **Skills registry** | **[`tinyhumansai/openhuman-skills`](https://github.com/tinyhumansai/openhuman-skills)** on GitHub — canonical skill packages and TS build; not vendored in this tree. |
|
||
| **`Cargo.toml`** (root) | Core crate; `cargo build --bin openhuman-core` produces the CLI binary. Helper binaries: `slack-backfill`, `gmail-backfill-3d` in `src/bin/`. |
|
||
| **`docs/`** | Architecture and deep-internal references |
|
||
| **`gitbooks/developing/`** | Public contributor docs — frontend, Tauri shell, testing, release, agent harness, CEF, observability |
|
||
|
||
Commands in documentation assume the **repo root** unless noted: `pnpm dev` runs Vite-only inside the `app` workspace; `pnpm dev:app` runs the full Tauri desktop dev (CEF runtime).
|
||
|
||
**Skills registry:** Skill sources and the bundler live in **[github.com/tinyhumansai/openhuman-skills](https://github.com/tinyhumansai/openhuman-skills)**. The desktop app's skills catalog defaults to that GitHub slug; override with `VITE_SKILLS_GITHUB_REPO` (see [`app/src/utils/config.ts`](app/src/utils/config.ts)). Note: since the QuickJS runtime was removed, the desktop app no longer *executes* skill packages — it only discovers, installs metadata, and renders catalog entries. Skill execution surfaces are being rebuilt; check the current domain modules before assuming a skill can run end-to-end.
|
||
|
||
---
|
||
|
||
## Runtime scope
|
||
|
||
- **Shipped product**: desktop — Windows, macOS, Linux (see [`gitbooks/developing/architecture.md`](gitbooks/developing/architecture.md) "Platform reach").
|
||
- **Tauri host** (`app/src-tauri`): **desktop-only**. Do not add Android/iOS branches.
|
||
- **Core runs in-process** as a tokio task inside the Tauri host (sidecar removed in PR #1061). The host owns its lifetime via `core_process::CoreProcessHandle` in `app/src-tauri/src/core_process.rs`. Frontend RPC still goes over HTTP to `http://127.0.0.1:<port>/rpc` authenticated with a per-launch hex bearer in `OPENHUMAN_CORE_TOKEN`; the Tauri command `core_rpc_token` exposes it to the renderer. Set `OPENHUMAN_CORE_REUSE_EXISTING=1` to attach to an externally-started `openhuman-core` process for debugging.
|
||
|
||
**Where logic lives**
|
||
|
||
- **Rust (`openhuman` / repo root `src/`)**: **Business logic and execution**—domains, RPC, persistence, CLI behavior. Authoritative.
|
||
- **Tauri + React (`app/`)**: **Interaction and UX**—screens, navigation, input, accessibility, windowing, and bridging to the in-process core. The shell presents and orchestrates; it does not duplicate core business rules.
|
||
|
||
---
|
||
|
||
## Commands (from repository root)
|
||
|
||
```bash
|
||
# Vite dev only (no Tauri host)
|
||
pnpm dev
|
||
|
||
# Full desktop with Tauri/CEF (loads env via scripts/load-dotenv.sh)
|
||
pnpm dev:app
|
||
|
||
# Production UI build (app workspace)
|
||
pnpm build
|
||
|
||
# Typecheck / lint / format
|
||
pnpm typecheck # alias for `pnpm compile` (tsc --noEmit)
|
||
pnpm lint
|
||
pnpm format # Prettier + cargo fmt
|
||
pnpm format:check
|
||
|
||
# `pnpm core:stage` is a no-op — sidecar removed in PR #1061; core is in-process.
|
||
|
||
# Skills — author / build in the registry repo (tinyhumansai/openhuman-skills).
|
||
# There are no `skills:build` / `skills:watch` scripts in this repo's app workspace.
|
||
|
||
# Rust — core library + CLI (repo root)
|
||
cargo check --manifest-path Cargo.toml
|
||
cargo build --manifest-path Cargo.toml --bin openhuman-core
|
||
|
||
# Rust — Tauri shell only
|
||
cargo check --manifest-path app/src-tauri/Cargo.toml
|
||
pnpm rust:check # same as above
|
||
|
||
# whisper-rs / llama.cpp on macOS Tahoe (Apple Silicon) fail with `-mcpu=native`.
|
||
# Workaround for `cargo check`/`cargo test`:
|
||
GGML_NATIVE=OFF cargo check --manifest-path Cargo.toml
|
||
```
|
||
|
||
**Tests**: Vitest in `app/` (`pnpm test`, `pnpm test:coverage`); Rust via `pnpm test:rust` (runs `scripts/test-rust-with-mock.sh`).
|
||
|
||
**Quality**: ESLint + Prettier + Husky in the `app` workspace. Pre-push hook runs `pnpm rust:check`. Use `--no-verify` only for unrelated pre-existing breakage and call it out in the PR body.
|
||
|
||
### Codex web / Linear-launched PR checklist
|
||
|
||
Before opening AI-authored PRs from Codex web sessions or Linear-launched implementation agents, follow [`docs/agent-workflows/codex-pr-checklist.md`](docs/agent-workflows/codex-pr-checklist.md).
|
||
|
||
This checklist is required for remote agents because OpenHuman has several merge gates that are easy to miss in partial environments: Prettier, Rust formatting, TypeScript typecheck, focused Vitest coverage, controller dispatch parity, and Tauri vendored dependency availability. If a command cannot run in the remote environment, the PR body must report the exact blocked command and error instead of claiming validation passed.
|
||
|
||
### Agent debug runners (`scripts/debug/`)
|
||
|
||
Use these wrappers instead of invoking Vitest / WDIO / cargo directly when iterating — they keep stdout summary-sized and tee full output to `target/debug-logs/<kind>-<suffix>-<timestamp>.log`. Add `--verbose` to also stream raw output. See [`scripts/debug/README.md`](scripts/debug/README.md).
|
||
|
||
```bash
|
||
# Vitest
|
||
pnpm debug unit # full suite
|
||
pnpm debug unit src/components/Foo.test.tsx # one file (positional pattern)
|
||
pnpm debug unit -t "renders empty state" # filter by test name
|
||
pnpm debug unit Foo -t "renders empty" --verbose
|
||
|
||
# WDIO E2E (one spec at a time)
|
||
pnpm debug e2e test/e2e/specs/smoke.spec.ts
|
||
pnpm debug e2e test/e2e/specs/cron-jobs-flow.spec.ts cron-jobs --verbose
|
||
|
||
# cargo tests (delegates to scripts/test-rust-with-mock.sh)
|
||
pnpm debug rust
|
||
pnpm debug rust json_rpc_e2e
|
||
|
||
# Inspect saved logs
|
||
pnpm debug logs # list 50 most recent
|
||
pnpm debug logs last # print most recent (last 400 lines)
|
||
pnpm debug logs unit # most recent matching prefix "unit"
|
||
pnpm debug logs last --tail 100
|
||
```
|
||
|
||
Files: `scripts/debug/{cli,unit,e2e,rust,logs,lib}.sh`. Entry point: `pnpm debug` (`scripts/debug/cli.sh`).
|
||
|
||
### Coverage requirement (merge gate)
|
||
|
||
PRs must meet **≥ 80% coverage on changed lines**. Enforced by [`.github/workflows/coverage.yml`](.github/workflows/coverage.yml) via `diff-cover` over merged Vitest + `cargo-llvm-cov` (core + Tauri shell) lcov outputs. Below the threshold the PR will not merge. Run `pnpm test:coverage` and `pnpm test:rust` locally; add tests for new/changed lines (happy path + at least one failure / edge case).
|
||
|
||
---
|
||
|
||
## Configuration
|
||
|
||
Environment variables are documented in two `.env.example` files:
|
||
|
||
- **[`.env.example`](.env.example)** (repo root) — Rust core, Tauri shell, backend URL, logging, proxy, storage, web search, local AI binary overrides. Loaded via `source scripts/load-dotenv.sh`.
|
||
- **[`app/.env.example`](app/.env.example)** — Frontend `VITE_*` vars (core RPC URL, backend URL, Sentry DSN, skills repo, dev helpers). Copy to `app/.env.local` for local overrides.
|
||
|
||
**Frontend config** is centralized in [`app/src/utils/config.ts`](app/src/utils/config.ts). All `VITE_*` env vars should be read there and re-exported — do not read `import.meta.env` directly in other files.
|
||
|
||
**Rust config** uses a TOML-based `Config` struct (`src/openhuman/config/schema/types.rs`) with env var overrides applied in `src/openhuman/config/schema/load.rs`. Env vars override config file values at runtime (e.g. `OPENHUMAN_API_URL` overrides `config.api_url`).
|
||
|
||
---
|
||
|
||
## 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
|
||
pnpm test:unit
|
||
pnpm 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
|
||
pnpm mock:api
|
||
curl -s http://127.0.0.1:18473/__admin/health
|
||
```
|
||
|
||
### E2E tests (WDIO — dual platform)
|
||
|
||
Full guide: [`gitbooks/developing/e2e-testing.md`](gitbooks/developing/e2e-testing.md).
|
||
|
||
Two automation backends:
|
||
- **Linux (CI default)**: `tauri-driver` (WebDriver, port 4444) — drives the debug binary directly
|
||
- **macOS (local dev)**: Appium Mac2 (XCUITest, port 4723) — drives the `.app` bundle
|
||
|
||
- **Where specs live**: `app/test/e2e/specs/*.spec.ts`
|
||
- **Shared harness**:
|
||
- Platform detection: `app/test/e2e/helpers/platform.ts`
|
||
- Element helpers: `app/test/e2e/helpers/element-helpers.ts`
|
||
- Deep link helpers: `app/test/e2e/helpers/deep-link-helpers.ts`
|
||
- App lifecycle: `app/test/e2e/helpers/app-helpers.ts`
|
||
- Mock backend: `app/test/e2e/mock-server.ts`
|
||
- WDIO config: `app/test/wdio.conf.ts` (auto-detects platform)
|
||
|
||
- **Build + run**:
|
||
|
||
```bash
|
||
# Build app + stage core sidecar (detects macOS vs Linux automatically)
|
||
pnpm test:e2e:build
|
||
|
||
# Run one spec
|
||
bash app/scripts/e2e-run-spec.sh test/e2e/specs/smoke.spec.ts smoke
|
||
|
||
# Run all flow specs
|
||
pnpm test:e2e:all:flows
|
||
|
||
# Docker on macOS (run Linux E2E locally)
|
||
docker compose -f e2e/docker-compose.yml run --rm e2e
|
||
```
|
||
|
||
- **Authoring rules**:
|
||
- Ensure each spec is runnable in isolation.
|
||
- Use helpers from `element-helpers.ts` — never use raw `XCUIElementType*` selectors in specs.
|
||
- Use `clickNativeButton()`, `hasAppChrome()`, `waitForWebView()`, `clickToggle()` for cross-platform element interaction.
|
||
- Assert both UI outcomes and backend/mock effects when relevant.
|
||
- Add failure diagnostics (request logs, `dumpAccessibilityTree()`) 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)"
|
||
pnpm 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 (`pnpm 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
|
||
pnpm 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"
|
||
}
|
||
```
|
||
|
||
- **Rust test file naming**: when extracting Rust tests out of an implementation file, prefer a sibling `*_test.rs` file wired in with `#[cfg(test)] #[path = "..._test.rs"] mod tests;`. Do not create ad hoc `_test/` or `_tests/` directories for single-module Rust tests unless a broader multi-file test fixture truly requires a directory.
|
||
|
||
### 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:
|
||
- `pnpm 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:
|
||
|
||
`Sentry.ErrorBoundary` → `Redux Provider` → `PersistGate` (with `PersistRehydrationScreen`) → `BootCheckGate` → **`CoreStateProvider`** → **`SocketProvider`** → **`ChatRuntimeProvider`** → `HashRouter` → `CommandProvider` → `ServiceBlockingGate` → `AppShell` (`AppRoutes` + `BottomTabBar` + `AppWalkthrough` + `MascotFrameProducer`).
|
||
|
||
`CoreStateProvider` owns auth: session tokens are NOT in redux-persist; they live in the in-process core and are fetched via `fetchCoreAppSnapshot()` RPC. There is no `UserProvider`, `AIProvider`, `SkillProvider`, or `TelegramProvider`.
|
||
|
||
### State (`app/src/store/`)
|
||
|
||
Redux Toolkit slices: `accounts`, `channelConnections`, `chatRuntime`, `coreMode`, `deepLinkAuth`, `mascot`, `notification`, `providerSurface`, `socket` (+ `socketSelectors`), `thread`. Plus `userScopedStorage` for per-user persistence keys. Prefer Redux (and redux-persist where configured) over ad hoc `localStorage` for app state. Documented exception: ephemeral UI state like upsell-banner dismiss flags use `localStorage` with the `openhuman:upsell:` prefix.
|
||
|
||
### Services (`app/src/services/`)
|
||
|
||
Singleton-style modules: `apiClient`, `socketService`, `coreRpcClient`, `coreCommandClient`, `chatService`, `analytics`, `notificationService`, `webviewAccountService`, `daemonHealthService`, `meetCallService`, `memorySyncService`, `bootCheckService`, `walletApi`, plus domain `api/*` clients. Always call the in-process core via `invoke('core_rpc_relay', ...)` — never raw `fetch()` (CORS preflight) or `callCoreRpc()` for service-status calls (socket may not be connected yet).
|
||
|
||
### MCP (`app/src/lib/mcp/`)
|
||
|
||
Transport, validation, and types for JSON-RPC-style messaging over Socket.io. Tooling for agents is driven by the **skills** catalog metadata + backend tool registry; see `agentToolRegistry.ts` and core RPC. (Skill execution itself moved out-of-process when the QuickJS runtime was removed.)
|
||
|
||
### Routing (`app/src/AppRoutes.tsx`, HashRouter)
|
||
|
||
`/` (Welcome, public), `/onboarding/*`, `/home`, `/human`, `/intelligence`, `/skills`, `/chat` (unified agent + connected web apps — replaces the old `/conversations` and `/accounts` routes), `/channels`, `/invites`, `/notifications`, `/rewards`, `/webhooks` → redirect to `/settings/webhooks-triggers`, `/settings/*`. Default `*` → `DefaultRedirect`. There is **no** `/login`, **no** `/mnemonic` (Recovery Phrase moved to Settings panel), **no** `/agents`, **no** `/conversations`.
|
||
|
||
### 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. Top-level modules: `core_process`, `core_rpc`, `cdp`, `cef_preflight`, `cef_profile`, `dictation_hotkeys`, `file_logging`, `mascot_native_window`, `native_notifications`, `notification_settings`, `process_kill`, `process_recovery`, `screen_capture`, `window_state`, plus per-provider scanners (`discord_scanner`, `gmessages_scanner`, `imessage_scanner`, `meet_scanner`, `slack_scanner`, `telegram_scanner`, `whatsapp_scanner`), `meet_audio` / `meet_call` / `meet_video`, `fake_camera`, `webview_accounts`, `webview_apis`.
|
||
|
||
**Core lifecycle**: `core_process::CoreProcessHandle` spawns the in-process JSON-RPC server and authenticates inbound RPC with a hex bearer (`OPENHUMAN_CORE_TOKEN`). Stale-listener policy (#1130): on conflict the handle probes `GET /`, decides if the listener is an OpenHuman core, then `kill_pid_term` → `kill_pid_force` with PID revalidation guarding against PID reuse. `restart_core_process` / `start_core_process` Tauri commands let the frontend cycle it for updates.
|
||
|
||
Registered IPC commands (see [`gitbooks/developing/architecture/tauri-shell.md`](gitbooks/developing/architecture/tauri-shell.md)) include `greet`, `write_ai_config_file`, `ai_get_config`, `ai_refresh_config`, `core_rpc_relay`, `core_rpc_token`, `start_core_process`, `restart_core_process`, window commands, and `openhuman_*` daemon helpers.
|
||
|
||
Deep link plugin is registered where supported; behavior is platform-specific (see platform notes below).
|
||
|
||
---
|
||
|
||
## Rust core (repo root `src/`)
|
||
|
||
- **`src/openhuman/`** — Domain logic. Current domains: `about_app`, `accessibility`, `agent`, `app_state`, `approval`, `autocomplete`, `billing`, `channels`, `composio`, `config`, `context`, `cost`, `credentials`, `cron`, `doctor`, `embeddings`, `encryption`, `health`, `heartbeat`, `integrations`, `learning`, `local_ai`, `meet`, `meet_agent`, `memory`, `migration`, `node_runtime`, `notifications`, `overlay`, `people`, `prompt_injection`, `provider_surfaces`, `providers`, `redirect_links`, `referral`, `routing`, `scheduler_gate`, `screen_intelligence`, `security`, `service`, `skills`, `socket`, `subconscious`, `team`, `text_input`, `threads`, `tokenjuice`, `tool_timeout`, `tools`, `tree_summarizer`, `update`, `voice`, `wallet`, `webhooks`, `webview_accounts`, `webview_apis`, `webview_notifications`. RPC controllers in per-domain `rpc.rs`; use **`RpcOutcome<T>`** pattern (see "RPC Controller Pattern" below).
|
||
- **`src/openhuman/` module layout**: **New** functionality must live in a **dedicated subdirectory** (e.g. `openhuman/my_domain/mod.rs` plus related files, or a new subfolder under an existing domain). Do **not** add new standalone `*.rs` files directly at `src/openhuman/` root (`dev_paths.rs` and `util.rs` are grandfathered).
|
||
- **Controller schema contract**: Shared controller metadata types live in `src/core/types.rs` / `src/core/mod.rs` (`ControllerSchema`, `FieldSchema`, `TypeSchema`) and are consumed by adapters (RPC/CLI).
|
||
- **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 domain `mod.rs`.
|
||
- **Controller-only exposure rule**: Expose domain functionality to **CLI and JSON-RPC through the controller registry** (`schemas.rs` + registered handlers wired into `src/core/all.rs`). Do **not** add domain-specific branches in `src/core/cli.rs` or `src/core/jsonrpc.rs`.
|
||
- **Light `mod.rs` rule**: Keep domain `mod.rs` files light and export-focused. Put operational code in sibling files (`ops.rs`, `store.rs`, `schedule.rs`, `types.rs`, `bus.rs`).
|
||
- **`src/core/`** — Transport only: Axum/HTTP, JSON-RPC envelope, CLI parsing, **dispatch** (`src/core/dispatch.rs`), auth, observability, event bus. **No** heavy business logic here. (Older docs that say `core_server` mean this directory; there is no `src/core_server/`.)
|
||
- **Layering**: Implementation in `openhuman::<domain>/`, controllers in `openhuman::<domain>/rpc.rs`, routes/dispatch in `src/core/`.
|
||
|
||
The previous QuickJS / `rquickjs` skills runtime has been removed. `src/openhuman/skills/` now contains metadata helpers only (`ops_create`, `ops_discover`, `ops_install`, `ops_parse`, `inject`, `schemas`, `types`) — its `mod.rs` and `types.rs` carry the marker comment "Legacy … retained after QuickJS runtime removal." Do not assume the runtime can execute a `.skill` package end-to-end; check what `ops_install` and the current agent tool path actually do before planning a feature that needs it.
|
||
|
||
### Controller migration checklist
|
||
|
||
- `src/openhuman/<domain>/mod.rs`: keep export-focused, add `mod schemas;` and re-export:
|
||
- `all_controller_schemas as all_<domain>_controller_schemas`
|
||
- `all_registered_controllers as all_<domain>_registered_controllers`
|
||
- `src/openhuman/<domain>/schemas.rs` must define:
|
||
- `schemas(function: &str) -> ControllerSchema`
|
||
- `all_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.rs` functions during migration.
|
||
- Wire domain exports into `src/core/all.rs` for both declared schemas and registered handlers.
|
||
- Keep adapters generic: do not add domain-specific logic to `src/core/cli.rs` or `src/core/jsonrpc.rs`.
|
||
- Remove migrated method branches from `src/rpc/dispatch.rs` once registry coverage is in place.
|
||
|
||
### Event bus (`src/core/event_bus/`)
|
||
|
||
A typed pub/sub event bus for **decoupled cross-module communication** plus a **native, in-process typed request/response** surface. Both are singletons — one instance each for the whole application. Do **not** construct `EventBus` or `NativeRegistry` directly; use the module-level functions.
|
||
|
||
**When to use which surface:**
|
||
|
||
- **Broadcast events** (`publish_global` / `subscribe_global`) — fire-and-forget notification. One publisher, many subscribers, no return value. Use when a module needs to _announce_ something happened and other modules may react independently.
|
||
- **Native request/response** (`register_native_global` / `request_native_global`) — one-to-one typed Rust dispatch keyed by a method string. **Zero serialization**: trait objects (`Arc<dyn Provider>`), streaming channels (`mpsc::Sender<T>`), oneshot senders, and anything else `Send + 'static` all pass through unchanged. Use when a module needs a typed return value from another module in-process. This is **internal-only** — anything that needs to be callable over JSON-RPC should register against `src/core/all.rs` instead.
|
||
|
||
**Core types** (all in `src/core/event_bus/`):
|
||
|
||
| Type | File | Purpose |
|
||
|------|------|---------|
|
||
| `DomainEvent` | `events.rs` | `#[non_exhaustive]` enum — all cross-module events live here, grouped by domain |
|
||
| `EventBus` | `bus.rs` | Singleton backed by `tokio::sync::broadcast`. Construction is `pub(crate)` — tests only |
|
||
| `NativeRegistry` / `NativeRequestError` | `native_request.rs` | In-process typed request/response registry keyed by method name. Rust types only — passes trait objects, `mpsc::Sender`, and `oneshot::Sender` through without serialization |
|
||
| `EventHandler` | `subscriber.rs` | Async trait with optional `domains()` filter for selective subscription |
|
||
| `SubscriptionHandle` | `subscriber.rs` | RAII handle — subscriber task is cancelled on drop |
|
||
| `TracingSubscriber` | `tracing.rs` | Built-in debug logger for all events (registered at startup) |
|
||
|
||
**Singleton API** (all modules use these — never hold or pass `EventBus` / `NativeRegistry` instances):
|
||
|
||
| Function | Purpose |
|
||
|----------|---------|
|
||
| `event_bus::init_global(capacity)` | Initialize both singletons (broadcast bus + native registry) at startup (once) |
|
||
| `event_bus::publish_global(event)` | Publish a broadcast event from anywhere (no-op if not yet initialized) |
|
||
| `event_bus::subscribe_global(handler)` | Subscribe to broadcast events from anywhere (returns `None` if not yet initialized) |
|
||
| `event_bus::register_native_global(method, handler)` | Register a typed native request handler for a method name — called at startup by each domain's `bus.rs` |
|
||
| `event_bus::request_native_global(method, req)` | Dispatch a typed native request to the registered handler — zero serialization |
|
||
| `event_bus::global()` / `event_bus::native_registry()` | Get the underlying singleton for advanced use |
|
||
|
||
**Domains:** `agent`, `memory`, `channel`, `cron`, `skill`, `tool`, `webhook`, `system`. See `events.rs` for the full variant list — events carry rich payloads so subscribers have everything they need.
|
||
|
||
**Domain subscriber files** — each domain owns its `bus.rs` with `EventHandler` impls:
|
||
- `cron/bus.rs` — `CronDeliverySubscriber` (delivers job output to channels)
|
||
- `webhooks/bus.rs` — `WebhookRequestSubscriber` (routes incoming requests to skills, emits responses via socket)
|
||
- `channels/bus.rs` — `ChannelInboundSubscriber` (runs agent loop for inbound socket messages)
|
||
- `skills/bus.rs` — stub for future subscribers
|
||
|
||
**Adding events for a new domain:**
|
||
|
||
1. Add variants to `DomainEvent` in `events.rs` (prefix with domain name, e.g. `BillingInvoiceCreated { ... }`).
|
||
2. Add the domain string to the `domain()` match arm.
|
||
3. Create a `bus.rs` file **inside your domain module** (e.g. `src/openhuman/billing/bus.rs`) for subscriber implementations — each domain owns its handlers.
|
||
4. Register subscribers in startup (e.g. `channels/runtime/startup.rs`) via the singleton.
|
||
5. Publish events with `event_bus::publish_global(DomainEvent::YourEvent { ... })`.
|
||
|
||
**Example — publishing:**
|
||
```rust
|
||
use crate::core::event_bus::{publish_global, DomainEvent};
|
||
|
||
publish_global(DomainEvent::CronDeliveryRequested {
|
||
job_id: job.id.clone(),
|
||
channel: "telegram".into(),
|
||
target: "chat-123".into(),
|
||
output: "Job completed".into(),
|
||
});
|
||
```
|
||
|
||
**Example — subscribing (trait-based, in `<domain>/bus.rs`):**
|
||
```rust
|
||
use crate::core::event_bus::{DomainEvent, EventHandler};
|
||
use async_trait::async_trait;
|
||
|
||
pub struct MyDomainSubscriber { /* dependencies */ }
|
||
|
||
#[async_trait]
|
||
impl EventHandler for MyDomainSubscriber {
|
||
fn name(&self) -> &str { "my_domain::handler" }
|
||
fn domains(&self) -> Option<&[&str]> { Some(&["cron"]) } // filter by domain
|
||
async fn handle(&self, event: &DomainEvent) {
|
||
if let DomainEvent::CronJobCompleted { job_id, success } = event {
|
||
// react to the event
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
**Convention:** Name the handler struct `<Purpose>Subscriber` (e.g. `CronDeliverySubscriber`) and the `name()` return value `"<domain>::<purpose>"` for grep-friendly tracing output.
|
||
|
||
**Adding a native request handler for a new domain:**
|
||
|
||
1. Define the **request and response types** in the domain (e.g. `src/openhuman/billing/bus.rs`). Use owned fields, `Arc`s, and channels — not borrows. Types only need `Send + 'static`, not `Serialize`.
|
||
2. Register the handler at startup from the same `bus.rs`, keyed by a stable method name prefixed with the domain (e.g. `"billing.charge_invoice"`).
|
||
3. Callers import the request/response types from the domain's public surface and dispatch via `request_native_global`.
|
||
4. Method name convention: `"<domain>.<verb>"` — same naming scheme as JSON-RPC method roots for consistency, but these are **not** exposed over JSON-RPC.
|
||
|
||
**Example — native request (typed request/response, in `<domain>/bus.rs`):**
|
||
```rust
|
||
use crate::core::event_bus::{register_native_global, request_native_global};
|
||
use std::sync::Arc;
|
||
use tokio::sync::mpsc;
|
||
|
||
// Request carries non-serializable state directly — trait objects and
|
||
// streaming channels all pass through unchanged.
|
||
pub struct BillingChargeRequest {
|
||
pub provider: Arc<dyn BillingProvider>,
|
||
pub amount_cents: u64,
|
||
pub progress_tx: Option<mpsc::Sender<String>>,
|
||
}
|
||
pub struct BillingChargeResponse {
|
||
pub charge_id: String,
|
||
}
|
||
|
||
// At startup:
|
||
pub async fn register_billing_handlers() {
|
||
register_native_global::<BillingChargeRequest, BillingChargeResponse, _, _>(
|
||
"billing.charge",
|
||
|req| async move {
|
||
let id = req.provider.charge(req.amount_cents).await
|
||
.map_err(|e| e.to_string())?;
|
||
Ok(BillingChargeResponse { charge_id: id })
|
||
},
|
||
).await;
|
||
}
|
||
|
||
// From another module:
|
||
let resp: BillingChargeResponse = request_native_global(
|
||
"billing.charge",
|
||
BillingChargeRequest { provider, amount_cents: 500, progress_tx: None },
|
||
).await?;
|
||
```
|
||
|
||
**Tests:** override production handlers by calling `register_native_global` again for the same method before exercising the code under test — the most recent registration wins. For full isolation, construct a fresh `NativeRegistry` directly via `NativeRegistry::new()` and use its `register` / `request` methods.
|
||
|
||
---
|
||
|
||
## 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. Implementation tokens live in [`app/tailwind.config.js`](app/tailwind.config.js).
|
||
|
||
## Desktop shell (Tauri) vs application code
|
||
|
||
In the parent **OpenHuman** desktop app, **Tauri / Rust is a delivery vehicle**: windowing, process lifecycle, IPC to the core sidecar, and other host concerns. **Keep as much UI behavior and product logic as practical in TypeScript/React** (`app/`). Avoid growing Rust in the shell for flows that belong in the web layer unless there is a hard platform or security reason.
|
||
|
||
## Git workflow
|
||
|
||
- **Never write code on `main`.** Before making any code changes, fork a new branch off the latest `main` (`git fetch upstream && git checkout -b <branch> upstream/main`). All work happens on that feature branch; `main` stays clean and only advances via merged PRs.
|
||
- **GitHub issues on upstream** — File and track issues on **[tinyhumansai/openhuman](https://github.com/tinyhumansai/openhuman/)** ([Issues](https://github.com/tinyhumansai/openhuman/issues)), not only a fork’s tracker, unless the workflow explicitly says otherwise.
|
||
- **GitHub issue templates** — Use **[`.github/ISSUE_TEMPLATE/feature.md`](.github/ISSUE_TEMPLATE/feature.md)** for new features and **[`.github/ISSUE_TEMPLATE/bug.md`](.github/ISSUE_TEMPLATE/bug.md)** for 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](https://github.com/tinyhumansai/openhuman)** ([pull requests](https://github.com/tinyhumansai/openhuman/pulls)), not only a fork’s default remote, unless the workflow explicitly says otherwise.
|
||
- **Public repo**; push to your working branch; PRs target **`main`**.
|
||
- **Agent branch rule** — If an agent starts work while checked out on `main`, it should create its own descriptive working branch before committing or pushing. Do not leave agent-authored commits on local `main`; move the pending work onto the new branch and ship from there.
|
||
- Use [`.github/PULL_REQUEST_TEMPLATE.md`](.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.
|
||
- **Documentation with code**: New or changed behavior must ship with matching documentation. At minimum, add concise rustdoc / code comments where the flow is not obvious, and update `AGENTS.md`, architecture docs, or feature docs when repository rules or user-visible behavior change.
|
||
|
||
---
|
||
|
||
## Debug logging rule (must follow)
|
||
|
||
- **Default to verbose diagnostics on new/changed flows**: Add substantial, development-oriented logs while implementing features or fixes so issues are easy to trace end-to-end.
|
||
- **Log critical checkpoints**: Include logs at entry/exit points, branch decisions, external calls, retries/timeouts, state transitions, and error handling paths.
|
||
- **Use structured, grep-friendly context**: Prefer stable prefixes (for example `[domain]`, `[rpc]`, `[ui-flow]`) and include correlation fields such as request IDs, method names, and entity IDs when available.
|
||
- **Platform conventions**: In Rust, use `log` / `tracing` at `debug` or `trace`; in `app/`, use namespaced `debug` logs and dev-only detail as needed.
|
||
- **Keep logs safe**: Never log secrets or sensitive payloads (API keys, JWTs, credentials, full PII). Redact or omit sensitive fields.
|
||
- **Treat debuggability as a deliverable**: Changes lacking sufficient logging for diagnosis are incomplete and should be updated before handoff.
|
||
|
||
---
|
||
|
||
## 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.<namespace>_<function>`). Reuse or extend documented flows in [`gitbooks/developing/architecture.md`](gitbooks/developing/architecture.md) and sibling guides; avoid parallel architectures.
|
||
2. **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.
|
||
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** (`pnpm test` / `pnpm test:unit` in `app/`).
|
||
6. **App E2E** — Add **desktop E2E** specs where the feature is user-visible (`pnpm test:e2e*`, isolated workspace — see [Testing Guide (Unit + E2E)](#testing-guide-unit--e2e)) so the full stack (UI → Tauri → sidecar) behaves as intended.
|
||
|
||
**Capability catalog** — When a change adds, removes, renames, relocates, or materially changes a user-facing feature, update **`src/openhuman/about_app/`** in the same work so the runtime capability catalog remains the source of truth for what the app can do.
|
||
|
||
**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 `pnpm 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).
|
||
- **No dynamic imports** in production **`app/src`** code — use **static** `import` / `import type` at the top of the module. Do **not** use `import()` (async dynamic import), `React.lazy(() => import(...))`, or `await import('…')` to load app modules, Tauri APIs, or RPC clients. **Why:** predictable chunk graph, simpler static analysis, fewer surprises in Tauri + Vite, and easier code review. **If a module must not run at load time** (e.g. heavy optional path), use a static import and **guard the call site** with `try/catch` or an explicit runtime check instead of deferring module load via dynamic import. **Exceptions:** Vitest harness patterns (`vi.importActual`, dynamic imports **only** inside `*.test.ts` / `__tests__` / `test/setup.ts` when required by the runner); ambient `typeof import('…')` in `.d.ts`; config files (e.g. `tailwind.config.js` JSDoc).- **Type-only imports**: `import type` where appropriate.
|
||
- **Dual socket / tool sync**: If you change realtime protocol, keep **frontend** (`socketService` / MCP transport) and **core** socket behavior aligned (see [`gitbooks/developing/architecture.md`](gitbooks/developing/architecture.md) dual-socket section).
|
||
|
||
---
|
||
|
||
## Platform notes
|
||
|
||
- **macOS deep links**: Often require a built **`.app`** bundle; not only `tauri dev`.
|
||
- **`window.__TAURI__`**: Not assumed at module load; use `isTauri()` (from `app/src/services/webviewAccountService.ts`) or wrap `invoke(...)` in `try/catch`.
|
||
- **Core is in-process**: `core_rpc` reaches `http://127.0.0.1:<port>/rpc` (default port `7788`) authenticated with `OPENHUMAN_CORE_TOKEN`. `scripts/stage-core-sidecar.mjs` no longer exists; `pnpm core:stage` is a no-op echo (sidecar removed in PR #1061). For standalone debugging: `./target/debug/openhuman-core serve` writes its token to `{workspace}/core.token` (default `~/.openhuman-staging/core.token` under `OPENHUMAN_APP_ENV=staging`); public endpoints `GET /health`, `GET /schema`, `GET /events` need no auth.
|
||
|
||
---
|
||
|
||
_Last aligned with monorepo layout (`app/` + root `src/`), in-process core (no sidecar), QuickJS removed, skills catalog on GitHub (`tinyhumansai/openhuman-skills`), and Tauri shell IPC as of `openhuman-app` v0.53.45 / repo `main`._
|
||
|
||
---
|
||
|
||
## Cursor Cloud specific instructions
|
||
|
||
### Environment overview
|
||
|
||
Two services run independently for development:
|
||
|
||
| Service | Start command | Port | Notes |
|
||
|---------|--------------|------|-------|
|
||
| **Vite dev server** | `pnpm dev` (from repo root) | 1420 | React frontend with HMR |
|
||
| **Core JSON-RPC server** | `./target/debug/openhuman-core serve` | 7788 | Rust core, writes bearer token to `~/.openhuman-staging/core.token` |
|
||
|
||
The app connects to a **remote staging backend** at `https://staging-api.tinyhumans.ai` — there is no local backend to run.
|
||
|
||
### Running the core server standalone
|
||
|
||
The core generates a bearer token at startup written to `{workspace_dir}/core.token` (default `~/.openhuman-staging/core.token` when `OPENHUMAN_APP_ENV=staging`). Read that file for authenticated RPC calls:
|
||
|
||
```bash
|
||
TOKEN=$(cat ~/.openhuman-staging/core.token)
|
||
curl http://localhost:7788/rpc -X POST \
|
||
-H 'Content-Type: application/json' \
|
||
-H "Authorization: Bearer $TOKEN" \
|
||
-d '{"jsonrpc":"2.0","method":"core.ping","params":{},"id":1}'
|
||
```
|
||
|
||
Public endpoints (no token needed): `GET /health`, `GET /schema`, `GET /events`.
|
||
|
||
### Linux build dependencies (non-obvious)
|
||
|
||
Compiling the Rust core on Linux requires these system packages beyond the basics:
|
||
`libasound2-dev libxi-dev libxtst-dev libxdo-dev libudev-dev libssl-dev clang cmake pkg-config libstdc++-14-dev`
|
||
|
||
The `libstdc++-14-dev` package is needed because clang selects GCC 14 headers; without it, whisper-rs-sys fails with `fatal error: 'array' file not found`. A symlink may also be needed: `ln -sf /usr/lib/gcc/x86_64-linux-gnu/13/libstdc++.so /usr/lib/x86_64-linux-gnu/libstdc++.so`.
|
||
|
||
### Quick reference for common dev commands
|
||
|
||
All commands are documented in `CLAUDE.md` and `AGENTS.md` above. The most-used subset:
|
||
|
||
- **Lint**: `pnpm lint` (ESLint, 0 errors expected; warnings are acceptable)
|
||
- **Typecheck**: `pnpm typecheck` (`tsc --noEmit`)
|
||
- **Unit tests**: `pnpm test` (Vitest, runs 1000+ tests)
|
||
- **Rust check**: `cargo check --manifest-path Cargo.toml`
|
||
- **Rust tests**: `cargo test --lib` (5600+ tests)
|
||
- **Format check**: `pnpm format:check`
|
||
|
||
### Running the Tauri desktop app on Linux cloud VMs
|
||
|
||
The full desktop app can be built and run on headless Linux VMs with:
|
||
|
||
```bash
|
||
export CEF_PATH="$HOME/Library/Caches/tauri-cef"
|
||
export LD_LIBRARY_PATH="$CEF_PATH/146.0.9/cef_linux_x86_64:$LD_LIBRARY_PATH"
|
||
source scripts/load-dotenv.sh
|
||
cargo tauri dev -- -- --no-sandbox
|
||
```
|
||
|
||
Key requirements:
|
||
- `--no-sandbox` is required because Chromium refuses to run as root without it.
|
||
- `LD_LIBRARY_PATH` must include the CEF distribution directory so `libcef.so` is found at runtime.
|
||
- The vendored CEF-aware `cargo-tauri` must be installed first via `bash scripts/ensure-tauri-cli.sh`.
|
||
- First build downloads ~300MB CEF binary and compiles ~900 crates; subsequent builds are incremental.
|
||
- GTK/cairo libraries are required: `libgtk-3-dev libwebkit2gtk-4.1-dev libsoup-3.0-dev libjavascriptcoregtk-4.1-dev libglib2.0-dev libcairo2-dev libpango1.0-dev libgdk-pixbuf-2.0-dev libatk1.0-dev libdbus-1-dev`.
|
||
- WebGL errors in the log (`ContextResult::kFatalFailure: WebGL1/2 blocklisted`) are normal on GPU-less VMs and do not affect app functionality.
|
||
|
||
### Gotchas
|
||
|
||
- `pnpm install` may warn about ignored build scripts (`@sentry/cli`, `esbuild`, etc.). The esbuild binary is correctly installed via its native platform package despite the warning — Vite and Vitest work fine.
|
||
- Git submodules (`app/src-tauri/vendor/tauri-cef`, `app/src-tauri/vendor/tauri-plugin-notification`) must be initialized for Tauri shell compilation. Run `git submodule update --init --recursive` if not already done.
|
||
- `pnpm test:unit` does not exist at the root level; use `pnpm test` instead (which delegates to `vitest run` in the `app` workspace).
|
||
- The Tauri shell `cargo check` requires GTK/desktop system libraries; without them, the pre-push hook's `pnpm rust:check` will fail. Use `--no-verify` on push if GTK libs are missing and the change is unrelated to the Tauri shell.
|
||
|
||
|
||
<claude-mem-context>
|
||
# Memory Context
|
||
|
||
# [openhuman] recent context, 2026-04-22 9:52am PDT
|
||
|
||
Legend: 🎯session 🔴bugfix 🟣feature 🔄refactor ✅change 🔵discovery ⚖️decision
|
||
Format: ID TIME TYPE TITLE
|
||
Fetch details: get_observations([IDs]) | Search: mem-search skill
|
||
|
||
Stats: 20 obs (8,333t read) | 593,112t work | 99% savings
|
||
|
||
### Apr 22, 2026
|
||
2848 9:07a ✅ openhuman: All Three Review Branches Pushed to Fork Successfully
|
||
2849 " 🔵 openhuman review-daemon-lifecycle: Two Post-Push Issues — Unstaged Prettier Changes + Missing tauri-cef Vendor
|
||
2851 9:08a ✅ openhuman daemon lifecycle: Prettier Format Committed as Follow-Up
|
||
2855 9:09a ✅ openhuman: All Three Review Branches Fully Pushed — PRs Ready to Open
|
||
2857 9:10a 🔵 openhuman: GitHub Connector Cannot Create PRs to tinyhumansai/openhuman — 403 Forbidden
|
||
2858 9:11a 🔵 openhuman webhooks-ingress: Session Stalled — Instruction Not Processed After 10+ Minutes
|
||
2860 " 🔵 openhuman webhooks: WebhooksDebugPanel Architecture for E2E Smoke Spec
|
||
2861 9:13a 🔵 openhuman webhooks-ingress: Full Spec Surface Mapped — RPC Log Strings + UI Navigation Path
|
||
2866 9:15a 🟣 openhuman webhooks-ingress: webhooks-ingress-flow.spec.ts Written
|
||
2869 9:18a ⚖️ openhuman Memory Refactor Plan: Trait Shape, L1 Pointer, and Missing Pieces
|
||
2871 " 🔵 openhuman Memory Architecture: Auto-Inject Pattern Has 3 Separate Implementations
|
||
2873 9:31a 🟣 openhuman: Draft PR Opened — Config Runtime Dir Refactor for Testability
|
||
2874 9:32a 🟣 openhuman: 3 More Draft PRs Opened — Threads Schema, Daemon Lifecycle, Webhooks E2E
|
||
2875 9:33a 🔵 openhuman Memory Namespace: 3 Auto-Inject Sites, Not 1
|
||
2876 " ⚖️ openhuman Memory Refactor: Breaking Trait Change + Flag-Off + ToolDiscovery Hybrid
|
||
2877 " ✅ Memory Namespace Refactor Plan Written to docs/plans/memory-namespace-refactor.md
|
||
2879 9:34a 🔵 openhuman Memory Trait: 15 Impls, Not 14; MemoryRecalled Has No Live Emit Site
|
||
2880 " 🔵 openhuman SQLite Schema: memory_docs Already Has namespace Column; Migration Scope Minimal
|
||
2881 " 🔵 openhuman Memory Trait Current Signatures: No Namespace Param on Any Method
|
||
2882 " 🔵 openhuman Eval Infra: Does Not Exist; Phase D Requires Bootstrap from Scratch
|
||
|
||
Access 593k tokens of past work via get_observations([IDs]) or mem-search skill.
|
||
</claude-mem-context>
|