How It Works
The three layers, the Ask Loop, and which notification comes from where.
Zeph is three cooperating layers. Hooks fire whether or not the model cooperates; MCP tools give the model a way to reach you on purpose.
zeph-to/plugin (Claude Code plugin)
├─ hooks/zeph-setup.js → SessionStart: inject the behavioral rules
├─ hooks/zeph-stop.sh → Stop: auto completion push
├─ hooks/zeph-ask.sh → PreToolUse: question push
├─ hooks/zeph-remote.sh → UserPromptSubmit: phone-sent message → REMOTE mode
├─ .mcp.json → registers the MCP server
└─ builds on:
├─ @zeph-to/cli → hooks + notify/list/dismiss + tmux remote control
└─ @zeph-to/mcp-server → zeph_ask / zeph_prompt / zeph_input / clipboard / file …| Layer | Package | Role | Reliability |
|---|---|---|---|
| Hooks | @zeph-to/cli | auto-fire on Claude events | 100%, no AI cooperation needed |
| MCP server | @zeph-to/mcp-server | AI-callable tools: ask, prompt, input, and the rest | depends on the model following rules |
| Plugin | zeph-to/plugin | bundles hooks, MCP, and rules | installed once |
Session flow and the Ask Loop
SessionStart hook
├─ read ~/.zeph/config.json
├─ HOOK_ID present → inject ask/prompt/input rules
└─ HOOK_ID absent → inject notify-only rules
Working…
├─ Choice/input needed → zeph_ask → button or text reply from mobile → continue
├─ Complex question → AskUserQuestion → Ask hook push → answer at terminal
│ └─ in tmux under `zeph listener`? the phone's
│ terminal mirror answers it too (↑/↓, Enter)
├─ Task complete → zeph_ask "Done. Next?" → pick or type → execute → loop
│ └─ tap "Done" → session ends
└─ Fallback: AI skipped zeph_ask → Stop hook sends a one-way pushWhen a Hook ID is set, Claude uses zeph_ask as its final action after real work. Your reply is
treated as a direct instruction — executed without re-confirming — and then Claude asks again.
The loop also starts from the phone: send a message via the app's agent chat, and the
zeph listener records exactly what it injected. The plugin's UserPromptSubmit hook verifies
the match, and Claude knows you are remote.
Notification matrix
Who fires what, and whether it can double up:
| Event | Source | Reliability | Duplicates |
|---|---|---|---|
| Task completed | Stop hook | 100% | No — skipped if the AI already sent zeph_ask |
| Question asked | Ask hook | 100% | No |
| Decision or input needed | zeph_ask | ~80%, the AI must call it | No |
| Decision only | zeph_prompt | ~80% | No |
| Text input only | zeph_input | ~80% | No |
| Manual push | zeph_notify | on request | No |
Driving a session from your phone
Launch Claude through zeph cc and the phone's Active Agents picker can type directly into the
running session — even after a zeph_ask window has closed. Start a refactor from the couch,
answer follow-ups over lunch, come back to a finished branch.
zeph cc # claude in a named tmux session the phone can reach
zeph codex # same for Codex
zeph cursor # same for cursor-agent, Cursor's terminal TUI
zeph gemini # same for GeminiThe one-step setup and the full architecture are under CLI & SDK → Remote Control.
Autonomous mode
Hand Claude a time budget and walk away:
/zeph-auto 2h fix the flaky testsClaude loops explore → plan → implement → verify → commit until the budget runs out, committing each verified unit on a work branch.
Questions arrive on your phone as zeph_ask buttons with a stated default — answer to steer,
or ignore and the run proceeds on the safe default after the timeout. Irreversible actions such as
push, deploy, or delete never happen on a timeout; they wait for an explicit tap.
The run ends with a report of what was committed, skipped, and auto-defaulted, plus buttons to extend, review, or finish.
Duration accepts 2h, 90m, 1h30m, or plain minutes, defaulting to 1h. /zeph-status shows
the remaining budget mid-run.