Claude Code on your phone. A self-hosted web UI built on the Agent SDK, designed for mobile over Tailscale.
- Streaming chat with thinking blocks, tool pills, and markdown
- Three modes — Ask (read-only), Agent (file edits allowed), Auto (shell too). Switch mid-chat.
- Slash-command skills —
/simplify,/risk-scan,/pr-review, plus repo-local and user skills. Type/to browse. - Voice — push-to-talk input (STT) and auto-speak output (TTS) via Yapper. Graceful degradation when offline.
- MCP tools — reads
~/.cursor/mcp.json, passes servers to every session - File browser — view and edit repo files, switch between worktree roots
- Worktree sandbox — opt-in git worktree isolation per session
- Session resilience — phone sleeps, WS drops, session survives. Reattach on reconnect. Message snapshot recovery for iOS silent drops.
- Auto-rename sessions — sessions get meaningful names via LLM summarization after every few prompts
- Quick actions — one-tap commands via
.mitzo.json - Push notifications — ntfy + Pushover (Apple Watch) when Claude needs approval
- Image attachments — send photos/screenshots from your camera
- Session history — resume past conversations, swipe to dismiss
git clone https://github.com/dimakis/mitzo.git && cd mitzo
npm install && cd frontend && npm install && cd ..
cp .env.example .env # set AUTH_PASSPHRASE, AUTH_SECRET, REPO_PATH
npm run build && npm start
# http://localhost:3100Access from your phone: install Tailscale on server and phone, then open http://<tailscale-ip>:3100. No HTTPS needed — Tailscale encrypts via WireGuard.
Phone (Tailscale) ──┬── HTTP: REST API
└── WebSocket: v2 streaming protocol
│
Server (Node + TypeScript)
│
├── query-loop: SDK events → v2 protocol
├── session-registry: detach/reattach/snapshot
├── MCP servers from Cursor config
├── git worktrees (opt-in)
└── passphrase + JWT auth
The server translates raw SDK stream events into a v2 block lifecycle protocol (block_start → block_delta → block_end). Explicit turn boundaries (message_start/message_end), deferred finalization, and message snapshots for reconnect recovery. See docs/design/message-protocol-v2.md.
| Core | Purpose |
|---|---|
query-loop.ts |
SDK → v2 event translator. Deferred message_end, snapshot state, block lifecycle. |
chat.ts |
Agent SDK query(), prompt assembly, streaming-input queue, session restore API |
session-registry.ts |
Session state: detach, reattach, rekey, TTL abort, snapshot storage |
permission-handler.ts |
canUseTool callback — auto-allow by tier, prompt via WS + push notifications |
async-queue.ts |
AsyncIterable queue for follow-up messages and interrupt |
| Skills | Purpose |
|---|---|
skills.ts |
Skill registry — scoped discovery, precedence, collisions |
slash-commands.ts |
Slash-command parsing and prompt expansion |
skill-policy.ts |
Per-turn tool restriction from skill frontmatter |
native-commands.ts |
Built-in native commands (/skills) |
| Supporting | Purpose |
|---|---|
tool-tiers.ts |
Risk classification + mode/tier auto-allow matrix |
tool-summary.ts |
Summarizes tool inputs for pill display |
permissions.ts |
Request/response registry |
content-blocks.ts |
SDK content block parsing |
event-store.ts |
Persistent event store for session replay |
auto-rename.ts |
LLM-based session auto-renaming |
hook-bridge.ts |
Project hooks → Agent SDK bridge |
api-schemas.ts / ws-schemas.ts |
Zod validation schemas |
mcp-config.ts |
Loads Cursor MCP config |
worktree.ts |
Git worktree lifecycle |
repo-config.ts |
.mitzo.json reader |
auth.ts |
Passphrase + JWT |
notify.ts / pushover.ts |
Push notifications |
logger.ts / constants.ts / git-version.ts / port-check.ts / index.ts |
Infrastructure |
Five pages (Login, SessionList, ChatView, FileViewer, InboxView), a useReducer-based message state machine (useChatMessages), module-level WebSocket pool with 500-message buffer, and components for thinking blocks, tool pills, tool groups, permission banners, and a slash-command picker.
| Variable | Description | Required |
|---|---|---|
AUTH_PASSPHRASE |
Login passphrase | Yes |
AUTH_SECRET |
JWT signing key (min 32 chars) | Yes |
REPO_PATH |
Default repo for sessions | Yes |
PORT |
Server port (default: 3100) |
No |
WORKTREE_ENABLED |
Allow worktrees (default: true) |
No |
MCP_CONFIG_PATH |
MCP config path (default: ~/.cursor/mcp.json) |
No |
See .env.example for the full list.
Drop this in your repo root for quick actions and Python venv support:
{
"quickActions": [
{
"label": "Run Tests",
"desc": "Full suite",
"prompt": "Run tests and report.",
"extraTools": "Bash"
}
],
"venvPaths": [".venv/bin"]
}npm run dev # backend + frontend concurrently
npm test # vitest (525 tests, 48 files)
npm run lint # eslint
npm run format:check # prettierPre-commit: husky + lint-staged + commitlint (conventional commits).
Node.js, Express, React 19, Vite, TypeScript, Claude Agent SDK, Vitest, ESLint, Prettier.
Evolved from claude-command-center by Afstkla. The original used tmux; Mitzo uses the Agent SDK directly.
MIT