Getting Started
Quick start guide to building Kunkun extensions
Get started building your first Kunkun extension in minutes.
Prerequisites
- Node.js 18+ or Bun runtime
- Basic knowledge of TypeScript/JavaScript
- Familiarity with React (for worker extensions) or any frontend framework (for custom UI)
Choose Your Extension Type
| Type | Description |
|---|---|
| Custom UI | Full control with any framework (Svelte, Vue, etc.) |
| Worker Extension | Raycast-style React components |
| Headless Command | Background operations without UI |
| Service Plugin | Expose APIs for other plugins and AI |
Quick Start: Custom UI Extension
1. Create Project
# Using SvelteKit (recommended for custom UI)
npx sv create my-extension
cd my-extension
pnpm add @kunkunsh/api2. Configure for Static Build
Create src/routes/+layout.ts:
export const prerender = true;
export const ssr = false;3. Add Manifest
Update package.json:
{
"$schema": "../../packages/api/manifest-schema.json",
"kunkun": {
"identifier": "com.yourname.my-extension",
"name": "My Extension",
"icon": {
"type": "iconify",
"value": "mdi:puzzle",
"invert": true
},
"shortDescription": "My first Kunkun extension",
"permissions": ["clipboard-read", "clipboard-write", "storage"],
"commands": [
{
"name": "main",
"title": "My Command",
"mode": "custom-view",
"main": "/",
"dist": "build",
"devMain": "http://localhost:5173"
}
]
}
}4. Use the API
Edit src/routes/+page.svelte:
<script lang="ts">
import { Clipboard, showToast, Toast } from '@kunkunsh/api'
let text = $state('')
async function readClipboard() {
text = await Clipboard.readText()
await showToast({ title: 'Read!', style: Toast.Style.Success })
}
</script>
<div class="p-6">
<h1>My Extension</h1>
<button onclick={readClipboard}>Read Clipboard</button>
<p>Content: {text}</p>
</div>5. Build
pnpm buildThe extension is ready in the build folder.
Quick Start: Worker Extension
1. Create Project
mkdir my-worker-ext
cd my-worker-ext
pnpm init
pnpm add @kunkunsh/api react valibot
pnpm add -D @types/react @types/bun2. Create Component
Create src/App.tsx:
import { useState } from "react";
import { Button, Div, H2, P } from "@kunkunsh/api/ui";
import { Clipboard, showToast, Toast } from "@kunkunsh/api";
export default function App() {
const [text, setText] = useState("");
return (
<Div className="p-6">
<H2>My Worker Extension</H2>
<Button
title="Read Clipboard"
variant="primary"
onClick={async () => {
setText(await Clipboard.readText());
await showToast({ title: "Read!", style: Toast.Style.Success });
}}
/>
<P>Content: {text}</P>
</Div>
);
}3. Create Build Script
Create build.ts:
import { dedupeReact, kunkunCommandPlugin } from "@kunkunsh/api/build";
import type { BunPlugin } from "bun";
await Bun.build({
entrypoints: ["./src/App.tsx"],
outdir: "./dist",
target: "browser",
format: "esm",
minify: true,
plugins: [
kunkunCommandPlugin({ mode: "view" }) as BunPlugin,
dedupeReact(import.meta.dir)
],
});4. Add Manifest
Update package.json:
{
"$schema": "../../packages/api/manifest-schema.json",
"kunkun": {
"identifier": "com.example.my-worker-ext",
"name": "My Worker Extension",
"source": "kunkun",
"icon": { "type": "iconify", "invert": true, "value": "mdi:puzzle" },
"permissions": ["clipboard-read", "storage"],
"commands": [
{
"name": "main",
"title": "My Command",
"mode": "worker-view",
"main": "dist/App.js"
}
]
},
"scripts": {
"build": "bun build.ts"
}
}5. Build
bun run buildInstalling Extensions
Development
- Open Kunkun
- Go to Settings > Developer
- Click Load Extension
- Select your extension directory
Production
Publish to npm and users can install from the built-in extension store.
Next Steps
- Custom UI Extension - Full UI control
- Worker Extension - React components
- Headless Commands - Background operations
- Services - Exposed APIs
- Permissions - Security model
Example Projects
apps/sample-ext- Custom UI with SvelteKitapps/sample-worker-ext- Worker and Node extensions