Approvals and “Confirm on Mac”
An approval card can describe an agent request without necessarily owning a channel that can answer it. Moshline shows remote actions only when the route is real and still valid.
Outcome
You can tell whether a phone action will unblock the agent, why some requests remain host-local, and how timeout and risk policy change the available actions.
Visibility and control are different facts
Hooks can always report an observed permission request. Remote approval requires more: the provider hook must remain blocked, Moshline must retain the exact request identity, and the provider must define valid allow/deny output on hook stdout.
Moshline records that distinction in approval_scope. A bridge_relay request has a live synchronous path. A host_local request is useful context, but must be answered where the provider is running.
Current approval routes
| Path | Phone action | What reaches the agent | Fallback |
|---|---|---|---|
| Claude Code PermissionRequest + current Hook | Approve / Deny while relay is live | Hook stdout returns Claude allow / deny protocol JSON | Claude local permission UI |
| Claude event without a synchronous decision channel | Confirm on Mac / Open Terminal | No remote decision is sent | Claude local UI |
| Native Codex Hook | Confirm on Mac / Open Terminal | Observational event only | Codex local UI |
| Other observational provider Hooks | Confirm on Mac / Open Terminal | Observational event only | Provider local UI |
| Bridge-managed compatibility runner | Approve / Deny when its runner is active | Runner-specific protocol response | Runner or terminal prompt |
| Apple Watch | Low-risk actions forwarded through iPhone | Same verified mobile route | Open iPhone or terminal |
How the Claude relay reaches the blocked hook
- 01Claude invokes the Moshline PermissionRequest hook and waits.
- 02The hook posts the request to the local Host daemon with awaiting_decision and a relay deadline.
- 03The daemon returns the stored request event ID; the hook long-polls the authenticated decision endpoint.
- 04iPhone or Watch sends a decision bound to that exact request and agent run.
- 05The daemon records permission.decided and wakes the matching hook waiter.
- 06The hook writes Claude's allow or deny JSON to stdout, which unblocks the provider.
What happens on timeout or network failure
- The expired relay no longer accepts a late mobile decision.
- Hook stdout stays empty when the Bridge is unreachable or no valid decision arrives.
- Empty stdout deliberately returns control to the provider's normal local permission prompt.
- The Inbox keeps the event as context but removes remote actions after the route expires.
- Open Terminal remains available for full context and manual confirmation.
Risk policy still applies
A technically reachable route is not automatically safe for every surface. Apple Watch only exposes decisions that the iPhone classifies as safely actionable with limited context. Higher-risk or unknown requests should be reviewed in the App or terminal with command, cwd, risk, policy, and reason visible.
What “Confirm on Mac” means
It usually means Moshline received a real request but does not own a valid synchronous reply channel for that provider, or the previously valid relay has expired. It is not necessarily a pairing or notification failure.
- Open the matching terminal session and answer the provider prompt.
- For Claude Code, re-run Host Helper setup if the PermissionRequest hook is outdated.
- For Codex, trust the current hook definition so events remain visible; native remote approval is still host-local.
- Do not repeatedly tap an old notification after its relay deadline.
Related