The package exports typed lazy bridges for embedded apps, a connect() client for local external processes, shared request and result types, and validation helpers.
Embedded Namespaces
Import these namespaces in browser code that Kucedr opens as an app:
import { agent, app, coder, isKucedr, models, terminal, win } from '@kucedr/sdk';
| Namespace | Purpose | Availability |
|---|---|---|
app | Theme, language, application settings, events, and isolated app storage | Embedded; most non-storage settings are also available remotely. |
agent | Agent and workspace APIs | Embedded, with sensitive operations restricted by the host. The remote client exposes workspace operations only. |
models | Configured model APIs, including image generation and source-image editing | Embedded only. Provider credentials are not exposed to the app. |
win | Native context menus, window state, and host-rendered titlebar controls | Embedded only. |
coder | Projects, persistent sessions, Agent and Shell runs, settings, authentication, streaming, and cancellation | Embedded only and reserved for the registered Coder app. |
terminal | Owner-scoped pseudoterminal creation, input, resize, output, and exit events | Embedded only and restricted to authorized Kucedr windows and the Coder app. |
The bridge is lazy: importing a namespace is safe, but calling it outside Kucedr throws an error. Use isKucedr() before the first host call.
App Storage
Embedded apps receive their own storage namespace automatically. They never pass or choose an app ID.
import { app, isExtensionStoreValue } from '@kucedr/sdk';
await app.setExtensionStoreValue('preferences', {
compact: true,
accent: 'violet',
});
const value = await app.getExtensionStoreValue('preferences');
if (!isExtensionStoreValue(value)) {
throw new Error('Unsupported stored value');
}
Values may contain finite numbers, strings, booleans, null, dense arrays, and plain objects. Do not store secrets: values are JSON saved in plaintext. Stored values and files remain when an app is removed, so reinstalling the same app ID restores its state.
File methods use Uint8Array and paths relative to the app's isolated files directory:
const data = new TextEncoder().encode('Draft content');
await app.writeExtensionStoreFile('drafts/first.txt', data);
const saved = await app.readExtensionStoreFile('drafts/first.txt');
console.log(new TextDecoder().decode(saved));
await app.deleteExtensionStoreFile('drafts/first.txt');
Paths must use forward slashes. Absolute paths, empty paths, and . or .. segments are rejected. Deleting a missing value or file is safe; reading a missing file rejects.
Themes And Window Controls
Use Kucedr's resolved theme rather than assuming that the saved system mode is light or dark:
const stopTheme = app.onThemeModeChanged((theme) => {
document.documentElement.dataset.theme = theme.isDark ? 'dark' : 'light';
});
win.setTitlebarOptions({
title: 'Project dashboard',
leftButtons: [
{
id: 'toggle-sidebar',
label: 'Toggle sidebar',
icon: 'panel-left',
expanded: true,
},
],
sidebarOpen: true,
sidebarWidth: 240,
});
const stopButtons = win.onTitlebarButtonClick((buttonId) => {
if (buttonId === 'toggle-sidebar') {
// Update your app state, then send the new titlebar options.
}
});
// Call these during cleanup.
stopTheme();
stopButtons();
Titlebar icons must come from EXTENSION_TITLEBAR_BUTTON_ICONS; arbitrary markup cannot cross the window boundary. Pass null to win.setTitlebarOptions() to restore the manifest title and remove app-provided controls.
Image Generation
models.image.createImage() uses the image provider and model configured in Kucedr:
const generated = await models.image.createImage({
prompt: 'A calm, modern reading room',
});
const revised = await models.image.createImage({
prompt: 'Replace the armchair with a leather lounge chair.',
source: {
base64: generated.base64,
mimeType: 'image/png',
},
});
Source images accept JPEG, PNG, or WebP data and are limited to 18 MiB. Use the returned MIME type when turning result bytes into a data URL or file.
External Client
Kucedr writes a bearer token to <userData>/sdk-token. On macOS the default path is ~/Library/Application Support/Kucedr/sdk-token. Keep the token private and read it at runtime instead of copying it into source code.
import { readFileSync } from 'node:fs';
import { connect } from '@kucedr/sdk';
const kucedr = connect({
token: readFileSync(
'/Users/me/Library/Application Support/Kucedr/sdk-token',
'utf8',
).trim(),
});
await kucedr.ping();
const files = await kucedr.agent.listWorkspaceFiles();
const userProfile = await kucedr.agent.readWorkspaceFile('USER.md');
const stop = kucedr.agent.onWorkspaceChanged((event) => {
console.log(event.type, event.path);
});
// During shutdown:
stop();
kucedr.close();
connect() defaults to http://127.0.0.1:8765 and accepts an alternative url or fetch implementation. Event callbacks open a Server-Sent Events connection on first use. Call close() during shutdown to stop that stream.
Runtime Safety
- Treat the SDK token like a password; any process that has it can call the exposed local API.
- Keep app storage free of credentials because it is plaintext.
- Expect the host to reject APIs that the current app is not authorized to use.
- A project working directory is not an operating-system sandbox. Coding and terminal operations run with the desktop user's authority.
- Apps receive redacted agent-tool events and do not receive provider credentials.