Model or dataset
jakemor/kanna avatar
jakemor/kanna

Kanna: a browser front end for the Claude Code and Codex CLIs

A beautiful web-based UI for Claude Code & Codex

716 stars98 forksTypeScriptNOASSERTION

At a glance

What is it?
Kanna is a Bun and React application that puts a web UI in front of the agent CLIs, connecting to Claude Code, Codex, cursor-agent and others over stdio. It keeps a JSONL event log on disk, and it can be exposed on a LAN or through a Cloudflare tunnel when you want to reach it from a phone.
Who is it for?
Kanna fits someone who drives the Claude Code or Codex CLI from a phone or a second machine, or who wants a project sidebar and readable transcripts instead of a terminal stream, and who is comfortable exposing a local server on a LAN. It does not fit anyone who needs the agent to run on a machine with no browser-reachable host, since the agents are local processes reached over stdio, and it does not fit a team that cannot accept a custom licence review.
Can I use it commercially?
Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
Is it still maintained?
Yes. The repository last received commits 2 days ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Kanna does not replace the agent CLIs, it drives them

Kanna is described as a web UI for the Claude Code and Codex CLIs, and the architecture diagram in the README is the clearest statement of what that means. A browser running React and Zustand talks to a Bun server over a WebSocket. The Bun server, which handles HTTP and WebSockets, talks over stdio to the Claude Agent SDK, the Codex App Server, cursor-agent or the grok CLI, all of which are local processes. Below that sits the local file system, with a data directory at ~/.kanna/data/ and the project directories themselves. So the model provider and the agent loop are still the ones you already use, and Kanna is the presentation and coordination layer in front of them. That is the difference from building your own agent loop, and it also means the quality of the result depends on the CLI you have installed and authenticated.

Install is one command, and Bun is a hard requirement

The quickstart is short because the runtime is a single dependency.

bash
bun install -g kanna-code

If Bun is not on the machine, the README points at the official installer.

bash
curl -fsSL https://bun.sh/install | bash

After that you run the binary from any project directory and it opens in your browser.

bash
kanna

The default URL is http://localhost:3210. The requirements list is explicit: Bun v1.3.5 or newer, a working Claude Code environment, and optionally the Codex CLI if you want the Codex provider. The package manifest confirms the floor, with the packageManager field set to [email protected] and the engines field requiring bun at 1.3.5 or newer. The published binary is registered as kanna pointing at ./bin/kanna, and the package ships the bin directory plus the built server, client and export-viewer output.

Five providers, one chat input

The provider story is the feature that most directly changes daily use. The README lists multi-provider support with switching between Claude, Codex from OpenAI, Cursor, Grok Build and Pi, all from the chat input, with per-provider model selection, reasoning effort controls and a Codex fast mode. The bundled Pi agent is worth a separate note: the pi coding agent ships as a dependency and runs in process through the Model Registry in Settings, so you can point it at OpenRouter, OpenAI or any custom OpenAI-compatible endpoint, pin favourite models to the picker and use any model id with standardized reasoning efforts, with no local pi installation involved. The server side of this is the AgentCoordinator, which handles multi-provider turn management, and the ProviderCatalog, which does provider, model and effort normalization so the front end does not need to know which vendor is behind a given model.

State lives in a JSONL log with compacted snapshots

The key patterns listed in the README are event sourcing for all state mutations, CQRS with separate write and read paths, reactive broadcasting, multi-provider coordination with tool gating for user approval flows, and provider-agnostic transcript hydration. Put plainly, the browser does not hold the authoritative state. Mutations are appended to an event log, and the views are derived from it, with the EventStore handling JSONL persistence and snapshot compaction, and ReadModels producing the derived sidebar, chat and project views. Subscribers then get fresh snapshots pushed on every state change, which is why the interface can survive a refresh: the README describes the routes as refresh-safe and backed by JSONL event logs and compacted snapshots. The React side uses Zustand for that client state.

Localhost by default, with deliberate ways to widen the exposure

