Skip to content

refactor: remove QuickJS skills runtime#508

Merged
senamakel merged 6 commits intotinyhumansai:mainfrom
senamakel:feat/remove-skills
Apr 11, 2026
Merged

refactor: remove QuickJS skills runtime#508
senamakel merged 6 commits intotinyhumansai:mainfrom
senamakel:feat/remove-skills

Conversation

@senamakel
Copy link
Copy Markdown
Member

@senamakel senamakel commented Apr 11, 2026

Summary

  • Remove the in-repo QuickJS skills runtime and its app-side management layer.
  • Stop registering skills controllers, CLI entrypoints, and dynamic skill delegation tools in the Rust core.
  • Simplify onboarding, settings, deep link, socket, and mnemonic flows so they no longer depend on the removed runtime.
  • Keep Composio and other integration-facing paths intact while replacing shared skill status usage with a lightweight frontend type.

Problem

  • The product still carried a custom QuickJS-based skills runtime even though integrations are now expected to come from external providers instead of the local JS runtime.
  • That runtime added dead execution paths, bridge code, webhook handling, onboarding/setup UI, and maintenance surface across both Rust and the app.
  • Keeping those paths around increases ambiguity about the supported integration model and makes future integration work harder to reason about.

Solution

  • Delete the QuickJS runtime implementation, skill bridge modules, registry/cache helpers, and related UI/runtime management files.
  • Remove skill-specific controller registration and CLI/json-rpc bootstrap wiring so the core no longer starts or exposes the local runtime.
  • Update remaining skill-related UX and docs text to reflect Composio/integration-only behavior instead of local QuickJS execution.
  • Retain only lightweight shared types and no-op compatibility shims where needed to avoid unnecessary churn in unaffected code paths.

Submission Checklist

  • Unit tests — Vitest (app/) and/or cargo test (core) for logic you add or change
  • E2E / integration — Where behavior is user-visible or crosses UI → Tauri → sidecar → JSON-RPC; use existing harnesses (app/test/e2e, mock backend, tests/json_rpc_e2e.rs as appropriate)
  • N/A — Full new test coverage was not added in this refactor; verification for this change set was limited to type/build checks listed below.
  • Doc comments/// / //! (Rust), JSDoc or brief file/module headers (TS) on public APIs and non-obvious modules
  • Inline comments — Where logic, invariants, or edge cases aren’t clear from names alone (keep them grep-friendly; avoid restating the code)

Verification run:

  • cargo check --manifest-path Cargo.toml
  • yarn typecheck
  • repo pre-push checks: format:check, lint, tsc --noEmit, cargo check --manifest-path app/src-tauri/Cargo.toml

Impact

  • Desktop app and core sidecar no longer ship or bootstrap the local QuickJS skills runtime.
  • Existing runtime-specific settings/onboarding flows are removed or reduced to integration-only behavior.
  • Webhook requests that depended on the local skill runtime now return a removed/unavailable response instead of attempting execution.
  • Residual mentions may remain in tests or copy, but active compiled runtime paths for QuickJS skills are removed.

Related

  • Issue(s): none linked
  • Follow-up PR(s)/TODOs: clean up remaining legacy test fixtures/copy that still reference the removed skills runtime

Summary by CodeRabbit

  • Removed Features

    • Dropped support for QuickJS-based custom skills, runtime tooling, management UIs, CLI commands, debugging, and related sync/cron capabilities.
  • Simplified Setup

    • Recovery phrase now only derives/stores an encryption key (wallet address persistence removed).
    • Onboarding defers integration setup and no longer auto-opens integration setup flows; many connection/config UIs simplified.
  • Updated Documentation

    • Skills agent/prompt language refocused to Composio-managed integrations.
  • Other

    • OAuth deep-link flow simplified; error reports no longer label source as "skill."

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 11, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 3f14e8c0-6e28-43f1-ad39-261d28f6b3a1

📥 Commits

Reviewing files that changed from the base of the PR and between 367d75c and 52a3220.

📒 Files selected for processing (1)
  • app/src/components/skills/SkillCard.tsx

📝 Walkthrough

Walkthrough

The PR removes the QuickJS-based "skills" subsystem across frontend and backend: runtime, CLI, JSON-RPC schemas/handlers, runtime bridges, schedulers, registry, many React skill UIs/hooks, Tauri skill commands, related types, and the rquickjs Cargo dependency.

Changes

