The browser UI is a single Rust binary (catcode-web, crate web/) plus a Leptos CSR WASM render surface (web/frontend). The hub is a thin HTTP + WebSocket shell around catcode-core. It never runs an agent loop.
- URL:
http://127.0.0.1:49283/(default). Bind with--host/--portorHOST/PORT. - UI: Leptos 0.8 CSR. Build with
./scripts/build-web-frontend.sh. The hub servesfrontend/distat runtime. - One WebSocket (
GET /ws) fans in every live core. Closing the browser never kills a mid-turn session.
| Feature | How |
|---|---|
| Project switching | Names in the left rail. Ctrl/Cmd+1..9 jumps. Closing a project leaves cores and session files alone. |
| Add projects | Browse home + registered folders, create a directory, or git clone. Registration in projects.json is the capability grant. |
| Git panel | Read-only snapshot in the inspect drawer (⌘I). Closed by default. |
| Multi-session chat | One catcode-core per session .jsonl. New / switch from the left rail (⌘B collapses it). Conversation is the page. |
| Live feed | GET /ws hydrates with a server snapshot then streams raw core events. Reconnect always re-attaches and replaces the snapshot. The WASM client applies the same reduce.rs as the server. |
| Cross-device | hub-layout.json stores open project chips + last session per project. Any signed-in device reopens the same chats and reattaches live cores. |
| Cross-session status | session_status broadcasts streaming / needs attention / viewers. Notification center + project badges. |
| Account | First-run setup, devices, Sign out (this device only). Signing out never tears down live cores. |
| Sheets | Command palette, settings (General/Models/Skills/Plugins/MCP), devices, account, login, models, goal, help, shortcuts, folder picker, confirm, and HITL all use the foundry sheet in app.css. |
| TUI parity | Every TUI slash that is not terminal chrome (/exit, /mouse-wheel, /footer-metrics) has a hub surface: usage/stats/context/status/tree/jobs/checkpoints/browser/sandbox/vision/memory drawers, search keys, vision config, steer/compact/run/parallel/chain prompts, find, copy last reply, goal plan review, plugin install scope, and next-session launch knobs (no-network, idle timeout, max tokens). |
| Session maintenance | Archive/restore, fork, export/import, and edit-from-here (session_branch). Worktrees switch from Inspect → Repo. |
Chat sessions are owned by the server Bridge pool — not by the browser connection:
- Close the tab: WS subscribers detach; live cores keep running (idle GC only after 2h with no viewers and no mid-turn work).
- Sign out: revokes this device cookie only. Sign back in (any device) restores tabs + last-viewed session paths and reattaches still-running cores.
- Another device: same layout + same session files → same live feed. No "restart the chat" step.
- The ONLY paths that end a core: idle GC, explicit session delete, or a hub-process exit (on-disk JSONL still resumes).
web/src/main.rs CLI: --host --port --origin --core
web/src/hub.rs axum router + one WebSocket
web/src/bridge.rs pool keyed by abs session path, GC, snapshots
web/src/core_proc.rs spawn core, JSONL stdin/stdout
web/src/reduce.rs Event → AgentState (shared with WASM)
web/frontend/ Leptos CSR app (signals + same reducer)
web/assets/app.css foundry tokens + responsive chrome
Session files live under ~/.config/catalyst-code/sessions/<project-hash>/ (same layout as the TUI). The hub spawns catcode-core with --session pointing at those files so web and TUI share history.
Mobile < 840px: rail and inspect become drawers. Composer stays sticky.
cargo test --manifest-path web/Cargo.toml
cargo test --manifest-path web/frontend/Cargo.toml --lib
./scripts/build-web-frontend.sh
(cd web/e2e && npm test)