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-31 23:52:44 +01:00
## Quick Reference
| Task | Command |
|------|---------|
| Dev server | `npx tsx src/index.ts web` |
| Type check | `tsc --noEmit` |
2026-02-27 17:54:59 +01:00
| Lint | `npm run lint` (fix: `npm run lint:fix` ) |
| Format | `npm run format` (check: `npm run format:check` ) |
2026-01-31 23:52:44 +01:00
| Single test | `npx vitest run test/<file>.test.ts` |
2026-02-26 16:44:34 +01:00
| Production | `npm run build && systemctl --user restart codeman-web` |
2026-01-31 23:52:44 +01:00
2026-02-12 10:29:57 +01:00
## CRITICAL: Session Safety
2026-01-21 04:44:19 +01:00
2026-02-26 16:44:34 +01:00
**You may be running inside a Codeman-managed tmux session.** Before killing ANY tmux or Claude process:
2026-01-21 04:44:19 +01:00
2026-02-28 01:35:37 +01:00
1. Check: `echo $CODEMAN_MUX` - if `1` , you're in a managed session
2026-02-12 14:41:27 +01:00
2. **NEVER** run `tmux kill-session` , `pkill tmux` , or `pkill claude` without confirming
2026-02-12 10:29:57 +01:00
3. Use the web UI or `./scripts/tmux-manager.sh` instead of direct kill commands
2026-01-21 04:44:19 +01:00
2026-02-15 06:02:19 +01:00
## CRITICAL: Always Test Before Deploying
**NEVER COM without verifying your changes actually work.** For every fix:
1. **Backend changes** : Hit the API endpoint with `curl` and verify the response
2. **Frontend changes** : Use Playwright to load the page and assert the UI renders correctly. Use `waitUntil: 'domcontentloaded'` (not `networkidle` — SSE keeps the connection open). Wait 3-4s for polling/async data to populate, then check element visibility, text content, and CSS values
3. **Only after verification passes** , proceed with COM
2026-03-01 14:50:17 +01:00
The production server caches static files for 1 year (`maxAge: '1y'` in `server.ts` ). After deploying frontend changes, users may need a hard refresh (Ctrl+Shift+R) to see updates.
2026-02-15 06:02:19 +01:00
2026-01-27 23:15:25 +01:00
## COM Shorthand (Deployment)
2026-01-25 18:09:25 +01:00
2026-02-27 10:58:10 +01:00
Uses [Semantic Versioning ](https://semver.org/ ) (`MAJOR.MINOR.PATCH` ) via `@changesets/cli` .
2026-01-26 21:27:08 +01:00
2026-02-27 10:58:10 +01:00
When user says "COM":
1. **Determine bump type** : `COM` = patch (default), `COM minor` = minor, `COM major` = major
2. **Create a changeset file** (no interactive prompts). Write a `.md` file in `.changeset/` with a random filename:
```bash
cat > .changeset/$(openssl rand -hex 4).md << 'CHANGESET'
---
2026-02-28 02:28:31 +01:00
"aicodeman": patch
2026-02-27 10:58:10 +01:00
---
2026-03-11 19:13:49 +01:00
Detailed description of ALL changes since last release (not just the most recent commit — review full git log since last version tag)
2026-02-27 10:58:10 +01:00
CHANGESET
` ``
Replace ` patch` with ` minor` or ` major` as needed. Include ` "xterm-zerolag-input": patch` on a separate line if that package changed too.
3. **Consume the changeset**: ` npm run version-packages` (bumps versions in ` package.json` files and updates ` CHANGELOG.md`)
4. **Sync CLAUDE.md version**: Update the ` **Version**` line below to match the new version from ` package.json`
5. **Commit and deploy**: ` git add -A && git commit -m "chore: version packages" && git push && npm run build && systemctl --user restart codeman-web`
2026-03-25 00:18:14 +01:00
**Version**: 0.5.2 (must match ` package.json`)
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-02-26 16:44:34 +01:00
Codeman is a Claude Code session manager with web interface and autonomous Ralph Loop. Spawns Claude CLI via PTY, streams via SSE, supports respawn cycling for 24+ hour autonomous runs.
2026-01-18 04:50:46 +01:00
2026-02-27 00:34:38 +01:00
**Tech Stack**: TypeScript (ES2022/NodeNext, strict mode), Node.js, Fastify, node-pty, xterm.js. Supports both Claude Code and OpenCode AI CLIs via pluggable CLI resolvers.
2026-01-28 00:45:37 +01:00
2026-03-01 14:50:17 +01:00
**TypeScript Strictness** (see ` tsconfig.json`): ` noUnusedLocals`, ` noUnusedParameters`, ` noImplicitReturns`, ` noImplicitOverride`, ` noFallthroughCasesInSwitch`, ` allowUnreachableCode: false`, ` allowUnusedLabels: false`.
2026-01-27 00:41:00 +01:00
2026-02-12 14:41:27 +01:00
**Requirements**: Node.js 18+, Claude CLI, tmux
2026-01-20 08:56:15 +01:00
2026-03-03 22:40:18 +01:00
**Git**: Main branch is ` master`. SSH session chooser: ` sc` (interactive), ` sc 2` (quick attach), ` sc -l` (list).
2026-01-18 05:17:06 +01:00
2026-03-03 22:40:18 +01:00
## Additional Commands
2026-01-25 04:57:09 +01:00
2026-03-03 22:40:18 +01:00
` npm run dev` = dev server. Default port: ` 3000`. Commands not in Quick Reference:
2026-01-29 16:13:18 +01:00
2026-03-03 22:40:18 +01:00
| Task | Command |
|------|---------|
| Dev with TLS | ` npx tsx src/index.ts web --https` |
| Continuous typecheck | ` tsc --noEmit --watch` |
| Test coverage | ` npm run test:coverage` |
| Production start | ` npm run start` |
| Production logs | ` journalctl --user -u codeman-web -f` |
2026-01-30 17:20:53 +01:00
2026-03-03 22:40:18 +01:00
**CI**: ` .github/workflows/ci.yml` runs ` typecheck`, ` lint`, ` format:check` on push to master (Node 22). Tests excluded (they spawn tmux).
2026-01-18 05:17:06 +01:00
2026-03-07 07:00:18 +01:00
**Code style**: Prettier (` singleQuote: true`, ` printWidth: 120`, ` trailingComma: "es5"`). ESLint flat config (` eslint.config.js`) allows ` no-console`, warns on ` @typescript -eslint/no-explicit-any`. Ignores: ` app.js`, ` scripts/**/*.mjs`, ` src/web/public/vendor/**`, ` tools/**`, ` remotion/**`.
2026-02-28 01:35:37 +01:00
2026-01-31 23:52:44 +01:00
## Common Gotchas
2026-03-03 22:56:40 +01:00
- **Single-line prompts only** — ` writeViaMux()` sends text+Enter separately; multi-line breaks Ink
- **ESM only** — Never ` require()`, use ` await import()`. ` tsx` masks CJS/ESM issues in dev but production breaks
- **Package ≠ product name** — npm: ` aicodeman`, product: **Codeman**. Release renames tags accordingly
- **Global regex ` lastIndex`** — Use ` createAnsiPatternFull/Simple()` factories, not shared ` g`-flag patterns in loops
2026-01-31 23:52:44 +01:00
2026-03-03 22:56:40 +01:00
**Import conventions**: Utils from ` ./utils`, types from ` ./types` (barrel), config from specific ` ./config/*` files.
2026-01-31 23:52:44 +01:00
2026-01-18 07:31:19 +01:00
## Architecture
2026-01-18 05:17:06 +01:00
2026-03-03 22:40:18 +01:00
### Core Files (by domain)
2026-01-19 16:45:32 +01:00
2026-03-03 22:40:18 +01:00
| Domain | Key files | Notes |
|--------|-----------|-------|
2026-03-03 22:56:40 +01:00
| **Entry** | ` src/index.ts`, ` src/cli.ts` | |
2026-03-07 07:33:44 +01:00
| **Session** | ` src/session.ts` ★, ` src/session-manager.ts`, ` src/session-auto-ops.ts`, ` src/session-cli-builder.ts`, ` src/session-lifecycle-log.ts`, ` src/session-task-cache.ts` | |
2026-03-03 22:56:40 +01:00
| **Mux** | ` src/mux-interface.ts`, ` src/mux-factory.ts`, ` src/tmux-manager.ts` | |
| **Respawn** | ` src/respawn-controller.ts` ★ + 4 helpers (` -adaptive-timing`, ` -health`, ` -metrics`, ` -patterns`) | Read ` docs/respawn-state-machine.md` first |
| **Ralph** | ` src/ralph-tracker.ts` ★, ` src/ralph-loop.ts` + 5 helpers (` -config`, ` -fix-plan-watcher`, ` -plan-tracker`, ` -stall-detector`, ` -status-parser`) | Read ` docs/ralph-wiggum-guide.md` first |
2026-03-22 01:57:17 +01:00
| **Orchestrator** | ` src/orchestrator-loop.ts`, ` src/orchestrator-planner.ts`, ` src/orchestrator-verifier.ts` | Read ` docs/orchestrator-loop-architecture.md` first |
2026-03-03 22:56:40 +01:00
| **Agents** | ` src/subagent-watcher.ts` ★, ` src/team-watcher.ts`, ` src/bash-tool-parser.ts`, ` src/transcript-watcher.ts` | |
| **AI** | ` src/ai-checker-base.ts`, ` src/ai-idle-checker.ts`, ` src/ai-plan-checker.ts` | |
| **Tasks** | ` src/task.ts`, ` src/task-queue.ts`, ` src/task-tracker.ts` | |
| **State** | ` src/state-store.ts`, ` src/run-summary.ts`, ` src/session-lifecycle-log.ts` | |
| **Infra** | ` src/hooks-config.ts`, ` src/push-store.ts`, ` src/tunnel-manager.ts`, ` src/image-watcher.ts`, ` src/file-stream-manager.ts` | |
| **Plan** | ` src/plan-orchestrator.ts`, ` src/prompts/*.ts`, ` src/templates/claude-md.ts` | |
2026-03-22 03:38:14 +01:00
| **Web** | ` src/web/server.ts`, ` src/web/sse-events.ts`, ` src/web/routes/*.ts` (14 route modules + barrel), ` src/web/route-helpers.ts`, ` src/web/ports/*.ts`, ` src/web/middleware/auth.ts`, ` src/web/schemas.ts` | |
2026-03-22 01:57:17 +01:00
| **Frontend** | ` src/web/public/app.js` (~2.6K lines, core) + 5 infra modules (` constants.js`, ` mobile-handlers.js`, ` voice-input.js`, ` notification-manager.js`, ` keyboard-accessory.js`) + 7 domain modules (` terminal-ui.js`, ` respawn-ui.js`, ` ralph-panel.js`, ` orchestrator-panel.js`, ` settings-ui.js`, ` panels-ui.js`, ` session-ui.js`) + 4 feature modules (` ralph-wizard.js`, ` api-client.js`, ` subagent-windows.js`, ` input-cjk.js`) + ` sw.js` | |
2026-03-22 23:55:39 +01:00
| **Types** | ` src/types/index.ts` → 14 domain files | See ` @fileoverview ` in index.ts |
2026-01-19 19:56:37 +01:00
2026-03-03 22:56:40 +01:00
★ = Large file (>50KB). All files have ` @fileoverview ` JSDoc — read that before diving in.
2026-02-02 04:49:15 +01:00
2026-03-03 22:56:40 +01:00
**Local package**: ` packages/xterm-zerolag-input/` — local echo overlay for xterm.js; copy embedded in ` app.js`.
2026-02-26 16:04:00 +01:00
2026-03-03 22:56:40 +01:00
**Config**: ` src/config/` — 9 files. Import from specific files, not barrel.
2026-02-26 16:04:00 +01:00
2026-03-22 23:55:39 +01:00
**Utilities**: ` src/utils/` — re-exported via index. Key: ` CleanupManager`, ` LRUMap`, ` StaleExpirationMap`, ` BufferAccumulator`, ` stripAnsi`, ` Debouncer`, ` KeyedDebouncer`. Also: ` claude-cli-resolver`/` opencode-cli-resolver` (CLI path resolution), ` string-similarity` (fuzzy matching), ` regex-patterns` (ANSI/token/spinner patterns), ` assertNever` (exhaustive checks), ` token-validation` (auth tokens), ` nice-wrapper` (process priority).
2026-02-28 01:35:37 +01:00
2026-01-18 07:38:19 +01:00
### Data Flow
2026-01-27 23:15:25 +01:00
1. Session spawns ` claude --dangerously-skip-permissions` via node-pty
2. PTY output buffered, ANSI stripped, parsed for JSON messages
3. WebServer broadcasts to SSE clients at ` /api/events`
2026-02-26 16:44:34 +01:00
4. State persists to ` ~/.codeman/state.json` via StateStore
2026-01-18 07:31:19 +01:00
2026-01-27 23:15:25 +01:00
### Key Patterns
2026-01-19 18:34:43 +01:00
2026-03-03 22:40:18 +01:00
**Input**: ` session.writeViaMux()` for programmatic input — tmux ` send-keys -l` (literal) + ` send-keys Enter`. Single-line only.
2026-01-19 18:34:43 +01:00
2026-01-27 23:15:25 +01:00
**Idle detection**: Multi-layer (completion message → AI check → output silence → token stability). See ` docs/respawn-state-machine.md`.
2026-01-22 21:36:43 +01:00
2026-03-03 22:40:18 +01:00
**Hook events**: Claude Code hooks trigger via ` /api/hook-event`. Key events: ` permission_prompt`, ` elicitation_dialog`, ` idle_prompt`, ` stop`, ` teammate_idle`, ` task_completed`. See ` src/hooks-config.ts`.
2026-01-23 10:20:37 +01:00
2026-03-03 22:40:18 +01:00
**Agent Teams**: ` TeamWatcher` polls ` ~/.claude/teams/`, matches to sessions via ` leadSessionId`. Teammates are in-process threads appearing as subagents. Enable: ` CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1`. See ` agent-teams/`.
2026-01-23 10:20:37 +01:00
2026-03-03 22:40:18 +01:00
**Circuit breaker**: Prevents respawn thrashing. States: ` CLOSED` → ` HALF_OPEN` → ` OPEN`. Reset: ` /api/sessions/:id/ralph-circuit-breaker/reset`.
2026-02-27 08:28:30 +01:00
2026-03-03 22:40:18 +01:00
**Port interfaces**: Routes declare dependencies via port interfaces (` src/web/ports/`). Routes use intersection types (e.g., ` SessionPort & EventPort`).
2026-02-12 10:29:57 +01:00
2026-03-03 22:40:18 +01:00
### Frontend
2026-02-19 08:49:36 +01:00
2026-03-22 01:57:17 +01:00
Frontend JS modules have ` @fileoverview ` with ` @dependency `/` @loadorder ` tags. Load order: ` constants.js`(1) → ` mobile-handlers.js`(2) → ` voice-input.js`(3) → ` notification-manager.js`(4) → ` keyboard-accessory.js`(5) → ` input-cjk.js`(5.5) → ` app.js`(6) → ` terminal-ui.js`(7) → ` respawn-ui.js`(8) → ` ralph-panel.js`(9) → ` orchestrator-panel.js`(9.5) → ` settings-ui.js`(10) → ` panels-ui.js`(11) → ` session-ui.js`(12) → ` ralph-wizard.js`(13) → ` api-client.js`(14) → ` subagent-windows.js`(15). ` input-cjk.js` handles CJK IME composition via an always-visible textarea below the terminal (` window.cjkActive` blocks xterm's onData).
2026-02-19 08:49:36 +01:00
**Z-index layers**: subagent windows (1000), plan agents (1100), log viewers (2000), image popups (3000), local echo overlay (7).
2026-03-03 22:40:18 +01:00
**Respawn presets**: ` solo-work` (3s/60min), ` subagent-workflow` (45s/240min), ` team-lead` (90s/480min), ` ralph-todo` (8s/480min), ` overnight-autonomous` (10s/480min).
2026-02-19 08:49:36 +01:00
2026-03-03 22:40:18 +01:00
**Keyboard shortcuts**: Escape (close), Ctrl+? (help), Ctrl+Enter (quick start), Ctrl+W (kill), Ctrl+Tab (next), Ctrl+K (kill all), Ctrl+L (clear), Ctrl+Shift+R (restore size), Ctrl/Cmd +/- (font).
2026-02-19 08:49:36 +01:00
### Security
2026-03-03 22:40:18 +01:00
| Layer | Details |
|-------|---------|
| **Auth** | Optional HTTP Basic via ` CODEMAN_USERNAME`/` CODEMAN_PASSWORD` env vars |
| **QR Auth** | Single-use 6-char tokens (60s TTL) for tunnel login. See ` docs/qr-auth-plan.md` |
| **Sessions** | 24h cookie (` codeman_session`), auto-extend, device context audit |
| **Rate limit** | 10 failed auth/IP → 429 (15min decay). QR has separate limiter |
| **Hook bypass** | ` /api/hook-event` exempt from auth (localhost-only, schema-validated) |
| **Env vars** | ` CODEMAN_MUX` (managed session), ` CODEMAN_API_URL` (auto-set for hooks) |
| **Validation** | Zod schemas, path allowlist regex, ` CLAUDE_CODE_*` env prefix allowlist |
| **Headers** | CORS localhost-only, CSP, X-Frame-Options, HSTS if HTTPS |
2026-02-19 08:49:36 +01:00
2026-03-03 22:40:18 +01:00
### SSE Event Registry
2026-02-19 08:49:36 +01:00
2026-03-15 03:47:18 +01:00
~106 event types in ` src/web/sse-events.ts` (backend) and ` SSE_EVENTS` in ` constants.js` (frontend). Both must be kept in sync.
2026-02-19 08:49:36 +01:00
2026-03-03 22:56:40 +01:00
### API Routes
2026-02-19 08:49:36 +01:00
2026-03-22 01:57:17 +01:00
~124 handlers across 14 route files in ` src/web/routes/`: system (36), sessions (25), orchestrator (10), ralph (9), plan (8), respawn (7), cases (7), files (5), mux (5), scheduled (4), push (4), teams (2), hooks (1), ws (1 WebSocket). Each file has ` @fileoverview ` with endpoint details.
2026-02-19 08:49:36 +01:00
2026-01-27 23:15:25 +01:00
## Adding Features
2026-01-19 13:41:27 +01:00
2026-03-03 22:40:18 +01:00
- **API endpoint**: Types in ` src/types/` domain file, route in ` src/web/routes/*-routes.ts`, use ` createErrorResponse()`. Validate with Zod schemas in ` schemas.ts`.
- **SSE event**: Add to ` src/web/sse-events.ts` + ` SSE_EVENTS` in ` constants.js`, emit via ` broadcast()`, handle in ` app.js` (` addListener(`)
- **Session setting**: Add to ` SessionState`, include in ` session.toState()`, call ` persistSessionState()`
- **Hook event**: Add to ` HookEventType`, add hook in ` hooks-config.ts:generateHooksConfig()`, update ` HookEventSchema`
- **Mobile feature**: Add to relevant singleton, guard with ` MobileDetection.isMobile()`
2026-03-07 07:00:18 +01:00
- **New test**: Pick unique port (search ` const PORT =`). Route tests use ` app.inject()` (no port needed) — see ` test/routes/_route-test-utils.ts`.
2026-01-21 09:54:42 +01:00
2026-03-03 22:40:18 +01:00
**Validation**: Zod v4 (different API from v3). Define schemas in ` schemas.ts`, use ` .parse()`/` .safeParse()`.
2026-01-30 17:20:53 +01:00
2026-01-20 08:56:15 +01:00
## State Files
2026-03-03 22:56:40 +01:00
All in ` ~/.codeman/`: ` state.json` (sessions, settings, respawn), ` mux-sessions.json` (tmux recovery), ` settings.json` (user prefs), ` push-keys.json` (VAPID), ` push-subscriptions.json`, ` session-lifecycle.jsonl` (audit log).
2026-01-30 17:20:53 +01:00
2026-01-27 23:15:25 +01:00
## Testing
2026-01-20 08:56:15 +01:00
2026-03-03 22:40:18 +01:00
**CRITICAL: You are running inside a Codeman-managed tmux session.** Never run ` npx vitest run` (full suite) — it spawns/kills tmux sessions and will crash your own session. Only run individual files:
2026-01-21 19:49:44 +01:00
2026-02-13 08:04:20 +01:00
` ``bash
2026-03-03 22:40:18 +01:00
npx vitest run test/<specific-file>.test.ts # Single file (SAFE)
npx vitest run -t "pattern" # By name (SAFE)
# npx vitest run # DANGEROUS — DON'T DO THIS
2026-02-13 08:04:20 +01:00
` ``
2026-03-03 22:40:18 +01:00
**Config**: Vitest with ` globals: true`, ` fileParallelism: false`. Timeout 30s, teardown 60s.
2026-02-13 08:04:20 +01:00
2026-03-03 22:40:18 +01:00
**Safety**: ` test/setup.ts` snapshots pre-existing tmux sessions and never kills them. Only ` registerTestTmuxSession()` sessions get cleaned up.
2026-01-22 22:43:09 +01:00
2026-03-03 22:40:18 +01:00
**Ports**: Pick unique ports manually. Search ` const PORT =` before adding new tests.
2026-01-21 19:49:44 +01:00
2026-03-03 22:40:18 +01:00
**Respawn tests**: Use ` MockSession` from ` test/respawn-test-utils.ts`. **Route tests**: ` app.inject()` in ` test/routes/`. **Mobile tests**: Playwright suite in ` mobile-test/` (135 device profiles).
2026-01-21 04:27:09 +01:00
2026-03-03 22:40:18 +01:00
## Screenshots
2026-02-19 14:52:39 +01:00
2026-03-03 22:56:40 +01:00
Mobile screenshots in ` ~/.codeman/screenshots/`. API: ` GET /api/screenshots`, ` POST /api/screenshots`.
2026-02-16 12:10:44 +01:00
2026-03-03 22:56:40 +01:00
## Debugging
2026-02-16 12:10:44 +01:00
` ``bash
2026-03-03 22:40:18 +01:00
tmux list-sessions # List tmux sessions
curl localhost:3000/api/sessions | jq # Check sessions
curl localhost:3000/api/status | jq # Full app state
curl localhost:3000/api/subagents | jq # Background agents
cat ~/.codeman/state.json | jq # Persisted state
2026-01-20 08:56:15 +01:00
` ``
2026-03-03 22:56:40 +01:00
## Performance & Limits
2026-02-04 07:24:32 +01:00
2026-03-03 22:56:40 +01:00
Target: 20 sessions, 50 agent windows at 60fps. Limits in ` src/config/`: terminal 2MB, text 1MB, messages 1000, max agents 500, max sessions 50, max SSE clients 100. Use ` LRUMap` for bounded caches, ` StaleExpirationMap` for TTL cleanup. Anti-flicker pipeline: ` docs/terminal-anti-flicker.md`.
2026-02-02 04:49:15 +01:00
2026-03-03 22:40:18 +01:00
## References
2026-01-27 18:16:19 +01:00
2026-03-22 03:38:14 +01:00
Deep-dive docs in ` docs/`: ` respawn-state-machine.md`, ` ralph-wiggum-guide.md`, ` claude-code-hooks-reference.md`, ` terminal-anti-flicker.md`, ` opencode-integration.md`, ` qr-auth-plan.md`, ` orchestrator-loop-architecture.md`, ` browser-testing-guide.md`. Agent Teams: ` agent-teams/README.md`. SSE events: ` src/web/sse-events.ts` + ` constants.js`.
2026-01-28 04:04:40 +01:00
2026-01-29 12:59:42 +01:00
## Scripts
2026-01-28 07:07:18 +01:00
2026-03-03 22:56:40 +01:00
Key: ` scripts/tmux-manager.sh` (safe tmux mgmt), ` scripts/tunnel.sh` (tunnel start/stop/url). Production: ` scripts/codeman-web.service`, ` scripts/codeman-tunnel.service`.
2026-01-28 07:07:18 +01:00
2026-01-30 17:20:53 +01:00
## Memory Leak Prevention
2026-01-30 11:30:51 +01:00
2026-03-03 22:56:40 +01:00
24+ hour sessions: use ` CleanupManager`, clear Maps in ` stop()`, guard async with ` if (this.cleanup.isStopped) return`. Frontend: store handler refs, clean in ` close*()`. Verify: ` npx vitest run test/memory-leak-prevention.test.ts`.
2026-01-31 14:32:20 +01:00
## Common Workflows
2026-03-03 22:56:40 +01:00
**Bug investigation**: Dev server → reproduce in browser → check terminal + ` ~/.codeman/state.json`.
**Respawn changes**: Read ` docs/respawn-state-machine.md` first. Use ` MockSession` from ` test/respawn-test-utils.ts`.
2026-01-31 14:32:20 +01:00
2026-03-03 22:56:40 +01:00
## Tunnel
2026-01-31 14:32:20 +01:00
2026-03-03 22:56:40 +01:00
` ./scripts/tunnel.sh start|stop|url`. **Always set ` CODEMAN_PASSWORD`** before exposing via tunnel.