Warning
This repository is obsolete and no longer maintained.
moshi-hooks has been superseded by the moshi-hook daemon, distributed via the Homebrew tap at rjyo/homebrew-moshi.
Please file any issues there: https://github.com/rjyo/homebrew-moshi/issues
Hook adapter for Claude Code, Codex CLI, and OpenCode that bridges agent lifecycle events to the Moshi API, which fans out push notifications to update the Live Activity on your iPhone.
Claude Code → hooks (stdin) → moshi-hooks → Moshi API → APNs → Live Activity
Codex CLI → hooks (stdin) → moshi-hooks → Moshi API → APNs → Live Activity
OpenCode → in-process plugin → Moshi API → APNs → Live Activity
Requires Bun. Zero runtime dependencies.
bun i -g moshi-hooksOr run directly without installing:
bunx moshi-hooks setupFirst, set your Moshi API token:
moshi-hooks token <YOUR_TOKEN>moshi-hooks setup # user scope (~/.claude/settings.json)
moshi-hooks setup --local # user scope (~/.claude/settings.local.json, not committed)
moshi-hooks setup . # project scope (.claude/settings.json in cwd)
moshi-hooks setup --local . # project scope (.claude/settings.local.json in cwd)moshi-hooks setup --codex # writes quiet Codex hooks to ~/.codex/hooks.json + enables codex_hooks feature flagCodex hook commands are registered as bunx --silent moshi-hooks --source codex
so Bun's dependency-resolution output does not get reported as hook output.
moshi-hooks setup --opencode # generates plugin at .opencode/plugins/moshi-hooks.tsmoshi-hooks uninstall # Claude Code (settings.json)
moshi-hooks uninstall --local # Claude Code (settings.local.json)
moshi-hooks uninstall --codex # Codex CLI
moshi-hooks uninstall --opencode # OpenCodeAll setup/uninstall commands are idempotent and preserve existing hooks from other tools.
| Hook Event | eventType | category | Sends to API? |
|---|---|---|---|
SessionStart |
— | — | No (persists model to state file) |
Stop |
stop |
task_complete |
Yes (visible push) |
SubagentStop |
agent_turn_complete |
info |
Yes (visible push) |
Notification |
notification |
approval_required |
Yes (visible push) |
PreToolUse |
pre_tool |
tool_running |
Yes, filtered (silent) |
PostToolUse |
post_tool |
tool_finished |
Yes, filtered (silent) |
UserPromptSubmit |
— | — | No (skipped) |
Tool events are filtered to only fire for: Bash, Edit, Write, WebFetch, WebSearch, Task.
| Hook Event | eventType | category | Sends to API? |
|---|---|---|---|
SessionStart (matcher startup|resume) |
— | — | No (persists model to state file) |
Stop |
stop |
task_complete |
Yes (visible push) |
PreToolUse |
pre_tool |
tool_running |
Yes, filtered (silent) |
PostToolUse |
post_tool |
tool_finished |
Yes, filtered (silent) |
Registered via ~/.codex/hooks.json (same shape as Claude's settings.json) and enabled by setting codex_hooks = true under [features] in ~/.codex/config.toml.
| OpenCode event | Notification title | eventType | category |
|---|---|---|---|
tool.execute.before (bash/edit/write/read/glob/grep/task/apply_patch/webfetch/websearch) |
Running <Tool> |
pre_tool |
tool_running |
tool.execute.after (same set) |
Finished <Tool> |
post_tool |
tool_finished |
tool.execute.before (question) |
Question |
notification |
approval_required |
permission.asked / permission.updated |
Permission Required |
notification |
approval_required |
message.part.updated (text, question-shaped) |
Waiting for Reply |
notification |
approval_required |
message.part.updated (step-start) |
Thinking |
notification |
info |
message.part.updated (reasoning) |
Reasoning |
notification |
info |
message.part.updated (step-finish) |
Step Complete |
notification |
info |
message.part.updated (subtask) |
Delegating |
notification |
info |
session.status (retry) |
Retrying |
notification |
error |
session.error |
Session Error |
notification |
error |
session.idle (when not awaiting input / has activity) |
Task Complete |
stop |
task_complete |
The plugin suppresses session.idle completions while awaiting a permission / question / assistant reply, deduplicates repeated permission and reasoning events with short TTLs, and skips child (subagent) sessions to avoid duplicate noise.
Claude Code and Codex CLI pipe JSON to stdin for each hook event — a fresh moshi-hooks process normalizes the payload and POSTs to the Moshi API. OpenCode is different: its generated plugin runs in-process inside OpenCode and POSTs directly to the Moshi API, so it can maintain wait-state, dedup, and child-session info across events without paying a process-spawn tax per event.
Cross-event state (Claude / Codex) is persisted to /tmp/moshi-hook-{session_id}.json so that later events (like Stop) can include the model name and last tool from earlier events. The OpenCode plugin keeps equivalent state in memory for its session lifetime.
Context window usage is estimated by reading the last ~10KB of the Claude transcript JSONL and parsing the most recent usage data.
The OpenCode plugin (templates/opencode-plugin.ts) is adapted from opencode-moshi-live by young5lee, MIT licensed. It contributed the in-process architecture, wait-state tracking, TTL deduplication, child-session filtering, assistant-question inference, tool-argument formatting, and the rich progress event mapping (Thinking / Reasoning / Step Complete / Delegating / Retrying).
bun testbun typecheck