Kunkun
Concepts

Architecture

The multi-shell/core design that keeps Kunkun portable — and what it means for your extension.

Kunkun's defining decision is that it is not an Electron app. Electron is the current desktop shell — not the product. The same backend/core is designed to run from Electron today, and from a CLI/TUI, a headless server, a browser UI, or a native shell tomorrow, by swapping adapters at the edges.

For you as an extension author, this has one practical consequence: your extension talks to a typed HostAPI, not to Electron. The host it runs under is an implementation detail. A worker-view extension you write for the desktop app can run unchanged when the same core is driven by a CLI or a browser.

One core, many shells

Electrondesktop shellCLI / TUIapps/cliHeadlessserver hostBrowser UIover WebSocketNativeTauri / futuretransport: IPC · WebSocket · stdio · postMessage · in-processPortable Core@kunkunsh/core · @kunkunsh/db · @kunkunsh/sdk@kunkunsh/plugin-runtime · @kunkunsh/agentshell adapters: windows · keychain · process spawning · native fs · dialogsYour extensionscustom-view · worker-view · node-view · headless · servicestalk to a scoped, permission-checked HostAPI over kkrpc
Every shell drives the same core; extensions only ever see a scoped HostAPI.

The layered model

Requests flow through the same layers no matter which shell you run:

Only the top (interfaces) and bottom (adapters) layers change per shell. The middle — API views, business logic, permission enforcement, the plugin runtime, the database — is shared and shell-agnostic.

Ports and adapters

Kunkun follows a strict ports-and-adapters split:

  • The backend/core owns business logic, permission enforcement, plugin orchestration, the database, and process-lifecycle policy.
  • Shell adapters own platform concerns: windows, menus, protocol registration, OS keychain, native clipboard, process spawning, native filesystem/watchers.
  • Transport is a choice, not part of business logic. The same core method is reachable over Electron IPC, a WebSocket, stdio, a Worker postMessage, or an in-process call.

Contributor rule of thumb

Portable-looking logic (schema, migrations, queries, validation, service contracts, plugin orchestration, permission composition) belongs in a package, not in apps/desktop/electron. Electron files should only contain things that genuinely need BrowserWindow, the tray, protocol registration, the OS keychain, native dialogs, or process spawning.

Where code lives

PackageResponsibilityImports Electron?
@kunkunsh/coreBackend API impl, service orchestration, permission compositionNo
@kunkunsh/dbDrizzle schema, migrations, portable queries, client factoryNo
@kunkunsh/sdkPlugin-facing SDK, manifest schema, HostAPI contracts, runtime bootstrapsNo
@kunkunsh/plugin-runtimeElectron-free plugin runtime primitives + permission gatingNo
@kunkunsh/agentPortable AI agent loop + provider systemNo (external APIs only)
apps/desktopElectron shell, SvelteKit renderer, native adapters, transport wiringYes — only here
apps/cliCLI/TUI shell, Effect composition root, Hono/WebSocket hostNo

Caller identity, not implicit trust

Every RPC connection or in-process caller carries a session describing who is calling:

interface BackendSession {
  sessionId: string
  callerKind: "trusted-shell" | "plugin-view" | "plugin-worker" | "url-view" | "cli" | "browser-ui"
  installationId?: string
  extensionIdentifier?: string
  commandName?: string
  permissionScope: PermissionScope
  transport: KunkunTransportDescriptor
}

Two rules follow, and both matter to extension authors:

  1. Permission checks run on every sensitive call, using this session — not only at connection setup.
  2. Plugin identity is host-created and never trusted from plugin code. The host binds the kkrpc listener to your window/worker and constructs your HostAPI from trusted state. You cannot spoof another extension's identifier to reach its storage or permissions.

Not one API — scoped views

Different callers get different, scoped surfaces built from the same shared implementation modules:

API viewCallerSurfaceEnforcement
KunkunShellAPITrusted shell (Electron/CLI/browser UI)BroadCapability-checked
KunkunHostAPIPlugin view / worker / backendScoped by manifest + dynamic grantsFull permission enforcement
KunkunUrlViewAPIURL-backed pagesVery narrow, default-disabledDefault-deny

A clipboard operation, for example, lives once in a shared clipboard-ops module. The shell API calls it directly; the plugin HostAPI wraps it with a clipboard-read permission check before delegating to the same module.

What this means for you

  • You import @kunkunsh/sdk and call typed methods. Under the hood those calls are kkrpc messages to the host.
  • You declare permissions in your manifest; the host enforces them.
  • Because the core is portable, extensions that don't hard-depend on a specific shell (e.g. worker-view UIs, services, headless commands) can run across hosts — and the most ambitious extensions ship as both a CLI and a plugin.

Knowledge Graph

Every doc page and every cross-reference between them, visualised as an interactive, force-directed graph. Drag nodes, zoom, and click any page to navigate.

Next: How Extensions Run — the kkrpc + HostAPI mechanics.

On this page