Skip to content

fix(core,cef): run core in-process and stop orphaning CEF helpers on Cmd+Q#1061

Merged
senamakel merged 4 commits into
tinyhumansai:mainfrom
senamakel:fix/rust-shutdown
May 1, 2026
Merged

fix(core,cef): run core in-process and stop orphaning CEF helpers on Cmd+Q#1061
senamakel merged 4 commits into
tinyhumansai:mainfrom
senamakel:fix/rust-shutdown

Conversation

@senamakel
Copy link
Copy Markdown
Member

@senamakel senamakel commented May 1, 2026

Summary

Two related bugs on app exit: the spawned `openhuman-core` sidecar and CEF helper processes (renderers / GPU / utility) were left running after Cmd+Q. Phase 1 removes the sidecar architecture entirely and runs the core in-process; phase 2 makes the CEF teardown deterministic so leftover helpers don't get re-parented to launchd.

Changes

Phase 1 — core in-process (commit `d700f538`)

The Tauri shell now links `openhuman_core` as a path dep and spawns its HTTP/JSON-RPC server as a tokio task inside the GUI process. Core's lifetime is tied to the host so `RunEvent::ExitRequested` ⇒ `task.abort()` ⇒ no orphan.

  • Drop `CoreRunMode` (InProcess / ChildProcess), `Child` plumbing, SIGTERM/SIGKILL, `core_bin` resolution from `core_process.rs`.
  • Delete `core_update.rs` (770 lines) — auto-update is now strictly via `tauri-plugin-updater` since core ships with the app.
  • Stub `check_core_update` / `apply_core_update` IPC commands so the existing frontend wrappers keep working without changes.
  • `run_core_from_args` now dispatches into the linked lib instead of shelling out to a separate binary.
  • Remove `externalBin` from `tauri.conf.json` and the `flate2` / `tar` / `zip` / `semver` deps that only `core_update` used.
  • The existing port-7788 probe in `ensure_running` still attaches to a manual `openhuman-core run` harness when one is already listening, so debugging workflows are unchanged.

Phase 2 — CEF teardown (commit `2cb6607f`)

The vendored `tauri-runtime-cef` already calls `cef::shutdown()` after `RunEvent::Exit`, but two gaps remained:

  1. 50 ms drain after our teardown in `RunEvent::ExitRequested` so queued browser-close messages reach CEF before the runtime drains the message loop. A webview that was mid-load when the user quit could otherwise race `cef::shutdown()` and orphan its renderer.
  2. `pkill -TERM -P $$` sweep after the Tauri event loop returns. Anything that survived `cef::shutdown()` (CEF bug or mid-spawn helper) would otherwise be re-parented to launchd / init. The sweep logs a warn-level line when it actually killed something so a real leak shows up in logs. No-op on Windows where job objects already terminate the helper tree.

Net diff

```
7 files changed, 3100 insertions(+), 1853 deletions(-)
delete mode 100644 app/src-tauri/src/core_update.rs
```

The big +inserts number is `Cargo.lock` reconciliation from linking `openhuman_core`.

Test plan

  • `cargo check --manifest-path app/src-tauri/Cargo.toml` clean
  • `cargo check --manifest-path app/src-tauri/Cargo.toml --tests` clean
  • `pnpm tauri dev`, open a couple of webview accounts, Cmd+Q
  • `pgrep -f "OpenHuman Helper"` returns nothing after exit
  • `pgrep -f openhuman-core` returns nothing after exit
  • Log line `[app] sweep: no leftover children (clean exit)` is present on a clean Cmd+Q
  • Set `OPENHUMAN_CORE_PORT=7788` and run `cargo run --bin openhuman-core -- run --port 7788` manually, then start the app — log says `[core] reusing port 7788 — another `openhuman-core` instance is already listening`
  • On macOS, first launch re-prompts for any TCC permissions previously granted to the standalone sidecar (expected — TCC identity is now the .app bundle)

Caveats

  1. macOS TCC: pre-existing accessibility / screen recording / microphone grants on the `openhuman-core` sidecar are tied to that binary's identity. After this change, those grants live on the Tauri `.app` bundle's identity and existing users will see the OS prompt once on first launch.
  2. Compile time: `app/src-tauri` now pulls all of core's deps (`whisper-rs`, `rusqlite bundled`, etc.). Cold builds are noticeably slower; incremental builds are unaffected. Acceptable trade for killing the orphan-sidecar class of bugs.
  3. `pnpm core:stage` and `app/src-tauri/binaries/` are now unused but harmless. Cleanup is a separate small PR.

Summary by CodeRabbit

  • Chores
    • Core now runs embedded in-process rather than as a separate sidecar binary.
    • Sidecar staging and bundling removed; distributed app packages no longer include a standalone core binary.
    • Automatic in-place core update checks/updates simplified to compatibility stubs; update flow reduced.
    • Development scripts and CI/release workflows simplified to skip sidecar build/staging and use a manual release trigger.

Embed openhuman_core as a path dep in the Tauri shell and run its
HTTP/JSON-RPC server as a tokio task inside the GUI process. Ties the
core's lifetime to the Tauri host so Cmd+Q no longer orphans an
`openhuman-core` child or its CEF helpers.

- Drop CoreRunMode (InProcess/ChildProcess), all child-process spawn,
  SIGTERM/SIGKILL, and core_bin resolution from core_process.rs.
- Delete core_update.rs (auto-update now via tauri-plugin-updater).
- Stub check_core_update / apply_core_update IPC commands so the
  frontend keeps working without errors.
- run_core_from_args dispatches into the linked lib instead of
  shelling out to a separate binary.
- Remove externalBin from tauri.conf.json and the flate2/tar/zip/semver
  deps that only core_update used.

The existing port-7788 probe in ensure_running still attaches to a
manual `openhuman-core run` harness when one is already listening.
After moving the core in-process the visible failure mode of an
unclean Cmd+Q is leftover "OpenHuman Helper" CEF processes. The
vendored tauri-runtime-cef already calls cef::shutdown() after our
RunEvent::Exit returns, but two gaps remained:

1. RunEvent::ExitRequested closes child webviews synchronously but
   the actual CEF teardown is async — a webview that was mid-load
   could race cef::shutdown() and leave its renderer orphaned.
   Add a 50ms sleep after our teardown so queued close messages
   reach CEF before the runtime drains the message loop.

2. Anything that survives cef::shutdown() (CEF bug or mid-spawn
   helper) gets re-parented to launchd / init when the GUI exits.
   Add a `pkill -TERM -P <pid>` sweep after the Tauri event loop
   returns so leftover direct children are notified before our
   process exits. The status code is logged at warn level when it
   actually killed something, so a real leak is visible in logs.

No-op on Windows where job objects already terminate the CEF
helper tree when the parent exits.
@senamakel senamakel requested a review from a team May 1, 2026 05:16
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 1, 2026

📝 Walkthrough

Walkthrough

This PR embeds openhuman_core into the Tauri binary and replaces the external core sidecar with an in-process Tokio task; it removes sidecar staging, update logic, and related CI/workflow steps, and simplifies core lifecycle and shutdown handling.

Changes