Cohort / File(s) Summary
Cargo
Cargo.toml
Removed rquickjs dependency.
Frontend: skill UI & onboarding
app/src/components/skills/*, app/src/components/settings/..., app/src/pages/onboarding/steps/SkillsStep.tsx
Deleted numerous skill UI components and flows (SetupWizard, SetupModal, ManagementPanel, DebugModal, SetupFormRenderer, AuthModeSelector, RuntimeSkillCronList); simplified settings and onboarding to remove skill discovery/setup modals and per-skill state.
Frontend: skill APIs, hooks & types
app/src/lib/skills/*, app/src/utils/tauriCommands/skills.ts, app/src/utils/tauriCommands/index.ts
Removed frontend skills library: manager, runtime wrappers, transport, hooks, types, RPC client layer, sync tooling; removed Tauri skill command exports.
Frontend: small behavior/type changes
app/src/features/*/use*SkillStatus.ts, app/src/types/skillStatus.ts, app/src/utils/desktopDeepLinkListener.ts, app/src/services/socketService.ts, app/src/services/errorReportQueue.ts, app/src/lib/composio/composioApi.ts
Moved SkillConnectionStatus type to new file; changed desktop OAuth deep-link to emit oauth:success with integrationId/toolkit (removed skill-start/notify); removed post-connect skill resync call; narrowed error report source union; doc tweak.
Frontend: mnemonic & tests
app/src/pages/Mnemonic.tsx, app/test/Mnemonic.test.tsx, app/src/pages/__tests__/skillsSyncUi.test.ts
Removed wallet-address persistence and related derivation; tests updated to expect encryption-key behavior; removed skills sync UI tests.
Frontend: settings panels & misc
app/src/components/settings/SettingsHome.tsx, app/src/components/settings/panels/ConnectionsPanel.tsx, app/src/components/settings/panels/CronJobsPanel.tsx, app/src/components/settings/panels/RecoveryPhrasePanel.tsx, app/src/components/ErrorReportNotification.tsx, app/src/pages/Conversations.tsx
Removed skill-manager calls and modal state; adjusted confirmation copy; removed runtime cron UI and skill-source badge; minor lint/test comment removal.
Rust core bootstrap & CLI
src/core/jsonrpc.rs, src/core/all.rs, src/core/cli.rs, src/core/skills_cli.rs, src/core/mod.rs
Removed skills CLI and skill runtime bootstrap: dropped skills controller registrations, removed skills CLI dispatch and deleted skills_cli.rs; refactored bootstrap to not initialize QuickJS runtime or skill background schedulers.
Rust: skills subsystem (major removal)
src/openhuman/skills/** (many files: manifest, qjs_engine, qjs_skill_instance/, quickjs_libs/, registry_*, cron_scheduler, ping_scheduler, paths, preferences, bridge/net, storage, utils, schemas, skill_registry, etc.)
Removed virtually all QuickJS/skills runtime code and related modules (manifests, engine, instance/event loop, js helpers/handlers, ops_core/net/state/storage/webhook, IndexedDB shim, cron/ping schedulers, registry + cache + ops, bridge/net, preferences, SkillManager equivalents, RPC schemas). Retained only a minimal skills surface with many re-exports removed.
Rust: agent & tool registry changes
src/openhuman/agent/agents/skills_agent/*, src/openhuman/composio/tools.rs, src/openhuman/agent/harness/session/builder.rs
Removed QuickJS skill-tool injection into agent tool registry and removed QuickJS tool mentions from agent prompt/config; updated Composio comment.

Sequence Diagram(s)

sequenceDiagram
  participant Browser
  participant DesktopDeepLinkListener
  participant FrontendSkillManager as SkillManager
  participant BackendCore as CoreRuntime

  rect rgba(200,200,255,0.5)
    Browser->>DesktopDeepLinkListener: open oauth deep link (params)
  end

  Note over DesktopDeepLinkListener,FrontendSkillManager: OLD flow (removed)
  DesktopDeepLinkListener->>FrontendSkillManager: extract skillId, clientKey...
  FrontendSkillManager->>BackendCore: startSkill(skillId)
  BackendCore-->>FrontendSkillManager: started
  FrontendSkillManager->>FrontendSkillManager: notifyOAuthComplete(...)
  FrontendSkillManager->>Browser: navigate to skill UI

  Note over DesktopDeepLinkListener,BackendCore: NEW flow (current)
  DesktopDeepLinkListener-->>Browser: dispatch window event oauth:success {integrationId, toolkit}
  DesktopDeepLinkListener->>Browser: navigate to `#/skills`
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Possibly related PRs

Poem

🐰 I hopped through code with nimble paws,

QuickJS gardens trimmed of laws.
Bridges folded, toolkits rest,
Quiet burrow, time to nest.
I twitch my nose, then hop — onward we build the next.

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

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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
src/core/jsonrpc.rs (1)

821-823: ⚠️ Potential issue | 🟡 Minor

Log message references "skill" subscriber that is no longer registered.

The log lists "skill" among registered subscribers, but register_skill_cleanup_subscriber() is no longer called in this function. This could cause confusion when debugging.

📝 Suggested fix
     log::info!(
-        "[event_bus] webhook, channel, health, skill, composio, restart subscribers + agent native handlers registered"
+        "[event_bus] webhook, channel, health, composio, restart subscribers + agent native handlers registered"
     );
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/core/jsonrpc.rs` around lines 821 - 823, The log message currently claims
"skill" subscribers are registered but register_skill_cleanup_subscriber() is no
longer called; either remove "skill" from the log string or reintroduce the
missing call to register_skill_cleanup_subscriber() to keep the message
accurate—update the logging statement that contains "[event_bus] webhook,
channel, health, skill, composio, restart subscribers + agent native handlers
registered" to reflect the actual subscribers registered by this function or add
a call to register_skill_cleanup_subscriber() where other subscribers are
registered.
app/src/services/errorReportQueue.ts (1)

48-48: ⚠️ Potential issue | 🟡 Minor

Remove the unused 'skill' source from the PendingErrorReport type union.

The 'skill' literal is dead code—no code in the codebase calls enqueueError with source: 'skill'. Only 'manual' and 'global' sources are actually used. Since the PR removed the QuickJS skills runtime entirely, remove 'skill' from the type definition to keep it consistent with the updated documentation and actual usage:

source: 'react' | 'global' | 'manual';
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/src/services/errorReportQueue.ts` at line 48, Update the
PendingErrorReport type by removing the unused 'skill' literal from the source
union (change source: 'react' | 'global' | 'manual') and then update any related
type annotations/usages (e.g., enqueueError signature and its callers) to match
the new union so there are no lingering references to 'skill'; search for
PendingErrorReport and enqueueError to adjust types and remove dead branches
that handle 'skill'.
app/src/components/skills/SkillCard.tsx (1)

1-19: ⚠️ Potential issue | 🟡 Minor

Use import type for ReactNode props.

UnifiedSkillCardProps uses type-only React symbols (React.ReactNode) but imports React only for runtime values. Add a type import for ReactNode and use it directly to align with repo TypeScript conventions.

Suggested change
 import { useEffect, useRef, useState } from 'react';
+import type { ReactNode } from 'react';

 export interface UnifiedSkillCardProps {
-  icon: React.ReactNode;
+  icon: ReactNode;
   title: string;
   description: string;
@@
   secondaryActions?: Array<{
     label: string;
-    icon: React.ReactNode;
+    icon: ReactNode;
     onClick: () => void;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/src/components/skills/SkillCard.tsx` around lines 1 - 19, The props use
the type React.ReactNode but the file imports React only for runtime hooks; add
a type-only import for ReactNode and replace React.ReactNode usages in
UnifiedSkillCardProps (and in the secondaryActions.icon type) with the imported
ReactNode to follow repo TypeScript conventions; specifically add an import type
{ ReactNode } from 'react' and update UnifiedSkillCardProps.icon and
secondaryActions[].icon to use ReactNode while leaving the existing runtime
imports (useEffect, useRef, useState) unchanged.
🧹 Nitpick comments (5)
app/src/components/settings/panels/CronJobsPanel.tsx (2)

36-48: Add namespaced debug checkpoints in the updated cron load path.

This changed flow now drives the panel’s primary fetch/refresh behavior but has no debug entry/success/failure checkpoints, which makes tracing harder during app-side + sidecar investigations.

Proposed logging patch
   const loadCronSkills = useCallback(async () => {
+    console.debug('[cron-panel] loadCronSkills:start');
     setLoading(true);
     setCoreError(null);

     try {
       await loadCoreCronJobs();
+      console.debug('[cron-panel] loadCronSkills:success');
     } catch (err) {
       const message = err instanceof Error ? err.message : String(err);
+      console.debug('[cron-panel] loadCronSkills:error', { message });
       setCoreError(`Failed to load core cron jobs: ${message}`);
     } finally {
+      console.debug('[cron-panel] loadCronSkills:done');
       setLoading(false);
     }
   }, [loadCoreCronJobs]);

As per coding guidelines: “Add substantial, development-oriented logs on new/changed flows in TypeScript/React app code; use namespaced debug logs…”.

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

In `@app/src/components/settings/panels/CronJobsPanel.tsx` around lines 36 - 48,
Add namespaced debug checkpoints to the cron load flow in loadCronSkills: log an
entry at the start, a success after loadCoreCronJobs completes, and a failure in
the catch including the full error; use a consistent namespace like
"app:settings:CronJobsPanel:loadCronSkills" and call the logger (or
console.debug) before setLoading/setCoreError to aid tracing. Reference the
loadCronSkills function and the loadCoreCronJobs call, and ensure the catch logs
the error details while still setting setCoreError and finally toggling
setLoading(false).

36-52: Rename loadCronSkills to reflect current behavior.

After runtime removal, this callback only loads core scheduler jobs. Renaming will reduce future confusion and keep call sites self-documenting.

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

In `@app/src/components/settings/panels/CronJobsPanel.tsx` around lines 36 - 52,
The function name loadCronSkills is misleading because it only loads core
scheduler jobs; rename it to something explicit (e.g., loadCoreCronJobsOnly or
loadCoreCronJobsWrapper) and update all references in this file: change the
useCallback declaration name, the dependency array (keep loadCoreCronJobs), and
the useEffect invocation (void loadCoreCronJobsOnly()); preserve the same async
logic, error handling (setCoreError), and state updates (setLoading) so behavior
is unchanged.
app/src/utils/desktopDeepLinkListener.ts (1)

249-252: Stale simulation example still references skillId.

The __simulateDeepLink example comment at line 250 still includes skillId=notion, but the OAuth success handler no longer uses skillId. Consider updating the example to reflect the current expected parameters.

-      // window.__simulateDeepLink('openhuman://oauth/success?integrationId=69cafd0b103bd070232d3223&skillId=notion')
+      // window.__simulateDeepLink('openhuman://oauth/success?integrationId=69cafd0b103bd070232d3223&toolkit=notion')
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/src/utils/desktopDeepLinkListener.ts` around lines 249 - 252, Update the
stale simulation comment for the test helper: change the sample URL passed to
window.__simulateDeepLink so it matches the current OAuth success handler's
expected query params (remove the obsolete skillId or replace it with the
current param name used by handleDeepLinkUrls, e.g., provider) and ensure the
example still shows a realistic integrationId; the helper is the
win.__simulateDeepLink assignment and the call into handleDeepLinkUrls([url]).
app/src/components/settings/panels/ConnectionsPanel.tsx (2)

85-85: Hardcoded status value creates dead code path.

connectionStatus is hardcoded to 'setup_required' and never used dynamically. Since all connectOptions have comingSoon: true, the badge rendering at lines 95-102 (which checks option.skillId) will never execute. This appears to be placeholder code.

Consider either:

  1. Removing the skill-specific badge logic entirely since it's unreachable
  2. Adding a comment explaining this is preserved for future use
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/src/components/settings/panels/ConnectionsPanel.tsx` at line 85, The code
sets connectionStatus = 'setup_required' (type SkillConnectionStatus) and leaves
all connectOptions with comingSoon: true, making the skill-specific badge
rendering that checks option.skillId unreachable; either remove the dead badge
logic that depends on option.skillId and related branches (clean up the
conditional rendering around the badge) or keep the rendering but add a clear
comment above connectionStatus and the connectOptions explaining this is
placeholder preserved for future dynamic status and will be updated when
connectOptions are no longer comingSoon; update or remove references to
connectionStatus and the badge conditional accordingly (look for
connectionStatus, SkillConnectionStatus, connectOptions, and option.skillId to
locate the relevant code).

172-175: handleConnect is now a no-op for all current options.

With all connection options marked as comingSoon: true, and the skillId check added at line 174, handleConnect effectively does nothing for any option. This is acceptable as transitional code, but consider adding a brief comment or TODO to clarify the intended future behavior.

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

In `@app/src/components/settings/panels/ConnectionsPanel.tsx` around lines 172 -
175, handleConnect currently returns early for all options because every
ConnectOption has comingSoon=true and you also short-circuit when option.skillId
is present; add a concise TODO comment inside the handleConnect function
explaining that this is intentionally a temporary no-op and what should happen
later (e.g., open a connection modal or dispatch a connect action when
comingSoon is false or a skillId is provided). Reference the early-return checks
(option.comingSoon and option.skillId) in the comment so future maintainers know
where to implement the real connect flow (open modal, route, or call connect
handler) when options become active.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@app/src/components/skills/SkillCard.tsx`:
- Around line 1-19: The props use the type React.ReactNode but the file imports
React only for runtime hooks; add a type-only import for ReactNode and replace
React.ReactNode usages in UnifiedSkillCardProps (and in the
secondaryActions.icon type) with the imported ReactNode to follow repo
TypeScript conventions; specifically add an import type { ReactNode } from
'react' and update UnifiedSkillCardProps.icon and secondaryActions[].icon to use
ReactNode while leaving the existing runtime imports (useEffect, useRef,
useState) unchanged.

In `@app/src/services/errorReportQueue.ts`:
- Line 48: Update the PendingErrorReport type by removing the unused 'skill'
literal from the source union (change source: 'react' | 'global' | 'manual') and
then update any related type annotations/usages (e.g., enqueueError signature
and its callers) to match the new union so there are no lingering references to
'skill'; search for PendingErrorReport and enqueueError to adjust types and
remove dead branches that handle 'skill'.

In `@src/core/jsonrpc.rs`:
- Around line 821-823: The log message currently claims "skill" subscribers are
registered but register_skill_cleanup_subscriber() is no longer called; either
remove "skill" from the log string or reintroduce the missing call to
register_skill_cleanup_subscriber() to keep the message accurate—update the
logging statement that contains "[event_bus] webhook, channel, health, skill,
composio, restart subscribers + agent native handlers registered" to reflect the
actual subscribers registered by this function or add a call to
register_skill_cleanup_subscriber() where other subscribers are registered.

---

Nitpick comments:
In `@app/src/components/settings/panels/ConnectionsPanel.tsx`:
- Line 85: The code sets connectionStatus = 'setup_required' (type
SkillConnectionStatus) and leaves all connectOptions with comingSoon: true,
making the skill-specific badge rendering that checks option.skillId
unreachable; either remove the dead badge logic that depends on option.skillId
and related branches (clean up the conditional rendering around the badge) or
keep the rendering but add a clear comment above connectionStatus and the
connectOptions explaining this is placeholder preserved for future dynamic
status and will be updated when connectOptions are no longer comingSoon; update
or remove references to connectionStatus and the badge conditional accordingly
(look for connectionStatus, SkillConnectionStatus, connectOptions, and
option.skillId to locate the relevant code).
- Around line 172-175: handleConnect currently returns early for all options
because every ConnectOption has comingSoon=true and you also short-circuit when
option.skillId is present; add a concise TODO comment inside the handleConnect
function explaining that this is intentionally a temporary no-op and what should
happen later (e.g., open a connection modal or dispatch a connect action when
comingSoon is false or a skillId is provided). Reference the early-return checks
(option.comingSoon and option.skillId) in the comment so future maintainers know
where to implement the real connect flow (open modal, route, or call connect
handler) when options become active.

In `@app/src/components/settings/panels/CronJobsPanel.tsx`:
- Around line 36-48: Add namespaced debug checkpoints to the cron load flow in
loadCronSkills: log an entry at the start, a success after loadCoreCronJobs
completes, and a failure in the catch including the full error; use a consistent
namespace like "app:settings:CronJobsPanel:loadCronSkills" and call the logger
(or console.debug) before setLoading/setCoreError to aid tracing. Reference the
loadCronSkills function and the loadCoreCronJobs call, and ensure the catch logs
the error details while still setting setCoreError and finally toggling
setLoading(false).
- Around line 36-52: The function name loadCronSkills is misleading because it
only loads core scheduler jobs; rename it to something explicit (e.g.,
loadCoreCronJobsOnly or loadCoreCronJobsWrapper) and update all references in
this file: change the useCallback declaration name, the dependency array (keep
loadCoreCronJobs), and the useEffect invocation (void loadCoreCronJobsOnly());
preserve the same async logic, error handling (setCoreError), and state updates
(setLoading) so behavior is unchanged.

In `@app/src/utils/desktopDeepLinkListener.ts`:
- Around line 249-252: Update the stale simulation comment for the test helper:
change the sample URL passed to window.__simulateDeepLink so it matches the
current OAuth success handler's expected query params (remove the obsolete
skillId or replace it with the current param name used by handleDeepLinkUrls,
e.g., provider) and ensure the example still shows a realistic integrationId;
the helper is the win.__simulateDeepLink assignment and the call into
handleDeepLinkUrls([url]).

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: b8d90abd-6cb8-4196-b32f-57d59051fd6a

📥 Commits

Reviewing files that changed from the base of the PR and between 5420ede and ea3a098.

⛔ Files ignored due to path filters (2)
  • Cargo.lock is excluded by !**/*.lock
  • app/src-tauri/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (94)
  • Cargo.toml
  • app/src/components/settings/SettingsHome.tsx
  • app/src/components/settings/panels/ConnectionsPanel.tsx
  • app/src/components/settings/panels/CronJobsPanel.tsx
  • app/src/components/settings/panels/RecoveryPhrasePanel.tsx
  • app/src/components/settings/panels/cron/RuntimeSkillCronList.tsx
  • app/src/components/skills/AuthModeSelector.tsx
  • app/src/components/skills/SetupFormRenderer.tsx
  • app/src/components/skills/SkillCard.tsx
  • app/src/components/skills/SkillDebugModal.tsx
  • app/src/components/skills/SkillManagementPanel.tsx
  • app/src/components/skills/SkillSetupModal.tsx
  • app/src/components/skills/SkillSetupWizard.tsx
  • app/src/components/skills/shared.tsx
  • app/src/features/autocomplete/useAutocompleteSkillStatus.ts
  • app/src/features/screen-intelligence/useScreenIntelligenceSkillStatus.ts
  • app/src/features/voice/useVoiceSkillStatus.ts
  • app/src/lib/composio/composioApi.ts
  • app/src/lib/skills/hooks.ts
  • app/src/lib/skills/index.ts
  • app/src/lib/skills/manager.ts
  • app/src/lib/skills/paths.ts
  • app/src/lib/skills/runtime.ts
  • app/src/lib/skills/skillEvents.ts
  • app/src/lib/skills/skillsApi.ts
  • app/src/lib/skills/sync.ts
  • app/src/lib/skills/transport.ts
  • app/src/lib/skills/types.ts
  • app/src/pages/Mnemonic.tsx
  • app/src/pages/__tests__/skillsSyncUi.test.ts
  • app/src/pages/onboarding/steps/SkillsStep.tsx
  • app/src/pages/skillsSyncUi.ts
  • app/src/services/errorReportQueue.ts
  • app/src/services/socketService.ts
  • app/src/types/skillStatus.ts
  • app/src/utils/desktopDeepLinkListener.ts
  • app/src/utils/tauriCommands/index.ts
  • app/src/utils/tauriCommands/skills.ts
  • src/core/all.rs
  • src/core/cli.rs
  • src/core/jsonrpc.rs
  • src/core/mod.rs
  • src/core/skills_cli.rs
  • src/openhuman/agent/agents/skills_agent/agent.toml
  • src/openhuman/agent/agents/skills_agent/prompt.md
  • src/openhuman/agent/harness/session/builder.rs
  • src/openhuman/composio/tools.rs
  • src/openhuman/skills/bridge/mod.rs
  • src/openhuman/skills/bridge/net.rs
  • src/openhuman/skills/bus.rs
  • src/openhuman/skills/cron_scheduler.rs
  • src/openhuman/skills/manifest.rs
  • src/openhuman/skills/mod.rs
  • src/openhuman/skills/paths.rs
  • src/openhuman/skills/ping_scheduler.rs
  • src/openhuman/skills/preferences.rs
  • src/openhuman/skills/qjs_engine.rs
  • src/openhuman/skills/qjs_skill_instance/event_loop/mod.rs
  • src/openhuman/skills/qjs_skill_instance/event_loop/rpc_handlers.rs
  • src/openhuman/skills/qjs_skill_instance/event_loop/webhook_handler.rs
  • src/openhuman/skills/qjs_skill_instance/instance.rs
  • src/openhuman/skills/qjs_skill_instance/js_handlers.rs
  • src/openhuman/skills/qjs_skill_instance/js_helpers.rs
  • src/openhuman/skills/qjs_skill_instance/mod.rs
  • src/openhuman/skills/qjs_skill_instance/types.rs
  • src/openhuman/skills/quickjs_libs/bootstrap.js
  • src/openhuman/skills/quickjs_libs/mod.rs
  • src/openhuman/skills/quickjs_libs/qjs_ops/mod.rs
  • src/openhuman/skills/quickjs_libs/qjs_ops/ops.rs
  • src/openhuman/skills/quickjs_libs/qjs_ops/ops_core.rs
  • src/openhuman/skills/quickjs_libs/qjs_ops/ops_net.rs
  • src/openhuman/skills/quickjs_libs/qjs_ops/ops_state.rs
  • src/openhuman/skills/quickjs_libs/qjs_ops/ops_storage.rs
  • src/openhuman/skills/quickjs_libs/qjs_ops/ops_webhook.rs
  • src/openhuman/skills/quickjs_libs/qjs_ops/types.rs
  • src/openhuman/skills/quickjs_libs/storage.rs
  • src/openhuman/skills/registry_cache.rs
  • src/openhuman/skills/registry_ops.rs
  • src/openhuman/skills/registry_types.rs
  • src/openhuman/skills/schemas.rs
  • src/openhuman/skills/skill_registry.rs
  • src/openhuman/skills/types.rs
  • src/openhuman/skills/utils.rs
  • src/openhuman/skills/working_memory.rs
  • src/openhuman/subconscious/situation_report.rs
  • src/openhuman/tools/impl/agent/mod.rs
  • src/openhuman/tools/impl/agent/spawn_subagent.rs
  • src/openhuman/tools/impl/network/mod.rs
  • src/openhuman/tools/impl/network/skill_bridge.rs
  • src/openhuman/tools/mod.rs
  • src/openhuman/tools/orchestrator_tools.rs
  • src/openhuman/tools/traits.rs
  • src/openhuman/webhooks/bus.rs
  • src/openhuman/webhooks/ops.rs
