Get Moshi
hooks

Hooks

Install moshi-hook so Claude Code, Codex, OpenCode, Gemini, Cursor, Kimi, and Qwen can talk to Moshi — and unlock context detection, diff view, and browser preview.

updated 4 days ago22 min readpage 21 / 32

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.

The same daemon powers the in-app Diff viewer and Browser preview, and feeds the iOS Live Activity.

Supported agents

The installer can wire these agents:

  • Claude Code.
  • Codex CLI.
  • OpenCode.
  • Gemini CLI.
  • Cursor.
  • Kimi.
  • Qwen Code.

The exact event surface differs by agent, but Moshi normalizes events into a small set of inbox categories.

Install on macOS

Open Settings -> Hooks in Moshi and copy your pairing token. Then run:

macOS
$brew tap 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:

headless macOS
$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

Linux
$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 setup, run moshi-hook serve under your process manager of choice.

Update

On macOS, refresh the tap and upgrade:

macOS
$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:

Linux
$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.json and the needed Codex config flag.
  • OpenCode: .opencode/plugins/moshi-hooks.ts in the current project.
  • Gemini: ~/.gemini/settings.json.
  • Cursor: ~/.cursor/hooks.json.
  • Kimi: ~/.kimi/config.toml.
  • Qwen: ~/.qwen/settings.json.

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: Claude Code, Codex, OpenCode, Gemini, Cursor, Kimi, and Qwen all post 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 if 24543 is already taken.
  • moshi-hook context — one-shot terminal-context probe. Reads $TMUX_PANE, $ZELLIJ, $HERDR_ENV from 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:

approval_required
An agent needs permission or a user answer.
task_complete
A turn or idle task finished.
session_started
A new agent session or first prompt started.
tool_running
A tool started running, throttled to reduce noise.
tool_finished
A tool finished, throttled to reduce noise.

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.

Third-party harnesses

Custom harnesses that are not installed through moshi-hook, such as oh-my-pi notification plugins, can use Moshi's compatibility webhook:

curl -X POST https://api.getmoshi.app/api/v1/agent-events \
  -H "Authorization: Bearer $MOSHI_USER_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "source": "opencode",
    "eventType": "notification",
    "sessionId": "omp-session-1",
    "category": "task_complete",
    "title": "Task complete",
    "message": "oh-my-pi finished a turn",
    "eventId": "omp-event-1"
  }'

Use category values from the table above. approval_required events should include pendingActionId, expiresAt, and hostId only when the harness can also route decisions back to the running host. Host-resident daemons should prefer POST /api/v1/hosts/:hostId/events with the host secret.

Diagnostics

Useful commands:

moshi-hook checks
$moshi-hook status
$moshi-hook status --json
$moshi-hook logs -f
$moshi-hook usage --sync

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.