Kanna binds to 127.0.0.1 by default, and the flags for going wider are documented carefully. The --host flag binds a specific interface, and --remote is a shorthand for 0.0.0.0. The README gives concrete examples including a Tailscale IP in the 100.64 range, and notes that when --host is given a hostname the browser opens that hostname automatically so other machines on the network can connect. Password protection is a separate concern: with --password the backend requires authentication for API routes and for the /ws endpoint, the password is verified once and then a browser-session cookie is set, and the password itself is not stored in the browser. The SPA shell still loads and /health stays public for restart detection. That last point is a deliberate hole, and it is worth knowing before you put the app on a shared network.

The share flag opens a public Cloudflare tunnel

The --share flag creates a temporary public trycloudflare.com URL and prints a terminal QR code so you can open it on a phone.

bash
kanna --share
kanna --share --port 4000
kanna --cloudflared <token>

With a token, Kanna runs cloudflared tunnel run with the token and the local URL. If it can detect the public hostname from the cloudflared output, it prints the QR code, the public URL and the local URL. If it cannot, it keeps the tunnel running, warns that no public hostname was detected, and prints the local URL so you can use the hostname already configured for that tunnel in Cloudflare. Two restrictions are stated plainly: --share is incompatible with --host and --remote, and it does not open a browser automatically. The point of the QR code is that you can drive the agent from a phone, and that is also the point at which the security trade-off gets real, so pair it with a password rather than running it open.

A fast release cadence and a licence worth reading

The project moves quickly. The version is 0.82.1, with v0.82.0 on 2026-10-07 and v0.81.0 on 2026-10-06, and the last push was on 2026-10-22, so releases land roughly daily at times. The repository is not archived. The package manifest declares the licence as MIT, but GitHub reports the repository licence as a custom one that it cannot classify, so the LICENSE file at the root is the authority and worth reading if you intend to redistribute the application. The repository layout shows a Bun and Vite project with a src directory, a bin directory, a macos directory, several Vite configs including a demo config and an export-viewer config, a Tailwind config, and separate skills and agent directories. The scripts cover building the client, the export viewer and the server separately, plus a check script that type checks and builds every target, a test script running bun test, and a smoke:package script that verifies the published package.

Editorial conclusion

Kanna fits someone who drives the Claude Code or Codex CLI from a phone or a second machine, or who wants a project sidebar and readable transcripts instead of a terminal stream, and who is comfortable exposing a local server on a LAN. It does not fit anyone who needs the agent to run on a machine with no browser-reachable host, since the agents are local processes reached over stdio, and it does not fit a team that cannot accept a custom licence review. Verify first that your provider CLI is installed and working, since Kanna drives the local process rather than replacing it, and read the password and tunnel flags carefully before binding beyond localhost.

Frequently asked questions

How do I install and start Kanna?

Run bun install -g kanna-code, install Bun first with curl -fsSL https://bun.sh/install | bash if needed, then run kanna from any project directory. It opens in your browser at localhost:3210, and requires Bun v1.3.5 or newer plus a working Claude Code environment.

Which agent CLIs can Kanna drive?

The README lists Claude, Codex from OpenAI, Cursor, Grok Build and Pi. The architecture diagram shows the server talking over stdio to the Claude Agent SDK, the Codex App Server, cursor-agent or the grok CLI as local processes, and the pi coding agent ships as a bundled dependency that runs in process.

How does Kanna store chat history?

State is event sourced. The EventStore handles JSONL persistence and snapshot compaction in the local data directory at ~/.kanna/data/, and ReadModels derive the sidebar, chat and project views from that log, with fresh snapshots pushed to subscribers on every change so routes survive a refresh.

Can I protect Kanna with a password and reach it from another device?

Yes. The --password flag makes the backend require authentication for API routes and the websocket, verified once and then held in a browser session cookie, with the health endpoint left public. To reach it from elsewhere you can use --host with a LAN or Tailscale IP, or --share for a temporary public trycloudflare.com URL with a terminal QR code.

Official sources

  1. Issues
  2. jakemor/kanna on GitHub
  3. README
  4. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/jakemor-kanna.svg)](https://hysenlabs.com/projects/jakemor-kanna)

Was this useful?