💤 Files with no reviewable changes (64)
  • Cargo.toml
  • src/core/mod.rs
  • app/src/components/settings/panels/RecoveryPhrasePanel.tsx
  • app/src/services/socketService.ts
  • src/core/cli.rs
  • src/openhuman/agent/harness/session/builder.rs
  • src/openhuman/skills/quickjs_libs/mod.rs
  • src/openhuman/skills/bridge/mod.rs
  • app/src/pages/tests/skillsSyncUi.test.ts
  • app/src/components/skills/AuthModeSelector.tsx
  • src/core/all.rs
  • app/src/pages/Mnemonic.tsx
  • app/src/components/settings/panels/cron/RuntimeSkillCronList.tsx
  • app/src/utils/tauriCommands/index.ts
  • app/src/components/skills/SkillSetupModal.tsx
  • src/openhuman/skills/cron_scheduler.rs
  • src/openhuman/skills/qjs_skill_instance/event_loop/webhook_handler.rs
  • app/src/lib/skills/transport.ts
  • src/core/skills_cli.rs
  • app/src/lib/skills/paths.ts
  • src/openhuman/skills/quickjs_libs/qjs_ops/ops.rs
  • app/src/lib/skills/index.ts
  • src/openhuman/skills/qjs_skill_instance/mod.rs
  • app/src/lib/skills/skillEvents.ts
  • app/src/components/skills/SkillDebugModal.tsx
  • src/openhuman/skills/schemas.rs
  • app/src/lib/skills/manager.ts
  • src/openhuman/skills/qjs_skill_instance/types.rs
  • src/openhuman/skills/paths.rs
  • app/src/components/skills/shared.tsx
  • src/openhuman/skills/quickjs_libs/qjs_ops/mod.rs
  • app/src/components/skills/SetupFormRenderer.tsx
  • src/openhuman/skills/quickjs_libs/qjs_ops/ops_state.rs
  • src/openhuman/skills/qjs_skill_instance/js_handlers.rs
  • src/openhuman/skills/registry_types.rs
  • src/openhuman/skills/ping_scheduler.rs
  • src/openhuman/skills/quickjs_libs/qjs_ops/ops_net.rs
  • app/src/lib/skills/types.ts
  • app/src/components/skills/SkillSetupWizard.tsx
  • src/openhuman/skills/utils.rs
  • app/src/components/skills/SkillManagementPanel.tsx
  • app/src/pages/skillsSyncUi.ts
  • src/openhuman/skills/qjs_skill_instance/js_helpers.rs
  • src/openhuman/skills/quickjs_libs/qjs_ops/types.rs
  • app/src/lib/skills/runtime.ts
  • src/openhuman/skills/quickjs_libs/qjs_ops/ops_storage.rs
  • src/openhuman/skills/quickjs_libs/qjs_ops/ops_webhook.rs
  • src/openhuman/skills/registry_cache.rs
  • src/openhuman/skills/quickjs_libs/bootstrap.js
  • src/openhuman/skills/quickjs_libs/qjs_ops/ops_core.rs
  • app/src/lib/skills/skillsApi.ts
  • src/openhuman/skills/bridge/net.rs
  • src/openhuman/skills/registry_ops.rs
  • src/openhuman/skills/manifest.rs
  • app/src/utils/tauriCommands/skills.ts
  • src/openhuman/skills/qjs_skill_instance/event_loop/rpc_handlers.rs
  • src/openhuman/skills/qjs_skill_instance/event_loop/mod.rs
  • src/openhuman/skills/qjs_engine.rs
  • app/src/lib/skills/hooks.ts
  • src/openhuman/skills/quickjs_libs/storage.rs
  • src/openhuman/skills/skill_registry.rs
  • src/openhuman/skills/preferences.rs
  • app/src/lib/skills/sync.ts
  • src/openhuman/skills/qjs_skill_instance/instance.rs

