# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Project Overview Jacques is a real-time manager for terminal-based AI coding assistants. The production integrations today are Claude Code, Gemini CLI, Codex, and OpenCode, with additional Cursor support elsewhere in the product. It displays **exact token usage percentage** in real-time through: - CLI TUI (Ink/React-based terminal interface) - In-app statusLine integration - Session lifecycle tracking The system uses a three-layer architecture: 1. **Hooks** (Python/Bash) → send events via Unix socket 2. **Server** (Node.js/TypeScript) → manages sessions and broadcasts updates via WebSocket 3. **CLI** (Ink/React) → displays real-time context usage **Platform Support**: macOS, Linux, Windows. See `docs/PLATFORM-SUPPORT.md` for terminal compatibility. **Current Status**: Phases 1-4, 6-12 complete. Phase 5 (context breakdown) pending. ## Key Commands ### Setup & Installation ```bash npm run setup # Full setup: install deps, build (incl. GUI), symlink hooks # Also checks tmux availability (warns if not installed) npm run configure # Configure Claude Code settings.json with hooks ``` ### Quick Start ```bash npm run go # Build all packages and start server (one command) ``` ### Remote Access ```bash npm run start:remote # Start server with Tailscale remote access + QR code (cross-platform) # Works on macOS, Linux, and Windows. See docs/REMOTE.md npm run dev:remote # Remote dev mode: Vite HMR over Tailscale (see docs/REMOTE.md) # Pair with: JACQUES_TAILSCALE_AUTH=true npm run start:server # tailscale serve --bg 5173 ``` ### Development ```bash npm run install:all # Install dependencies for core, server, cli, and gui npm run build:all # Build all packages (core → server → cli → gui) # Server npm run dev:server # Server dev mode (tsc --watch) npm run start:server # Start Jacques server cd server && npm test # Run server tests # CLI (Terminal TUI) npm run dev:cli # CLI dev mode (tsc --watch) npm run start:cli # Start terminal CLI # GUI (Web Interface) npm run build:gui # Build GUI (required before serving) npm run start:server # Server serves GUI at http://localhost:4243 npm run dev:gui # OR: Run GUI dev server at http://localhost:5173 (hot reload) ``` ### Running the Web GUI The GUI can be accessed three ways: 1. **Production mode** (served by server): ```bash npm run build:all # Build everything including GUI npm run start:server # Start server - GUI at http://localhost:4243 ``` 2. **Development mode** (hot reload): ```bash npm run start:server # Start server for API (port 4243) npm run dev:gui # Start GUI dev server at http://localhost:5173 ``` 3. **Remote development mode** (HMR over Tailscale): ```bash JACQUES_TAILSCALE_AUTH=true npm run start:server # Start server with auth npm run dev:remote # Vite with remote HMR config tailscale serve --bg 5173 # Expose Vite dev server ``` Access from iPad/phone at `https://`. GUI changes hot-reload instantly. See `docs/REMOTE.md` for details. **Important**: Always rebuild GUI (`npm run build:gui`) before using production mode if you made changes. ### Testing ```bash cd server && npm test # Run all server tests cd core && npm test # Run core tests cd cli && npm test # Run cli tests cd hooks && python3 -m pytest adapters/test_*.py # Run hook adapter tests ``` **Important**: Tests use `--experimental-vm-modules` because the codebase uses ES modules (`"type": "module"`). **Test Organization**: - `server/src/auth/*.test.ts`: Auth module tests (tailscale-auth, approved-users, setup-code) - `server/src/*.test.ts`: Server component tests - `core/src/**/*.test.ts`: Core module tests (plan-extractor, catalog, plan progress) - `core/src/board/*.test.ts`: Board tests (parser, serializer, board-manager) - `core/src/plan/*.test.ts`: Plan progress tests (plan-parser, task-extractor, progress-matcher, progress-computer) - `cli/src/**/*.test.ts`: CLI tests (sources, context, archive) - `hooks/adapters/test_*.py`: Hook adapter tests - Tests use mock data, no actual AI tool sessions required ## Architecture ``` Claude Code/Cursor ↓ (hooks via Unix socket /tmp/jacques.sock) Jacques Server (Node.js + TypeScript + node-pty) ↓ (WebSocket + HTTP on port 4243) CLI (Ink/React TUI) ``` - **Server** (`server/src/`): Unix socket listener, session registry, WebSocket broadcaster (dual endpoints: `/ws/app` for session updates, `/ws/terminal` for terminal I/O), HTTP API, node-pty terminal I/O. Three terminal backends: tmux (macOS/Linux), daemon (Windows), direct (fallback) - **Core** (`core/src/`): Shared business logic — archive, catalog, context indexing, session parsing, handoff generation, task board - **CLI** (`cli/src/`): Ink/React TUI with components, archive UI, context management - **Hooks** (`hooks/`): Python/Bash scripts that send events from Claude Code/Cursor to the server - **GUI** (`gui-v2/`): Web-based GUI (React + Vite) for browsing sessions, plans, and subagents **Build order**: Core → Server → CLI (each depends on the previous) ## Project Discovery Projects are discovered from `~/.claude/projects/` where Claude Code stores JSONL session transcripts. **Path decoding**: Claude Code encodes project paths by replacing `/` with `-` (e.g., `/Users/gole/Desktop/my-project` → `-Users-gole-Desktop-my-project`). Decoding uses three tiers: 1. `sessions-index.json` `originalPath` — authoritative (written by Claude Code) 2. `cwd` field from first JSONL entry — reliable fallback (most projects) 3. Naive decode (all `-` → `/`) — last resort, ambiguous for paths with hyphens **Git worktree grouping**: Multiple worktrees of the same repo are grouped into a single project using `gitRepoRoot`. The `discoverProjects()` function (`core/src/cache/project-discovery.ts`) handles all grouping in two passes: - **First pass**: Groups projects where sessions have `gitRepoRoot` in the index or `detectGitInfo()` succeeds on disk. - **Second pass**: Merges orphaned non-git projects that have `gitBranch` evidence (deleted/zombie worktrees) into matching git projects via two strategies: 1. **Zombie worktree `.git` file**: `readWorktreeRepoRoot()` reads the `.git` text file (contains `gitdir: /path/to/main-repo/.git/worktrees/`) to find the exact repo root. Works when the directory exists but git metadata is cleaned up. 2. **Name-prefix heuristic**: For truly deleted worktrees (directory gone), matches by repo name prefix (e.g., `my-repo-feature` → `my-repo`). Uses longest prefix match when ambiguous; skips if no match. **Non-git projects**: Projects without a git repo are standalone entries — each directory is its own project. **Hidden projects**: Users can hide unwanted projects (e.g., `/tmp`) via `DELETE /api/projects/:name` or the X button in the ProjectSelector. Hidden list persisted in `~/.jacques/hidden-projects.json`. Use `hideProject()`/`unhideProject()` from core. **Data flow**: 1. `discoverProjects()` scans `~/.claude/projects/`, cross-references with the session index, groups by git repo root, merges deleted worktrees, filters hidden projects 2. `GET /api/projects` exposes this as a server endpoint; `DELETE /api/projects/:name` hides a project 3. `useProjectScope` fetches on mount; `ProjectSelector` uses discovered projects as primary source 4. After sync, `refreshProjects()` is called to reload the project list **External tool projects**: Projects from Gemini CLI, Codex, and OpenCode are discovered by `external-project-discovery.ts` which reads each tool's native storage (JSON files, SQLite databases). Results are merged with Claude Code projects via `mergeProjectCandidates()` in `project-discovery.ts`. **Manual projects**: Users can manually add project paths via the Projects Hub modal or `POST /api/projects/manual`. Stored in `~/.jacques/manual-projects.json`. **Platform support**: macOS/Linux paths use `-` encoding. Windows drive letters strip the colon (`C:\foo` → `-C-foo`). See `docs/PLATFORM-SUPPORT.md`. ## Session Lifecycle Sessions are tracked through their entire lifecycle, from start to end. ### Session Detection - **Hooks**: When Claude Code starts, `SessionStart` hook fires → registers session with terminal identity - **Process Scanner**: At server startup, scans for running `claude` processes → discovers active sessions from JSONL files - **Auto-registration**: `statusLine` hook can auto-register sessions that started before the server ### Session Termination - **Normal exit**: `SessionEnd` hook fires → unregisters session, triggers catalog extraction - **Ctrl+C / Crash**: No hook fires → process verification detects dead process → unregisters session, triggers catalog extraction ### Process Verification (every 30s) Sessions with PID-based terminal keys are verified: 1. Extract PID from terminal_key (e.g., `DISCOVERED:TTY:ttys012:68231`) 2. Check if process is still running (`kill -0 PID`) 3. If dead, unregister session and trigger catalog extraction ### Bypass Mode (`--dangerously-skip-permissions`) Sessions can be launched with `--dangerously-skip-permissions` via the GUI Settings toggle. Tracked as `is_bypass` boolean (orthogonal to session mode). Detection paths: 1. **Launch-time**: GUI toggle → server marks CWD as pending bypass → auto-registration picks it up 2. **Startup**: `detectBypassSessions()` checks process command lines for discovered sessions with PIDs 3. **Hook-based**: `storeTerminalPid()` stores PID from first hook event and checks bypass (covers iTerm sessions without PIDs in terminal keys) See `docs/CONNECTION.md` for full details. ### Catalog Extraction on Removal When any session is removed (hook, process verification, or cleanup): 1. Extract session manifest → `.jacques/sessions/{id}.json` 2. Extract plans → `.jacques/plans/` 3. Extract subagent results → `.jacques/subagents/` This ensures sessions killed with Ctrl+C are still saved to history with their plans. ## TypeScript Configuration - **Target**: ES2022 - **Module**: NodeNext (ES modules with `.js` extensions in imports) - **All imports must use `.js` extension** even for `.ts` files (e.g., `import { foo } from './types.js'`) - Output directory: `dist/` - Source maps and declarations enabled ## File Organization ``` jacques-context-manager/ ├── core/src/ # Shared business logic (TypeScript) │ ├── archive/ # Cross-project search and archiving (archive-store.ts is facade over archive-paths, archive-index, archive-manifests, archive-conversations, archive-plans; also plan-constants.ts) │ ├── cache/ # Session indexing (14 submodules: types, persistence, metadata-extractor → title-extractor + agent-extractor + index-builder, mode-detector, project-discovery, project-candidates, project-identity, external-project-discovery, manual-projects, git-utils, hidden-projects) │ ├── catalog/ # Catalog extraction (extractor.ts split into explore-extractor, search-extractor, session-manifest; also types.ts, bulk-extractor.ts) │ ├── context/ # Project knowledge management (index.json) │ ├── handoff/ # Session handoff generation (generator.ts split into data-extractor.ts + formatter.ts) │ ├── logging/ # Structured logging (Logger interface, error classification) │ ├── board/ # Task board (Kanban) — parser, serializer, board-manager │ ├── plan/ # Plan progress tracking (task extraction, progress matching) │ ├── notifications/ # Shared notification types, constants, utilities │ ├── session/ # JSONL parsing, filtering, transformation (includes entry-types.ts, statistics.ts) │ ├── sources/ # External source adapters (Obsidian, etc.) │ └── utils/ # Settings, Claude token management, format.ts, validation.ts ├── server/src/ # Node.js server (TypeScript) ├── server/src/auth/ # Tailscale auth (identity, approved users, setup codes) ├── server/src/startup/ # Server initialization (service-factory, server-lifecycle, terminal-bootstrap, client-message-router, session-discovery, tailscale-recovery, upload-cleanup) ├── server/src/types/ # Domain-specific types (session-types, event-types, ws-server-messages, ws-client-messages, window-types, worktree-types, notification-types, github-types, config-types) ├── server/src/session/ # Session state (session-factory, process-monitor, cleanup-service, focus-manager, mode-detector, session-linker) ├── server/src/connection/ # Claude Code connection layer (terminal keys, process detection, etc.) │ ├── session-resolvers/ # Per-tool session resolvers (codex-resolver, gemini-resolver, opencode-resolver, resolver-utils) │ └── worktree/ # Worktree sub-modules (types, validation, lifecycle, inspection, diff, processes) ├── server/src/handlers/ # WebSocket message handlers (event, session, window, worktree, settings) │ └── terminal/ # Terminal I/O sub-modules (terminal-lifecycle, terminal-io, terminal-attach, terminal-recovery, terminal-types) ├── server/src/mcp/ # MCP server for archive search ├── server/src/routes/ # HTTP route handlers (session, project, auth, terminal, preferences, tools-routes, etc.; includes session-service.ts, github-service.ts) ├── server/src/terminal/ # Terminal management (node-pty bridges, tmux manager, daemon backend, registry, protocol) │ └── daemon/ # PTY daemon backend (daemon-manager, daemon-pty-bridge, pty-daemon) ├── cli/src/ # CLI TUI (Ink/React) │ ├── components/ # React/Ink UI components │ │ ├── sessions/ # Session detail extraction │ │ └── dashboard/ # SessionList, ProjectStats │ ├── hooks/ # Custom React hooks (state management) │ │ └── setup/ # Setup wizard modules (types, install-steps, useSetupWizard) │ ├── handoff/ # Handoff tests (imports from @jacques-ai/core) │ └── templates/ # Skill templates ├── gui-v2/src/ # Web GUI (React + Vite) │ ├── api/ # HTTP API client (13 domain modules: sources, archive, sessions, plans, context, sync, handoffs, usage, server-config, auth, terminals, board, tools) │ ├── components/ # React components │ │ ├── auth/ # Auth gate, pending approval, approved devices │ │ ├── board/ # Kanban board components (KanbanBoard, KanbanColumn, KanbanCard, etc.) │ │ ├── context/ # Context Catalog GUI components │ │ ├── runner/ # Script list sub-components │ │ ├── terminal/ # Terminal emulator components (xterm.js) │ │ ├── ui/ # shadcn/ui components (50+) + custom wrappers (see docs/GUI.md) │ │ ├── ProjectsHubModal.tsx # Projects Hub modal for browsing/adding projects │ │ ├── ProjectTreeItem.tsx # Tree item component for project sidebar │ │ └── HookPreviewModal.tsx # Hook setup preview modal for agents settings │ ├── hooks/ # Custom React hooks (useTerminal, useTerminalManager, useSharedPreferences, useJacquesSubscribers, useJacquesActions, usePinnedProjects, useSidebarTree, useSidebarTreeContext, browser-client-dispatch, terminal-protocol) │ ├── pages/ # Route pages │ │ └── settings-sections/ # 11 settings section components │ ├── styles/ # Tailwind CSS v4 config (tailwind.css), theme presets, fonts │ └── utils/ # Shared utilities (session-display.tsx) ├── hooks/ # Claude Code/Cursor hooks (Python/Bash) │ └── claude-code/ # register-session, pre-tool-use, report-activity, session-idle, unregister-session, subagent-start, subagent-stop, notification, stop-failure, pre-compact, post-compact, user-prompt ├── hotkeys/ # Native macOS global hotkey daemon (Swift) ├── scripts/ # Setup and configuration scripts └── docs/ # Documentation ``` ## Dependencies ### Required System Tools - **Python 3.x**: For hook scripts (`python3` on Unix, `python` on Windows) - **jq**: Optional, legacy only (`brew install jq`) - **nc** (netcat): Optional, legacy only (usually pre-installed on Unix) ### Node.js Dependencies - **ws**: WebSocket library for server and client - **node-pty**: PTY spawning for terminal I/O (ships prebuilt binaries for macOS/Linux/Windows) - **ink**: React-based CLI framework for terminal TUI - **commander**: CLI argument parsing - **geist**: Bundled Geist Mono font for terminal and app UI (GUI only) - **tailwindcss** (v4): Utility-first CSS framework — all GUI styling uses Tailwind classes (no CSS-in-JS) - **shadcn/ui**: Headless component library (Radix UI + Tailwind). Config: `gui-v2/components.json` - **class-variance-authority**: Component variant system (CVA) for typed style variants - **clsx + tailwind-merge**: Class name merging via `cn()` utility (`gui-v2/src/lib/utils.ts`) - **sonner**: Toast notifications (replaces custom Toast components) - **lucide-react**: Icon library for GUI ## Common Operations Before exploring source code, read the relevant `docs/` file listed below. The docs contain architecture, key files, data flows, and API endpoints for each component. | Task | Read first | Then | |------|-----------|------| | Work on catalog extraction | `docs/CORE.md` (Catalog Module section) | `core/src/catalog/` | | Work on server API | `docs/SERVER.md` (HTTP API section) | `server/src/http-api.ts` | | Work on CLI TUI | `docs/CLI.md` | `cli/src/components/` | | Work on web GUI | `docs/GUI.md` | `gui-v2/src/` | | Work on GUI styling/components | `docs/GUI.md` (Styling System + shadcn sections) | `gui-v2/src/components/ui/`, `gui-v2/src/styles/tailwind.css` | | Work on project discovery | `docs/PLATFORM-SUPPORT.md` (Path encoding section) | `core/src/cache/project-discovery.ts` (`discoverProjects`) | | Work on hooks | `docs/HOOKS.md` | `hooks/` | | Work on multi-agent adapters | `docs/ADAPTERS.md` | `core/src/adapters/`, `hooks/adapters/` | | Work on multi-tool project discovery | `docs/ADAPTERS.md` | `core/src/cache/external-project-discovery.ts`, `server/src/routes/tools-routes.ts` | | Work on notifications | `docs/NOTIFICATIONS.md` | `core/src/notifications/`, `server/src/services/notification-service.ts` | | Parse JSONL transcripts | `docs/JSONL-FORMAT.md` | `core/src/session/` | | Work on plans/dedup | `docs/CORE.md` (Plan Identity section) | `core/src/catalog/extractor.ts`, `core/src/archive/plan-cataloger.ts` | | Work on plan progress | `docs/CORE.md` (Plan Progress section) | `core/src/plan/`, `server/src/http-api.ts` (tasks endpoint) | | Work on task board (Kanban) | `docs/CORE.md` (Board Module section) | `core/src/board/`, `server/src/routes/board-routes.ts`, `gui-v2/src/components/board/` | | Work on archive/search | `docs/CORE.md` (Archive Module section) | `core/src/archive/` | | Work on remote access / Tailscale auth | `docs/REMOTE.md` | `server/src/auth/`, `gui-v2/src/components/auth/` | | Debug unexpected behavior | `docs/PITFALLS.md` | Relevant source files | | Work on session resolvers | `docs/CONNECTION.md` (Session Resolver Pattern) | `server/src/connection/session-resolvers/` | | Work on terminal status detection | `docs/ADAPTERS.md` (Terminal Status Detection) | `server/src/services/terminal-status-service.ts` | | Work on multi-path catalog extraction | `docs/CORE.md` (Catalog Module) | `core/src/catalog/extractor.ts` (`extractMinimalCatalog`) | | Work on worktree management | `docs/CONNECTION.md` (Worktree Management section) | `server/src/connection/worktree/` (worktree.ts is facade), `server/src/handlers/worktree-handler.ts` | | Work on process/terminal detection | `docs/CONNECTION.md` | `server/src/connection/` | | Work on bypass mode detection | `docs/CONNECTION.md` (Bypass Mode section) | `server/src/session-registry.ts`, `server/src/connection/process-detection.ts` | | Work on terminal launching | `docs/CONNECTION.md` (Terminal Launching section) | `server/src/terminal-launcher.ts` | | Work on managed terminals (node-pty) | `docs/SERVER.md` (Terminal Module section), `docs/STATE.md` | `server/src/terminal/`, `server/src/terminal/daemon/`, `server/src/handlers/terminal-handler.ts` (facade over `handlers/terminal/`) | | Work on shared preferences | `docs/STATE.md` | `core/src/utils/settings.ts`, `server/src/routes/preferences-routes.ts` | | Work on font settings | `docs/STATE.md`, `docs/GUI.md` | `gui-v2/src/styles/terminal-fonts.ts`, `gui-v2/src/pages/Settings.tsx`, `core/src/utils/settings.ts` | | Work on global hotkeys | `docs/HOTKEYS.md` | `hotkeys/`, `server/src/hotkeys-daemon.ts`, `server/src/routes/hotkey-routes.ts` | | Work on usage limits | `docs/SERVER.md` (Usage section) | `server/src/routes/usage-routes.ts` (multi-provider) | | Build and test everything | Use commands in Key Commands above | `cd core && npx tsc && cd ../server && npx tsc && cd ../cli && npx tsc` | | Re-sync all sessions | Start server, then `curl -X POST http://localhost:4243/api/sync?force=true` | Or use GUI Settings → Re-sync All | ## Detailed Documentation Architecture docs by component (read when working on that component): - `docs/CORE.md` — Core package modules: session parsing, archive, catalog, context, handoff - `docs/SERVER.md` — Server: session registry, event flow, HTTP API, WebSocket, MCP - `docs/CLI.md` — CLI TUI: Ink components, keyboard shortcuts, views - `docs/GUI.md` — Web GUI: React pages, API client, plan loading flow - `docs/HOOKS.md` — Hook scripts: adapters, field mappings, token estimation - `docs/CONNECTION.md` — Connection layer: terminal keys, process detection, focus tracking - `docs/REMOTE.md` — Remote access: Tailscale auth, device approval, setup codes, launch script - `docs/HOTKEYS.md` — Global hotkeys: Swift daemon, key bindings, setup, config - `docs/ADAPTERS.md` — Multi-agent adapter system: per-tool capabilities, hooks, context tracking, adding new tools Reference docs (read when working on specific problems): - `docs/JSONL-FORMAT.md` — Claude Code JSONL entry types, structures, token data - `docs/PLATFORM-SUPPORT.md` — Cross-platform support: macOS, Linux, Windows; terminal detection - `docs/STATE.md` — Unified state management: shared preferences, config sync - `docs/PHASES.md` — Development phase history and progress tracking - `docs/PITFALLS.md` — Common pitfalls, known bugs, and lessons learned ## Jacques Instructions for Jacques-related workflows (handoffs, plan tracking, session continuity). ### Plan Tracking When working with a plan file (from handoff or `/plan` mode): 1. **After completing a phase/step**: Edit the plan file to update progress - Change `☐` to `☑` for completed items - Move the `← CURRENT` or `← NEXT` marker to the next item - Add any notes about what was learned or changed 2. **Plan file location**: Usually at `~/.claude/plans/.md` or noted in the handoff's "Plan Status" section 3. **Before ending session**: If you completed phases, ensure the plan file is updated so the next session has accurate progress ### Handoff Workflow - `/jacques-handoff` — Generate handoff document before ending a session - `/jacques-continue` — Load most recent handoff when starting a new session The handoff captures: project context, progress made, user decisions, plan status, blockers, and next steps.