kanna-code
v0.18.0
Published
A beautiful web UI for Claude Code
Downloads
4,288
Maintainers
Readme
Quickstart
bun install -g kanna-codeIf Bun isn't installed, install it first:
curl -fsSL https://bun.sh/install | bashThen run from any project directory:
kannaThat's it. Kanna opens in your browser at localhost:3210.
Features
- Multi-provider support — switch between Claude and Codex (OpenAI) from the chat input, with per-provider model selection, reasoning effort controls, and Codex fast mode
- Project-first sidebar — chats grouped under projects, with live status indicators (idle, running, waiting, failed)
- Drag-and-drop project ordering — reorder project groups in the sidebar with persistent ordering
- Local project discovery — auto-discovers projects from both Claude and Codex local history
- Rich transcript rendering — hydrated tool calls, collapsible tool groups, plan mode dialogs, and interactive prompts with full result display
- Quick responses — lightweight structured queries (e.g. title generation) via Haiku with automatic Codex fallback
- Plan mode — review and approve agent plans before execution
- Persistent local history — refresh-safe routes backed by JSONL event logs and compacted snapshots
- Auto-generated titles — chat titles generated in the background via Claude Haiku
- Session resumption — resume agent sessions with full context preservation
- WebSocket-driven — real-time subscription model with reactive state broadcasting
Architecture
Browser (React + Zustand)
↕ WebSocket
Bun Server (HTTP + WS)
├── WSRouter ─── subscription & command routing
├── AgentCoordinator ─── multi-provider turn management
├── ProviderCatalog ─── provider/model/effort normalization
├── QuickResponseAdapter ─── structured queries with provider fallback
├── EventStore ─── JSONL persistence + snapshot compaction
└── ReadModels ─── derived views (sidebar, chat, projects)
↕ stdio
Claude Agent SDK / Codex App Server (local processes)
↕
Local File System (~/.kanna/data/, project dirs)Key patterns: Event sourcing for all state mutations. CQRS with separate write (event log) and read (derived snapshots) paths. Reactive broadcasting — subscribers get pushed fresh snapshots on every state change. Multi-provider agent coordination with tool gating for user-approval flows. Provider-agnostic transcript hydration for unified rendering.
Requirements
- Bun v1.3.5+
- A working Claude Code environment
- (Optional) Codex CLI for Codex provider support
Embedded terminal support uses Bun's native PTY APIs and currently works on macOS/Linux.
Install
Install Kanna globally:
bun install -g kanna-codeIf Bun isn't installed, install it first:
curl -fsSL https://bun.sh/install | bashOr clone and build from source:
git clone https://github.com/jakemor/kanna.git
cd kanna
bun install
bun run buildUsage
kanna # start with defaults (localhost only)
kanna --port 4000 # custom port
kanna --no-open # don't open browser
kanna --share # create a public share URL + terminal QRDefault URL: http://localhost:3210
Network access (Tailscale / LAN)
By default Kanna binds to 127.0.0.1 (localhost only). Use --host to bind a specific interface, or --remote as a shorthand for 0.0.0.0:
kanna --remote # bind all interfaces — browser opens localhost:3210
kanna --host dev-box # bind to a specific hostname — browser opens http://dev-box:3210
kanna --host 192.168.1.x # bind to a specific LAN IP
kanna --host 100.64.x.x # bind to a specific Tailscale IPWhen --host <hostname> is given, the browser opens http://<hostname>:3210 automatically. Other machines on your network can connect to the same URL:
Public share link
Use --share to create a temporary public trycloudflare.com URL and print a terminal QR code:
kanna --share
kanna --share --port 4000--share is incompatible with --host and --remote. It does not open a browser automatically; instead it prints:
QR Code:
...
Public URL:
https://<random>.trycloudflare.com
Local URL:
http://localhost:3210Development
bun run devThe same --remote and --host flags can be used with bun run dev for remote development.
--share is also supported in dev mode and exposes the Vite client URL publicly:
bun run dev --share
bun run dev --port 3333 --shareIn dev, --port sets the Vite client port and the backend runs on port + 1, so bun run dev --port 3333 --share publishes http://localhost:3333.
--share remains incompatible with --host and --remote.
Use bun run dev --port 4000 to run the Vite client on 4000 and the backend on 4001.
Or run client and server separately:
bun run dev:client # http://localhost:5174
bun run dev:server # http://localhost:5175Scripts
| Command | Description |
| -------------------- | ---------------------------- |
| bun run build | Build for production |
| bun run check | Typecheck + build |
| bun run dev | Run client + server together |
| bun run dev:client | Vite dev server only |
| bun run dev:server | Bun backend only |
| bun run start | Start production server |
Project Structure
src/
├── client/ React UI layer
│ ├── app/ App router, pages, central state hook, socket client
│ ├── components/ Messages, chat chrome, dialogs, buttons, inputs
│ ├── hooks/ Theme, standalone mode detection
│ ├── stores/ Zustand stores (chat input, preferences, project order)
│ └── lib/ Formatters, path utils, transcript parsing
├── server/ Bun backend
│ ├── cli.ts CLI entry point & browser launcher
│ ├── server.ts HTTP/WS server setup & static serving
│ ├── agent.ts AgentCoordinator (multi-provider turn management)
│ ├── codex-app-server.ts Codex App Server JSON-RPC client
│ ├── provider-catalog.ts Provider/model/effort normalization
│ ├── quick-response.ts Structured queries with provider fallback
│ ├── ws-router.ts WebSocket message routing & subscriptions
│ ├── event-store.ts JSONL persistence, replay & compaction
│ ├── discovery.ts Auto-discover projects from Claude and Codex local state
│ ├── read-models.ts Derive view models from event state
│ └── events.ts Event type definitions
└── shared/ Shared between client & server
├── types.ts Core data types, provider catalog, transcript entries
├── tools.ts Tool call normalization and hydration
├── protocol.ts WebSocket message protocol
├── ports.ts Port configuration
└── branding.ts App name, data directory pathsData Storage
All state is stored locally at ~/.kanna/data/:
| File | Purpose |
| ---------------- | ----------------------------------------- |
| projects.jsonl | Project open/remove events |
| chats.jsonl | Chat create/rename/delete events |
| messages.jsonl | Transcript message entries |
| turns.jsonl | Agent turn start/finish/cancel events |
| snapshot.json | Compacted state snapshot for fast startup |
Event logs are append-only JSONL. On startup, Kanna replays the log tail after the last snapshot, then compacts if the logs exceed 2 MB.