- Removed the 'skill' source option from the error report structure to streamline error reporting.
- Refactored the ConnectionsPanel component to simplify connection status badge rendering and improve clarity.
- Updated the CronJobsPanel to enhance logging for cron job loading processes.
- Adjusted SkillCard component to use a more consistent type for icons.
- Deleted outdated end-to-end tests for Gmail and Notion skills, improving test suite maintainability.
…nent

- Cleaned up the Conversations component by removing the ESLint disable comment for exhaustive dependencies in the useEffect hook, improving code clarity and maintainability.
- Eliminated an extra line of whitespace in the Conversations component, enhancing code readability and maintainability.
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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
app/src/components/settings/panels/CronJobsPanel.tsx (1)

17-48: ⚠️ Potential issue | 🟡 Minor

Rename the debug namespace to match the core-only path.

Line 17 still uses loadCronSkills, which is stale after removing runtime skills and makes log grep/correlation noisier.

Suggested diff
-const loadCronJobsLog = createDebug('app:settings:CronJobsPanel:loadCronSkills');
+const loadCoreCronJobsLog = createDebug('app:settings:CronJobsPanel:loadCoreCronJobs');

-    loadCronJobsLog('start');
+    loadCoreCronJobsLog('start');
...
-      loadCronJobsLog('success');
+      loadCoreCronJobsLog('success');
...
-      loadCronJobsLog('failure', err);
+      loadCoreCronJobsLog('failure', err);

