Project overview
A local-only web UI that puts every Claude Code session and a real shell for each project into one Chromium window — reading the ~/.claude/projects JSONL you already have, spawning live terminals per tab, and never touching the cloud.
The stack, explained
A React framework for building full-stack web apps, with file-based routing, server rendering, and bundling built in. The App Router organises pages, layouts, and API route handlers in one tree.
Here: powers the App Router UI and rides on a custom http.Server for the HTTP path.
A JavaScript library for building user interfaces out of composable components whose output updates as their data changes. It is the rendering layer most of the modern web is built on.
Here: renders the whole interface — sidebar, conversation viewer, and terminal tabs.
A Node.js library that forks a real pseudoterminal (PTY) process, so you can spawn and drive shells exactly as if they were running in a terminal. It is the foundation for terminal emulators built on Node.
Here: forks the real shells behind every terminal tab.
why this choice →A front-end terminal emulator component that lets a web app embed a fully-featured terminal in the browser. It renders terminal output and handles keyboard input for shells and command-line programs.
Here: draws those shells in the browser, addons for fit, WebGL, and links.
A simple, fast WebSocket client and server implementation for Node.js. It keeps an open, two-way connection so a server and browser can exchange messages in real time.
Here: carries PTY bytes and file-watcher events over one authenticated socket.
why this choice →A cross-platform Node.js library for watching files and folders and reacting to add, change, and delete events. Build tools and dev servers use it to trigger work automatically when files change.
Here: watches ~/.claude/projects/ for live session changes.
why this choice →A JavaScript and TypeScript library for scheduling tasks with cron expressions, running a function at set times or intervals. It can also compute when the next run of an expression is due.
Here: fires scheduled prompts into persistent Claude tabs.
why this choice →A small, fast state-management library for React with a simple hook-based API for sharing data across components, without the boilerplate of heavier stores.
Here: holds local UI state — open tabs, panes, and layout.
A library for managing server state — the fetching, caching, synchronising, and updating of data from APIs. It removes much of the manual work of loading remote data and keeping it fresh.
Here: fetches and caches projects and sessions from the REST API.
A React component for rendering very long lists and tables efficiently by drawing only the items currently on screen. It handles items of varying sizes so large datasets scroll smoothly.
Here: virtualises the long conversation and session lists.
why this choice →A TypeScript-first schema validation library that describes the expected shape of data and checks that real values match it. From one schema it also infers the matching static types.
Here: validates every request body and JSONL event shape.
A utility-first CSS framework that styles elements through small, composable classes applied directly in markup, instead of writing separate stylesheets. It keeps styling close to the components.
Here: styles the interface alongside shadcn / Radix primitives.
A syntax highlighter that colours source code using the same TextMate grammars and themes as code editors, producing accurate, editor-quality highlighting for code blocks on the web.
Here: highlights code blocks inside rendered sessions, loaded lazily per language.
Why this stack
node-pty behind client-ACK backpressure
A real shell can out-run the browser, so the PTY is paused at 1 MB unacked and capped at 16 tabs — bounded memory no matter what runs.
full decision in the course → what is node-pty ↑One http.Server for HTTP and raw WebSockets
A single listener means one bind, one Origin check, and one cookie to secure — instead of a second server doubling the attack surface.
full decision in the course → what is ws ↑croner fires prompts only when Claude is idle
A ready-check, a per-tab mutex, and bracketed paste land a scheduled prompt at the input prompt — never in the middle of a streaming response.
full decision in the course → what is croner ↑chokidar watch, not interval polling
An OS-level watch costs nothing until a session file actually changes, then pushes the update over WebSocket — the opposite spend profile from a poll.
full decision in the course → what is chokidar ↑react-virtuoso over render-everything
Virtualising mounts only the rows on screen, so a 2000-message session scrolls above 30 fps instead of freezing the tab on open.
full decision in the course → what is react-virtuoso ↑What it gives you
Glossary
The numbers
DataLines of code, work time across sessions, the language split, and the full file breakdown — the dry numbers behind codehelm.
Why it's built this way
CourseA cinematic "why" course — the architectural decisions, the traps they avoided, and the roads not taken.
Audited & remediated
Securitysecurity audit not run yet