2026-01-18 04:50:46 +01:00
# CLAUDE.md
2026-01-18 07:31:19 +01:00
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
2026-01-18 04:50:46 +01:00
2026-01-21 04:44:19 +01:00
## ⚠️ CRITICAL: Screen Session Safety
**You may be running inside a Claudeman-managed screen session.** Before killing ANY screen or Claude process:
1. **Check environment** : `echo $CLAUDEMAN_SCREEN` - if it returns `1` , you're in a managed session
2. **NEVER run** `screen -X quit` , `pkill screen` , or `pkill claude` without first confirming you're not killing yourself
3. **Safe debugging** : Use `screen -ls` to LIST sessions, but don't kill them blindly
4. **If you need to kill screens** : Use the web UI or `./scripts/screen-manager.sh` instead of direct commands
**Why this matters** : Killing your own screen terminates your session mid-work, losing context and potentially corrupting state.
2026-01-25 18:09:25 +01:00
## ⚡ COM Shorthand (Deployment)
2026-01-26 21:27:08 +01:00
When user says "COM":
1. Increment version in BOTH `package.json` AND `CLAUDE.md` (keep them in sync)
2. Run: `git add -A && git commit -m "chore: bump version to X.XXXX" && git push && npm run build && systemctl --user restart claudeman-web`
Always bump version on every COM, even for small changes.
2026-01-25 18:09:25 +01:00
2026-01-18 04:50:46 +01:00
## Project Overview
2026-01-18 05:17:06 +01:00
2026-01-18 07:31:19 +01:00
Claudeman is a Claude Code session manager with a web interface and autonomous Ralph Loop. It spawns Claude CLI processes via PTY, streams output in real-time via SSE, and supports scheduled/timed runs.
2026-01-18 04:50:46 +01:00
2026-01-27 00:41:00 +01:00
### Mission: Rock-Solid Performance
**The app MUST remain fast, responsive, and never hang** — even with many tabs open and many subagent windows active. This is a core design principle, not a nice-to-have. Every feature must be built with this constraint in mind:
- **60fps terminal rendering** with batched writes and `requestAnimationFrame`
- **Auto-trimming buffers** prevent memory bloat in long-running sessions
- **Debounced state persistence** (500ms) avoids disk thrashing
- **SSE batching** (16ms) reduces client-side event storms
- **Lazy loading** of agent transcripts and historical data
- **No blocking operations** in the main event loop
When adding new features, always ask: "Will this maintain responsiveness with 20 sessions and 50 agent windows?"
2026-01-27 18:16:19 +01:00
**Version** : 0.1400 (must match `package.json` )
2026-01-25 04:07:43 +01:00
2026-01-19 11:19:13 +01:00
**Tech Stack** : TypeScript (ES2022/NodeNext, strict mode), Node.js, Fastify, Server-Sent Events, node-pty
2026-01-18 05:17:06 +01:00
2026-01-24 02:46:24 +01:00
**Key Dependencies** : fastify (REST API), node-pty (PTY spawning), ink/react (TUI), xterm.js (web terminal), @modelcontextprotocol/sdk (MCP server for spawn protocol)
2026-01-21 23:55:16 +01:00
2026-01-24 17:53:16 +01:00
**Requirements** : Node.js 18+, Claude CLI (`claude` ) installed, GNU Screen (`apt install screen` / `brew install screen` )
> **Note**: `claude` does not need to be in the server process's PATH. Claudeman auto-discovers the binary from common install locations (`~/.local/bin`, `~/.claude/local`, `/usr/local/bin`, etc.) and augments PATH for spawned sessions.
2026-01-19 02:06:37 +01:00
2026-01-24 19:12:47 +01:00
> **Runtime**: The web server runs as a systemd user service (`claudeman-web.service`) on HTTPS port 3000 with a self-signed certificate. It auto-restarts and survives logout.
2026-01-20 08:56:15 +01:00
## First-Time Setup
```bash
npm install
```
2026-01-18 07:31:19 +01:00
## Commands
2026-01-18 05:17:06 +01:00
2026-01-19 19:56:37 +01:00
**CRITICAL** : `npm run dev` runs CLI help, NOT the web server. Use `npx tsx src/index.ts web` for development.
2026-01-19 16:45:32 +01:00
2026-01-26 19:42:01 +01:00
**Quick reference** :
- Dev server: `npx tsx src/index.ts web` (or `web --https` for notifications)
- Type check: `npx tsc --noEmit`
- Single test: `npx vitest run test/<file>.test.ts`
- Restart prod: `systemctl --user restart claudeman-web`
2026-01-25 04:57:09 +01:00
### Build & Clean
2026-01-18 05:17:06 +01:00
```bash
2026-01-24 02:46:24 +01:00
npm run build # Compile TS + copy static files + templates + make bins executable
2026-01-18 07:38:19 +01:00
npm run clean # Remove dist/
2026-01-25 04:57:09 +01:00
npm run typecheck # Type check without building (or: npx tsc --noEmit)
```
2026-01-18 05:17:06 +01:00
2026-01-25 04:57:09 +01:00
### Web Server
```bash
2026-01-19 03:43:59 +01:00
npx tsx src/index.ts web # Dev mode - no build needed (RECOMMENDED)
npx tsx src/index.ts web -p 8080 # Dev mode with custom port
2026-01-24 02:46:24 +01:00
npx tsx src/index.ts web --https # Dev mode with self-signed TLS (enables browser notifications)
2026-01-20 19:43:29 +01:00
npm run web # After npm run build (shorthand)
2026-01-19 03:43:59 +01:00
node dist/index.js web # After npm run build
claudeman web # After npm link
2026-01-25 04:57:09 +01:00
```
2026-01-19 03:43:59 +01:00
2026-01-25 04:57:09 +01:00
### TUI (Terminal User Interface)
```bash
2026-01-21 09:54:42 +01:00
npx tsx src/index.ts tui # Dev mode - prompts to start web if not running
2026-01-21 06:21:25 +01:00
claudeman tui # After npm link
2026-01-21 09:54:42 +01:00
claudeman tui --with-web # Auto-start web server if not running (no prompt)
claudeman tui --no-web # Skip web server check entirely
claudeman tui -p 8080 # Specify web server port
2026-01-25 04:57:09 +01:00
```
2026-01-21 06:21:25 +01:00
2026-01-25 04:57:09 +01:00
### Testing
```bash
2026-01-19 05:28:45 +01:00
npm run test # Run all tests once
npm run test:watch # Watch mode
npm run test:coverage # With coverage report
npx vitest run test/session.test.ts # Single file
npx vitest run -t "should create session" # By pattern
2026-01-25 04:57:09 +01:00
```
2026-01-20 08:56:15 +01:00
2026-01-25 04:57:09 +01:00
**Test Configuration** (vitest.config.ts):
- `globals: true` - no imports needed for `describe` /`it` /`expect`
- `testTimeout: 30000` - 30s for integration tests
- `teardownTimeout: 60000` - 60s ensures cleanup runs even on failures
- `fileParallelism: false` - sequential file execution to respect screen session limits
- Coverage excludes entry points: `src/index.ts` , `src/cli.ts`
2026-01-20 08:56:15 +01:00
2026-01-25 04:57:09 +01:00
**Test Port Allocation** (integration tests spawn servers):
2026-01-19 13:41:27 +01:00
2026-01-25 04:57:09 +01:00
| Port | Test File |
|------|-----------|
| 3099 | quick-start.test.ts |
| 3102 | session.test.ts |
| 3105 | scheduled-runs.test.ts |
| 3107 | sse-events.test.ts |
| 3110 | edge-cases.test.ts |
| 3115 | integration-flows.test.ts |
| 3120 | session-cleanup.test.ts |
| 3125 | ralph-integration.test.ts |
2026-01-25 07:57:12 +01:00
| 3127 | respawn-integration.test.ts (reserved) |
2026-01-25 19:49:58 +01:00
| 3130 | hooks-config.test.ts (Hook Event API) |
| 3131 | hooks-config.test.ts (Hook Data Sanitization) |
| 3150 | browser-e2e.test.ts (main browser tests) |
| 3151 | browser-e2e.test.ts (SSE events tests) |
| 3152 | browser-e2e.test.ts (hook events tests) |
| 3153 | browser-e2e.test.ts (Ralph panel tests) |
2026-01-25 23:41:59 +01:00
| 3154 | file-link-click.test.ts |
2026-01-26 23:37:14 +01:00
| 3155 | browser-playwright.test.ts |
| 3156 | browser-puppeteer.test.ts |
| 3157 | browser-agent.test.ts |
| 3158-3160 | browser-comparison.test.ts |
| 3180-3182 | scripts/browser-comparison.mjs (benchmark) |
2026-01-27 17:46:43 +01:00
| 3183 | test/e2e/workflows/quick-start.e2e.ts |
| 3184 | test/e2e/workflows/session-input.e2e.ts |
| 3185 | test/e2e/workflows/session-delete.e2e.ts |
| 3186 | test/e2e/workflows/multi-session.e2e.ts |
| 3187 | test/e2e/workflows/agent-interactions.e2e.ts |
| 3188 | test/e2e/workflows/input-interactions.e2e.ts |
| 3189 | test/e2e/workflows/respawn-flow.e2e.ts |
2026-01-25 18:09:25 +01:00
2026-01-27 17:46:43 +01:00
**Next available port** : 3190
2026-01-19 11:19:13 +01:00
2026-01-26 23:37:14 +01:00
**Browser Testing** : Three frameworks available (Playwright, Puppeteer, Agent-Browser). See `docs/browser-testing-guide.md` for full comparison and patterns.
```bash
# Run browser benchmark (standalone - recommended)
npx tsx scripts/browser-comparison.mjs
# Run existing browser E2E tests
npm test -- test/browser-e2e.test.ts
```
**Browser Testing Key Points** :
- **Vitest hook issue**: Browser tests using `beforeAll` /`afterAll` timeout even when tests pass. Use standalone scripts or run browser code directly in tests.
- **Recommended framework**: Playwright for most cases (auto-waiting, debugging). Puppeteer for Chrome-specific/CDP features.
- **Required browser args**: `--no-sandbox` , `--disable-setuid-sandbox` , `--disable-dev-shm-usage`
- **Install browsers**: `npx playwright install chromium` after npm install
2026-01-27 17:46:43 +01:00
### E2E Test Suite
Real browser-based end-to-end tests using Playwright that validate actual user workflows. These tests catch issues that unit tests miss (like the cpulimit bug that broke screen creation).
**Setup** :
```bash
npm install # Install dependencies (pixelmatch, pngjs)
npx playwright install chromium # Install browser
```
**Running E2E Tests** :
```bash
npm run test:e2e # Run all E2E tests
npm run test:e2e:quick # Run quick-start test only (critical path)
npx vitest run test/e2e/workflows/quick-start.e2e.ts # Run single test file
npx vitest run test/e2e/ -t "should create session" # Run by pattern
```
**Test Fixtures** (`test/e2e/fixtures/` ):
| Fixture | Purpose |
|---------|---------|
| `server.fixture.ts` | `createServerFixture(port)` / `destroyServerFixture()` - Server lifecycle |
| `browser.fixture.ts` | `createBrowserFixture()` / `destroyBrowserFixture()` - Playwright browser with required args |
| `cleanup.fixture.ts` | `CleanupTracker` - Tracks sessions, cases, screens for cleanup |
| `screenshot.fixture.ts` | `captureAndCompare()` - Visual regression testing with pixelmatch |
**Workflow Tests** (`test/e2e/workflows/` ):
| Test | Port | What it validates |
|------|------|-------------------|
| `quick-start.e2e.ts` | 3183 | **Critical path** : click button → session created → screen created → terminal visible |
| `session-input.e2e.ts` | 3184 | Terminal input, Ctrl+C cancel, multi-line input |
| `session-delete.e2e.ts` | 3185 | Delete button → screen killed → UI updated |
| `multi-session.e2e.ts` | 3186 | Multiple sessions, tab switching, Ctrl+Tab shortcut |
| `agent-interactions.e2e.ts` | 3187 | Subagent windows, parent attachment, visibility |
| `input-interactions.e2e.ts` | 3188 | Modals, checkboxes, Ctrl+Enter/W shortcuts |
| `respawn-flow.e2e.ts` | 3189 | Respawn enable/start/stop via API and UI |
| `ralph-loop.e2e.ts` | 3190 | Ralph Loop wizard: open, configure, start, verify tracker enabled |
**Screenshot Validation** :
- Baselines stored in `test/e2e/screenshots/baselines/`
- Current screenshots in `test/e2e/screenshots/current/`
- Diff images (on failure) in `test/e2e/screenshots/diffs/`
- First run auto-creates baselines; subsequent runs compare
- Default threshold: 5% pixel difference allowed
**Cleanup Behavior** :
- All test cases use `e2e-test-*` prefix for easy identification
- `CleanupTracker.forceCleanupAll()` removes ALL `e2e-test-*` resources
- try/finally patterns ensure cleanup even on test failures
- `afterAll` hooks call cleanup as safety net
**E2E Test Pattern** (avoids Vitest hook timeout issue):
```typescript
it ( 'should create session' , async () => {
let browser : BrowserFixture | null = null ;
const caseName = generateCaseName ( 'test' );
try {
serverFixture = await createServerFixture ( PORT );
cleanup = new CleanupTracker ( serverFixture . baseUrl );
cleanup . trackCase ( caseName );
browser = await createBrowserFixture ();
// ... test code ...
} finally {
if ( browser ) await destroyBrowserFixture ( browser );
}
}, 90000 );
```
**E2E Installation Summary** :
| Component | Details |
|-----------|---------|
| **Test Files** | 14 TypeScript files in `test/e2e/` |
| **Fixtures** | server, browser, cleanup, screenshot, index, pixelmatch types |
| **Workflows** | quick-start, session-input, session-delete, multi-session, agent-interactions, input-interactions, respawn-flow |
| **Dependencies** | `playwright` , `pixelmatch` , `pngjs` , `@types/pngjs` |
| **Browser** | Chromium via `npx playwright install chromium` |
| **NPM Scripts** | `npm run test:e2e` (all), `npm run test:e2e:quick` (critical path) |
| **Ports** | 3183-3189 (see workflow tests table above) |
| **Gitignore** | `test/e2e/screenshots/current/` and `diffs/` ignored; `baselines/` tracked |
2026-01-26 23:37:14 +01:00
**Unit tests** (no server needed): `respawn-controller` , `ralph-tracker` , `pty-interactive` , `task-queue` , `task` , `ralph-loop` , `session-manager` , `state-store` , `types` , `templates` , `ralph-config` , `spawn-detector` , `spawn-types` , `spawn-orchestrator` , `ai-idle-checker` , `ai-plan-checker`
2026-01-25 07:57:12 +01:00
**Test Utilities** : `test/respawn-test-utils.ts` provides MockSession, MockAiIdleChecker, MockAiPlanChecker, time controller, state tracker, and event recorder for respawn controller testing. See `test/respawn-test-plan.md` for architecture and `test/respawn-scenarios.md` for comprehensive test scenarios.
2026-01-25 04:57:09 +01:00
**Test Safety** : `test/setup.ts` enforces max 10 concurrent screens, performs orphan cleanup, and protects its own process tree. You can safely run tests from within a Claudeman-managed session - the cleanup will not kill your own Claude instance. The respawn-controller tests use MockSession (not real screens).
2026-01-25 09:08:57 +01:00
**Test Cleanup Patterns** : Integration tests track resources in `createdSessions` and `createdCases` arrays, cleaned up by `afterAll` /`afterEach` hooks. However, some tests perform cleanup in the test body itself (e.g., `edge-cases.test.ts:273-302` creates 5 sessions and cleans them in a loop). If assertions fail before cleanup code runs, resources leak.
2026-01-26 21:27:08 +01:00
**Known Cleanup Issues** (technical debt):
2026-01-25 09:08:57 +01:00
- `pty-interactive.test.ts` : Uses `await session.stop()` at end of each test, not in `afterEach` . Test failures leave sessions running.
- `edge-cases.test.ts` : Multiple sessions created in test body with cleanup at end; failures leak sessions.
- Test cases (`~/claudeman-cases/` ): Cases named `flow-test-*` , `ralph-track-loop-*` , `session-detail-*` may persist after test failures.
**Manual Cleanup** :
```bash
# Remove orphaned test cases
rm -rf ~/claudeman-cases/flow-test-* ~/claudeman-cases/ralph-track-loop-* ~/claudeman-cases/session-detail-*
# Kill orphaned test screens (only detached claudeman screens)
screen -ls | grep -E 'Detached.*claudeman' | cut -d. -f1 | xargs -I{} screen -S {} -X quit
```
2026-01-25 04:57:09 +01:00
### MCP Server
```bash
2026-01-24 02:46:24 +01:00
npx tsx src/mcp-server.ts # Dev mode (stdio transport)
2026-01-25 04:57:09 +01:00
```
2026-01-24 02:46:24 +01:00
2026-01-25 04:57:09 +01:00
Configure in Claude Code's MCP settings:
```json
{ "command" : "node" , "args" : [ "dist/mcp-server.js" ], "env" : { "CLAUDEMAN_API_URL" : "http://localhost:3000" , "CLAUDEMAN_SESSION_ID" : "<id>" } }
```
### Debugging
```bash
2026-01-19 11:19:13 +01:00
screen -ls # List GNU screen sessions
2026-01-20 17:43:36 +01:00
screen -r <name> # Attach to screen session (Ctrl+A D to detach)
2026-01-19 11:19:13 +01:00
curl localhost:3000/api/sessions # Check active sessions
2026-01-20 17:43:36 +01:00
curl localhost:3000/api/status | jq . # Full app state including respawn
2026-01-20 08:56:15 +01:00
cat ~/.claudeman/state.json | jq . # View main state
2026-01-21 22:36:45 +01:00
cat ~/.claudeman/state-inner.json | jq . # View Ralph loop state
2026-01-25 04:57:09 +01:00
```
2026-01-20 17:43:36 +01:00
2026-01-25 04:57:09 +01:00
### Systemd Service
```bash
2026-01-24 04:06:35 +01:00
systemctl --user status claudeman-web # Check status
systemctl --user restart claudeman-web # Restart
systemctl --user stop claudeman-web # Stop
journalctl --user -u claudeman-web -f # Stream logs
2026-01-25 04:57:09 +01:00
```
2026-01-24 04:06:35 +01:00
2026-01-25 04:57:09 +01:00
Install: `ln -sf scripts/claudeman-web.service ~/.config/systemd/user/`
Enable: `systemctl --user enable claudeman-web && loginctl enable-linger $USER`
### Kill Stuck Screens
```bash
2026-01-20 17:43:36 +01:00
screen -X -S <name> quit # Graceful quit
pkill -f "SCREEN.*claudeman" # Force kill all claudeman screens
2026-01-18 05:17:06 +01:00
```
2026-01-21 23:55:16 +01:00
## CLI Commands
```bash
claudeman session [ s] # Manage Claude sessions
start # Start new session
stop <id> # Stop session
list [ ls] # List all
logs <id> # View output
claudeman task [ t] # Manage tasks
add <prompt> # Add task
list [ ls] # List tasks
status <id> # Task details
remove [ rm] <id> # Remove task
clear # Clear completed/failed
claudeman ralph [ r] # Control Ralph loop
start # Start loop
stop # Stop loop
status # Show status
claudeman web # Start web interface
claudeman tui # Start TUI
claudeman status # Overall status
claudeman reset # Reset all state
```
2026-01-18 07:31:19 +01:00
## Architecture
2026-01-18 05:17:06 +01:00
2026-01-20 08:56:15 +01:00
### Key Files
2026-01-19 16:45:32 +01:00
2026-01-25 18:09:25 +01:00
**Core Session Management:**
2026-01-20 08:56:15 +01:00
| File | Purpose |
|------|---------|
| `src/session.ts` | Core PTY wrapper for Claude CLI. Modes: `runPrompt()` , `startInteractive()` , `startShell()` |
| `src/screen-manager.ts` | GNU screen persistence, ghost discovery, 4-strategy kill |
2026-01-25 18:09:25 +01:00
| `src/session-manager.ts` | Session lifecycle, task assignment, cleanup |
2026-01-20 17:43:36 +01:00
| `src/state-store.ts` | JSON persistence to `~/.claudeman/` with debounced writes |
2026-01-25 18:09:25 +01:00
| `src/types.ts` | All TypeScript interfaces |
**Autonomous Features:**
| File | Purpose |
|------|---------|
| `src/respawn-controller.ts` | State machine for autonomous session cycling |
| `src/ai-idle-checker.ts` | Spawns Claude to analyze terminal output for IDLE/WORKING verdict |
| `src/ai-plan-checker.ts` | Spawns Claude to detect plan mode prompts for auto-accept |
| `src/ralph-tracker.ts` | Detects `<promise>PHRASE</promise>` , todos, loop status |
| `src/ralph-config.ts` | Parses `.claude/ralph-loop.local.md` and CLAUDE.md for Ralph config |
2026-01-27 18:16:19 +01:00
| `src/plan-orchestrator.ts` | Multi-agent plan generation with parallel analysis + verification |
2026-01-25 22:05:28 +01:00
| `src/run-summary.ts` | Tracks session events for "what happened while away" summaries |
2026-01-25 18:09:25 +01:00
**Spawn Protocol (Autonomous Agents):**
| File | Purpose |
|------|---------|
| `src/spawn-orchestrator.ts` | Full agent lifecycle: spawn, monitor, budget, queue, cleanup |
| `src/mcp-server.ts` | MCP server binary exposing spawn tools to Claude Code |
| `src/subagent-watcher.ts` | Monitors Claude Code background agents in `~/.claude/projects/*/subagents/*.jsonl` |
**Web & TUI:**
| File | Purpose |
|------|---------|
2026-01-20 08:56:15 +01:00
| `src/web/server.ts` | Fastify REST API + SSE at `/api/events` |
| `src/web/public/app.js` | Frontend: SSE handling, xterm.js, tab management |
2026-01-25 18:09:25 +01:00
| `src/tui/App.tsx` | TUI main component (Ink/React) |
| `src/tui/DirectAttach.ts` | Full-screen console attach with tab switching |
2026-01-19 19:56:37 +01:00
2026-01-18 07:38:19 +01:00
### Data Flow
2026-01-24 17:53:16 +01:00
1. **Session** spawns `claude -p --dangerously-skip-permissions` via `node-pty` (PATH augmented to include claude's install directory)
2026-01-18 07:38:19 +01:00
2. PTY output is buffered, ANSI stripped, and parsed for JSON messages
3. **WebServer** broadcasts events to SSE clients at `/api/events`
2026-01-22 20:49:09 +01:00
4. Full session state (settings, tokens, respawn config, Ralph state) persists to `~/.claudeman/state.json` via **StateStore**
5. Screen metadata persists separately to `~/.claudeman/screens.json` for session recovery
2026-01-18 07:31:19 +01:00
2026-01-19 18:34:43 +01:00
### Respawn State Machine
2026-01-25 07:57:12 +01:00
State machine for autonomous session cycling: `watching` → `confirming_idle` → `ai_checking` → `sending_update` → `waiting_update` → `sending_clear` → `waiting_clear` → `sending_init` → `waiting_init` → `monitoring_init` → (optionally) `sending_kickstart` . Steps can be skipped via config (`sendClear: false` , `sendInit: false` ). After each step, waits for `completionConfirmMs` (10s) of output silence before proceeding. AI idle check uses a fresh Claude session to analyze terminal output for IDLE/WORKING verdict.
2026-01-19 18:34:43 +01:00
2026-01-24 19:47:07 +01:00
See `docs/respawn-state-machine.md` for the full state diagram, idle detection layers, and auto-accept behavior.
2026-01-22 21:36:43 +01:00
2026-01-23 10:20:37 +01:00
### Spawn1337 Protocol (Autonomous Agents)
2026-01-24 19:47:07 +01:00
Spawned agents are full-power Claude sessions in their own screen sessions, managed via MCP tools (`spawn_agent` , `list_agents` , `get_agent_status` , `get_agent_result` , `send_agent_message` , `cancel_agent` ). Max 5 concurrent, max depth 3, default timeout 30min. Agents communicate via filesystem (`spawn-comms/` ) and signal completion via `<promise>PHRASE</promise>` .
2026-01-23 10:20:37 +01:00
2026-01-24 19:47:07 +01:00
See `docs/spawn-protocol.md` for the full protocol flow, directory structure, resource governance, and MCP configuration.
2026-01-23 10:20:37 +01:00
2026-01-25 17:40:28 +01:00
### Subagent Watcher (Claude Code Background Agents)
Monitors Claude Code's internal background agents (the `Task` tool) in real-time. Watches `~/.claude/projects/{project}/{session}/subagents/agent-{id}.jsonl` files and emits structured events.
**Events** : `subagent:discovered` , `subagent:tool_call` , `subagent:progress` , `subagent:message` , `subagent:completed`
**API** :
- `GET /api/subagents` - List all known subagents (optional `?minutes=60` for recent only)
- `GET /api/subagents/:agentId` - Get subagent info
- `GET /api/subagents/:agentId/transcript` - Get transcript (`?limit=N` , `?format=formatted` )
- `DELETE /api/subagents/:agentId` - Kill subagent process
- `GET /api/sessions/:id/subagents` - Get subagents for session's working directory
**Status lifecycle** : `active` → `idle` (30s no activity) → `completed` (process exited or file stale)
2026-01-25 18:09:25 +01:00
**Settings** : Can be disabled via App Settings → Display → "Enable Subagent Tracking" (default: enabled). Setting is stored in `~/.claudeman/settings.json` as `subagentTrackingEnabled` .
Implementation: `src/subagent-watcher.ts` - singleton `subagentWatcher` started on server boot (if enabled).
2026-01-25 17:40:28 +01:00
2026-01-27 01:23:12 +01:00
### Subagent Window Management (Frontend)
Floating subagent windows in the web UI show real-time activity from Claude Code's background agents. Each window displays tool calls, progress, and messages, with visual connection lines to the parent session tab.
**Parent Session Discovery** (`app.js:findParentSessionForSubagent()` ):
1. When a subagent is discovered via SSE event, the frontend must determine which Claudeman session spawned it
2. Matching uses `workingDir` → `projectHash` conversion: `/home/user/project` becomes `-home-user-project`
3. For each session, calls `/api/sessions/{id}/subagents` which returns subagents matching that session's `workingDir`
4. First match wins: checks active session first, then iterates through other sessions
5. Once found, caches `parentSessionId` and `parentSessionName` in the agent object
**Window Visibility** (`app.js:updateSubagentWindowVisibility()` ):
- "Show for Active Tab Only" setting controls whether windows are hidden when their parent session isn't active
- Windows with unknown parents (discovery pending) are always shown
- Minimized windows stay minimized regardless of visibility setting
**Tab Badge System** :
- Minimized subagents appear as a badge on their parent session's tab
- Badge dropdown allows restoring or permanently dismissing each agent
- `minimizedSubagents` Map tracks agentIds per sessionId
**Parent Matching Algorithm** (to handle multiple sessions with same workingDir):
1. **Strategy 1 - Sibling matching** : If another subagent with the same Claude `sessionId` already has a parent, use that same parent. This ensures all subagents from the same Claude session go to the same Claudeman session.
2. **Strategy 2 - WorkingDir matching with heuristics** : Find all sessions matching by `workingDir` . If multiple match, prefer the most recently created session (newest session likely spawned the subagent).
**Session Rename Handling** : When a session is renamed, `updateSubagentParentNames()` updates all subagent objects and their window headers via the `session:updated` SSE handler.
**Key Frontend Data Structures** (`app.js` ):
```javascript
this . subagents = new Map (); // agentId → SubagentInfo (includes parentSessionId, parentSessionName)
this . subagentWindows = new Map (); // agentId → { element, minimized, hidden, position }
this . minimizedSubagents = new Map (); // sessionId → Set<agentId> (for tab badges)
```
**Implementation Files** :
- Server: `src/subagent-watcher.ts` (discovery, monitoring, events)
- Server: `src/web/server.ts` (SSE broadcast, REST endpoints)
- Frontend: `src/web/public/app.js:6183-6550` (window management, parent discovery, visibility)
2026-01-19 16:45:32 +01:00
### Session Modes
Sessions have a `mode` property (`SessionMode` type):
- **`'claude'` **: Runs Claude CLI for AI interactions (default)
- **`'shell'` **: Runs a plain bash shell for debugging/testing
2026-01-21 04:44:19 +01:00
### Screen-Aware Sessions
All Claude sessions spawned by Claudeman receive environment variables indicating they're running in a managed screen:
| Variable | Value | Purpose |
|----------|-------|---------|
| `CLAUDEMAN_SCREEN` | `1` | Indicates session is managed by Claudeman |
| `CLAUDEMAN_SESSION_ID` | `<uuid>` | Unique session identifier |
| `CLAUDEMAN_SCREEN_NAME` | `claudeman-<name>` | GNU screen session name |
This prevents Claude from accidentally killing its own screen session. The default CLAUDE.md template includes guidance about this.
2026-01-24 17:53:16 +01:00
**Implementation** : Set in `screen-manager.ts:createScreen()` for screen-based sessions and `session.ts:startInteractive()` /`startShell()` for PTY-only sessions. Both paths also augment `PATH` with the claude binary's directory to ensure discovery in restricted environments (systemd, non-login shells).
2026-01-21 04:44:19 +01:00
2026-01-18 05:17:06 +01:00
## Code Patterns
2026-01-27 17:46:43 +01:00
### Memory Leak Prevention
The frontend (`app.js` ) runs for extended periods and must avoid memory leaks. Key patterns:
**SSE Reconnection** : When EventSource reconnects, all event listeners are re-registered on the new instance. The old EventSource is closed, but any orphaned reconnect timeouts must be cleared:
```javascript
// Clear pending reconnect timeout before creating new connection
if ( this . sseReconnectTimeout ) {
clearTimeout ( this . sseReconnectTimeout );
this . sseReconnectTimeout = null ;
}
```
**Cleanup on Init** : When `handleInit()` is called (SSE reconnect), clear all Maps and timers that could contain stale data:
- `idleTimers` - Clear all timeouts, then clear the Map
- `subagentActivity` , `subagentToolResults` - Clear to remove stale agent data
- `pendingHooks` , `tabAlerts` , `_shownCompletions` - Clear state tracking Sets
**Interval Management** : Always provide a stop method for intervals:
```javascript
startSystemStatsPolling () {
this . stopSystemStatsPolling (); // Clear existing before starting
this . systemStatsInterval = setInterval (...);
}
stopSystemStatsPolling () {
if ( this . systemStatsInterval ) {
clearInterval ( this . systemStatsInterval );
this . systemStatsInterval = null ;
}
}
```
**Session Cleanup** : When a session is deleted, clean up ALL associated resources:
- Respawn state (`respawnStatus` , `respawnTimers` , `respawnCountdownTimers` , `respawnActionLogs` )
- Subagent data (windows, activity, tool results)
- Timers (idle timers, pending hooks)
**Subagent Data** : Clean up activity/toolResults for completed agents after 5 minutes to prevent unbounded growth during long sessions.
2026-01-19 12:52:29 +01:00
### Pre-compiled Regex Patterns
For performance, regex patterns that are used frequently should be compiled once at module level:
```typescript
// Good - compile once
const ANSI_ESCAPE_PATTERN = /\x1b\[[0-9;]*m/g ;
const TOKEN_PATTERN = /(\d+(?:\.\d+)?)\s*([kKmM])?\s*tokens/ ;
// Bad - recompiles on each call
function parse ( line : string ) {
return line . replace ( /\x1b\[[0-9;]*m/g , '' );
}
```
2026-01-18 07:31:19 +01:00
### Claude Message Parsing
Claude CLI outputs newline-delimited JSON. Strip ANSI codes before parsing:
2026-01-18 05:17:06 +01:00
```typescript
2026-01-19 12:52:29 +01:00
const cleanLine = line . replace ( ANSI_ESCAPE_PATTERN , '' );
2026-01-18 07:31:19 +01:00
const msg = JSON . parse ( cleanLine ) as ClaudeMessage ;
2026-01-18 21:37:03 +01:00
// msg.type: 'system' | 'assistant' | 'user' | 'result'
2026-01-18 07:31:19 +01:00
// msg.message?.content: Array<{ type: 'text', text: string }>
// msg.total_cost_usd: number (on result messages)
2026-01-18 05:17:06 +01:00
```
2026-01-18 21:37:03 +01:00
### PTY Spawn Modes
2026-01-24 17:53:16 +01:00
All PTY spawns pass `PATH: getAugmentedPath()` in the env to ensure `claude` is discoverable even when the server runs in a restricted environment (e.g., systemd). The `getAugmentedPath()` function (in `session.ts` ) resolves the claude binary's directory once at startup and prepends it to PATH. The `screen-manager.ts` equivalent (`findClaudeDir()` ) does the same for screen-based spawns via `export PATH="<dir>:$PATH"` in the bash command.
2026-01-18 21:37:03 +01:00
```typescript
2026-01-19 10:36:30 +01:00
// One-shot mode (JSON output for token tracking)
2026-01-24 17:53:16 +01:00
pty . spawn ( 'claude' , [ '-p' , '--dangerously-skip-permissions' , '--output-format' , 'stream-json' , prompt ], {
env : { ... process . env , PATH : getAugmentedPath (), ... }
})
2026-01-18 21:37:03 +01:00
2026-01-19 10:36:30 +01:00
// Interactive mode (tokens parsed from status line)
2026-01-24 17:53:16 +01:00
pty . spawn ( 'claude' , [ '--dangerously-skip-permissions' ], {
env : { ... process . env , PATH : getAugmentedPath (), ... }
})
2026-01-19 18:04:50 +01:00
// Shell mode (debugging/testing - no Claude CLI)
pty . spawn ( 'bash' , [], { ... })
2026-01-18 21:37:03 +01:00
```
2026-01-24 17:53:16 +01:00
**PATH resolution search order** (both `session.ts` and `screen-manager.ts` ):
1. `which claude` (respects current PATH)
2. `~/.local/bin/claude`
3. `~/.claude/local/claude`
4. `/usr/local/bin/claude`
5. `~/.npm-global/bin/claude`
6. `~/bin/claude`
2026-01-20 08:40:14 +01:00
### Sending Input to Sessions
2026-01-19 16:35:20 +01:00
2026-01-24 19:12:47 +01:00
Two methods:
1. ** `session.write(data)` ** - Direct PTY write (used by `/api/sessions/:id/input` endpoint)
2. ** `session.writeViaScreen(data)` ** - Via GNU screen (RECOMMENDED for programmatic input). Used by RespawnController, auto-compact, auto-clear.
2026-01-20 08:40:14 +01:00
**How `writeViaScreen` works internally** (in `screen-manager.ts:sendInput` ):
2026-01-27 17:55:45 +01:00
1. Strips all `\n` newlines and `\r` carriage returns from text
2026-01-20 08:40:14 +01:00
2. Sends text first: `screen -S name -p 0 -X stuff "text"`
3. Sends Enter separately: `screen -S name -p 0 -X stuff "$(printf '\015')"`
2026-01-24 19:12:47 +01:00
**Why separate commands?** Claude CLI uses Ink (React for terminals) which requires text and Enter as separate `screen -X stuff` commands. Combining them doesn't work. This is a critical implementation detail when debugging input issues.
2026-01-19 16:35:20 +01:00
2026-01-27 17:55:45 +01:00
**IMPORTANT** : All prompts sent via `writeViaScreen` (respawn updatePrompt, kickstartPrompt, auto-compact, etc.) must be **single-line** . Newlines are stripped, so multi-line prompts become one long line.
2026-01-18 07:31:19 +01:00
### Idle Detection
2026-01-19 15:00:49 +01:00
**Session** : emits `idle` /`working` events on prompt detection + 2s activity timeout.
2026-01-18 07:31:19 +01:00
2026-01-24 19:47:07 +01:00
**RespawnController** : Multi-layer detection (completion message → AI idle check → output silence → token stability → working pattern absence). See `docs/respawn-state-machine.md` for full details.
2026-01-23 01:25:45 +01:00
2026-01-19 10:36:30 +01:00
### Token Tracking
2026-01-18 21:37:03 +01:00
2026-01-19 10:36:30 +01:00
- **One-shot mode**: Uses `--output-format stream-json` for detailed token usage from JSON
- **Interactive mode**: Parses tokens from Claude's status line (e.g., "123.4k tokens"), estimates 60/40 input/output split
2026-01-18 21:37:03 +01:00
2026-01-19 13:08:53 +01:00
### Auto-Compact & Auto-Clear
2026-01-19 15:00:49 +01:00
| Feature | Default Threshold | Action |
|---------|------------------|--------|
| Auto-Compact | 110k tokens | `/compact` with optional prompt |
| Auto-Clear | 140k tokens | `/clear` to reset context |
2026-01-19 13:08:53 +01:00
2026-01-19 15:00:49 +01:00
Both wait for idle. Configure via `session.setAutoCompact()` / `session.setAutoClear()` .
2026-01-19 13:08:53 +01:00
2026-01-21 22:36:45 +01:00
### Ralph / Todo Tracking
2026-01-19 13:24:45 +01:00
2026-01-24 19:47:07 +01:00
Detects Ralph loops and todos inside Claude sessions. **Disabled by default** but auto-enables when Ralph-related patterns are detected (promise tags, TodoWrite, iteration patterns, etc.). See `ralph-tracker.ts:shouldAutoEnable()` for the full pattern list.
2026-01-21 22:36:45 +01:00
2026-01-27 18:05:03 +01:00
**Auto-Loading @fix_plan.md** : When a session starts, the Ralph tracker automatically:
1. Loads existing `@fix_plan.md` from the working directory (if present)
2. Imports todos and shows them in the Ralph panel
3. Watches the file for changes and reloads when modified by Claude
4. Auto-enables the tracker if todos are found
This means you can create a session in a folder with an existing `@fix_plan.md` and the tracker will immediately show and track those tasks.
2026-01-24 19:12:47 +01:00
**Auto-Configuration from Ralph Plugin State** : When a session starts, Claudeman reads `.claude/ralph-loop.local.md` to auto-configure:
2026-01-21 22:36:45 +01:00
```yaml
---
enabled : true
iteration : 5
max-iterations : 50
completion-promise : "COMPLETE"
---
```
2026-01-24 19:12:47 +01:00
Priority: 1) `.claude/ralph-loop.local.md` (official Ralph plugin state), 2) `CLAUDE.md` `<promise>` tags (fallback). See `src/ralph-config.ts` .
2026-01-21 22:36:45 +01:00
2026-01-24 19:12:47 +01:00
**Completion Detection** (multi-strategy):
2026-01-20 17:43:36 +01:00
- 1st occurrence of `<promise>PHRASE</promise>` : Stores as expected phrase (likely in prompt)
- 2nd occurrence: Emits `completionDetected` event (actual completion)
- **Bare phrase detection**: Also detects phrase without tags once expected phrase is known
- **All complete detection**: When "All X files/tasks created/completed" detected, marks all todos complete and emits completion
- If loop is already active (via `/ralph-loop:ralph-loop` ): Emits immediately on first occurrence
**Session Lifecycle** : Each session has its own independent tracker:
- New session → Fresh tracker (no carryover)
- Close tab → Tracker state cleared, UI panel hides
- `tracker.reset()` → Clears todos/state, keeps enabled status
- `tracker.fullReset()` → Complete reset to initial state
2026-01-24 19:12:47 +01:00
- `tracker.configure({ enabled?, completionPhrase?, maxIterations? })` → Partial config update
2026-01-20 17:43:36 +01:00
**API** :
2026-01-21 22:36:45 +01:00
- `GET /api/sessions/:id/ralph-state` - Get loop state and todos
- `POST /api/sessions/:id/ralph-config` - Configure tracker:
2026-01-20 17:43:36 +01:00
- `{ enabled: boolean }` - Enable/disable
- `{ reset: true }` - Soft reset (keep enabled)
- `{ reset: "full" }` - Full reset
2026-01-19 15:00:49 +01:00
### Terminal Display Fix
2026-01-19 13:24:45 +01:00
2026-01-19 15:00:49 +01:00
Tab switch/new session fix: clear xterm → write buffer → resize PTY → Ctrl+L redraw. Uses `pendingCtrlL` Set, triggered on `session:idle` /`session:working` events.
2026-01-19 11:19:13 +01:00
2026-01-19 05:28:45 +01:00
### SSE Events
2026-01-18 07:31:19 +01:00
2026-01-19 05:28:45 +01:00
All events broadcast to `/api/events` with format: `{ type: string, sessionId?: string, data: any }` .
2026-01-18 07:31:19 +01:00
2026-01-25 17:40:28 +01:00
Event prefixes: `session:` , `task:` , `respawn:` , `spawn:` , `subagent:` , `hook:` , `scheduled:` , `case:` , `screen:` , `init` .
2026-01-20 08:56:15 +01:00
2026-01-24 19:12:47 +01:00
Key events (see `app.js:handleSSEEvent()` ):
- `session:idle` , `session:working` - Status indicators
2026-01-20 08:56:15 +01:00
- `session:terminal` , `session:clearTerminal` - Terminal content
2026-01-21 22:36:45 +01:00
- `session:ralphLoopUpdate` , `session:ralphTodoUpdate` , `session:ralphCompletionDetected` - Ralph tracking
2026-01-24 19:12:47 +01:00
- `respawn:detectionUpdate` - Idle detection status
- `spawn:queued` , `spawn:started` , `spawn:completed` , `spawn:failed` - Agent lifecycle
2026-01-25 17:40:28 +01:00
- `subagent:discovered` , `subagent:tool_call` , `subagent:progress` , `subagent:message` , `subagent:completed` - Claude Code background agents
2026-01-24 19:12:47 +01:00
- `hook:idle_prompt` , `hook:permission_prompt` , `hook:elicitation_dialog` , `hook:stop` - Claude Code hooks
2026-01-19 11:19:13 +01:00
2026-01-25 22:05:28 +01:00
### Run Summary
Per-session event tracking for "what happened while you were away" view. Click the chart icon (📊) on any session tab to view.
**Tracked Events** : session start/stop, respawn cycles, state changes, idle/working transitions, token milestones (every 50k), auto-compact/clear, Ralph completions, AI check results, hook events, errors/warnings, state stuck warnings (>10min same state).
**Stats** : respawn cycles, peak tokens, active time, idle time, error/warning counts.
**Storage** : In-memory only (not persisted). Fresh tracker created per session; cleared when session is deleted.
**Implementation** : `RunSummaryTracker` class in `src/run-summary.ts` , integrated via `setupSessionListeners()` and `setupRespawnListeners()` in `server.ts` .
2026-01-19 11:19:13 +01:00
### Frontend (app.js)
2026-01-24 19:12:47 +01:00
Vanilla JS + xterm.js. 60fps rendering: server batches terminal data every 16ms, client uses `requestAnimationFrame` to batch xterm.js writes.
2026-01-19 05:28:45 +01:00
2026-01-24 02:46:24 +01:00
### HTTPS & Browser Notifications
2026-01-24 19:12:47 +01:00
**HTTPS** : The `--https` flag generates/reuses self-signed certificates in `~/.claudeman/certs/` . Required for the Web Notification API.
2026-01-24 02:46:24 +01:00
2026-01-24 19:12:47 +01:00
**Notifications** (`NotificationManager` in `app.js` ): In-app drawer, tab title flashing, Web Notification API (rate limited 3s), audio alerts (critical only), tab blinking (red=action, yellow=idle).
2026-01-24 02:46:24 +01:00
2026-01-24 19:12:47 +01:00
**Hook Event Data** : `/api/hook-event` forwards `data` field into SSE broadcast. Hook events: `permission_prompt` , `elicitation_dialog` , `idle_prompt` , `stop` .
2026-01-24 02:46:24 +01:00
2026-01-19 15:00:49 +01:00
### State Store
2026-01-19 12:55:08 +01:00
2026-01-24 19:12:47 +01:00
Writes debounced (500ms) to `~/.claudeman/state.json` via `persistSessionState()` on every meaningful change.
2026-01-22 20:49:09 +01:00
**Per-session fields stored** (`SessionState` in `types.ts` ):
2026-01-24 19:12:47 +01:00
- `id` , `pid` , `status` , `name` , `mode` - Core identity
- `workingDir` , `createdAt` , `lastActivityAt` - Location and timestamps
- `autoClearEnabled/Threshold` , `autoCompactEnabled/Threshold/Prompt` - Context management
- `ralphEnabled` , `ralphCompletionPhrase` - Ralph tracker state
- `respawnEnabled` , `respawnConfig` - Respawn controller state
- `totalCost` , `inputTokens` , `outputTokens` - Token tracking
- `parentAgentId` , `childAgentIds` - Spawn agent tree
2026-01-22 20:49:09 +01:00
2026-01-24 19:12:47 +01:00
CLI commands (`claudeman status/session list` ) read from `state.json` to display web-managed sessions.
2026-01-19 12:55:08 +01:00
2026-01-20 08:56:15 +01:00
### TypeScript Config
2026-01-25 04:57:09 +01:00
Module resolution: NodeNext. Target: ES2022. Strict mode enabled with all additional strictness flags (`noUnusedLocals` , `noUnusedParameters` , `noImplicitReturns` , `noFallthroughCasesInSwitch` , etc.). No ESLint/Prettier configured - rely on TypeScript strict mode.
2026-01-21 19:49:44 +01:00
2026-01-25 04:57:09 +01:00
TUI uses React JSX (`jsx: react-jsx` , `jsxImportSource: react` ) for Ink components.
2026-01-20 08:56:15 +01:00
2026-01-19 07:33:33 +01:00
## Adding New Features
2026-01-20 08:56:15 +01:00
- **API endpoint**: Add types in `types.ts` , route in `server.ts:buildServer()` , use `createErrorResponse()` for errors
- **SSE event**: Emit via `broadcast()` in server.ts, handle in `app.js:handleSSEEvent()` switch
- **Session event**: Add to `SessionEvents` interface in `session.ts` , emit via `this.emit()` , subscribe in server.ts, handle in frontend
2026-01-22 20:49:09 +01:00
- **Session setting**: Add field to `SessionState` in `types.ts` , include in `session.toState()` , call `this.persistSessionState(session)` in server.ts after the change
2026-01-24 02:46:24 +01:00
- **MCP tool**: Add tool definition in `mcp-server.ts` using `server.tool()` , use `apiRequest()` to call Claudeman REST API
2026-01-27 17:46:43 +01:00
- **New test file**: Create `test/<name>.test.ts` , pick unique port (next available: 3190), add to port allocation table above
2026-01-20 17:43:36 +01:00
### API Error Codes
Use `createErrorResponse(code, details?)` from `types.ts` :
| Code | Use Case |
|------|----------|
| `NOT_FOUND` | Session/resource doesn't exist |
| `INVALID_INPUT` | Bad request parameters |
| `SESSION_BUSY` | Session is currently processing |
| `OPERATION_FAILED` | Action couldn't complete |
| `ALREADY_EXISTS` | Duplicate resource |
| `INTERNAL_ERROR` | Unexpected server error |
2026-01-19 07:33:33 +01:00
2026-01-19 11:31:32 +01:00
## Session Lifecycle & Cleanup
2026-01-21 04:44:19 +01:00
- **Limit**: Web server: `MAX_CONCURRENT_SESSIONS = 50` (`server.ts:56` ), UI tab limit: 20, CLI default: 5 (`types.ts:DEFAULT_CONFIG` )
2026-01-19 15:00:49 +01:00
- **Kill** (`killScreen()` ): child PIDs → process group → screen quit → SIGKILL
- **Ghost discovery**: `reconcileScreens()` finds orphaned screens on startup
2026-01-22 20:49:09 +01:00
- **Cleanup** (`cleanupSession()` ): stops respawn, clears buffers/timers, kills screen, removes from `state.json`
- **State sync**: Every session create/delete/update calls `persistSessionState()` which writes full state (including respawn config from controller) to `state.json`
2026-01-22 21:36:43 +01:00
- **Recovery on restart**: Server reads `state.json` first (has all settings), falls back to `screens.json` for any sessions not found. Settings (auto-compact, auto-clear, respawn config, Ralph state) restored to live session objects after screen reattachment.
2026-01-19 11:31:32 +01:00
2026-01-24 19:12:47 +01:00
## TUI (WIP)
2026-01-21 22:36:45 +01:00
2026-01-26 19:42:01 +01:00
Ink/React-based TUI in `src/tui/` . Client to the web server, uses `/api/*` endpoints and attaches to screens via GNU screen.
**Key files** : `App.tsx` (main component), `DirectAttach.ts` (full-screen attach with tab switching), `SessionList.tsx` , `SessionView.tsx` .
**Current state** : Basic session list and direct attach work. Missing: full session management UI, settings panel, notifications.
2026-01-21 22:36:45 +01:00
2026-01-19 12:52:29 +01:00
## Buffer Limits
| Buffer | Max Size | Trim To |
|--------|----------|---------|
2026-01-21 23:55:16 +01:00
| Terminal | 2MB | 1.5MB |
| Text output | 1MB | 768KB |
2026-01-19 12:52:29 +01:00
| Messages | 1000 | 800 |
| Line buffer | 64KB | (flushed every 100ms) |
| Respawn buffer | 1MB | 512KB |
2026-01-24 19:12:47 +01:00
Tab switch uses `tail=256KB` for fast initial load, then chunked 64KB writes via `requestAnimationFrame` .
2026-01-21 23:55:16 +01:00
2026-01-24 19:12:47 +01:00
## API Routes
2026-01-19 13:41:27 +01:00
2026-01-24 19:12:47 +01:00
All routes defined in `server.ts:buildServer()` . Key endpoint groups:
- `/api/events` - SSE stream | `/api/status` - Full app state
- `/api/sessions` - CRUD + `/input` , `/resize` , `/interactive`
- `/api/sessions/:id/respawn/*` - Start/stop/enable/config respawn controller
- `/api/sessions/:id/ralph-*` - Ralph tracker config and state
- `/api/sessions/:id/auto-compact` , `/auto-clear` - Token threshold settings
- `/api/quick-start` - Create case + start session (`{mode?: 'claude'|'shell'}` )
- `/api/cases` , `/api/screens` - Case and screen management
- `/api/spawn/*` - Agent lifecycle (list, status, result, messages, cancel, trigger)
2026-01-25 17:40:28 +01:00
- `/api/subagents` - List/get/kill Claude Code background agents, get transcripts
- `/api/sessions/:id/subagents` - Get subagents for a specific session's working directory
2026-01-25 22:05:28 +01:00
- `/api/sessions/:id/run-summary` - Get run summary (events, stats) for "what happened while away"
2026-01-24 19:12:47 +01:00
- `/api/hook-event` - Claude Code hook callbacks (`{event, sessionId, data?}` )
2026-01-19 13:41:27 +01:00
2026-01-21 09:54:42 +01:00
2026-01-20 08:56:15 +01:00
## State Files
| File | Purpose |
|------|---------|
2026-01-22 20:49:09 +01:00
| `~/.claudeman/state.json` | Full session state (all settings, tokens, respawn config, Ralph state), tasks, app config |
2026-01-21 22:36:45 +01:00
| `~/.claudeman/state-inner.json` | Ralph loop/todo state per session (separate to reduce writes) |
2026-01-22 20:49:09 +01:00
| `~/.claudeman/screens.json` | Screen session metadata (for recovery after restart) |
2026-01-25 18:09:25 +01:00
| `~/.claudeman/settings.json` | User preferences (lastUsedCase, custom template path, subagentTrackingEnabled) |
2026-01-24 02:46:24 +01:00
| `~/.claudeman/certs/` | Self-signed TLS certificates for `--https` mode |
2026-01-22 20:49:09 +01:00
2026-01-24 19:12:47 +01:00
**Recovery** : On restart, sessions restored from `state.json` (primary) with `screens.json` as fallback. All settings re-applied to live sessions. Cases created in `~/claudeman-cases/` by default.
2026-01-20 08:56:15 +01:00
2026-01-22 22:43:09 +01:00
### CLAUDE.md Templates
2026-01-21 19:49:44 +01:00
2026-01-22 22:43:09 +01:00
New cases get a CLAUDE.md generated from `src/templates/case-template.md` (bundled with the project). Template resolution order:
1. Custom path from `~/.claudeman/settings.json` (`defaultClaudeMdPath` field)
2. Bundled `case-template.md` (copied to `dist/templates/` during build)
3. Minimal fallback (if bundled template is missing)
Placeholders replaced:
2026-01-21 19:49:44 +01:00
- `[PROJECT_NAME]` → Case name
- `[PROJECT_DESCRIPTION]` → Description
- `[DATE]` → Current date (YYYY-MM-DD)
2026-01-21 04:27:09 +01:00
## Screen Session Manager (CLI Tool)
2026-01-24 19:12:47 +01:00
`./scripts/screen-manager.sh` - Interactive bash tool for managing screen sessions. Commands: `list` , `attach N` , `kill N,M` , `kill-all` , `info N` . Requires `jq` and `screen` .
2026-01-21 04:27:09 +01:00
2026-01-26 11:06:35 +01:00
## Web UI Keyboard Shortcuts
| Shortcut | Action |
|----------|--------|
| `Ctrl+Enter` | Quick-start session |
| `Ctrl+W` | Close session |
| `Ctrl+Tab` | Next session |
| `Ctrl+K` | Kill all sessions |
| `Ctrl+L` | Clear terminal |
2026-01-20 08:56:15 +01:00
## Documentation
2026-01-26 21:27:08 +01:00
**Reference docs** (read these for deep dives):
2026-01-24 19:47:07 +01:00
- `docs/respawn-state-machine.md` - Respawn controller states, idle detection, auto-accept
- `docs/spawn-protocol.md` - Spawn1337 agent protocol, MCP tools, resource governance
2026-01-24 19:12:47 +01:00
- `docs/ralph-wiggum-guide.md` - Ralph Wiggum loop guide (plugin reference, prompt templates)
- `docs/claude-code-hooks-reference.md` - Claude Code hooks documentation
2026-01-26 23:37:14 +01:00
- `docs/browser-testing-guide.md` - Browser testing frameworks comparison, patterns, and known issues
2026-01-20 08:56:15 +01:00
2026-01-26 21:27:08 +01:00
**Internal planning** (historical context, may be outdated):
- `docs/respawn-improvement-plan.md` - Planned respawn improvements
- `docs/run-summary-plan.md` - Run summary feature design
2026-01-24 19:12:47 +01:00
### Ralph Wiggum Loops
2026-01-20 08:56:15 +01:00
**Core Pattern** : `<promise>PHRASE</promise>` - The completion signal that tells the loop to stop.
2026-01-20 17:43:36 +01:00
**Skill Commands** :
2026-01-20 08:56:15 +01:00
```bash
2026-01-20 17:43:36 +01:00
/ralph-loop:ralph-loop # Start Ralph Loop in current session
/ralph-loop:cancel-ralph # Cancel active Ralph Loop
/ralph-loop:help # Show help and usage
2026-01-20 08:56:15 +01:00
```
2026-01-24 19:12:47 +01:00
The `RalphTracker` class (`src/ralph-tracker.ts` ) detects Ralph patterns in Claude output and tracks loop state, todos, and completion phrases. It auto-enables when Ralph-related patterns are detected.
2026-01-27 17:46:43 +01:00
**Ralph Loop Wizard** : The web UI wizard (`app.js:startRalphLoop()` ) provides a guided setup for Ralph Loops. It:
1. Creates/selects a case and starts a session
2. Configures the Ralph tracker with completion phrase and max iterations
3. Optionally generates a task plan (`@fix_plan.md` )
4. Sends the initial prompt with iteration protocol
2026-01-27 18:16:19 +01:00
**Plan Generation Modes** (Step 2 of wizard):
| Mode | Description | API Endpoint |
|------|-------------|--------------|
| **Brief** | High-level milestones only | `/api/generate-plan` |
| **Standard** | Balanced implementation steps | `/api/generate-plan` |
| **Enhanced** | Multi-agent orchestration with verification | `/api/generate-plan-detailed` |
**Enhanced Plan Generation** (`src/plan-orchestrator.ts` ): When "Enhanced" mode is selected, the plan is generated using parallel subagent orchestration:
1. **Phase 1 - Parallel Analysis** : Spawns 4 specialist subagents simultaneously:
- Requirements Analyst → Extracts explicit/implicit requirements
- Architecture Planner → Identifies modules, interfaces, types
- TDD Specialist → Designs test-first approach, edge cases
- Risk Analyst → Identifies failure points, dependencies, blockers
2. **Phase 2 - Synthesis** : Merges outputs, deduplicates, orders by dependency
3. **Phase 3 - Verification** : Review subagent validates plan, assigns P0/P1/P2 priorities, identifies gaps
The enhanced mode takes longer (~60-90s) but produces more thorough plans with quality scores. Switching between modes auto-regenerates the plan.
2026-01-27 17:55:45 +01:00
**Respawn for Ralph Loops** : Disabled by default (checkbox unchecked). When enabled, the respawn controller uses Ralph-specific prompts:
- **Update Prompt**: Instructs Claude to document progress to CLAUDE.md, update planning files (`@fix_plan.md` ), mark completed tasks, and write a summary before `/clear`
- **Kickstart Prompt**: After `/init` , tells Claude it's in a Ralph Wiggum loop and to continue work by reading `@fix_plan.md` and CLAUDE.md notes, then resume on uncompleted tasks