codehelm — lokalny command center dla Claude Code
Date Published

Claude Code zapisuje każdą sesję jako append-only JSONL w ~/.claude/projects/<slug>/<sessionId>.jsonl. Brzmi niewinnie. Po miesiącu intensywnego użycia masz pięćdziesiąt projektów, setki sesji i 800 MB plików, których nigdy nie otworzysz ręcznie. Znalezienie "tej jednej sesji, w której debugowałem race'a w PTY"? grep -r przez całe drzewo katalogów.
CLI jest świetny przy jednej sesji. Przestaje być świetny przy dwudziestu.
Stąd codehelm. Jedno okno Chromium, wszystkie projekty, wszystkie sesje, prawdziwy shell w każdej zakładce. Lokalnie, bez chmury, bez dodatkowych kosztów API.
Co jest w środku
Stack jest świeży i bez fajerwerków. Next.js 15 (App Router), custom server.ts zamiast next start, node-pty dla terminali, chokidar do watchowania JSONL-i, xterm.js w przeglądarce, CodeMirror 6 do edycji CLAUDE.md. Całość binduje się na 127.0.0.1, losowy port z zakresu 49152–65535.
Główne widoki:
- Sidebar z auto-discovery projektów, aliasami, favorites, grupowaniem po prefiksie ścieżki.
- Session explorer: preview, rozmiar, liczba wiadomości, estymata kosztu per sesja.
- Viewer ze streamingiem JSONL przez virtuoso, 9 typów eventów, diff rendering dla
Edit/Write, outline i minimapa. - Terminal z limitem 16 PTY, persystentnych między reloadami, z badgem git brancha i quick-actions row.
- Editor do
CLAUDE.mdz atomowym zapisem i diff-before-save. - Command palette pod
Ctrl+Ki overlay skrótów pod?.
Ostatni kwartał dołożył scheduled prompts. Cron, który pisze prompt do długo żyjącej zakładki Claude Code bezpośrednio w PTY, tak jakbyś sam wcisnął Enter. Scheduler (croner) tyka, hybrid ready-check patrzy czy Claude wygląda na idle (marker regex na ring bufferze albo > 3 s od ostatniego stdoutu), executor bierze per-tab mutex i wpisuje ESC[200~ <prompt> ESC[201~ \r. Bracketed paste, żeby multiline prompt nie rozpadł się na osobne Entery.
Security model, bo inaczej się nie da
Ta aplikacja odpala shell z pełnymi uprawnieniami usera. Jak ktoś dojdzie do socketu, ma twoje pudełko. Co z tym robić? Defense-in-depth jako konieczność, nie buzzword:
- Reachability —
127.0.0.1only, losowy port, 32-bajtowy token zcrypto.randomBytes, rotowany przy każdym starcie. - Auth — HttpOnly cookie, CSRF double-submit,
timingSafeEqualwszędzie. - Host allowlist — tylko
127.0.0.1:PORTilocalhost:PORT. Zabija DNS rebinding nawet jeśli cookie wycieknie. - CSP — per-request nonce,
strict-dynamic, zerounsafe-inlinew produkcji. - Path guard —
fs.realpath+ prefix equality, fuzz-testowany 100 payloadami. - PTY — cap 16, rate limit 10/min, backpressure po 1 MB unacked.
- Audit log — whitelist pól,
mode 0600, nigdy content, nigdy token.
564 unit + integration testów, 7 specyfikacji e2e, pnpm audit --prod --audit-level=high zwraca zero.
Czego to nie robi
Terminal pozostaje jedyną powierzchnią, która gada z Claude. Cron wpisuje tekst do istniejącego PTY, jakby user wcisnął Enter, i tyle. Nie parsuje odpowiedzi, nie chainuje jobów, nie próbuje być nowym chat UI. Co tu dużo mówić, CLI zostaje źródłem prawdy.
Gdzie to jest
→ github.com/bartek-filipiuk/codehelm
Jedna instancja na hoście, jeden user, zaufana maszyna. 127.0.0.1 to granica zaufania. Potrzebujesz remote access? Tailscale przed tym albo wcale.