Skip to main content

Chatticus

Panel plugins

The right-hand panel of the workspace is a plugin host. Context, Files and Costs are plugins, and so is anything added later (a Kanbus board, a code editor, a browser). This is the contract those plugins follow. The first draft lived in the project files as panel-plugin-contract.md.

A plugin is a custom element described by a manifest

A manifest (web/lib/panel-plugin-manifest.ts) names the plugin, the custom element tags it defines, the sizes it supports and the object types it handles:

{
  "id": "kanbus",
  "name": "Kanbus",
  "version": "0.1.0",
  "entry": "https://plugins.example/kanbus/0.1.0/index.js",
  "elements": { "panel": "kanbus-panel", "card": "kanbus-card" },
  "sizes": ["card", "split", "full"],
  "handles": ["kanbus.board", "kanbus.issue"],
  "permissions": ["workspace.files.read"]
}

What the host gives the element

The host creates the element and assigns the property chatticus, again each time anything changes:

element.chatticus = { context, host };

Not built yet from the draft contract: host.post, host.requestApproval, host.fetch, host.subscribe, and permissions enforcement. The manifest already carries permissions so plugins can declare them now.

Registering plugins

panelPluginRegistry (web/lib/panel-plugin-registry.ts) holds the tab order: core plugins first, then the others in registration order. Core ids cannot be replaced or removed. Set NEXT_PUBLIC_PANEL_PLUGIN_MANIFEST_URLS to a comma-separated list of manifest URLs and the workspace fetches and registers them at startup; invalid manifests are skipped with a console warning.

A plugin that fails to import, or never defines its element, shows an error in its own tab and leaves the other tabs working.

Core plugins

web/components/workspace/panel-plugins/core-panel-elements.tsx defines chatticus-context-panel, chatticus-files-panel, chatticus-costs-panel and chatticus-board-panel. defineReactPanelElement wraps any React component in such an element, rendering it into its own React root. Core plugins receive their controllers through context.services, which only first-party plugins may rely on.

The Board plugin (Kanbus)

The Board tab shows a Kanbus project that lives in the organization's workspace. A Kanbus project keeps one JSON file per issue under project/issues/. The panel finds /workspace/project/issues, or the first top-level folder of the workspace that has project/issues, lists it, and reads the issue files through the member file routes (GET /computer/files and GET /computer/files/content). Those routes answer from the saved copy while the computer is off, so the board does not need the computer running. The panel only reads.

Limits of that data path, all from docs/LIVE_FILES_PROTOCOL.md: there is no bulk read, so a load is one listing plus one read per issue file; reads are rate limited to 240 per user per minute and shared with the Files tab; a listing returns at most 2000 entries; a read returns at most 256 KiB. The panel therefore reads at most 200 issue files (the most recently modified first), four at a time, remembers each file by its content hash so a refresh re-reads only changed files, and says plainly when it shows fewer issues than the project holds. A bulk read route, or a server-side board route, is the next step if boards outgrow this.

The columns and cards are drawn by the Kanbus project's own component, IssueCollection from @kanbus/ui (which composes the Kanbus Board, BoardColumn and IssueCard). Chatticus does not draw a column or a card. It parses the issue files into the component's KanbanIssue records and builds a KanbanConfig (web/lib/kanbus-board.ts): the open, in progress and closed statuses always, any other status that has an issue after them in the default Kanbus workflow order, the default priority names, and a color per issue type. The component's own sort rules order the cards, and its column headers collapse and expand. The panel passes no selection handler, so it stays read-only.

@kanbus/ui is a dependency of web installed from the immutable kanbus-ui-0.3.1.tgz asset of the public AnthusAI/Kanbus release ui-v0.3.1 (the package is not on the npm registry). The lockfile records the tarball's integrity hash, so npm ci fetches exactly that file with no credentials. To move to a newer release, change the version in both places of the URL in web/package.json and run npm install.

The package's stylesheet is imported by web/styles/kanbus-board.css, which also maps the component's variables to the workspace tokens, inside the .chatticus-kanbus-board wrapper only. The package's tokens.css is not imported, because it sets --font-body and --font-mono on :root, which the workspace also uses. The component keys its dark palette off a .dark ancestor while the workspace follows prefers-color-scheme, so the wrapper gets the dark class when the panel's context.theme is dark. The package uses Tailwind utilities, so web/tailwind.config.ts scans the package's dist and maps the colors it names (card, muted, foreground and so on) to those variables.

The look is set by the package's own --kb-* variables, set on the wrapper and flat by default (no card border, no shadow):

Property Value in the wrapper Meaning
--kb-board-gap 0.5rem Space between columns
--kb-column-width min(20rem, 85%) Column width (at most 85% of the panel, so a column never fills a phone)
--kb-column-radius 1rem Column corner radius
--kb-card-radius 0.75rem Card corner radius
--kb-card-gap 0.5rem Space between cards
--kb-card-border 0 solid transparent Card border
--kb-card-shadow none Card shadow

The card color is --surface-0, the text colors follow --surface-foreground, and the keyboard focus ring is the component's own, in --cobalt.

Flat style

Plugins mark regions with the flat surface-* backgrounds (--surface-0/1/2) and never with borders, outlines or divider rules. See docs/BRAND_GUIDELINES.md.