Summary
Tapping the inline Approve button on the iOS Live Activity from the lock screen never reaches moshi-hook — the host daemon sees no inbound event. Tapping the Live Activity body to open the Moshi app, then tapping Approve inside the inbox view, works end-to-end and the hook proceeds.
Across an entire day of agent activity, zero approve/deny events arrive at the daemon from lock-screen taps. The outbound approval_required events do reach the iOS app (the Live Activity renders correctly), but the return path from inline button → cloud → WebSocket → daemon is silent.
Repro
- macOS host with
moshi-hook 0.1.15, paired, daemon running via brew services.
- Claude Code session with
PermissionRequest hook registered: '/opt/homebrew/bin/moshi-hook' claude-hook.
- Trigger a permission prompt (e.g. a non-allowlisted Bash command).
- Live Activity appears on iOS lock screen showing Approve / Deny inline buttons.
- Tap Approve on the lock screen.
Expected
Daemon receives the action over WebSocket. Hook subprocess returns approval to Claude Code. Session proceeds.
Actual
- Daemon log shows no inbound event corresponding to the tap.
- Claude session hangs until local timeout.
- Eventually the hook subprocess exits, leaving a
socket write error: broken pipe warning when the daemon later tries to write back (cosmetic; downstream of the real issue).
Workaround (proves the pipeline architecture works)
Tap the Live Activity body → Moshi app opens → tap Approve in the inbox view → daemon receives the WebSocket message → hook subprocess returns approval → Claude proceeds. End-to-end round-trip is healthy on this path.
Things I've already ruled out
- Outdated moshi-hook — on 0.1.15, the current stable from
rjyo/homebrew-moshi.
- Daemon crash / pairing rot —
moshi-hook status shows paired, WS bridge reconnects normally, status survives brew services restart.
- Stale pairing — full
moshi-hook unpair && moshi-hook pair --token <new> followed by brew services restart moshi-hook produced a clean new host_id and a healthy WS bridge, but the lock-screen inline Approve still does nothing. In-app Approve still works on the same fresh pairing.
- WS bridge dropped at the moment of tap — bridge was confirmed connected at the time of the tap (
ws bridge connected hostId=… shortly before, no subsequent dropped line).
This strongly suggests the bug is in the iOS Moshi app's Live Activity Button(intent:) wiring — the inline action is not being dispatched to the App Intent handler (or the handler is not forwarding the result over the configured channel to the host).
Environment
- moshi-hook: 0.1.15 (Homebrew, tap
rjyo/moshi)
- Host: macOS, Mac mini
- iOS: 26.4.2
- Moshi iOS app: 2.11.4
- Secret store: keychain
- Base URL: https://api.getmoshi.app/api/v1
Cosmetic side-note
The "socket write error: broken pipe" warnings in hook.log after a successful in-app approve are timing artefacts — the hook subprocess sometimes exits before the daemon writes back. Doesn't break the flow when in-app approve is used. Calling it out separately from the main bug above in case it's a quick fix to suppress.
Summary
Tapping the inline Approve button on the iOS Live Activity from the lock screen never reaches
moshi-hook— the host daemon sees no inbound event. Tapping the Live Activity body to open the Moshi app, then tapping Approve inside the inbox view, works end-to-end and the hook proceeds.Across an entire day of agent activity, zero approve/deny events arrive at the daemon from lock-screen taps. The outbound
approval_requiredevents do reach the iOS app (the Live Activity renders correctly), but the return path from inline button → cloud → WebSocket → daemon is silent.Repro
moshi-hook 0.1.15, paired, daemon running viabrew services.PermissionRequesthook registered:'/opt/homebrew/bin/moshi-hook' claude-hook.Expected
Daemon receives the action over WebSocket. Hook subprocess returns approval to Claude Code. Session proceeds.
Actual
socket write error: broken pipewarning when the daemon later tries to write back (cosmetic; downstream of the real issue).Workaround (proves the pipeline architecture works)
Tap the Live Activity body → Moshi app opens → tap Approve in the inbox view → daemon receives the WebSocket message → hook subprocess returns approval → Claude proceeds. End-to-end round-trip is healthy on this path.
Things I've already ruled out
rjyo/homebrew-moshi.moshi-hook statusshowspaired, WS bridge reconnects normally, status survivesbrew services restart.moshi-hook unpair && moshi-hook pair --token <new>followed bybrew services restart moshi-hookproduced a clean newhost_idand a healthy WS bridge, but the lock-screen inline Approve still does nothing. In-app Approve still works on the same fresh pairing.ws bridge connected hostId=…shortly before, no subsequentdroppedline).This strongly suggests the bug is in the iOS Moshi app's Live Activity
Button(intent:)wiring — the inline action is not being dispatched to the App Intent handler (or the handler is not forwarding the result over the configured channel to the host).Environment
rjyo/moshi)Cosmetic side-note
The "socket write error: broken pipe" warnings in
hook.logafter a successful in-app approve are timing artefacts — the hook subprocess sometimes exits before the daemon writes back. Doesn't break the flow when in-app approve is used. Calling it out separately from the main bug above in case it's a quick fix to suppress.