Cohort / File(s) Summary
Tauri manifest / Dependencies
app/src-tauri/Cargo.toml
Remove sidecar/update crates (semver, flate2, tar, zip); add workspace openhuman_core path dependency (default features disabled).
Core lifecycle & host integration
app/src-tauri/src/core_process.rs, app/src-tauri/src/lib.rs
Replace child-process-based core management with embedded JSON-RPC server task: CoreProcessHandle::new(port) simplified, spawn/abort tokio task instead of spawning/killing child, remove run-mode/bin selection and direct-service commands, and call openhuman_core::run_core_from_args for direct runs.
Core update removal
app/src-tauri/src/core_update.rs
Delete entire sidecar update subsystem and its public types/functions.
Tests
app/src-tauri/src/core_process_tests.rs
Trim tests that target binary-resolution/run-mode/update behavior; update remaining tests to new CoreProcessHandle::new(port) and token readiness semantics.
Build & CI workflows
.github/workflows/* (build.yml, build-windows.yml, release.yml, release-packages.yml, test.yml, e2e-agent-review.yml)
Remove steps that build/stage standalone openhuman-core; adjust comments and flow to reflect in-process core; change release trigger to manual where noted; simplify Sentry symbol uploads.
Dev tooling & scripts
app/package.json, package.json, scripts/* (scripts/release/stage-sidecar.sh, scripts/stage-core-sidecar.mjs)
Remove or no-op sidecar staging scripts and repo-level core:stage; delete shell/Node staging scripts.
Tauri config & frontend hooks
app/src-tauri/tauri.conf.json, app/package.json
Drop bundle.externalBin entry for binaries/openhuman-core; remove pnpm run core:stage from dev/build hooks; core:stage becomes no-op.
Misc documentation/tests changes
Various small files
Adjusted docs/tests/handlers to reflect embedded core and removed update/apply update behaviors.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant App as Tauri App
    participant Handle as CoreProcessHandle
    participant Tokio as Tokio Runtime
    participant Core as Embedded Core (openhuman_core)

    User->>App: start
    App->>Handle: CoreProcessHandle::new(port)
    Handle->>Tokio: spawn run_server_embedded(port)
    Tokio->>Core: start JSON-RPC server
    User->>App: invoke RPC via app
    App->>Core: JSON-RPC request
    Core-->>App: JSON-RPC response
    User->>App: shutdown
    App->>Handle: request shutdown / drop
    Handle->>Tokio: abort server task
    Tokio->>Core: stop & cleanup
    App->>App: final cleanup sweep (Unix pkill for stray children)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related issues

Possibly related PRs

Poem

🐰
I hopped inside the app today,
No sidecar trailing on my way.
With Tokio snug and tunnels warmed,
One core within, no harm befall'd. ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically summarizes the main changes: moving core to in-process execution and fixing orphaned CEF helpers on app exit.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Review rate limit: 3/5 reviews remaining, refill in 14 minutes and 24 seconds.

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
app/src-tauri/src/lib.rs (1)

1512-1519: ⚡ Quick win

Unnecessary allocation of args vector.

Since openhuman_core::run_core_from_args takes &[String] and the input args is already &[String], the intermediate Vec<String> allocation is unnecessary.

 pub fn run_core_from_args(args: &[String]) -> Result<(), String> {
-    // Core lives in-process: dispatch directly through the linked `openhuman_core`
-    // library instead of shelling out to a separate binary. The Tauri main()
-    // routes `OpenHuman core <args>` here so users can still drive the core CLI
-    // from the bundled app.
-    let owned: Vec<String> = args.to_vec();
-    openhuman_core::run_core_from_args(&owned).map_err(|e| format!("{e:#}"))
+    openhuman_core::run_core_from_args(args).map_err(|e| format!("{e:#}"))
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/src-tauri/src/lib.rs` around lines 1512 - 1519, The function
run_core_from_args unnecessarily allocates an owned Vec named `owned`; instead
pass the incoming slice directly to `openhuman_core::run_core_from_args`. Remove
the `owned: Vec<String> = args.to_vec();` allocation and call
`openhuman_core::run_core_from_args(args).map_err(|e| format!("{e:#}"))` so no
intermediate cloning occurs.
app/src-tauri/src/core_process.rs (1)

168-190: 💤 Low value

Consider consolidating duplicate abort logic.

shutdown() and send_terminate_signal() have identical implementations — both take the lock and abort the task. The only difference is the log message. Consider having send_terminate_signal delegate to shutdown or extracting a shared helper to reduce duplication.

+    async fn abort_task(&self, log_context: &str) {
+        let mut task_guard = self.task.lock().await;
+        if let Some(task) = task_guard.take() {
+            log::info!("[core] aborting embedded core server task {log_context}");
+            task.abort();
+        }
+    }
+
     /// Stop the embedded server task. Safe to call when nothing is running.
     pub async fn shutdown(&self) {
-        let mut task_guard = self.task.lock().await;
-        if let Some(task) = task_guard.take() {
-            log::info!("[core] aborting embedded core server task");
-            task.abort();
-        }
+        self.abort_task("").await;
     }

     /// Synchronous-friendly shutdown for `RunEvent::ExitRequested`.
-    ///
-    /// Aborts the embedded server task so any background tokio tasks the
-    /// server spawned stop driving I/O before CEF's teardown runs. Cheap
-    /// and non-blocking on the UI thread — `JoinHandle::abort` returns
-    /// immediately.
     pub async fn send_terminate_signal(&self) {
-        let mut task_guard = self.task.lock().await;
-        if let Some(task) = task_guard.take() {
-            log::info!("[core] aborting embedded core server task on app shutdown");
-            task.abort();
-        }
+        self.abort_task("on app shutdown").await;
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/src-tauri/src/core_process.rs` around lines 168 - 190, shutdown() and
send_terminate_signal() duplicate the same task-abort logic; extract the shared
behavior into a single helper (e.g., a private method like abort_embedded_task
or similar) that locks self.task, takes the JoinHandle and aborts it, then call
that helper from both shutdown() and send_terminate_signal() (or make
send_terminate_signal() delegate to shutdown()) while keeping distinct log
messages (or accept a log message parameter) so you remove the duplicated
lock/abort block while preserving the different log output; refer to the
existing methods shutdown, send_terminate_signal, and the self.task
field/JoinHandle to locate where to change.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@app/src-tauri/Cargo.toml`:
- Around line 98-104: The inline comment in the Cargo.toml entry for the
dependency openhuman_core contains a placeholder '#?' for an issue reference;
update that comment by either replacing '#?' with the actual issue number or
removing the placeholder entirely so the comment reads cleanly (for example edit
the comment containing "or CEF helpers behind) by tying the core's lifetime to
the GUI process." to remove or replace the '#?' token).

---

Nitpick comments:
In `@app/src-tauri/src/core_process.rs`:
- Around line 168-190: shutdown() and send_terminate_signal() duplicate the same
task-abort logic; extract the shared behavior into a single helper (e.g., a
private method like abort_embedded_task or similar) that locks self.task, takes
the JoinHandle and aborts it, then call that helper from both shutdown() and
send_terminate_signal() (or make send_terminate_signal() delegate to shutdown())
while keeping distinct log messages (or accept a log message parameter) so you
remove the duplicated lock/abort block while preserving the different log
output; refer to the existing methods shutdown, send_terminate_signal, and the
self.task field/JoinHandle to locate where to change.

In `@app/src-tauri/src/lib.rs`:
- Around line 1512-1519: The function run_core_from_args unnecessarily allocates
an owned Vec named `owned`; instead pass the incoming slice directly to
`openhuman_core::run_core_from_args`. Remove the `owned: Vec<String> =
args.to_vec();` allocation and call
`openhuman_core::run_core_from_args(args).map_err(|e| format!("{e:#}"))` so no
intermediate cloning occurs.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 18c8f1d5-1e5f-4b63-9eb2-1f60c0ad262b

📥 Commits

Reviewing files that changed from the base of the PR and between 8c65f10 and 2cb6607.

⛔ Files ignored due to path filters (1)
  • app/src-tauri/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (6)
  • app/src-tauri/Cargo.toml
  • app/src-tauri/src/core_process.rs
  • app/src-tauri/src/core_process_tests.rs
  • app/src-tauri/src/core_update.rs
  • app/src-tauri/src/lib.rs
  • app/src-tauri/tauri.conf.json
💤 Files with no reviewable changes (2)
  • app/src-tauri/tauri.conf.json
  • app/src-tauri/src/core_update.rs

Comment thread app/src-tauri/Cargo.toml
Core is now linked into the Tauri shell as a path dep (PR tinyhumansai#1061), so
the release pipeline no longer needs to build, stage, sign, or
package a standalone openhuman-core binary. Distribution of the core
as a headless artifact is Docker-only for now.

release.yml:
  - Drop "Resolve core manifest", "Build sidecar", "Stage sidecar",
    "Resolve standalone CLI artifact path", "Verify sidecar layout",
    "Package CLI tarball" (unix), "Package CLI zip" (windows), and
    "Upload standalone CLI artifacts" steps.
  - Rename "Re-sign sidecar with hardened runtime and notarize" to
    "Sign and notarize macOS .app" — the script always signed the
    whole bundle, the name was historical.
  - Sentry symbols upload now scans only the Tauri shell's target dir.

build.yml / build-windows.yml / test.yml:
  - Drop the cargo build --bin openhuman-core + stage steps; the
    Tauri build now pulls in openhuman_core via path dep.
  - build.yml: drop `pnpm run core:stage` from the inline beforeBuildCommand.

e2e-agent-review.yml:
  - Drop "Stage sidecar next to app binary" — there is no sidecar.

release-packages.yml:
  - Disable trigger (workflow_dispatch only) until a standalone CLI
    binary is reintroduced. Homebrew / apt / npm / Linux-arm64
    tarball jobs all wrapped the openhuman-core binary that no
    longer exists.

tauri.conf.json + package.json:
  - Drop `pnpm run core:stage` from beforeDevCommand and
    beforeBuildCommand.
  - Replace `core:stage` script with a no-op echo so any straggling
    references in dev-side helpers don't fail; remove the now-unused
    stage-core-sidecar.mjs and stage-sidecar.sh scripts.
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/workflows/build-windows.yml:
- Around line 74-75: The "Upload standalone CLI binary" step still references
nonexistent outputs from steps.core-paths (e.g., steps.core-paths.outputs.*),
causing runtime failures; remove that entire upload step or update it to use
existing outputs/artifacts instead. Locate the job step named "Upload standalone
CLI binary" and delete it or replace its use of steps.core-paths.outputs.* with
valid artifact/output names produced earlier in the workflow (or remove the
upload if the core is now embedded), ensuring no remaining references to
core-paths remain.

In @.github/workflows/release.yml:
- Around line 498-507: The current upload step only checks
deps_dir="app/src-tauri/target/${MATRIX_TARGET}/release/deps" and skips if
missing; change it to check both
app/src-tauri/target/${MATRIX_TARGET}/release/deps and
target/${MATRIX_TARGET}/release/deps (or iterate over an array of roots) and
call scripts/upload_sentry_symbols.sh "$VERSION" "$deps_dir" for each existing
path; update the logic around deps_dir and the echo messages so both possible
Tauri output roots are scanned and uploaded (retain MATRIX_TARGET and VERSION
usage and the existing upload script invocation).

In `@app/src-tauri/src/core_process.rs`:
- Around line 94-109: The readiness logic must verify the embedded task before
accepting the port: after your preflight probe detects a listener, acquire and
inspect self.task (the MutexGuard from self.task.lock().await) and ensure it is
Some and not task.is_finished(); if the guard is None or the task has finished
return an Err with context (similar to the existing error messages) instead of
returning Ok(()); only when the guard contains a live task should you drop the
guard and return Ok(()). This prevents attaching to foreign listeners and
ensures restart() will not wait on a port the app never owned.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 00d7f959-c16f-4908-b7ed-1dd7bc1395e1

📥 Commits

Reviewing files that changed from the base of the PR and between 2cb6607 and f548dd5.

📒 Files selected for processing (12)
  • .github/workflows/build-windows.yml
  • .github/workflows/build.yml
  • .github/workflows/e2e-agent-review.yml
  • .github/workflows/release-packages.yml
  • .github/workflows/release.yml
  • .github/workflows/test.yml
  • app/package.json
  • app/src-tauri/src/core_process.rs
  • app/src-tauri/tauri.conf.json
  • package.json
  • scripts/release/stage-sidecar.sh
  • scripts/stage-core-sidecar.mjs
💤 Files with no reviewable changes (3)
  • package.json
  • scripts/release/stage-sidecar.sh
  • scripts/stage-core-sidecar.mjs
✅ Files skipped from review due to trivial changes (2)
  • .github/workflows/e2e-agent-review.yml
  • .github/workflows/release-packages.yml
🚧 Files skipped from review as they are similar to previous changes (1)
  • app/src-tauri/tauri.conf.json

Comment on lines +74 to +75
# Core is linked into the Tauri binary as a path dep — no separate
# sidecar build / stage / path-resolution step needed.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail
python - <<'PY'
from pathlib import Path

path = Path(".github/workflows/build-windows.yml")
lines = path.read_text().splitlines()

has_core_paths = any("id: core-paths" in line for line in lines)
print(f"has `id: core-paths`: {has_core_paths}")

for i, line in enumerate(lines, 1):
    if "Upload standalone CLI binary" in line or "steps.core-paths.outputs" in line:
        print(f"{i}: {line}")
PY

Repository: tinyhumansai/openhuman

Length of output: 257


Remove the stale artifact upload step that references a non-existent step.

After dropping the separate core/sidecar build flow, the Upload standalone CLI binary step at lines 119-125 still references steps.core-paths.outputs.*, but there is no core-paths step defined in this workflow. This will cause the step to fail at runtime because the referenced step outputs do not exist.

Suggested fix
-      - name: Upload standalone CLI binary
-        uses: actions/upload-artifact@v4
-        with:
-          name: windows-cli
-          path: |-
-            ${{ steps.core-paths.outputs.core_target_dir }}/${{ steps.core-paths.outputs.core_bin_name }}.exe
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/build-windows.yml around lines 74 - 75, The "Upload
standalone CLI binary" step still references nonexistent outputs from
steps.core-paths (e.g., steps.core-paths.outputs.*), causing runtime failures;
remove that entire upload step or update it to use existing outputs/artifacts
instead. Locate the job step named "Upload standalone CLI binary" and delete it
or replace its use of steps.core-paths.outputs.* with valid artifact/output
names produced earlier in the workflow (or remove the upload if the core is now
embedded), ensuring no remaining references to core-paths remain.

Comment thread .github/workflows/release.yml
Comment on lines +94 to +109
let mut guard = self.task.lock().await;
if let Some(task) = guard.as_ref() {
if task.is_finished() {
let task = guard.take().expect("checked is_some");
drop(guard);
return match task.await {
Ok(_) => {
Err("in-process core server exited before becoming ready".to_string())
}
}
}
CoreRunMode::ChildProcess => {
let mut guard = self.child.lock().await;
if let Some(child) = guard.as_mut() {
match child.try_wait() {
Ok(Some(status)) => {
return Err(format!("core process exited before ready: {status}"));
}
Ok(None) => {}
Err(e) => {
return Err(format!("failed checking core process status: {e}"));
}
}
}
Err(err) => Err(format!(
"in-process core server task failed before ready: {err}"
)),
};
}
}
tokio::time::sleep(std::time::Duration::from_millis(100)).await;
tokio::time::sleep(Duration::from_millis(100)).await;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Check the embedded task before accepting the port as ready.

Right now the loop returns Ok(()) as soon as anything is listening on the port, and only afterwards checks whether the spawned embedded-core task has already died. If another process grabs the port after the preflight probe, this method can attach to that foreign listener, keep a stale managed task, and make a later restart() wait on a port the app never owned.

Suggested fix
         for _ in 0..40 {
-            if self.is_rpc_port_open().await {
-                log::info!("[core] core rpc became ready at {}", self.rpc_url());
-                return Ok(());
-            }
-
             let mut guard = self.task.lock().await;
             if let Some(task) = guard.as_ref() {
                 if task.is_finished() {
                     let task = guard.take().expect("checked is_some");
                     drop(guard);
                     return match task.await {
                         Ok(_) => {
                             Err("in-process core server exited before becoming ready".to_string())
                         }
                         Err(err) => Err(format!(
                             "in-process core server task failed before ready: {err}"
                         )),
                     };
                 }
             }
+            drop(guard);
+
+            if self.is_rpc_port_open().await {
+                log::info!("[core] core rpc became ready at {}", self.rpc_url());
+                return Ok(());
+            }
             tokio::time::sleep(Duration::from_millis(100)).await;
         }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/src-tauri/src/core_process.rs` around lines 94 - 109, The readiness logic
must verify the embedded task before accepting the port: after your preflight
probe detects a listener, acquire and inspect self.task (the MutexGuard from
self.task.lock().await) and ensure it is Some and not task.is_finished(); if the
guard is None or the task has finished return an Err with context (similar to
the existing error messages) instead of returning Ok(()); only when the guard
contains a live task should you drop the guard and return Ok(()). This prevents
attaching to foreign listeners and ensures restart() will not wait on a port the
app never owned.

Resolves conflicts with the core RPC auth (tinyhumansai#881) and "staging in
debug profile" (tinyhumansai#1044) changes that landed on main while this PR
was open.

CodeRabbit nits applied as part of the merge:
  - Cargo.toml: replace `#?` placeholder with the PR reference.
  - core_process.rs: dedupe shutdown/send_terminate_signal via a
    shared abort_task() helper.
  - lib.rs::run_core_from_args: drop the redundant args.to_vec()
    allocation and pass the slice through directly.

Conflict resolution summary:

  app/src-tauri/src/core_process.rs
  - Keep the in-process / no-sidecar architecture from this PR
    (no `Child`, no `core_bin`, no `CoreRunMode`).
  - Pull in the auth token plumbing from main: generate_rpc_token,
    CURRENT_RPC_TOKEN, and an `rpc_token` field on the handle.
    Set OPENHUMAN_CORE_TOKEN as a process-global env var before
    spawning the embedded server so the same-process tokio task
    reads exactly what a child sidecar would have received via
    Command::env. Publish to CURRENT_RPC_TOKEN only after spawn,
    matching upstream's invariant that the global only advertises
    a token a running listener has actually accepted.
  - Note in the harness-attach fast-path warning that an external
    listener won't see this process's token — Tauri-side
    authenticated calls will 401 unless the harness was started
    with the same OPENHUMAN_CORE_TOKEN.

  app/src-tauri/src/core_process_tests.rs
  - Drop run_mode / default_core_bin / same_executable_path /
    sidecar-staging tests (functions removed in this PR).
  - Keep upstream's token-related tests, simplified for the slim
    `CoreProcessHandle::new(port)` constructor.

  app/src-tauri/src/lib.rs
  - Module list: keep `mod core_rpc` (auth helper used by various
    Tauri commands), drop `mod core_update` — core_update.rs is
    deleted with the rest of the sidecar update subsystem.
  - check_core_update: keep the no-op stub; the frontend wrapper
    keeps working via `tauri-plugin-updater`.

  app/src-tauri/src/core_update.rs
  - Stays deleted. Core ships with the desktop app now; per-binary
    update is via tauri-plugin-updater.

  .github/workflows/release.yml
  - Drop upstream's resolve-core-paths / build-sidecar /
    stage-sidecar / cli-paths block; sidecar build is gone.
  - Collapse the split core/Tauri Sentry symbols upload into a
    single step: linked openhuman_core symbols now live under the
    Tauri shell's target dir.
  - Preserve upstream's staging→debug profile path expression in
    the bundle artifact upload.

  app/src-tauri/Cargo.lock
  - Regenerated against the merged Cargo.toml.
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
app/src-tauri/src/core_process.rs (1)

116-116: 💤 Low value

std::env::set_var in async context has soundness concerns.

std::env::set_var is not thread-safe; calling it while other threads may be reading environment variables can cause data races. Since Rust 1.66, this is formally deprecated in multi-threaded contexts. While the risk here is low (called once during startup, before heavy concurrency), consider passing the token directly to run_server_embedded as an argument if the API supports it.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/src-tauri/src/core_process.rs` at line 116, Avoid using std::env::set_var
at runtime to set OPENHUMAN_CORE_TOKEN due to thread-safety concerns; instead
modify the call site to pass the token directly into run_server_embedded (or an
equivalent initialization function) so the token comes from self.rpc_token
without mutating global environment state. Locate the usage of
std::env::set_var("OPENHUMAN_CORE_TOKEN", self.rpc_token.as_str()) and change
the server-start call (run_server_embedded) to accept an extra parameter for the
RPC token (or add a construction/Config object carrying self.rpc_token) and
thread that token through to where the server needs it, removing the environment
write. Ensure any tests or callers are updated to provide the token argument.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@app/src-tauri/src/core_process.rs`:
- Line 116: Avoid using std::env::set_var at runtime to set OPENHUMAN_CORE_TOKEN
due to thread-safety concerns; instead modify the call site to pass the token
directly into run_server_embedded (or an equivalent initialization function) so
the token comes from self.rpc_token without mutating global environment state.
Locate the usage of std::env::set_var("OPENHUMAN_CORE_TOKEN",
self.rpc_token.as_str()) and change the server-start call (run_server_embedded)
to accept an extra parameter for the RPC token (or add a construction/Config
object carrying self.rpc_token) and thread that token through to where the
server needs it, removing the environment write. Ensure any tests or callers are
updated to provide the token argument.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 2cac3e01-89f5-4f12-96a2-b4279be81f98

📥 Commits

Reviewing files that changed from the base of the PR and between f548dd5 and 813e0a0.

⛔ Files ignored due to path filters (1)
  • app/src-tauri/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (5)
  • .github/workflows/release.yml
  • app/src-tauri/Cargo.toml
  • app/src-tauri/src/core_process.rs
  • app/src-tauri/src/core_process_tests.rs
  • app/src-tauri/src/lib.rs
✅ Files skipped from review due to trivial changes (1)
  • app/src-tauri/Cargo.toml

@senamakel senamakel merged commit 016ad78 into tinyhumansai:main May 1, 2026
13 of 15 checks passed
CodeGhost21 added a commit to CodeGhost21/openhuman that referenced this pull request May 1, 2026
- React: drop the `beforeSend` opt-in queue and auto-forward sanitized
  events to `openhuman-react`. PII / breadcrumbs / request bodies /
  frame-level locals + source snippets are still stripped, and the
  `isAnalyticsEnabled()` consent check now gates `beforeSend`. Tag
  every event with `surface: "react"`. Add a `VITE_SENTRY_SMOKE_TEST`
  one-shot trigger for verifying the pipeline end-to-end.
- Delete `errorReportQueue` + `ErrorReportNotification` (the user-opt-in
  scaffolding) and the OAuth stale-app-version `enqueueError` call —
  replaced with a direct `Sentry.captureMessage` plus `console.warn`.
- Workflow: since tinyhumansai#1061 the core lives in-process inside the Tauri
  shell binary (one process → one `sentry::init` → one hub), so all
  Rust events from the desktop build route to `openhuman-tauri`.
  Repoint the Rust DIF upload step in `release.yml` and the Tauri-shell
  upload in `release-staging.yml` to `vars.SENTRY_PROJECT_TAURI`.
  Standalone `openhuman-core` CLI binary (built by the staging sidecar
  step and by `release-packages.yml`) still uploads to
  `vars.SENTRY_PROJECT_CORE`.
oxoxDev added a commit to oxoxDev/openhuman that referenced this pull request May 4, 2026
…ent (tinyhumansai#985)

The shipped `.app` was missing two macOS-required pieces for an app
that sends Apple Events:

* `NSAppleEventsUsageDescription` in `Info.plist` — without this key
  the OS-level consent dialog that fires on first AE attempt has no
  descriptive text and renders as the broken-looking error popup
  reported in tinyhumansai#985. With it present, macOS shows a proper
  "OpenHuman wants to control System Events" dialog with the user-
  facing text from this string and Allow / Don't Allow buttons; the
  decision is then sticky per-target.

* `com.apple.security.automation.apple-events` entitlement in
  `entitlements.sidecar.plist` — under the Hardened Runtime in signed
  DMG builds, AE calls are blocked outright before the consent dialog
  can render unless the calling app holds this entitlement.
  `entitlements.sidecar.plist` is the file wired at signing time per
  `tauri.conf.json` `bundle.macOS.entitlements`, so adding it here
  covers the main `OpenHuman` bin (PR tinyhumansai#1061 made the core in-process,
  so there is no separate sidecar to entitle).

Refs tinyhumansai#985.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
jwalin-shah added a commit to jwalin-shah/openhuman that referenced this pull request May 5, 2026
* feat(remotion): Ghosty character library with transparent MOV variants (tinyhumansai#1059)

Co-authored-by: WOZCODE <contact@withwoz.com>

* feat(composio/gmail): sync into memory tree (Slack-parity) (tinyhumansai#1056)

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(scheduler-gate): throttle background AI on battery / busy CPU (tinyhumansai#1062)

* fix(core,cef): run core in-process and stop orphaning CEF helpers on Cmd+Q (tinyhumansai#1061)

* ci: add dedicated staging release workflow (tinyhumansai#1066)

* fix(sentry): Rust source context + per-release deploy marker (tinyhumansai#405) (tinyhumansai#1067)

* fix(welcome): re-enable OAuth buttons with focus/timeout recovery (tinyhumansai#1049) (tinyhumansai#1069)

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* chore(dependencies): update pnpm-lock.yaml and Cargo.lock for package… (tinyhumansai#1082)

* fix(onboarding): personalize welcome agent greeting with user identity (tinyhumansai#1078)

* fix(chat): make agent message bubbles fit content width (tinyhumansai#1083)

* Feat/dmg checks (tinyhumansai#1084)

* fix(linux): Add X11 platform flags to .deb package launcher (tinyhumansai#1087)

Co-authored-by: unn-Known1 <unn-known1@users.noreply.github.com>

* fix(sentry): auto-send React events; collapse core→tauri for desktop (tinyhumansai#1086)

Co-authored-by: Steven Enamakel <enamakel@tinyhumans.ai>

* fix(cef): run blank reload guard on the CEF UI thread (tinyhumansai#1092)

* fix(app): reload webview instead of restart_app in dev mode (tinyhumansai#1068) (tinyhumansai#1071)

* fix(linux): deliver X11 ozone flags via custom .desktop template (tinyhumansai#1091)

* fix(webview-accounts): retry data-dir purge so CEF handle race doesn't leak cookies (tinyhumansai#1076) (tinyhumansai#1081)

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Steven Enamakel <enamakel@tinyhumans.ai>

* fix(webview/slack): media perms + deep-link isolation (tinyhumansai#1074) (tinyhumansai#1080)

Co-authored-by: Steven Enamakel <enamakel@tinyhumans.ai>

* ci(release): split staging vs production workflows; promote staging tags (tinyhumansai#1094)

* Update release-staging.yml (tinyhumansai#1097)

* chore(staging): v0.53.5

* chore(staging): v0.53.6

* ci(staging): cut staging from main; add act local-debug helper (tinyhumansai#1099)

* chore(staging): v0.53.7

* fix(ci): correct sentry-cli download URL and trap scope (tinyhumansai#1100)

* chore(staging): v0.53.8

* feat(chat): forward thread_id to backend for KV cache locality (tinyhumansai#1095)

* fix(ci): bump pinned sentry-cli to 3.4.1 (2.34.2 was never published) (tinyhumansai#1102)

* chore(staging): v0.53.9

* fix(ci): drop bash trap in upload_sentry_symbols.sh; inline cleanup (tinyhumansai#1103)

* chore(staging): v0.53.10

* refactor(session): flatten session_raw/, switch md to YYYY_MM_DD (tinyhumansai#1098)

* Add full Composio managed-auth toolkit catalog (tinyhumansai#1093)

* ci: add diff-aware 80% coverage gate (Vitest + cargo-llvm-cov) (tinyhumansai#1104)

* feat(scripts): pnpm work + pnpm debug for agent-driven workflows (tinyhumansai#1105)

* ci: pull pnpm into CI image, drop redundant setup steps (tinyhumansai#1107)

* docs: add Cursor Cloud specific instructions to AGENTS.md (tinyhumansai#1106)

Co-authored-by: Cursor Agent <cursoragent@cursor.com>

* chore(staging): v0.53.11

* docs: surface 80% coverage gate and scripts/debug runners (tinyhumansai#1108)

* feat(app): show Composio integrations as sorted icon grid on Skills (tinyhumansai#1109)

Co-authored-by: Cursor Agent <cursoragent@cursor.com>

* feat(composio): client-side trigger enable/disable toggles (tinyhumansai#1110)

* feat(skills): channels grid + integrations card polish; tolerant Composio trigger decode (tinyhumansai#1112)

* chore(staging): v0.53.12

* feat(home): early-bird banner + assistant→agent terminology (tinyhumansai#1113)

* feat(updater): in-app auto-update with auto-download + restart prompt (tinyhumansai#677) (tinyhumansai#1114)

* chore(claude): add ship-and-babysit slash command (tinyhumansai#1115)

* feat(home): EarlyBirdyBanner + agent terminology + LinkedIn enrichment model pin (tinyhumansai#1118)

* fix(chat): single onboarding thread in sidebar after wizard (tinyhumansai#1116)

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Steven Enamakel <senamakel@users.noreply.github.com>

* fix: filter out global namespace from citation chips (tinyhumansai#1124)

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
Co-authored-by: senamakel-droid <281415773+senamakel-droid@users.noreply.github.com>

* feat(nav): enable Memory tab in BottomTabBar (tinyhumansai#1125)

* feat(memory): singleton ingestion + status RPC + UI pill (tinyhumansai#1126)

* feat(human): mascot tab with viseme-driven lipsync (staging only) (tinyhumansai#1127)

* Fix CEF zombie processes on full app close and restart (tinyhumansai#1128)

Co-authored-by: senamakel-droid <281415773+senamakel-droid@users.noreply.github.com>
Co-authored-by: Steven Enamakel <enamakel@tinyhumans.ai>

* Update issue templates for GitHub issue types (tinyhumansai#1146)

* feat(human): expand mascot expressions and tighten reply-speech state machine (tinyhumansai#1147)

* feat(memory): ingestion pipeline + tree-architecture docs + ops/schemas split (tinyhumansai#1142)

* feat(threads): surface live subagent work in parent thread (tinyhumansai#1122) (tinyhumansai#1159)

* fix(human): keep mascot mouth animating when TTS ships no viseme data (tinyhumansai#1160)

* feat(composio): consume backend markdownFormatted for LLM output (tinyhumansai#1165)

* fix(subagent): lazy-register toolkit actions filtered out of fuzzy top-K (tinyhumansai#1162)

* feat(memory): user-facing long-term memory window preset (tinyhumansai#1137) (tinyhumansai#1161)

* fix(tauri-shell): proactively kill stale openhuman RPC on startup (tinyhumansai#1166)

* chore(staging): v0.53.13

* fix(composio): per-action tool consumes backend markdownFormatted (tinyhumansai#1167)

* fix(threads): persist selectedThreadId across reloads (tinyhumansai#1168)

* feat(memory_tree): switch embed model to bge-m3 (1024-dim, 8K context) (tinyhumansai#1174)

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(agent): drop redundant [Memory context] recall injection (tinyhumansai#1173)

* chore(memory_tree): drop body-read timeouts on Ollama HTTP calls (tinyhumansai#1171)

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(transcript): emit thread_id + fix orchestrator missing cost (tinyhumansai#1169)

* fix(composio/gmail): phase out html2md, prefer text/plain MIME part (tinyhumansai#1170)

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(tools): markdown output for internal tool results (tinyhumansai#1172)

* feat(security): enforce prompt-injection guard before model and tool execution (tinyhumansai#1175)

* fix(cef): popup paint dies after first frame — skip blank-page guard for popups (tinyhumansai#1079) (tinyhumansai#1182)

Co-authored-by: Steven Enamakel <31011319+senamakel@users.noreply.github.com>

* chore(sentry): rename OPENHUMAN_SENTRY_DSN → OPENHUMAN_CORE_SENTRY_DSN (tinyhumansai#1186)

* feat(remotion): add yellow mascot character with all animation variants (tinyhumansai#1193)

Co-authored-by: Neel Mistry <neelmistry@Neels-MacBook-Pro.local>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>

* refactor(composio): hide raw connection ID, derive friendly label (tinyhumansai#1153) (tinyhumansai#1185)

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>

* fix(windows): align install.ps1 MSI with per-machine scope (tinyhumansai#913) (tinyhumansai#1187)

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(tauri): deterministic CEF teardown on full app close (tinyhumansai#1120) (tinyhumansai#1189)

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(composio): cap Gmail HTML body before strip (crash mitigation) (tinyhumansai#1191)

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(auth): stop stale chat threads after signup (tinyhumansai#1192)

Co-authored-by: Cursor <cursoragent@cursor.com>

* feat(sentry): staging-only "Trigger Sentry Test" button (tinyhumansai#1072) (tinyhumansai#1183)

* chore(staging): v0.53.14

* chore(staging): v0.53.15

* feat(composio): format trigger slugs into human-readable labels (tinyhumansai#1129) (tinyhumansai#1179)

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>

* fix(ui): hide unsupported permission UI on non-macOS for Screen Intelligence (tinyhumansai#1194)

Co-authored-by: Cursor <cursoragent@cursor.com>

* chore(tauri-shell): retire embedded Gmail webview-account flow (tinyhumansai#1181)

* feat(onboarding): replace welcome-agent bot with react-joyride walkthrough (tinyhumansai#1180)

* chore(release): v0.53.16

* fix(threads): preserve selectedThreadId on cold-boot identity hydration (tinyhumansai#1196)

* feat(core): version/shutdown/update RPCs + mid-thread integration refresh (tinyhumansai#1195)

* fix(mascot): swap to yellow mascot via @remotion/player (tinyhumansai#1200)

* feat(memory_tree): cloud-default LLM, queue priority, entity filter, Memory tab UI (tinyhumansai#1198)

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Persist turn state + restore conversation history on cold-boot (tinyhumansai#1202)

* feat(mascot): floating desktop mascot via native NSPanel + WKWebView (macOS) (tinyhumansai#1203)

* fix(memory/tree): emit summary children as Obsidian wikilinks (tinyhumansai#1210)

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(tools): coding-harness baseline primitives (tinyhumansai#1205) (tinyhumansai#1208)

* docs: add Codex PR checklist for remote agents

---------

Co-authored-by: Steven Enamakel <31011319+senamakel@users.noreply.github.com>
Co-authored-by: WOZCODE <contact@withwoz.com>
Co-authored-by: sanil-23 <sanil@vezures.xyz>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Cyrus Gray <144336577+graycyrus@users.noreply.github.com>
Co-authored-by: CodeGhost21 <164498022+CodeGhost21@users.noreply.github.com>
Co-authored-by: oxoxDev <164490987+oxoxDev@users.noreply.github.com>
Co-authored-by: Mega Mind <146339422+M3gA-Mind@users.noreply.github.com>
Co-authored-by: Gaurang Patel <ptelgm.yt@gmail.com>
Co-authored-by: unn-Known1 <unn-known1@users.noreply.github.com>
Co-authored-by: Steven Enamakel <enamakel@tinyhumans.ai>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Steven Enamakel <senamakel@users.noreply.github.com>
Co-authored-by: Steven Enamakel's Droid <enamakel.agent@tinyhumans.ai>
Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
Co-authored-by: senamakel-droid <281415773+senamakel-droid@users.noreply.github.com>
Co-authored-by: YellowSnnowmann <167776381+YellowSnnowmann@users.noreply.github.com>
Co-authored-by: Neil <neil@maha.xyz>
Co-authored-by: Neel Mistry <neelmistry@Neels-MacBook-Pro.local>
Co-authored-by: obchain <167975049+obchain@users.noreply.github.com>
Co-authored-by: Jwalin Shah <jshah1331@gmail.com>
oxoxDev added a commit to oxoxDev/openhuman that referenced this pull request May 14, 2026
Bilateral mirror of the core binary's before_send filter — since tinyhumansai#1061
the Tauri shell runs the core in-process, so the same
is_session_expired_event guard must run here too. Drops
OPENHUMAN-TAURI-25 / -1Q / -27 / -1G regardless of which surface
captured the event.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
oxoxDev added a commit to oxoxDev/openhuman that referenced this pull request May 15, 2026
…ore_send wire

Recreates PR tinyhumansai#1719's surface against the current upstream/main (the
prior branch was 20+ commits behind and `SessionExpired` enum + matcher
`is_session_expired_message` + `expected_error_kind` arm + per-kind
`report_expected_message` arm all landed via tinyhumansai#1763, so the original
classifier-extension commits were duplicates).

Three remaining unique deltas land here in one commit:

- `is_session_expired_event(event)` in `src/core/observability.rs` —
  tag-and-body classifier that drops `(domain=llm_provider|backend_api|rpc)
  + status=401 + body matches is_session_expired_message` shapes, plus
  the pre-flight rpc dispatcher path that has no status tag. Composio's
  OAuth-state 401 is intentionally excluded — that's actionable and
  must reach Sentry.

- Bilateral before_send wire in `src/main.rs` (core binary) and
  `app/src-tauri/src/lib.rs` (Tauri shell — since tinyhumansai#1061 it links the
  core in-process, so any session-expired event captured by either
  surface lands in the same Sentry client and must be filtered
  identically). Both filters log only `event.event_id` per CR feedback
  from PR tinyhumansai#1719 — `event.message` carries the raw backend response
  body which CLAUDE.md forbids from local logs.

- Smoke test runtime path in `tests/observability_smoke.rs` — imports
  the new classifier and threads it into the same `before_send` chain
  shape the real binary installs, so the runtime drop is covered end-
  to-end alongside the existing budget / transient / updater filters.

Drops OPENHUMAN-TAURI-25 / -1Q / -27 / -1G (~185 events/day combined).
The original PR's emit-site demotions (compatible.rs / authed_json /
agent run_single) were superseded by tinyhumansai#1763 — leaving them out keeps
this PR scoped to the before_send defense-in-depth that tinyhumansai#1763 didn't
ship.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
senamakel added a commit that referenced this pull request May 21, 2026
## Summary

- Adds a **MCP Server** panel under Settings → Developer Options so users can configure external MCP clients without hand-editing JSON files
- New Tauri commands `mcp_resolve_binary_path` (returns binary path + OS) and `mcp_open_client_config` (opens the client's config file in the system editor)
- Generates correct per-client JSON snippets for Claude Desktop, Cursor, Codex, and Zed — OS-aware config file paths for macOS, Windows, and Linux
- Copy-to-clipboard and "Open Config File" (Tauri-only) buttons eliminate the manual setup steps that were blocking non-developer adoption

## Problem

- The `openhuman-core mcp` stdio server ships 10 memory/tree tools but has zero UI surface — users must locate the binary, find the per-client config file path, and hand-write the JSON
- Conversion drops to near-zero outside of developers; this is the bottleneck on MCP adoption for the features already merged in #1760, #1790, #1974

## Solution

- `app/src-tauri/src/mcp_commands.rs`: two new Tauri shell commands with OS-aware path resolution, auto-create config dirs/files if absent, and platform-specific `open`/`explorer`/`xdg-open` dispatch
- `McpServerPanel.tsx`: reads binary path on mount via `invoke`, generates the correct snippet shape per client (Zed uses `context_servers`, others use `mcpServers`), gracefully degrades when binary is not found
- Binary path resolution handles dev mode (walks up to `target/debug/`), env override (`OPENHUMAN_CORE_BINARY_PATH`), and release mode (sibling of host exe)
- All user-visible strings go through the i18n system; component is Tauri-gated for "Open Config File"

## Submission Checklist

- [x] Tests added or updated (happy path + at least one failure / edge case) — 8 Vitest tests + 9 Rust unit tests covering all client/OS combinations, clipboard copy, binary error fallback, Tauri gate
- [x] **Diff coverage ≥ 80%** — `pnpm test:coverage` passes; new React component and Rust pure functions are fully covered; Tauri command wrappers and release-mode binary path are not testable without a packaged build (noted in PR as a known caveat)
- [x] N/A: Coverage matrix — no new feature rows required; this surfaces existing MCP feature ID `11.1.4` in the UI
- [x] All affected feature IDs from the matrix listed below under Related
- [x] N/A: No new external network dependencies — no network calls; binary resolution is local filesystem only
- [x] N/A: Manual smoke checklist — not a release-cut surface
- [x] Linked issue closed via `Closes #2030`

## Impact

- Desktop only (macOS, Windows, Linux) — uses Tauri shell commands; web/CLI unaffected
- No performance implications; panel is lazy-loaded via routing
- Binary path resolution degrades gracefully if `openhuman-core` is not bundled in the packaged app — shows a build instruction fallback message

## Related

- Closes #2030
- Feature ID: `11.1.4` (MCP stdio server)
- Builds on: #1760, #1790, #1974
- Follow-up: verify `openhuman-core` binary is included in the packaged `.app` bundle (sidecar was removed in #1061; if the binary is not bundled the panel will show the fallback message in production)

---

## AI Authored PR Metadata (required for Codex/Linear PRs)

### Linear Issue
- Key: N/A
- URL: N/A

### Commit & Branch
- Branch: `feat/mcp-settings-panel`
- Commit SHA: 85e091d

### Validation Run
- [x] `pnpm --filter openhuman-app format:check`
- [x] `pnpm typecheck`
- [x] Focused tests: `pnpm debug unit McpServerPanel.test.tsx` — 8/8 passed
- [x] Rust fmt/check (if changed): `cargo fmt --check` + `cargo check --manifest-path app/src-tauri/Cargo.toml` — clean
- [x] Tauri fmt/check (if changed): included above

### Validation Blocked
- `command:` N/A
- `error:` N/A
- `impact:` N/A

### Behavior Changes
- Intended behavior change: Adds MCP Server panel to Settings → Developer Options with snippet generator and config file opener
- User-visible effect: Users can now configure Claude Desktop, Cursor, Codex, or Zed to use OpenHuman's MCP server in a few clicks instead of hand-editing JSON

### Parity Contract
- Legacy behavior preserved: No existing behavior changed; purely additive
- Guard/fallback/dispatch parity checks: `isTauri()` guard on "Open Config File" button; binary-not-found degrades to placeholder with build instructions

### Duplicate / Superseded PR Handling
- Duplicate PR(s): None
- Canonical PR: This PR
- Resolution: N/A

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

* **New Features**
  * Added an "MCP Server" settings panel under Developer Options with tabs for multiple clients (Claude Desktop, Cursor, Codex, Zed)
  * Shows resolved MCP/OpenHuman binary status, generates client-specific JSON snippets, copy-to-clipboard, and an "Open Config File" action when available

* **Tests**
  * Added UI tests for rendering, snippet content, copy behavior, binary-failure fallback, and open-config action

* **Localization**
  * Added translations for the MCP Server UI across many languages

<!-- review_stack_entry_start -->

[![Review Change Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](https://app.coderabbit.ai/change-stack/tinyhumansai/openhuman/pull/2355?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack)

<!-- review_stack_entry_end -->
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

Co-authored-by: M3gA-Mind <megamind@mahadao.com>
Co-authored-by: Steven Enamakel <enamakel@tinyhumans.ai>
mtkik pushed a commit to mtkik/openhuman-meet that referenced this pull request May 21, 2026
## Summary

- Adds a **MCP Server** panel under Settings → Developer Options so users can configure external MCP clients without hand-editing JSON files
- New Tauri commands `mcp_resolve_binary_path` (returns binary path + OS) and `mcp_open_client_config` (opens the client's config file in the system editor)
- Generates correct per-client JSON snippets for Claude Desktop, Cursor, Codex, and Zed — OS-aware config file paths for macOS, Windows, and Linux
- Copy-to-clipboard and "Open Config File" (Tauri-only) buttons eliminate the manual setup steps that were blocking non-developer adoption

## Problem

- The `openhuman-core mcp` stdio server ships 10 memory/tree tools but has zero UI surface — users must locate the binary, find the per-client config file path, and hand-write the JSON
- Conversion drops to near-zero outside of developers; this is the bottleneck on MCP adoption for the features already merged in tinyhumansai#1760, tinyhumansai#1790, tinyhumansai#1974

## Solution

- `app/src-tauri/src/mcp_commands.rs`: two new Tauri shell commands with OS-aware path resolution, auto-create config dirs/files if absent, and platform-specific `open`/`explorer`/`xdg-open` dispatch
- `McpServerPanel.tsx`: reads binary path on mount via `invoke`, generates the correct snippet shape per client (Zed uses `context_servers`, others use `mcpServers`), gracefully degrades when binary is not found
- Binary path resolution handles dev mode (walks up to `target/debug/`), env override (`OPENHUMAN_CORE_BINARY_PATH`), and release mode (sibling of host exe)
- All user-visible strings go through the i18n system; component is Tauri-gated for "Open Config File"

## Submission Checklist

- [x] Tests added or updated (happy path + at least one failure / edge case) — 8 Vitest tests + 9 Rust unit tests covering all client/OS combinations, clipboard copy, binary error fallback, Tauri gate
- [x] **Diff coverage ≥ 80%** — `pnpm test:coverage` passes; new React component and Rust pure functions are fully covered; Tauri command wrappers and release-mode binary path are not testable without a packaged build (noted in PR as a known caveat)
- [x] N/A: Coverage matrix — no new feature rows required; this surfaces existing MCP feature ID `11.1.4` in the UI
- [x] All affected feature IDs from the matrix listed below under Related
- [x] N/A: No new external network dependencies — no network calls; binary resolution is local filesystem only
- [x] N/A: Manual smoke checklist — not a release-cut surface
- [x] Linked issue closed via `Closes tinyhumansai#2030`

## Impact

- Desktop only (macOS, Windows, Linux) — uses Tauri shell commands; web/CLI unaffected
- No performance implications; panel is lazy-loaded via routing
- Binary path resolution degrades gracefully if `openhuman-core` is not bundled in the packaged app — shows a build instruction fallback message

## Related

- Closes tinyhumansai#2030
- Feature ID: `11.1.4` (MCP stdio server)
- Builds on: tinyhumansai#1760, tinyhumansai#1790, tinyhumansai#1974
- Follow-up: verify `openhuman-core` binary is included in the packaged `.app` bundle (sidecar was removed in tinyhumansai#1061; if the binary is not bundled the panel will show the fallback message in production)

---

## AI Authored PR Metadata (required for Codex/Linear PRs)

### Linear Issue
- Key: N/A
- URL: N/A

### Commit & Branch
- Branch: `feat/mcp-settings-panel`
- Commit SHA: 85e091d

### Validation Run
- [x] `pnpm --filter openhuman-app format:check`
- [x] `pnpm typecheck`
- [x] Focused tests: `pnpm debug unit McpServerPanel.test.tsx` — 8/8 passed
- [x] Rust fmt/check (if changed): `cargo fmt --check` + `cargo check --manifest-path app/src-tauri/Cargo.toml` — clean
- [x] Tauri fmt/check (if changed): included above

### Validation Blocked
- `command:` N/A
- `error:` N/A
- `impact:` N/A

### Behavior Changes
- Intended behavior change: Adds MCP Server panel to Settings → Developer Options with snippet generator and config file opener
- User-visible effect: Users can now configure Claude Desktop, Cursor, Codex, or Zed to use OpenHuman's MCP server in a few clicks instead of hand-editing JSON

### Parity Contract
- Legacy behavior preserved: No existing behavior changed; purely additive
- Guard/fallback/dispatch parity checks: `isTauri()` guard on "Open Config File" button; binary-not-found degrades to placeholder with build instructions

### Duplicate / Superseded PR Handling
- Duplicate PR(s): None
- Canonical PR: This PR
- Resolution: N/A

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

* **New Features**
  * Added an "MCP Server" settings panel under Developer Options with tabs for multiple clients (Claude Desktop, Cursor, Codex, Zed)
  * Shows resolved MCP/OpenHuman binary status, generates client-specific JSON snippets, copy-to-clipboard, and an "Open Config File" action when available

* **Tests**
  * Added UI tests for rendering, snippet content, copy behavior, binary-failure fallback, and open-config action

* **Localization**
  * Added translations for the MCP Server UI across many languages

<!-- review_stack_entry_start -->

[![Review Change Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](https://app.coderabbit.ai/change-stack/tinyhumansai/openhuman/pull/2355?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack)

<!-- review_stack_entry_end -->
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

Co-authored-by: M3gA-Mind <megamind@mahadao.com>
Co-authored-by: Steven Enamakel <enamakel@tinyhumans.ai>
CodeGhost21 pushed a commit to CodeGhost21/openhuman that referenced this pull request May 22, 2026
## Summary

- Adds a **MCP Server** panel under Settings → Developer Options so users can configure external MCP clients without hand-editing JSON files
- New Tauri commands `mcp_resolve_binary_path` (returns binary path + OS) and `mcp_open_client_config` (opens the client's config file in the system editor)
- Generates correct per-client JSON snippets for Claude Desktop, Cursor, Codex, and Zed — OS-aware config file paths for macOS, Windows, and Linux
- Copy-to-clipboard and "Open Config File" (Tauri-only) buttons eliminate the manual setup steps that were blocking non-developer adoption

## Problem

- The `openhuman-core mcp` stdio server ships 10 memory/tree tools but has zero UI surface — users must locate the binary, find the per-client config file path, and hand-write the JSON
- Conversion drops to near-zero outside of developers; this is the bottleneck on MCP adoption for the features already merged in tinyhumansai#1760, tinyhumansai#1790, tinyhumansai#1974

## Solution

- `app/src-tauri/src/mcp_commands.rs`: two new Tauri shell commands with OS-aware path resolution, auto-create config dirs/files if absent, and platform-specific `open`/`explorer`/`xdg-open` dispatch
- `McpServerPanel.tsx`: reads binary path on mount via `invoke`, generates the correct snippet shape per client (Zed uses `context_servers`, others use `mcpServers`), gracefully degrades when binary is not found
- Binary path resolution handles dev mode (walks up to `target/debug/`), env override (`OPENHUMAN_CORE_BINARY_PATH`), and release mode (sibling of host exe)
- All user-visible strings go through the i18n system; component is Tauri-gated for "Open Config File"

## Submission Checklist

- [x] Tests added or updated (happy path + at least one failure / edge case) — 8 Vitest tests + 9 Rust unit tests covering all client/OS combinations, clipboard copy, binary error fallback, Tauri gate
- [x] **Diff coverage ≥ 80%** — `pnpm test:coverage` passes; new React component and Rust pure functions are fully covered; Tauri command wrappers and release-mode binary path are not testable without a packaged build (noted in PR as a known caveat)
- [x] N/A: Coverage matrix — no new feature rows required; this surfaces existing MCP feature ID `11.1.4` in the UI
- [x] All affected feature IDs from the matrix listed below under Related
- [x] N/A: No new external network dependencies — no network calls; binary resolution is local filesystem only
- [x] N/A: Manual smoke checklist — not a release-cut surface
- [x] Linked issue closed via `Closes tinyhumansai#2030`

## Impact

- Desktop only (macOS, Windows, Linux) — uses Tauri shell commands; web/CLI unaffected
- No performance implications; panel is lazy-loaded via routing
- Binary path resolution degrades gracefully if `openhuman-core` is not bundled in the packaged app — shows a build instruction fallback message

## Related

- Closes tinyhumansai#2030
- Feature ID: `11.1.4` (MCP stdio server)
- Builds on: tinyhumansai#1760, tinyhumansai#1790, tinyhumansai#1974
- Follow-up: verify `openhuman-core` binary is included in the packaged `.app` bundle (sidecar was removed in tinyhumansai#1061; if the binary is not bundled the panel will show the fallback message in production)

---

## AI Authored PR Metadata (required for Codex/Linear PRs)

### Linear Issue
- Key: N/A
- URL: N/A

### Commit & Branch
- Branch: `feat/mcp-settings-panel`
- Commit SHA: 85e091d

### Validation Run
- [x] `pnpm --filter openhuman-app format:check`
- [x] `pnpm typecheck`
- [x] Focused tests: `pnpm debug unit McpServerPanel.test.tsx` — 8/8 passed
- [x] Rust fmt/check (if changed): `cargo fmt --check` + `cargo check --manifest-path app/src-tauri/Cargo.toml` — clean
- [x] Tauri fmt/check (if changed): included above

### Validation Blocked
- `command:` N/A
- `error:` N/A
- `impact:` N/A

### Behavior Changes
- Intended behavior change: Adds MCP Server panel to Settings → Developer Options with snippet generator and config file opener
- User-visible effect: Users can now configure Claude Desktop, Cursor, Codex, or Zed to use OpenHuman's MCP server in a few clicks instead of hand-editing JSON

### Parity Contract
- Legacy behavior preserved: No existing behavior changed; purely additive
- Guard/fallback/dispatch parity checks: `isTauri()` guard on "Open Config File" button; binary-not-found degrades to placeholder with build instructions

### Duplicate / Superseded PR Handling
- Duplicate PR(s): None
- Canonical PR: This PR
- Resolution: N/A

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

* **New Features**
  * Added an "MCP Server" settings panel under Developer Options with tabs for multiple clients (Claude Desktop, Cursor, Codex, Zed)
  * Shows resolved MCP/OpenHuman binary status, generates client-specific JSON snippets, copy-to-clipboard, and an "Open Config File" action when available

* **Tests**
  * Added UI tests for rendering, snippet content, copy behavior, binary-failure fallback, and open-config action

* **Localization**
  * Added translations for the MCP Server UI across many languages

<!-- review_stack_entry_start -->

[![Review Change Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](https://app.coderabbit.ai/change-stack/tinyhumansai/openhuman/pull/2355?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack)

<!-- review_stack_entry_end -->
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

Co-authored-by: M3gA-Mind <megamind@mahadao.com>
Co-authored-by: Steven Enamakel <enamakel@tinyhumans.ai>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant