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';
NamespacePurposeAvailability
appTheme, language, application settings, events, and isolated app storageEmbedded; most non-storage settings are also available remotely.
agentAgent and workspace APIsEmbedded, with sensitive operations restricted by the host. The remote client exposes workspace operations only.
modelsConfigured model APIs, including image generation and source-image editingEmbedded only. Provider credentials are not exposed to the app.
winNative context menus, window state, and host-rendered titlebar controlsEmbedded only.
coderProjects, persistent sessions, Agent and Shell runs, settings, authentication, streaming, and cancellationEmbedded only and reserved for the registered Coder app.
terminalOwner-scoped pseudoterminal creation, input, resize, output, and exit eventsEmbedded 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.