Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
148 changes: 109 additions & 39 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ npm run lint # ESLint (server + frontend)
npm run lint:fix # ESLint with auto-fix
npm run format # Prettier (write)
npm run format:check # Prettier (check only)
npm test # Vitest (22000+ tests across all packages)
npm test # Vitest (2587 tests across 177 suites)
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

πŸ”΅ unsafe_assumptions: Hardcoded test count "2587 tests across 177 suites" will go stale as soon as tests are added or removed. Consider a range or removing the count entirely (the command npm test is self-documenting). The previous value "22000+" was already wrong, and this replacement will be too eventually. [fixable]

```

**Deployment:** Mitzo runs as a launchd service (`com.mitzo.server`). The server is compiled to JS via `tsc` (not live-transpiled). Run `npm run deploy` to build and restart. Logs in `logs/server-{stdout,stderr}.log`.
Expand Down Expand Up @@ -53,9 +53,19 @@ The production backend stays untouched on `:3100`. Only the frontend is swapped.

## Architecture

Web-based command center for Claude Code sessions via the Agent SDK. Two npm projects share one repo:
Web-based command center for Claude Code sessions via the Agent SDK. The repo uses an npm workspace with three internal packages and two main directories:

**Backend** (`server/`) β€” Node.js + Express + TypeScript, run via `tsx`
### Packages (`packages/`) β€” npm workspace

| Package | Purpose |
| ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `@mitzo/protocol` | Core protocol types, Zod schemas (v2 WS messages, API schemas), tool summarization, event store definitions. Exports event-store module separately. |
| `@mitzo/harness` | Session registry, connection registry, permission handler, worktree guard, tool tiers, skill policy, auto-rename, notifications, logger |
| `@mitzo/client` | Frontend state management: `MitzoConnection` (single multiplexed WS), Zustand store (`createMitzoStore`), v2 protocol parser, session switching, message reducer |

### Backend (`server/`) β€” Node.js + Express + TypeScript, run via `tsx`

**Core** β€” Event streaming, session lifecycle, SDK integration

- `index.ts` β€” Express app, mounts routes, HTTP server + WebSocket. Sends `client_id` on WS connect for session reattach. Runs stale worktree cleanup on startup.
- `app.ts` β€” Express app factory (extracted from index.ts for testability via supertest).
Expand All @@ -64,59 +74,119 @@ Web-based command center for Claude Code sessions via the Agent SDK. Two npm pro
- `session-registry.ts` β€” `SessionRegistry` class: detach/reattach/rekey, TTL-based abort (10 min), `currentSnapshot` for reattach recovery, `findBySessionId` for reconnection.
- `permission-handler.ts` β€” Builds the `canUseTool` callback for SDK permission flow. Checks skill policy β†’ worktree guard β†’ `shouldAutoAllow()` before prompting. Falls back to WS-based prompting with ntfy/Pushover notifications.
- `async-queue.ts` β€” `AsyncQueue<T>` implementing `AsyncIterable<T>` for streaming-input. Supports `push()` for follow-up messages and `close()` for session teardown.
- `tool-tiers.ts` β€” Tool risk classification (`safe`, `standard`, `elevated`, `unknown`). `shouldAutoAllow()` implements mode x tier matrix. `.mitzo.json` tier overrides via `applyTierOverrides()`.
- `tool-summary.ts` β€” Tool input summarization. **SDK field names**: `file_path` (not `path`), `content` (not `contents`), `pattern`/`path` for Glob (not `glob_pattern`/`target_directory`).
- `content-blocks.ts` β€” SDK content block parsing (text, tool_use, tool_result). Used by stream and session restore API.
- `permissions.ts` β€” Permission request/response registry with tier metadata.

**Skills** β€” Slash-command system

- `skills.ts` β€” Skill registry: scoped discovery (bundled β†’ user β†’ repo), lazy metadata/body loading, deterministic precedence, collision tracking.
- `slash-commands.ts` β€” Slash-command parsing, prompt expansion, skill resolution from user input.
- `skill-policy.ts` β€” Per-turn tool restriction: skills declare `allowed-tools` in frontmatter, enforced as a ceiling on `canUseTool`.
- `native-commands.ts` β€” Built-in native commands (`/skills`) β€” TypeScript product behavior, not prompt-based.
- `auto-rename.ts` β€” Automatic session renaming every N user prompts via LLM summarization.
- `event-store.ts` β€” Persistent event store for session message replay.
- `hook-bridge.ts` β€” Bridges project-level hooks (`.claude/settings.json`) to Agent SDK sessions.
- `api-schemas.ts` β€” Zod schemas for HTTP request/response validation.
- `ws-schemas.ts` β€” Zod schemas for WebSocket message validation.
- `internal-token.ts` β€” Internal token generation for inter-process auth. Persisted to `~/.mitzo/internal-token` at startup so session hooks can authenticate with `POST /api/sessions`.
- `session-index.ts` β€” YAML session index at `<repo>/.claude/sessions/index.yaml`. Tracks active/closed sessions with repo worktree mappings.
- `repo-mcp-server.ts` β€” Repo-scoped MCP server configuration.
- `notification-helpers.ts` β€” Shared notification formatting utilities.
- `inbox.ts` β€” Inbox integration endpoint.

**Task Board** β€” Multi-session orchestration

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟑 bugs: useChatMessages is listed under "Hooks β€” hooks/ directory (21 hooks)" but doesn't exist in frontend/src/hooks/. It lives in @mitzo/client (packages/client/src/slices/messages.ts). Either move this entry to the Packages section or clarify its location. The hook count of 21 is correct for files in frontend/src/hooks/, but the listing adds an extra entry that isn't there. [fixable]

- `task-store.ts` β€” `TaskStore` class: SQLite persistence for tasks with tree queries, cascade status, DFS ordering, orphan detection. WAL mode + foreign keys.
- `task-tools.ts` β€” Pure handler functions for agent task tools (TaskSet, TaskComplete, TaskStatus, TaskBlock). Never throw β€” return error strings.
- `task-mcp-server.ts` β€” Stdio MCP server exposing task tools as `mcp__task-board__*`. Calls back to internal HTTP endpoints.
- `task-context.ts` β€” XML task context builder for system prompt injection. Includes current task, siblings, parent tree, and summaries (capped at 2000 chars).
- `task-orchestrator.ts` β€” `TaskOrchestrator`: event-driven state machine (idle/running/paused) with DFS sequential task assignment. Spec mode for human review of decompositions. Orphan detection reclaims tasks from dead sessions.

**Worktrees & Session Isolation**

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟑 bugs: Lib count says "27 utility files" but there are 28 actual files in frontend/src/lib/ (excluding tests). The enumerated list in the same section also has 28 items, contradicting the header count. [fixable]

- `worktree.ts` β€” Git worktree lifecycle: `createWorktree` (with optional dir/branch/prefix overrides), `createSessionWorktrees` (bulk creation for all repos), `removeWorktree`, `cleanupStaleWorktrees` (scans both `.claude/worktrees/` and `.cursor/worktrees/`), `listWorktrees`.
- `session-index.ts` β€” YAML session index at `<repo>/.claude/sessions/index.yaml`. Tracks active/closed sessions with repo worktree mappings.

**Observability**

- `logger.ts` β€” Pino structured logging: JSON output, `LOG_LEVEL` env filtering, pino-roll daily file rotation to `logs/`, OTel trace context mixin (trace_id/span_id), pino-pretty for dev. Lazy singleton init to avoid import-time side effects in tests. Loki integration when `LOKI_HOST` is set.
- `tracing.ts` β€” OpenTelemetry: BatchSpanProcessor with OTLP HTTP exporter to Jaeger. Opt-in when `OTEL_EXPORTER_OTLP_ENDPOINT` is set.
- `trace-context.ts` β€” Trace context utilities.
- `health-monitor.ts` β€” Service health monitoring (Yapper, ContexGin).

**Notifications**

- `notify.ts` β€” ntfy push notifications.
- `pushover.ts` β€” Pushover (Apple Watch) notifications.
- `apns.ts` β€” Apple Push Notification Service (iOS native).
- `notification-helpers.ts` β€” Shared notification formatting utilities.
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟑 bugs: Component count says "48 components" but there are 51 actual component files in frontend/src/components/. Additionally, ChatArea.tsx exists in the repo but is missing from the enumerated list. [fixable]


**WebSocket & Transport**

- `ws-handler-v2.ts` β€” v2 WebSocket message dispatcher: hello handshake β†’ session routing for send/stop/interrupt/permission_response/set_mode.
- `ws-transport.ts` β€” `SessionTransport` adapter wrapping WebSocket connections.
- `connection-registry.ts` (harness) β€” `ConnectionRegistry`: maps connectionId β†’ transport + sessionId, broadcasts to session observers.
- `mcp-config.ts` β€” Loads MCP server configs from Cursor mcp.json.
- `worktree.ts` β€” Git worktree lifecycle: `createWorktree` (with optional dir/branch/prefix overrides), `createSessionWorktrees` (bulk creation for all repos), `removeWorktree`, `cleanupStaleWorktrees` (scans both `.claude/worktrees/` and `.cursor/worktrees/`), `listWorktrees`.
- `worktree-guard.ts` (harness) β€” `checkWorktreePolicy()`: inspects Write/Edit/Bash tool inputs against session worktree paths. Denies out-of-bounds writes with a redirect message. Read operations pass through.
- `null-transport.ts` β€” Null transport for testing.
- `ws-schemas.ts` β€” Zod schemas for WebSocket message validation.

**Supporting**

- `tool-tiers.ts` β€” Tool risk classification (`safe`, `standard`, `elevated`, `unknown`). `shouldAutoAllow()` implements mode x tier matrix. `.mitzo.json` tier overrides via `applyTierOverrides()`.
- `tool-summary.ts` β€” Tool input summarization. **SDK field names**: `file_path` (not `path`), `content` (not `contents`), `pattern`/`path` for Glob (not `glob_pattern`/`target_directory`).
- `content-blocks.ts` β€” SDK content block parsing (text, tool_use, tool_result). Used by stream and session restore API.
- `permissions.ts` β€” Permission request/response registry with tier metadata.
- `event-store.ts` β€” Persistent event store for session message replay.
- `auto-rename.ts` β€” Automatic session renaming every N user prompts via LLM summarization.
- `hook-bridge.ts` β€” Bridges project-level hooks (`.claude/settings.json`) to Agent SDK sessions.
- `api-schemas.ts` β€” Zod schemas for HTTP request/response validation.
- `internal-token.ts` β€” Internal token generation for inter-process auth. Persisted to `~/.mitzo/internal-token` at startup so session hooks can authenticate with `POST /api/sessions`.
- `repo-config.ts` β€” `.mitzo.json` reader for quick actions, venv paths, tier overrides, and `repos` (secondary repo paths for multi-repo worktrees).
- `notify.ts` / `pushover.ts` β€” Push notifications (ntfy + Pushover/Apple Watch).
- `mcp-config.ts` β€” Loads MCP server configs from Cursor mcp.json.
- `inbox.ts` β€” Inbox integration endpoint.
- `auth.ts` β€” Passphrase login, JWT (HS256 via jose), cookie auth.
- `logger.ts` β€” Pino structured logging: JSON output, `LOG_LEVEL` env filtering, pino-roll daily file rotation to `logs/`, OTel trace context mixin (trace_id/span_id), pino-pretty for dev. Lazy singleton init to avoid import-time side effects in tests.
- `constants.ts` β€” Server-wide constants (timeouts, buffer limits, defaults).
- `git-version.ts` β€” Local/remote commit comparison for update detection.
- `port-check.ts` β€” Prevents duplicate server instances.
- `constants.ts` β€” Server-wide constants (timeouts, buffer limits, defaults).
- `goal-client.ts` β€” ContexGin Goal Registry client.
- `progress-tracker.ts` β€” Progress tracking utilities.
- `prompt-compare.ts` β€” Prompt comparison utilities.
- `workflow-templates.ts` β€” Workflow templates.
- `workload-store.ts` β€” Workload persistence.
- `session-overview.ts` β€” Session overview API.
- `signal-processor.ts` β€” Signal processing utilities.

**Packages** (`packages/`) β€” npm workspace packages shared between server and frontend

- `@mitzo/protocol` β€” Shared types, Zod schemas (v2 WS messages, API schemas), tool summarization.
- `@mitzo/harness` β€” Session registry, connection registry, permission handler, worktree guard, tool tiers, skill policy, auto-rename, notifications, logger.
- `@mitzo/client` β€” Frontend state management: `MitzoConnection` (single multiplexed WS), Zustand store (`createMitzoStore`), v2 protocol parser, session switching, message reducer.
### Frontend (`frontend/`) β€” React 19 + Vite + TypeScript

**Frontend** (`frontend/`) β€” React 19 + Vite + TypeScript
**Types** β€” `types/` directory

- `types/chat.ts` β€” v2 types: `StreamingBlock`, `StreamingMessage`, `FinishedBlock`, `FinishedMessage`, `BlockType`, `RawToolInput`, `PermissionRequest`, `ToolTier`, `Session`, `ImageAttachment`.
- `types/ws-messages.ts` β€” Typed WebSocket message unions (client β†’ server, server β†’ client).
- `types/task.ts` β€” Task model types (`Task`, `TaskStatus`, `LoopStatus`, `SessionPolicy`).
- `hooks/` β€” `useChatMessages` (useReducer for v2 protocol: MESSAGE_START/BLOCK_START/BLOCK_DELTA/BLOCK_END/TOOL_RESULT/MESSAGE_END/SESSION_END/MESSAGE_SNAPSHOT/RESTORE), `useChatSession`, `useChatConnection`, `usePermission`, `useTaskBoard` (task CRUD + loop control + WS subscriptions), `useFileNavigation`, `useFileEditor`, `useLongPress`.
- `lib/` β€” `groupMessages` (tool block grouping with configurable threshold), `constants`, `formatTime`, `paste-images`, `model-preference`, `rename-session`, `resizeImage`, `swipe-reveal`, `truncate`.
- Pages: `Login`, `SessionList`, `ChatView` (renders `current` inline + `messages[]` grouped), `DesktopChatView`, `FileViewer`, `InboxView`, `CalendarView`, `TodoView`, `TodoDetailView`, `TaskBoard`.
- Components: `MessageBubble` (UserBubble/TextBubble), `ThinkingBlock`, `ToolPill`, `ToolGroup`, `PermissionBanner`, `ChatInput`, `SlashPicker`, `ErrorBoundary`, `MitzoLogo`, `TaskNode`, `TaskCreateForm`, `LoopControls`, `TaskSidebar`.
- Auth via `ProtectedRoute` wrapper. Vite dev server proxies `/api` and `/ws` to backend.

**Hooks** β€” `hooks/` directory (21 hooks)

- `useChatMessages` β€” useReducer for v2 protocol: MESSAGE_START/BLOCK_START/BLOCK_DELTA/BLOCK_END/TOOL_RESULT/MESSAGE_END/SESSION_END/MESSAGE_SNAPSHOT/RESTORE
- `useTaskBoard` β€” task CRUD + loop control + WS subscriptions
- `useVoice` β€” STT (push-to-talk) + TTS (auto-speak toggle, voice selection, sequential chunk playback)
- `useFileNavigation` / `useFileEditor` β€” file browser and editing
- `useSessionOverview` β€” session metadata and statistics
- `useAutoSpeak` β€” auto-speak TTS preferences
- `useServiceHealth` β€” health status for Yapper, ContexGin
- `useCalendarData`, `useTodoData`, `useSessionList`, `useSessionSearch`, `useAttentionFeed`, `useProgress`, `useDocumentReader`, `useDraft`, `useTabBadges`, `useTheme`, `useLongPress`, `useMediaQuery`, `useQueuedMessages`, `useCopyFeedback`

**Lib** β€” `lib/` directory (27 utility files)

- `groupMessages` β€” tool block grouping with configurable threshold
- `tts.ts` β€” Text chunking at sentence boundaries, WAV synthesis via Yapper API, singleton AudioContext playback
- `api-fetch`, `audio`, `biometric`, `capacitor`, `clipboard`, `constants`, `event-bus-singleton`, `extractText`, `file-paths`, `formatTime`, `formatTokens`, `haptics`, `inbox-utils`, `keyboard`, `model-preference`, `paste-images`, `push`, `rename-session`, `resizeImage`, `splash`, `swipe-reveal`, `todo-utils`, `tracing`, `truncate`, `watch-auth`, `yapper-ws`

**Pages** β€” 10 pages

- `Login`, `SessionList`, `ChatView` (renders `current` inline + `messages[]` grouped), `DesktopChatView`, `FileViewer`, `InboxView`, `CalendarView`, `TodoView`, `TodoDetailView`, `TaskBoard`

**Components** β€” 48 components

- **Message rendering:** `MessageBubble` (UserBubble/TextBubble), `ThinkingBlock`, `ToolPill`, `ToolGroup`, `PermissionBanner`
- **Input:** `ChatInput`, `SlashPicker`, `MicButton`
- **Task board:** `TaskNode`, `TaskCreateForm`, `LoopControls`, `TaskSidebar`, `TaskBoardSection`
- **Navigation:** `DesktopNav`, `DesktopShell`, `MobileShell`, `TabBar`, `PageHeader`
- **Session management:** `ActiveSessionsList`, `SessionPanel`, `SessionOverview`, `SessionSearchBar`
- **File browser:** `FileBrowserPanel`
- **Context:** `ContextBlock`, `ContextPanel`, `ContextPicker`, `BootContextPill`
- **Voice:** `VoiceSettings`, `ReadAloudButton`
- **Utilities:** `ErrorBoundary`, `MitzoLogo`, `EmptyState`, `CopyButton`, `ScrollFab`, `StatusBar`, `TokenBar`, `ServiceStatus`, `ProgressWidget`, `CollapsibleSection`
- **Content cards:** `BriefingCard`, `EventCard`, `MarkdownPreviewCard`, `SubagentCard`, `TodoCard`
- **Sections:** `AttentionFeed`, `InboxSection`, `TelosSection`, `CommandCenter`, `SprintBar`
- **Forms:** `WorkflowCreateForm`

Auth via `ProtectedRoute` wrapper. Vite dev server proxies `/api` and `/ws` to backend.

**v2 protocol β€” key reducer behaviors:**

Expand Down Expand Up @@ -206,14 +276,14 @@ Web-based command center for Claude Code sessions via the Agent SDK. Two npm pro

- Skills are reusable prompt packages invoked via `/slash-command` in chat input.
- Three scopes: **Native** (TypeScript commands like `/skills`), **Skills** (markdown with YAML frontmatter), **Quick actions** (launchers from `.mitzo.json`).
- Discovery: repo-local (`.mitzo/skills/`), user (`~/.mitzo/skills/`), bundled (`server/bundled-skills/`).
- Discovery: repo-local (`.mitzo/skills/`), user (`~/.mitzo/skills/`), bundled (`./skills/`).
- Resolution order: Native β†’ Repo β†’ User β†’ Bundled. Deterministic precedence with collision metadata.
- `SlashPicker` component shows available skills when user types `/` in chat input, with type badges and collision notes.
- Skills can declare `allowed-tools` in frontmatter β€” enforced as a ceiling (never expands permissions) via `skill-policy.ts`.
- Bundled skills: `/simplify` (complexity, duplication, cleanup), `/risk-scan` (failure modes, missing tests, unsafe assumptions), `/pr-review` (diff/branch code review), `/person` (people profile lookup and update), `/review-response` (triage and fix PR review comments).
- Bundled skills: `/simplify` (complexity, duplication, cleanup), `/risk-scan` (failure modes, missing tests, unsafe assumptions), `/pr-review` (diff/branch code review), `/person` (people profile lookup and update), `/review-response` (triage and fix PR review comments), `/land-pr` (shepherd a PR from open to merged), `/pr-shepherd` (persistent PR monitoring and lifecycle).
- `GET /api/skills` returns merged registry with collision info, scoped by `cwd` query param.

**Voice integration (landing with PR #108):**
**Voice integration:**

- Client-direct architecture: frontend talks to [Yapper](~/projects/yapper/) for STT/TTS, server stays text-only.
- `lib/tts.ts` β€” Text chunking at sentence boundaries, WAV synthesis via Yapper API, singleton AudioContext playback.
Expand Down Expand Up @@ -260,7 +330,7 @@ All feature work follows TDD. This is not optional.
### Running Tests

```bash
npm test # Vitest β€” full suite
npm test # Vitest β€” full suite (2587 tests across 177 suites)
npm test -- --watch # Watch mode during development
npm test -- <path> # Run specific test file
```
Expand Down
Loading
Loading