Repository navigation
Features Plugins
Write a plugin that adds UI to Kanna and runs its own server-side process, then install, reload and debug it from the CLI or from a chat.
A Kanna plugin adds UI to Kanna itself: a page in the sidebar, a panel in the
chat footer, an entry in the / picker. Its server half runs in its own
process and talks to Kanna over typed RPC, so a misbehaving plugin cannot take
the server down with it.
This is not the same thing as a Claude Code or Codex plugin. Those add skills and commands to the agent and are managed under Settings → Plugins; see Package auto-update.
Plugins are off by default. While they are off, every plugin route, tool and
UI surface stays dark. Turn them on in ~/.kanna/data/settings.json:
{
"plugins": { "enabled": true }
}A Settings → Kanna plugins page then appears, listing what is installed.
A plugin is a directory with a manifest and an entry file. Ask the agent to
scaffold one (plugin_scaffold), or write the three files yourself:
{
"id": "hello",
"name": "Hello",
"version": "0.1.0",
"kannaPluginApi": 1
}import type { PluginContext } from "@kanna/plugin"
import { Panel } from "./panel.client"
export default function contribute(plugin: PluginContext) {
plugin.addSurface("main", Panel)
plugin.addSidebarItem({ id: "main", title: "Hello", icon: "Blocks", surface: "main" })
plugin.addCommandCenterItem({
name: "greet",
description: "Say hello",
prompt: "Say hello to the team in one sentence.",
})
return () => {}
}import type { PluginSurfaceProps } from "@kanna/plugin"
export function Panel({ theme }: PluginSurfaceProps) {
return <div style={{ color: theme.colors.foreground }}>Hello is running.</div>
}The id is lowercase letters, digits and hyphens, starts with a letter, and
kanna is reserved. entry in the manifest defaults to index.ts.
What a plugin can contribute:
| Call | Adds |
|---|---|
addSurface(id, Component) |
A React component, shown as a panel in the chat footer |
addSidebarItem({ id, title, icon, surface }) |
A sidebar entry that opens one of your surfaces as a page |
addCommandCenterItem({ name, description, prompt }) |
A / picker entry, listed as <pluginId>:<name>
|
handle(contract, handler) |
A server-side RPC handler, with defineRpc from @kanna/plugin/server
|
Selecting a plugin's / entry inserts its prompt text into the composer, so it
works on every provider. A plugin can add picker entries but never replace one:
if the name is already taken, the plugin's entry is dropped.
Kanna compiles the directory into a browser bundle and a server bundle, stores
them under ~/.kanna/plugins/<id>/, and remembers the install across restarts.
kanna plugin install ./my-plugin # compile and install from a directory
kanna plugin ls # list installed plugins and their state
kanna plugin reload hello # restart it, picking up a rebuilt bundle
kanna plugin logs hello --tail 50 # the plugin's most recent log linesThe agent has the same verbs as tools (plugin_scaffold, plugin_validate,
plugin_install, plugin_list, plugin_reload, plugin_logs), so you can ask a
chat to build and iterate on a plugin for you.
Each compile runs in a separate process with a 20-second deadline. A build that hangs fails cleanly instead of freezing Kanna.
This wiki is generated from wiki/src/content/docs in cuongtranba/kanna.
Edit the docs there: changes made on this wiki are overwritten on the next sync.
The same docs are published at https://kanna-wiki.lowbit.link.
Getting Started
Features
- Providers & Models
- Chat & Transcript
- Generative UI
- Projects & Sessions
- Boards
- Multi-repo Stacks
- Slash Commands
- Cron Jobs
- Loops
- Beacons
- Kanna Plugins
- Package Auto-Update
- Advanced
- Security
Guides
- User Guide
- Contributing
- Ops & Self-Host
Sharing
Reference