As per coding guidelines, "Use grep-friendly log prefixes ([feature], domain name, or JSON-RPC method) in app code for correlation with sidecar and Tauri output".

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

In `@app/src/components/settings/panels/CronJobsPanel.tsx` around lines 17 - 48,
The debug namespace string assigned to loadCronJobsLog is stale
("app:settings:CronJobsPanel:loadCronSkills"); change it to a grep-friendly name
that reflects the core-only path (e.g.,
"app:settings:CronJobsPanel:loadCoreCronJobs" or similar) and update all usages
(loadCronJobsLog(...) calls in loadCoreCronJobsOnly and any other places) so
logs correlate with the current CronJobsPanel core job flows; ensure the
variable name loadCronJobsLog and the function loadCoreCronJobsOnly remain the
same so the change is limited to the namespace string.
🧹 Nitpick comments (2)
app/test/Mnemonic.test.tsx (1)

449-458: Prefer behavior assertions over internal util-call assertions (and align test naming)

On Line 513, the test name claims navigation to /home, but it only asserts mockDeriveAesKey invocation. Also, both segments assert internal derivation calls, which are implementation-coupled. Prefer asserting user-visible outcomes/state effects (e.g., successful persistence + navigation), or rename tests so names match what is actually asserted.

♻️ Suggested direction
- it('derives the encryption key from the imported phrase and navigates to /home', async () => {
+ it('stores encryption key after importing a valid recovery phrase', async () => {
   ...
-  expect(mockDeriveAesKey).toHaveBeenCalledWith(FIXED_MNEMONIC);
+  expect(mockSetEncryptionKey).toHaveBeenCalledWith('aes-key-hex');
+  // add navigation assertion if this test intends to validate /home redirect
 });

As per coding guidelines "Prefer testing behavior over implementation details in Vitest unit tests".

Also applies to: 513-523

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

In `@app/test/Mnemonic.test.tsx` around lines 449 - 458, The test titled "calls
deriveAesKeyFromMnemonic with the generated mnemonic" is asserting an internal
util call (mockDeriveAesKey) but the name implies navigation to '/home' — change
the spec to assert external behavior instead of implementation details: assert
navigation to '/home' (check router history/location or call to navigate) and
that the mnemonic/key was persisted (e.g., inspect localStorage or the store)
after clicking continueButton(), or alternatively rename the test to accurately
state it only verifies deriveAesKeyFromMnemonic was called with FIXED_MNEMONIC;
locate the test using identifiers mockDeriveAesKey, continueButton(), and
FIXED_MNEMONIC to update assertions or rename accordingly.
src/core/jsonrpc.rs (1)

861-898: Make the socket bootstrap idempotent too.

register_domain_subscribers is guarded with Once, but this block always creates a new SocketManager, replaces the global singleton, and spawns another auto-connect task. If bootstrap_skill_runtime is called twice, different parts of the process can end up bound to different managers.

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

In `@src/core/jsonrpc.rs` around lines 861 - 898, The socket bootstrap
unconditionally creates a new SocketManager (SocketManager::new), calls
set_global_socket_manager(socket_mgr.clone()), and spawns the auto-connect task,
which breaks idempotency; change it to first check whether a global manager
already exists (use the corresponding getter for the global socket manager) and
only create/set a new SocketManager and spawn the tokio::spawn auto-connect
block if none is present. Specifically, in the bootstrap block that defines
socket_mgr and calls set_global_socket_manager and tokio::spawn, guard
creation/set/spawn behind a "if global not set" check so repeated calls to
bootstrap_skill_runtime reuse the existing manager instead of replacing it.
🤖 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/components/skills/SkillCard.tsx`:
- Around line 1-2: The file currently has two imports from 'react' (useEffect,
useRef, useState) and a separate type-only import for ReactNode which triggers
the no-duplicate-imports lint rule; merge them into a single import by adding
the type inline (e.g. include "type ReactNode") alongside the existing named
imports so only one import statement imports useEffect, useRef, useState and the
type ReactNode from 'react'.

In `@src/core/jsonrpc.rs`:
- Around line 831-835: The match on
crate::openhuman::config::Config::load_or_init().await currently returns early
on error which skips event-bus init, subscriber/native-handler registration and
socket setup while run_server_inner still marks the core as ready; change this
so bootstrap failure aborts startup instead of silently returning: propagate or
map the Config load error out of the caller (or call a controlled shutdown/exit)
so run_server_inner cannot proceed, or alternatively move config-independent
bootstrap steps (event-bus init, subscriber/native-handler registration, and
socket setup) above the Config::load_or_init() branch; update the code paths
around run_server_inner, the socket manager initialization, and the
event-bus/subscriber registration to ensure they either run before calling
load_or_init() or are not executed when load_or_init() fails.
- Around line 492-499: The SSE stream currently uses tokio_stream::once(...)
which ends immediately and causes clients to reconnect; replace that one-shot
stream with a stream that emits the sentinel Event (the
Event::default().event("webhooks_debug").data(...)) and then never terminates so
the connection stays open. Concretely, change the tokio_stream::once(...) usage
to a chained stream that yields the same Ok<Event> sentinel and then a
never-ending pending stream (i.e., chain the single-item stream with a
pending/never stream) before passing it to
Sse::new(...).keep_alive(...).into_response() so the connection remains open
after emitting the runtime_removed event.

---

Outside diff comments:
In `@app/src/components/settings/panels/CronJobsPanel.tsx`:
- Around line 17-48: The debug namespace string assigned to loadCronJobsLog is
stale ("app:settings:CronJobsPanel:loadCronSkills"); change it to a
grep-friendly name that reflects the core-only path (e.g.,
"app:settings:CronJobsPanel:loadCoreCronJobs" or similar) and update all usages
(loadCronJobsLog(...) calls in loadCoreCronJobsOnly and any other places) so
logs correlate with the current CronJobsPanel core job flows; ensure the
variable name loadCronJobsLog and the function loadCoreCronJobsOnly remain the
same so the change is limited to the namespace string.

---

Nitpick comments:
In `@app/test/Mnemonic.test.tsx`:
- Around line 449-458: The test titled "calls deriveAesKeyFromMnemonic with the
generated mnemonic" is asserting an internal util call (mockDeriveAesKey) but
the name implies navigation to '/home' — change the spec to assert external
behavior instead of implementation details: assert navigation to '/home' (check
router history/location or call to navigate) and that the mnemonic/key was
persisted (e.g., inspect localStorage or the store) after clicking
continueButton(), or alternatively rename the test to accurately state it only
verifies deriveAesKeyFromMnemonic was called with FIXED_MNEMONIC; locate the
test using identifiers mockDeriveAesKey, continueButton(), and FIXED_MNEMONIC to
update assertions or rename accordingly.

In `@src/core/jsonrpc.rs`:
- Around line 861-898: The socket bootstrap unconditionally creates a new
SocketManager (SocketManager::new), calls
set_global_socket_manager(socket_mgr.clone()), and spawns the auto-connect task,
which breaks idempotency; change it to first check whether a global manager
already exists (use the corresponding getter for the global socket manager) and
only create/set a new SocketManager and spawn the tokio::spawn auto-connect
block if none is present. Specifically, in the bootstrap block that defines
socket_mgr and calls set_global_socket_manager and tokio::spawn, guard
creation/set/spawn behind a "if global not set" check so repeated calls to
bootstrap_skill_runtime reuse the existing manager instead of replacing it.
🪄 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: a77f812d-518e-4796-b733-0d9396510dbb

📥 Commits

Reviewing files that changed from the base of the PR and between ea3a098 and 367d75c.

📒 Files selected for processing (16)
  • app/src/components/ErrorReportNotification.tsx
  • app/src/components/settings/panels/ConnectionsPanel.tsx
  • app/src/components/settings/panels/CronJobsPanel.tsx
  • app/src/components/skills/SkillCard.tsx
  • app/src/pages/Conversations.tsx
  • app/src/services/errorReportQueue.ts
  • app/src/utils/desktopDeepLinkListener.ts
  • app/test/Mnemonic.test.tsx
  • src/core/jsonrpc.rs
  • tests/json_rpc_e2e.rs
  • tests/skills_debug_e2e.rs
  • tests/skills_gmail_e2e.rs
  • tests/skills_gmail_oauth_proxy_rpc_e2e.rs
  • tests/skills_notion_live.rs
  • tests/skills_rpc_e2e.rs
  • tests/skills_sync_memory_test.rs
💤 Files with no reviewable changes (2)
  • app/src/components/ErrorReportNotification.tsx
  • app/src/pages/Conversations.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
  • app/src/services/errorReportQueue.ts
  • app/src/components/settings/panels/ConnectionsPanel.tsx

Comment thread app/src/components/skills/SkillCard.tsx Outdated
Comment thread src/core/jsonrpc.rs
Comment on lines +492 to 499
let stream = tokio_stream::once(Ok::<Event, std::convert::Infallible>(
Event::default()
.event("webhooks_debug")
.data("{\"event_type\":\"runtime_removed\"}"),
));
Sse::new(stream)
.keep_alive(KeepAlive::new().interval(std::time::Duration::from_secs(10)))
.into_response()
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.

🛠️ Refactor suggestion | 🟠 Major

Keep the webhook SSE connection open after the sentinel event.

tokio_stream::once(...) finishes immediately after the first frame, so EventSource clients will reconnect on every close. That turns the compatibility shim into a reconnect loop instead of a stable “runtime removed” signal.

💡 One way to keep the existing SSE contract stable
 async fn webhook_events_handler() -> Response {
     let stream = tokio_stream::once(Ok::<Event, std::convert::Infallible>(
         Event::default()
             .event("webhooks_debug")
             .data("{\"event_type\":\"runtime_removed\"}"),
-    ));
+    ))
+    .chain(tokio_stream::pending::<Result<Event, std::convert::Infallible>>());
     Sse::new(stream)
         .keep_alive(KeepAlive::new().interval(std::time::Duration::from_secs(10)))
         .into_response()
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
let stream = tokio_stream::once(Ok::<Event, std::convert::Infallible>(
Event::default()
.event("webhooks_debug")
.data("{\"event_type\":\"runtime_removed\"}"),
));
Sse::new(stream)
.keep_alive(KeepAlive::new().interval(std::time::Duration::from_secs(10)))
.into_response()
let stream = tokio_stream::once(Ok::<Event, std::convert::Infallible>(
Event::default()
.event("webhooks_debug")
.data("{\"event_type\":\"runtime_removed\"}"),
))
.chain(tokio_stream::pending::<Result<Event, std::convert::Infallible>>());
Sse::new(stream)
.keep_alive(KeepAlive::new().interval(std::time::Duration::from_secs(10)))
.into_response()
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/core/jsonrpc.rs` around lines 492 - 499, The SSE stream currently uses
tokio_stream::once(...) which ends immediately and causes clients to reconnect;
replace that one-shot stream with a stream that emits the sentinel Event (the
Event::default().event("webhooks_debug").data(...)) and then never terminates so
the connection stays open. Concretely, change the tokio_stream::once(...) usage
to a chained stream that yields the same Ok<Event> sentinel and then a
never-ending pending stream (i.e., chain the single-item stream with a
pending/never stream) before passing it to
Sse::new(...).keep_alive(...).into_response() so the connection remains open
after emitting the runtime_removed event.

Comment thread src/core/jsonrpc.rs
Comment on lines +831 to 835
let cfg = match crate::openhuman::config::Config::load_or_init().await {
Ok(cfg) => cfg,
Err(e) => {
log::error!("[runtime] Failed to create RuntimeEngine: {e}");
log::error!("[runtime] Failed to load config for socket manager: {e}");
return;
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

Don't silently continue startup after bootstrap config failure.

This early return skips event-bus init, subscriber/native-handler registration, and socket setup, but run_server_inner still announces the core as ready. Either move the config-independent bootstrap above this branch or make bootstrap failure abort startup.

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

In `@src/core/jsonrpc.rs` around lines 831 - 835, The match on
crate::openhuman::config::Config::load_or_init().await currently returns early
on error which skips event-bus init, subscriber/native-handler registration and
socket setup while run_server_inner still marks the core as ready; change this
so bootstrap failure aborts startup instead of silently returning: propagate or
map the Config load error out of the caller (or call a controlled shutdown/exit)
so run_server_inner cannot proceed, or alternatively move config-independent
bootstrap steps (event-bus init, subscriber/native-handler registration, and
socket setup) above the Config::load_or_init() branch; update the code paths
around run_server_inner, the socket manager initialization, and the
event-bus/subscriber registration to ensure they either run before calling
load_or_init() or are not executed when load_or_init() fails.

- Combined import statements in the SkillCard component to enhance code readability and maintainability.
@senamakel senamakel merged commit 403f239 into tinyhumansai:main Apr 11, 2026
7 of 9 checks passed
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