Hooks
Install moshi-hook so supported coding agents can talk to Moshi — and see which integrations include inbox events, approvals, and the native Chat View.
moshi-hook is the companion daemon that lets local coding agents report useful events to Moshi. It runs on your host, installs agent hook config, keeps a local Unix socket for hook calls, and maintains a WebSocket connection back to Moshi for approvals and status updates.
For every persistent daemon option—including background discovery, usage polling, notification suppression, and Browser Preview port filtering—see Hook settings.
The same daemon powers the in-app Diff viewer and Browser preview, and feeds the iOS Live Activity.
New to agent workflows? Best iOS Terminal App for AI Coding Agents covers why hooks, mosh, and push matter, and Moshi Agent Hooks is the deep dive on the inbox, Live Activities, and Apple Watch.
Supported agents
Hook support and Chat View support are separate. Hooks & inbox means moshi-hook can install the agent's integration and normalize its lifecycle events for the inbox, notifications, Live Activity, and supported approval flows. Chat View means Moshi can also render that agent's live terminal session as a native conversation with messages and tool cards.
Chat View is currently experimental and requires a live host-gateway connection to the agent's terminal session. See Chat View for setup, the interface, transport details, and current limitations.
The exact hook event surface differs by agent, but Moshi normalizes events into the same small set of inbox categories. Any other CLI still runs normally in Moshi's terminal; it just does not get the agent-aware features in this table.
Install on macOS
Open Settings -> Hooks in Moshi and copy your pairing token. Then run:
$brew tap rjyo/moshi$brew trust rjyo/moshi$brew install moshi-hook$moshi-hook pair --token <token from Moshi>$moshi-hook install$brew services start moshi-hook
On macOS, secrets are stored in Keychain by default. If you pair from SSH and Keychain is locked, unlock it first or use file-backed storage:
$security unlock-keychain ~/Library/Keychains/login.keychain-db$moshi-hook pair --token <token from Moshi>$moshi-hook pair --token <token from Moshi> --store file
Install on Linux (including WSL)
Same steps on a bare-metal Linux box, a VPS, or WSL on Windows — enable OpenSSH in the distro, then:
$curl -fsSL https://getmoshi.app/install.sh | sh$moshi-hook pair --token <token from Moshi>$moshi-hook install$moshi-hook serve
For a permanent Linux or WSL setup, run moshi-hook serve under your process manager of choice.
Update
On macOS, refresh the tap and upgrade:
$brew update$brew upgrade moshi-hook$brew services restart moshi-hook
On Linux, re-run the install script and restart your moshi-hook serve process:
$curl -fsSL https://getmoshi.app/install.sh | sh
Pairing and installed agent hooks survive an upgrade — no need to re-pair or re-run moshi-hook install.
What install changes
moshi-hook install writes Moshi-owned entries into supported agent config files. It is designed to leave user-owned hooks alone.
Managed locations include:
- Claude Code:
~/.claude/settings.json. - Codex:
~/.codex/hooks.jsonand the needed Codex config flag. - OpenCode:
.opencode/plugins/moshi-hooks.tsin the current project. - Antigravity:
~/.gemini/config/hooks.json(or$ANTIGRAVITY_CONFIG_DIR/hooks.json). - Cursor:
~/.cursor/hooks.json. - Kimi:
$KIMI_CODE_HOME/config.toml(defaults to~/.kimi-code/config.toml; legacy Kimi CLI uses$KIMI_SHARE_DIR/config.toml). - Qwen:
~/.qwen/settings.json. - Grok Build:
~/.grok/hooks/moshi-hooks.json. - Pi:
~/.pi/agent/extensions/moshi-hooks.ts. - OMP:
~/.omp/agent/extensions/moshi-hooks.ts(or the selected OMP profile). - Hermes:
~/.hermes/plugins/moshi-hooksand the plugin entry in~/.hermes/config.yaml.
Use moshi-hook uninstall to remove Moshi-owned entries.
What needs moshi-hook serve
moshi-hook is both a CLI and a long-running daemon. Some features rely on the daemon being up (it owns the local Unix socket that agents post events to, and the gateway on 127.0.0.1:24543 that the iOS app forwards to); others are one-shot CLI calls that work whether or not the daemon is running.
Needs moshi-hook serve running:
- Agent event delivery: every agent in the supported matrix posts hook events to the local Unix socket. Without the daemon, events go nowhere.
- Inbox notifications, Live Activity, and approval round-trips.
- In-app Diff viewer opened from a Moshi terminal session (the iOS app talks to the gateway port
24543). - In-app Browser preview.
- Live multiplexer detection — the signal that drives the swipe-to-switch-window gesture and the "in tmux/Zellij/Herdr right now" badge on a session. SSH preflight alone only tells Moshi the multiplexer is installed; the daemon's gateway tells it whether the current session is inside one.
Works without moshi-hook serve:
moshi <dir>— the project tmux launcher. Pure exec, no daemon.moshi diff <dir>— the standalone diff viewer opened in your laptop browser. Spawns its own short-lived server and exits when you close it; coexists with the daemon by falling back to an ephemeral port if24543is already taken.moshi-hook context— one-shot terminal-context probe. Reads$TMUX_PANE,$ZELLIJ,$HERDR_ENVfrom your own shell and prints the detected kind, session, pane, and cwd as JSON. Useful for debugging the tmux swipe gesture.moshi-hook pair,install,uninstall,status,update,version— all daemon-less.
The short rule: anything that streams state to the iOS app or accepts pushes from a coding agent needs serve; anything you invoke once from a shell does not.
Inbox categories
Moshi forwards a deliberately small set of events:
Moshi's inbox keeps one active row per agent session. New events for the same session update the row instead of creating a long stack of notifications.
Data privacy
moshi-hook is built so that the heavy, sensitive data stays between your host and your phone, and only small notification summaries touch Moshi's server.
Stays local, or goes directly between host and app:
- Full Claude Code and Codex transcripts. When you open a session's conversation in Moshi, the transcript streams from the host to the phone through the SSH-forwarded local gateway — it never passes through the Moshi backend.
- Diff payloads. The Diff viewer reads changes locally on the host and serves them to the app over the same local gateway.
- Your source files. File contents are never part of the cloud agent-event payload.
- Terminal traffic. Your actual sessions run over SSH, Mosh, or your Tailscale tailnet, directly to the host.
Reaches Moshi's server:
- Notification and inbox event summaries — the inbox categories above.
- Up to 200 characters of your prompt, used as the event body.
- Up to 80 characters of the assistant's response, used as the event title.
- The command or question behind an approval request, up to 256 characters, so you can decide from the notification.
- Metadata: project name, session ID, agent, model, tool name, terminal identifiers, account ID, and context-window percentage.
- Pairing, usage synchronization, approval decisions, and WebSocket control traffic.
Everything sent to the server is what you see rendered in a push notification or inbox row — nothing more is collected. For how the app itself stores credentials and what iCloud sync covers, see Security and sync.
Opt out of usage collection
Background usage collection (rate-limit polls on the host and snapshot uploads) is optional. To stop it on a host without unpairing:
moshi-hook set usage-collection off
brew services restart moshi-hook # macOS / Homebrew
systemctl --user restart moshi-hook.service # Linux / systemd
Approvals, inbox events, Chat View, and the local gateway keep working. Only the Usages rings stop updating from that host until you re-enable collection or run moshi-hook usage --sync by hand. See Agents & Usages.
Third-party harnesses
Custom harnesses that are not installed through moshi-hook, such as oh-my-pi notification plugins, can send completion messages through the custom webhook:
curl -X POST https://api.getmoshi.app/api/webhook \
-H "Content-Type: application/json" \
-d '{
"token": "YOUR_API_TOKEN",
"title": "Task complete",
"message": "oh-my-pi finished a turn"
}'
Add "unified": true to notify every opted-in device on the same Moshi license. Host-resident daemons that need structured agent state, Live Activities, or approval routing should use POST /api/v1/hosts/:hostId/events with the host secret.
Host status dot
When Show hook status is on, each saved host carries a small colored dot on its server icon, reflecting the last moshi-hook probe. The same five states drive the filter chips above the host list:
Tapping a host's dot opens a sheet that explains the state and, when something needs attention, gives copy-paste fix commands for macOS or Linux. You can turn the dots off in Moshi's settings.
Moshi runs the probe over a non-interactive login shell and resolves moshi-hook (and the moshi alias) from ~/.local/bin, ~/bin, /opt/homebrew/bin, /usr/local/bin, and /opt/local/bin, then from your login shell's own PATH. A standard Homebrew or install.sh install lands in one of those directories, so it is detected without any extra PATH setup. The running vs not running call is authoritative: Moshi opens a real connection to the gateway port rather than trusting a process name.
A host that shows not installed when moshi-hook really is installed usually means a custom install location — see moshi-hook is installed but shows as not installed.
Diagnostics
Useful commands:
$moshi-hook status$moshi-hook status --json$moshi-hook logs -f$moshi-hook usage --sync$moshi-hook set$moshi-hook set suppress-push-while-unlocked on
The human-readable status output includes the tmux, Zellij, and Herdr paths resolved by the running daemon. Use it to spot a service PATH mismatch; status --json deliberately skips that daemon lookup. See Hook settings for every moshi-hook set option, or A multiplexer works in the shell but Moshi still misses it to distinguish a daemon-path problem from an SSH-preflight problem.
If hooks are installed but Moshi does not update, check that moshi-hook serve or the macOS service is running and paired to the same Moshi account/token shown in the app.