Skip to content

feat(notch): always-visible macOS notch status pill (6/8 of #3307)#3345

Merged
M3gA-Mind merged 10 commits into
tinyhumansai:mainfrom
M3gA-Mind:feat/voice-split-6-notch
Jun 4, 2026
Merged

feat(notch): always-visible macOS notch status pill (6/8 of #3307)#3345
M3gA-Mind merged 10 commits into
tinyhumansai:mainfrom
M3gA-Mind:feat/voice-split-6-notch

Conversation

@M3gA-Mind
Copy link
Copy Markdown
Contributor

@M3gA-Mind M3gA-Mind commented Jun 4, 2026

Summary

Slice 6/8 of #3307always-visible macOS notch status pill.

  • Transparent NSPanel + WKWebView anchored at the top-centre of the primary screen showing live Ready / Listening / Processing; automate streams step progress to it via the overlay:attention socket bridge.
  • macOS only; no-op elsewhere.

Files (5)

app/src-tauri/src/notch_window.rs, app/src-tauri/src/lib.rs (notch show/hide + startup), app/src/notch/NotchApp.tsx, app/src/main.tsx, app/src/index.css.

Part of the #3307 split. PR 3307 (72 files) is being replaced by 7 small, dependency-ordered PRs (merge-train). Branches are stacked; each PR's true slice is shown once its predecessors merge and it is rebased onto main.
Stacked on slice 5 (#3344). i18n keys it consumes shipped in slice 5.

Summary by CodeRabbit

  • New Features

    • macOS-only floating notch indicator at top-center that auto-shows on startup, runs as a standalone overlay, and displays animated statuses (listening, transcribing, thinking, speaking, attention) with auto-dismiss behavior.
    • Overlay webview connects to the app core when available to receive real-time events.
  • Style

    • New CSS animations and layout rules for the notch UI.
  • Enhancement

    • Webviews can receive a per-process core token so overlays connect directly when ready.
  • Tests

    • Added unit tests covering the notch UI and token resolution.

M3gA-Mind added 6 commits June 4, 2026 14:09
Run enigo keyboard/mouse on the app main thread via a native-registry
executor; enigo's macOS TSMGetInputSourceProperty traps off-thread and
crashes the CEF host. Adds mouse/keyboard tools, the main_thread bridge,
and downscaled screenshots so the model can see them.

Slice 1/7 of tinyhumansai#3307 (was the 'computer control' area).
… loop

Adds the Rust-internal automate engine (poll-until-stable settle, playback
verification), the AXEnabled diagnostics field + settle primitives on
ax_interact, the Music fast-path, and the Windows UIA superset. Exposes
launch_platform as pub(crate) so the automate loop can launch apps mid-flow.

Slice 2/7 of tinyhumansai#3307 (accessibility/automate engine).
…trator

Registers the AutomateTool (multi-step UI flows in one call) and the
ax_interact denylist/opt-in plumbing; adds the catalog toggle, tool
definition, and orchestrator prompt guidance (automate + screenshot/
mouse/keyboard fallback for Electron apps with empty AX trees).

Slice 3/7 of tinyhumansai#3307 (tool wiring + prompts).
Continuous cpal mic → VAD segmenter → STT → agent with no hotkey, opt-in
via voice_server.always_on_enabled, 'Hey Tiny' wake word (English-forced
STT + fuzzy match), and screen-lock privacy pause. Adds the config schema,
live-apply on the settings RPC, start_if_enabled wiring, and a JSON-RPC
roundtrip E2E.

Slice 4/7 of tinyhumansai#3307 (always-on core).
Surfaces the always-on listening toggle in the reachable Voice panel,
adds the VoiceDebugPanel, the voice tauri-command wrapper, and the RPC
client method. Adds all voice.debug.* and notch.* i18n keys across the
14 locales (notch keys land here as inert strings; the notch UI that
consumes them ships in slice 6).

Slice 5/7 of tinyhumansai#3307 (always-on frontend).
Transparent NSPanel + WKWebView anchored at the top-centre of the primary
screen showing live Ready/Listening/Processing state; automate streams
step progress to it via the overlay:attention socket bridge. macOS only;
no-op elsewhere.

Slice 6/7 of tinyhumansai#3307 (notch status pill).
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jun 4, 2026

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: eed4e76b-75cf-4936-b5d6-e04504d0aa2b

📥 Commits

Reviewing files that changed from the base of the PR and between 226b60c and 9954618.

📒 Files selected for processing (2)
  • app/src/notch/NotchApp.test.tsx
  • app/src/services/__tests__/coreRpcClient.test.ts

📝 Walkthrough

Walkthrough

Adds a macOS-only floating notch panel (NSPanel + WKWebView) that injects core RPC URL and bearer token into the webview and renders a bundled NotchApp React pill UI which connects to core via Socket.IO and displays activity events.

Changes

macOS Notch Activity Indicator Feature

Layer / File(s) Summary
Tauri native panel & command wiring
app/src-tauri/src/lib.rs
Adds macOS-only notch_window module, Tauri notch_window_show/notch_window_hide commands, auto-show on startup, and registers commands for invoke handling.
Native notch implementation
app/src-tauri/src/notch_window.rs
Creates a borderless, click-through NSPanel with WKWebView, computes top-center frame, resolves dev or bundled page (adds window=notch), loads webview, and spawns a repeating timer that injects globals and dispatches notch:core-url.
Webview token resolution & tests
app/src/services/coreRpcClient.ts, app/src/services/__tests__/coreRpcClient.test.ts
getCoreRpcToken() reads globalThis.__OPENHUMAN_NOTCH_CORE_TOKEN__ first for non-Tauri webviews and a test verifies precedence of the injected token.
NotchApp React component, styling, tests, and app routing
app/src/notch/NotchApp.tsx, app/src/index.css, app/src/notch/NotchApp.test.tsx, app/src/main.tsx
New NotchApp reads injected globals or listens for notch:core-url, connects Socket.IO, handles dictation/transcription/companion/overlay events to drive pill modes/text; CSS adds notch keyframes; tests exercise UI; app boot routes window=notch to NotchApp.

Sequence Diagram

sequenceDiagram
  participant TauriRuntime
  participant NSPanel
  participant WKWebView as WKWebView (NotchApp)
  participant CoreProcess
  participant SocketIO

  TauriRuntime->>NSPanel: Create transparent panel at top-center
  TauriRuntime->>WKWebView: Load NotchApp (dev URL or bundled)
  WKWebView->>WKWebView: Page loads, listens for notch:core-url

  TauriRuntime->>TauriRuntime: Spawn injection timer
  loop Poll until ready
    TauriRuntime->>CoreProcess: Check OPENHUMAN_CORE_RPC_URL env
    TauriRuntime->>CoreProcess: Get current bearer token
  end

  TauriRuntime->>WKWebView: evaluateJavaScript inject globals + dispatch notch:core-url
  WKWebView->>SocketIO: Connect with injected token
  CoreProcess->>SocketIO: Emit dictation/transcription/state/attention
  SocketIO->>WKWebView: dictation:toggle, transcription, etc.
  WKWebView->>WKWebView: Update pill mode/text/styling
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • tinyhumansai/openhuman#2331: Overlaps on how the notch webview injects a per-process bearer token and how frontend sockets obtain/pass the core bearer token.
  • tinyhumansai/openhuman#2114: Related changes to getCoreRpcToken() and token-resolution logic used by this PR's injected-token path.
  • tinyhumansai/openhuman#2709: Changes to core RPC token propagation that affect the value consumed by the notch webview injection.

Suggested reviewers

  • graycyrus

Poem

🐰 Upon the notch a tiny pill does bide,

it listens, lights, and hums with sockets tied,
a token whispered in the webview's ear,
events arrive and waveforms dance so near,
the macOS notch keeps vigil — soft and spry.

🚥 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 'feat(notch): always-visible macOS notch status pill (6/8 of #3307)' accurately and concisely summarizes the main change—a new macOS-only always-visible notch status pill feature. It clearly conveys the primary functionality added and includes relevant context about the stacked PR series.
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.


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

@M3gA-Mind
Copy link
Copy Markdown
Contributor Author

📚 Stacked PR series (8 total) — split from #3307

Merge bottom-up; each builds on the one above it:

  1. feat(computer): main-thread synthetic-input executor + CEF crash fix (1/8 of #3307) #3340 — main-thread synthetic-input executor + CEF crash fix
  2. feat(accessibility): AX/UIA perception + automate engine (2/8 of #3307) #3341 — AX/UIA perception + automate engine
  3. feat(agent): wire automate/ax_interact computer tools (3/8 of #3307) #3342 — wire automate/ax_interact computer tools
  4. feat(voice): Phase 2 always-on listening engine + RPC (4/8 of #3307) #3343 — Phase 2 always-on listening engine + RPC
  5. feat(voice): always-on Settings toggle + debug panel + i18n (5/8 of #3307) #3344 — always-on Settings toggle + debug panel + i18n
  6. feat(notch): always-visible macOS notch status pill (6/8 of #3307) #3345 — always-visible macOS notch status pill
  7. feat(voice): Phase 3 fast command router (7/8 of #3307) #3346 — Phase 3 fast command router
  8. feat(accessibility): vision-click fallback for Electron/partial-AX apps (8/8 of #3307) #3362 — vision-click fallback for Electron/partial-AX apps (Phase 1.5 complete)

Tracker: docs/voice-system-actions.md.

M3gA-Mind added 2 commits June 4, 2026 21:25
…notch

# Conflicts:
#	app/src-tauri/src/lib.rs
#	docs/voice-automate-plan.md
#	docs/voice-system-actions.md
#	src/openhuman/accessibility/app_fastpaths/fastpaths_tests.rs
#	src/openhuman/accessibility/app_fastpaths/music.rs
#	src/openhuman/accessibility/automate.rs
#	src/openhuman/agent_registry/agents/orchestrator/agent.toml
#	src/openhuman/config/ops.rs
#	src/openhuman/config/schemas.rs
#	src/openhuman/tools/impl/browser/screenshot.rs
#	src/openhuman/tools/impl/computer/main_thread.rs
#	src/openhuman/voice/always_on.rs
…ch slice

Same stale 'runs without an approval prompt' section as tinyhumansai#3344 — not on main,
contradicts the tinyhumansai#3342 ApprovalGate fix. Tracked for a corrected follow-up.
@M3gA-Mind M3gA-Mind marked this pull request as ready for review June 4, 2026 15:58
@M3gA-Mind M3gA-Mind requested a review from a team June 4, 2026 15:58
@M3gA-Mind
Copy link
Copy Markdown
Contributor Author

Independent review (beyond the CodeRabbit pass)

Reviewed the notch slice — the native notch_window.rs NSPanel host, the NotchApp WKWebView UI, the main.tsx notch entry, and the coreRpcClient token path.

Reviewed clean

  • Main-thread safetynotch_window::show/hide acquire a MainThreadMarker (return a clean Err if not on the main thread) and the auto-show runs from the Tauri setup closure (main thread). NSPanel/WKWebView are correctly !Send/!Sync, accessed only on the main thread. Mirrors the proven mascot_native_window pattern.
  • ACL posturenotch_window_show/hide mirror mascot_window_show/hide exactly (no per-command permission toml, same default-capability posture); they're registered for completeness but the live path is the Rust-side auto-show, not a JS invoke, so there's no "Command not found" exposure.
  • i18nNotchApp renders status via t('notch.*') keys (shipped in slice 5); no hard-coded literals.
  • TokengetCoreRpcToken honors the host-injected __OPENHUMAN_NOTCH_CORE_TOKEN__ global first (the notch WKWebView has no Tauri IPC), ahead of the resolution cache so a late injection still wins. Correct for the non-Tauri webview.
  • Note: dropped the same stale orchestrator/prompt.md desktop-control section that rode along the branch (contradicts the feat(agent): wire automate/ax_interact computer tools (3/8 of #3307) #3342 ApprovalGate fix) — tracked for a corrected follow-up.

No correctness issues. LGTM once CI is green.

@coderabbitai coderabbitai Bot added feature Net-new user-facing capability or product behavior. rust-core Core Rust runtime in src/: CLI, core_server, shared infrastructure. labels Jun 4, 2026
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

🧹 Nitpick comments (2)
app/src/index.css (1)

57-91: ⚡ Quick win

Add a reduced-motion escape hatch for the new notch animations.

notch-pill-in, notch-bar, and notch-dot all animate here, but the existing prefers-reduced-motion override later in this file only disables the command-palette/help motion. The notch will still pulse continuously for users who have reduced-motion enabled.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/src/index.css` around lines 57 - 91, The new notch animations
notch-pill-in, notch-bar, and notch-dot currently run even when users set
prefers-reduced-motion; add a prefers-reduced-motion media query that targets
these keyframes/elements and disables or minimizes their animation (e.g., set
animation: none or animation-duration: 0.001s and remove transforms/opacity
transitions) so the notch no longer pulses for reduced-motion users; update CSS
selectors that apply these animations (where notch-pill-in, notch-bar, notch-dot
are referenced) to respect the prefers-reduced-motion override.
app/src/notch/NotchApp.tsx (1)

181-255: ⚡ Quick win

Replace console.* diagnostics with a namespaced debug logger.

These new console.debug / console.warn calls bypass the app's dev-only logging convention and will emit raw runtime details in production consoles. Please route them through a debug('notch') namespace instead. As per coding guidelines, "In app/src, use namespaced debug logs (e.g. from the debug npm package) with dev-only detail for development diagnostics."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/src/notch/NotchApp.tsx` around lines 181 - 255, Replace raw console calls
with a namespaced debug logger: add "import debug from 'debug'" at the top and
create a logger (e.g. const dbg = debug('notch')); then change every
console.debug(...) and console.warn(...) in NotchApp.tsx (notably inside the
socket.on handlers for 'dictation:toggle', 'dictation:transcription',
'companion:state_changed', 'overlay:attention', the socket.connect() log, and
the catch block) to use dbg(...) (format messages and include err with %O for
the catch). Keep the same text payloads and trimming logic; only swap out
console.* for the dbg(...) calls so logs follow the app’s namespaced dev-only
convention.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@app/src/notch/NotchApp.tsx`:
- Around line 214-227: The code currently falls back to the raw agentState
string when mapping text (modeMap/textMap and setState), exposing untranslated
backend values; update the logic in NotchApp (the modeMap/textMap and the
setState call that reads agentState) to never render raw agentState: add
explicit mappings for any expected companion states and change the default
fallback to a translated generic string using useT() (e.g. t('notch.unknown',
'Unknown') or t('notch.status.unknown', 'Status unknown')); ensure both the mode
and text branches use the translation fallback so all user-visible strings go
through useT().
- Around line 164-180: The connectSocket async initializer uses a local disposed
flag that only flips in an internal disposer which isn't wired into the effect
cleanup, so if unmount or route changes happen while connectCoreSocket() is
resolving the socket can still attach listeners and call setState; fix by
returning or exposing the disposer from connectSocket and ensuring callers (the
effect, the preload path and the "notch:core-url" handler) call that disposer on
cleanup/unmount (or store the disposer on a ref and call it in the useEffect
cleanup), ensuring disposed is set and any pending socket is disconnected and
prevented from setting socketRef.current or dispatching state after teardown
(refer to connectSocket, connectCoreSocket, socketRef.current and the effect
handler that registers "notch:core-url").

---

Nitpick comments:
In `@app/src/index.css`:
- Around line 57-91: The new notch animations notch-pill-in, notch-bar, and
notch-dot currently run even when users set prefers-reduced-motion; add a
prefers-reduced-motion media query that targets these keyframes/elements and
disables or minimizes their animation (e.g., set animation: none or
animation-duration: 0.001s and remove transforms/opacity transitions) so the
notch no longer pulses for reduced-motion users; update CSS selectors that apply
these animations (where notch-pill-in, notch-bar, notch-dot are referenced) to
respect the prefers-reduced-motion override.

In `@app/src/notch/NotchApp.tsx`:
- Around line 181-255: Replace raw console calls with a namespaced debug logger:
add "import debug from 'debug'" at the top and create a logger (e.g. const dbg =
debug('notch')); then change every console.debug(...) and console.warn(...) in
NotchApp.tsx (notably inside the socket.on handlers for 'dictation:toggle',
'dictation:transcription', 'companion:state_changed', 'overlay:attention', the
socket.connect() log, and the catch block) to use dbg(...) (format messages and
include err with %O for the catch). Keep the same text payloads and trimming
logic; only swap out console.* for the dbg(...) calls so logs follow the app’s
namespaced dev-only convention.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 68119d50-6f73-4c34-94b0-f3437c94fcdf

📥 Commits

Reviewing files that changed from the base of the PR and between e40fec9 and 90a7eac.

📒 Files selected for processing (6)
  • app/src-tauri/src/lib.rs
  • app/src-tauri/src/notch_window.rs
  • app/src/index.css
  • app/src/main.tsx
  • app/src/notch/NotchApp.tsx
  • app/src/services/coreRpcClient.ts

Comment thread app/src-tauri/src/notch_window.rs Outdated
Comment thread app/src/notch/NotchApp.tsx
Comment thread app/src/notch/NotchApp.tsx
…mount

CodeRabbit tinyhumansai#3345:
- notch_window.rs: log only the page source *kind* and file basenames, never
  absolute bundle paths (they contain /Users/<login>/… PII).
- NotchApp.tsx: capture connectSocket()'s disposer and call it on effect
  cleanup / on a new core-url, so a still-resolving connectCoreSocket can't
  attach listeners or setState after teardown.
coderabbitai[bot]
coderabbitai Bot previously approved these changes Jun 4, 2026
Clears the diff-cover gate for tinyhumansai#3345:
- NotchApp.test.tsx: drives a mock Socket.IO through all handlers
  (dictation toggle/transcription, companion state, overlay attention),
  both bootstrap paths (preloaded global + notch:core-url event), and the
  ready/listening/transcribing/thinking/speaking/attention render modes.
- coreRpcClient: cover the host-injected __OPENHUMAN_NOTCH_CORE_TOKEN__
  fast-path in getCoreRpcToken.
@M3gA-Mind M3gA-Mind merged commit f3e70e6 into tinyhumansai:main Jun 4, 2026
22 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature Net-new user-facing capability or product behavior. rust-core Core Rust runtime in src/: CLI, core_server, shared infrastructure.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant