Skip to main content

SDK Reference

The KanbanSDK class is the single source of truth for all Kanban Lite business logic. Every interface — CLI, REST API, MCP server, and VS Code extension — delegates to the same SDK methods, so your code uses the same proven paths that power the web UI.

  • Create and manage boards, cards, columns, and settings programmatically
  • Full webhook CRUD and event subscription via sdk.on()
  • Storage-agnostic: works with markdown, SQLite, MySQL, or custom providers
  • TypeScript-first with full type exports
  • Auth and policy hooks for access control
Quick usage
import { KanbanSDK } from 'kanban-lite';

const sdk = new KanbanSDK({ dir: '.kanban' });

// Create a card
const card = await sdk.createCard({ title: 'Fix login bug', priority: 'high', status: 'todo' });

// Move it
await sdk.moveCard(card.id, 'in-progress');

// Subscribe to events
sdk.on('task.created', (card) => console.log('New card:', card.id));

Kanban Lite SDK

The KanbanSDK class is the core engine behind Kanban Lite. It provides a complete, async API for managing cards, comments, attachments, columns, and board settings. The CLI, MCP server, VSCode extension, and standalone web server all delegate to this single SDK — so behavior is consistent everywhere.

Installation

npm install kanban-lite

Import

import { KanbanSDK } from 'kanban-lite/sdk'

You can also import types and utilities:

import type { Card, CardStatus, Priority, KanbanColumn, CardDisplaySettings, CreateCardInput } from 'kanban-lite/sdk'
import { parseCardFile, serializeCard, getTitleFromContent, DEFAULT_COLUMNS } from 'kanban-lite/sdk'
import { readConfig, writeConfig, configToSettings, settingsToConfig } from 'kanban-lite/sdk'

Quick Start

import { KanbanSDK } from 'kanban-lite/sdk'

const sdk = new KanbanSDK('/path/to/project/.kanban')

// Create a card
const card = await sdk.createCard({
  content: '# Implement auth\n\nAdd OAuth2 login flow.',
  status: 'todo',
  priority: 'high',
  labels: ['backend', 'security']
})

// List all cards (sorted by order)
const cards = await sdk.listCards()

// Move card to a different column
await sdk.moveCard(card.id, 'in-progress')

// Add a comment
await sdk.addComment(card.id, 'alice', 'Started working on this')

// Clean up
await sdk.deleteCard(card.id)

KanbanSDK Class

KanbanSDK

Core SDK for managing kanban boards with provider-backed card storage.

Provides full CRUD operations for boards, cards, columns, comments, attachments, and display settings. By default cards are persisted as markdown files with YAML frontmatter under the .kanban/ directory, organized by board and status column, but the resolved card.storage provider may also route card/comment persistence to SQLite, MySQL, or an external plugin.

This class is the foundation that the CLI, MCP server, and standalone HTTP server are all built on top of.

Kind: global class


new KanbanSDK(kanbanDir, options)

Creates a new KanbanSDK instance.

Param Description
kanbanDir Absolute path to the .kanban kanban directory. When omitted, the directory is auto-detected by walking up from process.cwd() to find the workspace root (via .git, package.json, or .kanban.json), then reading kanbanDirectory from .kanban.json (defaults to '.kanban').
options Optional configuration including an event handler callback and storage engine selection.

Example

const sdk = new KanbanSDK('/path/to/project/.kanban')
await sdk.init()
const cards = await sdk.listCards()

kanbanSDK.eventBus

The underlying SDK event bus for advanced event workflows.

Most consumers can use the convenience proxy methods on KanbanSDK itself (on, once, many, onAny, waitFor, etc.). Access the raw bus directly when you specifically need the shared EventBus instance.

Kind: instance property of KanbanSDK


kanbanSDK.storageEngine

The active storage engine powering this SDK instance. Returns the resolved card.storage provider implementation (for example markdown, sqlite, or mysql).

Kind: instance property of KanbanSDK


kanbanSDK.capabilities

The resolved storage/attachment capability bag for this SDK instance. Returns null when a pre-built storage engine was injected directly.

Kind: instance property of KanbanSDK


kanbanSDK._currentAuthContext

Returns the auth context installed by the nearest enclosing runWithAuth call, if any. @internal

Kind: instance property of KanbanSDK


kanbanSDK.workspaceRoot ⇒

The workspace root directory (parent of the kanban directory).

This is the project root where .kanban.json configuration lives.

Kind: instance property of KanbanSDK
Returns: The absolute path to the workspace root directory.
Example

const sdk = new KanbanSDK('/home/user/my-project/.kanban')
console.log(sdk.workspaceRoot) // '/home/user/my-project'

kanbanSDK.on()

Subscribe to an SDK event or wildcard pattern.

Kind: instance method of KanbanSDK


kanbanSDK.once()

Subscribe to the next matching SDK event only once.

Kind: instance method of KanbanSDK


kanbanSDK.many()

Subscribe to an SDK event a fixed number of times.

Kind: instance method of KanbanSDK


kanbanSDK.onAny()

Subscribe to every SDK event regardless of name.

Kind: instance method of KanbanSDK


kanbanSDK.off()

Remove a specific event listener.

Kind: instance method of KanbanSDK


kanbanSDK.offAny()

Remove a specific catch-all listener.

Kind: instance method of KanbanSDK


kanbanSDK.removeAllListeners()

Remove all event listeners for one event, or all listeners when omitted.

Kind: instance method of KanbanSDK


kanbanSDK.eventNames()

Return the registered event names currently tracked by the bus.

Kind: instance method of KanbanSDK


kanbanSDK.listenerCount()

Get the number of listeners for a specific event, or all listeners when omitted.

Kind: instance method of KanbanSDK


kanbanSDK.hasListeners()

Check whether any listeners are registered for an event or for the bus overall.

Kind: instance method of KanbanSDK


kanbanSDK.waitFor()

Wait for the next matching SDK event and resolve with its payload.

Kind: instance method of KanbanSDK


kanbanSDK.getStorageStatus() ⇒

Returns storage/provider metadata for host surfaces and diagnostics.

Use this to inspect resolved provider ids, file-backed status, and watcher behavior without reaching into capability internals.

Kind: instance method of KanbanSDK
Returns: A StorageStatus snapshot containing the active provider id, resolved provider selections (when available), whether cards are backed by local files, and the watcher glob used by file-backed hosts.
Example

const status = sdk.getStorageStatus()
console.log(status.storageEngine) // 'markdown' | 'sqlite' | 'mysql' | ...
console.log(status.watchGlob) // e.g. markdown card glob for board/status directories

kanbanSDK.getAuthStatus() ⇒

Returns auth provider metadata for host surfaces and diagnostics.

Use this to inspect which identity and policy providers are active and whether real auth enforcement is enabled.

Kind: instance method of KanbanSDK
Returns: An AuthStatus snapshot containing the active provider ids and boolean flags indicating whether non-noop providers are live.
Example

const status = sdk.getAuthStatus()
console.log(status.identityProvider) // 'noop' | 'my-token-plugin' | ...
console.log(status.identityEnabled)  // false when no plugin configured

kanbanSDK.getWebhookStatus() ⇒

Returns webhook provider metadata for host surfaces and diagnostics.

Use this to inspect which webhook delivery provider is active and whether kl-webhooks-plugin is installed.

Kind: instance method of KanbanSDK
Returns: A WebhookStatus snapshot containing the active provider id and a boolean flag indicating whether a provider is active.
Example

const status = sdk.getWebhookStatus()
console.log(status.webhookProvider)      // 'none' | 'webhooks' | ...
console.log(status.webhookProviderActive) // false when kl-webhooks-plugin not installed

kanbanSDK.getCardStateStatus()

Returns card-state provider metadata for host surfaces and diagnostics.

The status includes the stable auth-absent default actor contract and lets callers distinguish configured-identity failures from true backend unavailability via availability / errorCode.

Kind: instance method of KanbanSDK


kanbanSDK.getExtension(id) ⇒

Returns the SDK extension bag contributed by the plugin with the given id, or undefined when no active plugin has exported a matching sdkExtensionPlugin.

Use this to access plugin-owned SDK capabilities (e.g. webhook CRUD methods contributed by kl-webhooks-plugin) without importing plugin packages directly.

Kind: instance method of KanbanSDK
Returns: The resolved extension bag cast to T, or undefined when the plugin is not active or has not exported sdkExtensionPlugin.
Typeparam: T - Shape of the expected extension bag.

Param Description
id The plugin manifest id to look up (e.g. 'kl-webhooks-plugin').

Example

const webhookExt = sdk.getExtension<{ listWebhooks(): Webhook[] }>('kl-webhooks-plugin')
const webhooks = webhookExt?.listWebhooks() ?? []

kanbanSDK._requireCardStateCapabilities()

Kind: instance method of KanbanSDK
Internal:


kanbanSDK._resolveCardStateTarget()

Kind: instance method of KanbanSDK
Internal:


kanbanSDK._resolveCardStateActorId()

Kind: instance method of KanbanSDK
Internal:


kanbanSDK._getLatestUnreadActivityCursor()

Kind: instance method of KanbanSDK
Internal:


kanbanSDK._createUnreadSummary()

Kind: instance method of KanbanSDK
Internal:


kanbanSDK.getCardState()

Reads persisted card-state for the current actor without producing any side effects.

When domain is omitted, the unread cursor domain is returned. This method reads actor-scoped card.state only and does not reflect or modify active-card UI state.

Kind: instance method of KanbanSDK


kanbanSDK.getUnreadSummary()

Derives unread state for the current actor from persisted activity logs without mutating card state.

Unread derivation is SDK-owned for both the built-in file-backed backend and first-party compatibility backends such as sqlite.

Kind: instance method of KanbanSDK


kanbanSDK.markCardOpened()

Persists an explicit open-card mutation for the current actor.

Opening a card records the open domain and acknowledges the latest unread activity cursor for that actor without depending on setActiveCard. This does not change workspace active-card UI state.

Kind: instance method of KanbanSDK


kanbanSDK.markCardRead()

Persists an explicit read-through cursor for the current actor.

Reads are side-effect free; call this method when you want to acknowledge unread activity explicitly. Configured-identity failures surface as ERR_CARD_STATE_IDENTITY_UNAVAILABLE rather than backend unavailability.

Kind: instance method of KanbanSDK


kanbanSDK._authorizeAction(action, context) ⇒

Resolves caller identity and evaluates whether the named action is permitted.

This is the internal SDK pre-action authorization seam. SDK methods that represent mutating or privileged operations should call this before executing their logic.

When no auth plugins are configured the built-in noop path allows all actions anonymously, preserving the current open-access behavior for workspaces without an auth configuration.

Kind: instance method of KanbanSDK
Returns: Fulfilled AuthDecision when the action is permitted.
Throws:

  • AuthError When the policy plugin denies the action.

Internal:

Param Description
action Canonical action name (e.g. 'card.create', 'board.delete').
context Optional auth context from the inbound request.

kanbanSDK.runWithAuth(auth, fn) ⇒

Runs fn within an async scope where auth is the active auth context.

Use this on host surfaces (REST routes, CLI commands, MCP handlers) to bind a request-scoped AuthContext before calling SDK mutators. The context is propagated automatically through every await in the call tree without being threaded through method signatures.

Kind: instance method of KanbanSDK
Returns: The promise returned by fn.

Param Description
auth Request-scoped auth context to install for the duration of fn.
fn Async callback to execute with the auth context active.

Example

const card = await sdk.runWithAuth({ token: req.headers.authorization }, () =>
  sdk.createCard({ boardId: 'default', title: 'New task' })
)

kanbanSDK._resolveEventActor()

Kind: instance method of KanbanSDK
Internal:


kanbanSDK._runBeforeEvent(event, input, actor, boardId) ⇒

Dispatches a before-event to all registered listeners and returns a deep-merged clone of the input.

Clones input immediately with structuredClone so the caller's object is never mutated. Awaits all registered before-event listeners in registration order via EventBus.emitAsync. Each plain-object listener response is deep-merged in registration order over the clone so that later-registered listeners override earlier ones at every nesting depth. Arrays in listener responses replace (no concatenation). Non-plain-object, void, or empty {} responses contribute no keys and the accumulated input stays effectively unchanged.

Throwing aborts the mutation: any error thrown by a listener — including AuthError — propagates immediately to the caller. No subsequent listeners execute and no mutation write occurs.

Kind: instance method of KanbanSDK
Returns: Promise resolving to the deep-merged input clone after all listeners settle.
Internal:

Param Description
event Before-event name (e.g. 'card.create').
input Initial mutation input used as the clone/merge base.
actor Resolved acting principal, if known.
boardId Board context for this action, if applicable.

kanbanSDK._runAfterEvent(event, data, actor, boardId, meta)

Emits an after-event exactly once after a mutation has been committed.

Wraps data in an AfterEventPayload envelope and emits it on the event bus as an SDKEvent. After-event listeners are non-blocking: the event bus isolates errors per listener so a failing listener never prevents sibling listeners from executing and never propagates to the SDK caller.

Kind: instance method of KanbanSDK
Internal:

Param Description
event After-event name (e.g. 'task.created').
data The committed mutation result.
actor Resolved acting principal, if known.
boardId Board context for this event, if applicable.
meta Optional audit metadata.

kanbanSDK.getLocalCardPath(card) ⇒

Returns the local file path for a card when the active provider exposes one.

This is most useful for editor integrations or diagnostics that need to open or reveal the underlying source file. Providers that do not expose stable local card files return null.

Kind: instance method of KanbanSDK
Returns: The absolute on-disk card path, or null when the active provider does not expose one.

Param Description
card The resolved card object.

Example

const card = await sdk.getCard('42')
if (card) {
  console.log(sdk.getLocalCardPath(card))
}

kanbanSDK.getAttachmentStoragePath(card) ⇒

Returns the local attachment directory for a card when the active attachment provider exposes one.

File-backed providers typically return an absolute directory under the workspace, while database-backed or remote attachment providers may return null when attachments are not directly browseable on disk.

Kind: instance method of KanbanSDK
Returns: The absolute attachment directory, or null when the active attachment provider cannot expose one.

Param Description
card The resolved card object.

kanbanSDK.appendAttachment()

Requests an efficient in-place append for an attachment when the active attachment provider supports it.

Returns true when the provider handled the append directly and false when callers should fall back to rewriting the attachment through the normal copy/materialization path.

Kind: instance method of KanbanSDK


kanbanSDK.materializeAttachment(card, attachment) ⇒

Resolves or materializes a safe local file path for a named attachment.

For simple file-backed providers this usually returns the existing file. Other providers may need to materialize a temporary local copy first. The method also guards against invalid attachment names and only resolves files already attached to the card.

Kind: instance method of KanbanSDK
Returns: An absolute local path, or null when the attachment cannot be safely exposed by the current provider.

Param Description
card The resolved card object.
attachment Attachment filename exactly as stored on the card.

Example

const card = await sdk.getCard('42')
const pdfPath = card ? await sdk.materializeAttachment(card, 'report.pdf') : null

kanbanSDK.copyAttachment(sourcePath, card)

Copies an attachment through the resolved attachment-storage capability.

This is a low-level helper used by higher-level attachment flows. It writes the supplied source file into the active attachment provider for the given card, whether that provider is local filesystem storage or a custom plugin.

Kind: instance method of KanbanSDK

Param Description
sourcePath Absolute or relative path to the source file to copy.
card The target card that should own the copied attachment.

kanbanSDK.close()

Closes the storage engine and releases any held resources (e.g. database connections). Call this when the SDK instance is no longer needed.

Kind: instance method of KanbanSDK


kanbanSDK.destroy()

Tear down the SDK, destroying the event bus and all listeners.

Kind: instance method of KanbanSDK


kanbanSDK.emitEvent()

Kind: instance method of KanbanSDK
Internal:


kanbanSDK._resolveBoardId()

Kind: instance method of KanbanSDK
Internal:


kanbanSDK._boardDir()

Kind: instance method of KanbanSDK
Internal:


kanbanSDK._isCompletedStatus()

Kind: instance method of KanbanSDK
Internal:


kanbanSDK._ensureMigrated()

Kind: instance method of KanbanSDK
Internal:


kanbanSDK.init() ⇒

Initializes the SDK by running any pending filesystem migrations and ensuring the default board's directory structure exists.

This should be called once before performing any operations, especially on a fresh workspace or after upgrading from a single-board layout.

Kind: instance method of KanbanSDK
Returns: A promise that resolves when initialization is complete.
Example

const sdk = new KanbanSDK('/path/to/project/.kanban')
await sdk.init()

kanbanSDK.listBoards() ⇒

Lists all boards defined in the workspace configuration.

Kind: instance method of KanbanSDK
Returns: An array of BoardInfo objects containing each board's id, name, and optional description.
Example

const boards = sdk.listBoards()
// [{ id: 'default', name: 'Default Board', description: undefined }]

kanbanSDK.createBoard(id, name, options) ⇒

Creates a new board with the given ID and name.

If no columns are specified, the new board inherits columns from the default board. If the default board has no columns, a standard set of five columns (Backlog, To Do, In Progress, Review, Done) is used.

Kind: instance method of KanbanSDK
Returns: A BoardInfo object for the newly created board.
Throws:

  • Error If a board with the given id already exists.
Param Description
id Unique identifier for the board (used in file paths and API calls).
name Human-readable display name for the board.
options Optional configuration for the new board.
options.description A short description of the board's purpose.
options.columns Custom column definitions. Defaults to the default board's columns.
options.defaultStatus The default status for new cards. Defaults to the first column's ID.
options.defaultPriority The default priority for new cards. Defaults to the workspace default.

Example

const board = sdk.createBoard('bugs', 'Bug Tracker', {
  description: 'Track and triage bugs',
  defaultStatus: 'triage'
})

kanbanSDK.deleteBoard(boardId) ⇒

Deletes a board and its directory from the filesystem.

The board must be empty (no cards) and must not be the default board. The board's directory is removed recursively from disk, and the board entry is removed from the workspace configuration.

Kind: instance method of KanbanSDK
Returns: A promise that resolves when the board has been deleted.
Throws:

  • Error If the board does not exist.
  • Error If the board is the default board.
  • Error If the board still contains cards.
Param Description
boardId The ID of the board to delete.

Example

await sdk.deleteBoard('old-sprint')

kanbanSDK.getBoard(boardId) ⇒

Retrieves the full configuration for a specific board.

Kind: instance method of KanbanSDK
Returns: The BoardConfig object containing columns, settings, and metadata.
Throws:

  • Error If the board does not exist.
Param Description
boardId The ID of the board to retrieve.

Example

const config = sdk.getBoard('default')
console.log(config.columns) // [{ id: 'backlog', name: 'Backlog', ... }, ...]

kanbanSDK.updateBoard(boardId, updates) ⇒

Updates properties of an existing board.

Only the provided fields are updated; omitted fields remain unchanged. The nextCardId counter cannot be modified through this method.

Kind: instance method of KanbanSDK
Returns: The updated BoardConfig object.
Throws:

  • Error If the board does not exist.
Param Description
boardId The ID of the board to update.
updates A partial object containing the fields to update.
updates.name New display name for the board.
updates.description New description for the board.
updates.columns Replacement column definitions.
updates.defaultStatus New default status for new cards.
updates.defaultPriority New default priority for new cards.

Example

const updated = sdk.updateBoard('bugs', {
  name: 'Bug Tracker v2',
  defaultPriority: 'high'
})

kanbanSDK.getBoardActions(boardId) ⇒

Returns the named actions defined on a board.

Kind: instance method of KanbanSDK
Returns: A map of action key to display title.
Throws:

  • Error If the board does not exist.
Param Description
boardId Board ID. Defaults to the active board when omitted.

Example

const actions = sdk.getBoardActions('deployments')
console.log(actions.deploy) // 'Deploy now'

kanbanSDK.addBoardAction(boardId, key, title) ⇒

Adds or updates a named action on a board.

Kind: instance method of KanbanSDK
Returns: The updated actions map.
Throws:

  • Error If the board does not exist.
Param Description
boardId Board ID.
key Unique action key (used as identifier).
title Human-readable display title for the action.

Example

sdk.addBoardAction('deployments', 'deploy', 'Deploy now')

kanbanSDK.removeBoardAction(boardId, key) ⇒

Removes a named action from a board.

Kind: instance method of KanbanSDK
Returns: The updated actions map.
Throws:

  • Error If the board does not exist.
  • Error If the action key is not found on the board.
Param Description
boardId Board ID.
key The action key to remove.

Example

sdk.removeBoardAction('deployments', 'deploy')

kanbanSDK.triggerBoardAction(boardId, actionKey)

Fires the board.action webhook event for a named board action.

Kind: instance method of KanbanSDK
Throws:

  • Error If the board does not exist.
  • Error If the action key is not defined on the board.
Param Description
boardId The board that owns the action.
actionKey The key of the action to trigger.

Example

await sdk.triggerBoardAction('deployments', 'deploy')

kanbanSDK.transferCard(cardId, fromBoardId, toBoardId, targetStatus) ⇒

Transfers a card from one board to another.

The card file is physically moved to the target board's directory. If a target status is not specified, the card is placed in the target board's default status column. The card's order is recalculated to place it at the end of the target column. Timestamps (modified, completedAt) are updated accordingly.

Kind: instance method of KanbanSDK
Returns: A promise resolving to the updated Card card object.
Throws:

  • Error If either board does not exist.
  • Error If the card is not found in the source board.
Param Description
cardId The ID of the card to transfer.
fromBoardId The ID of the source board.
toBoardId The ID of the destination board.
targetStatus Optional status column in the destination board. Defaults to the destination board's default status.

Example

const card = await sdk.transferCard('42', 'inbox', 'bugs', 'triage')
console.log(card.boardId) // 'bugs'
console.log(card.status)  // 'triage'

kanbanSDK.getCard(cardId, boardId) ⇒

Retrieves a single card by its ID.

Supports partial ID matching -- the provided cardId is matched against all cards on the board.

Kind: instance method of KanbanSDK
Returns: A promise resolving to the matching Card card, or null if not found.

Param Description
cardId The full or partial ID of the card to retrieve.
boardId Optional board ID. Defaults to the workspace's default board.

Example

const card = await sdk.getCard('42')
if (card) {
  console.log(card.content)
}

kanbanSDK.getActiveCard(boardId) ⇒

Retrieves the card currently marked as active/open in this workspace.

Active-card state is persisted in the workspace so other interfaces (standalone server, CLI, MCP, and VS Code) can query the same card. Returns null when no card is currently active.

Kind: instance method of KanbanSDK
Returns: A promise resolving to the active Card, or null.

Param Description
boardId Optional board ID. When provided, returns the active card only if it belongs to that board.

Example

const active = await sdk.getActiveCard()
if (active) {
  console.log(active.id)
}

kanbanSDK.setActiveCard()

Kind: instance method of KanbanSDK
Internal:


kanbanSDK.clearActiveCard()

Kind: instance method of KanbanSDK
Internal:


kanbanSDK.createCard(data) ⇒

Creates a new card on a board.

The card is assigned an auto-incrementing numeric ID, placed at the end of its target status column using fractional indexing, and persisted as a markdown file with YAML frontmatter. If no status or priority is provided, the board's defaults are used.

Kind: instance method of KanbanSDK
Returns: A promise resolving to the newly created Card card.

Param Description
data The card creation input. See CreateCardInput.
data.content Markdown content for the card. The first # Heading becomes the title.
data.status Optional status column. Defaults to the board's default status.
data.priority Optional priority level. Defaults to the board's default priority.
data.assignee Optional assignee name.
data.dueDate Optional due date as an ISO 8601 string.
data.labels Optional array of label strings.
data.attachments Optional array of attachment filenames.
data.metadata Optional arbitrary key-value metadata stored in the card's frontmatter.
data.actions Optional per-card actions as action keys or key-to-title map.
data.forms Optional attached forms, using workspace-form references or inline definitions.
data.formData Optional per-form persisted values keyed by resolved form ID.
data.boardId Optional board ID. Defaults to the workspace's default board.

Example

const card = await sdk.createCard({
  content: '# Fix login bug\n\nUsers cannot log in with email.',
  status: 'todo',
  priority: 'high',
  labels: ['bug', 'auth'],
  boardId: 'bugs'
})
console.log(card.id) // '7'

kanbanSDK.updateCard(cardId, updates, boardId) ⇒

Updates an existing card's properties.

Only the provided fields are updated; omitted fields remain unchanged. The filePath, id, and boardId fields are protected and cannot be overwritten. If the card's title changes, the underlying file is renamed. If the status changes, the file is moved to the new status subdirectory and completedAt is updated accordingly.

Common update fields include content, status, priority, assignee, dueDate, labels, metadata, actions, forms, and formData.

Kind: instance method of KanbanSDK
Returns: A promise resolving to the updated Card card.
Throws:

  • Error If the card is not found.
Param Description
cardId The ID of the card to update.
updates A partial Card object with the fields to update.
boardId Optional board ID. Defaults to the workspace's default board.

Example

const updated = await sdk.updateCard('42', {
  priority: 'critical',
  assignee: 'alice',
  labels: ['urgent', 'backend']
})

kanbanSDK.submitForm(input) ⇒

Validates and persists a form submission for a card, then emits form.submit through the normal SDK event/webhook pipeline.

The target form must already be attached to the card, either as an inline card-local form or as a named reusable workspace form reference.

Partial-at-rest semantics: card.formData[formId] may be a partial record at rest (containing only previously submitted or pre-seeded fields). The merge below always produces a full canonical object, and that full object is what gets persisted and returned as result.data.

Merge order for the resolved base payload (lowest → highest priority):

  1. Workspace-config form defaults (KanbanConfig.forms[formName].data)
  2. Card-scoped attachment defaults (attachment.data)
  3. Persisted per-card form data (card.formData[formId], may be partial)
  4. Card metadata fields that are declared in the form schema
  5. The submitted payload passed to this method

Before the merge, string values in each source layer are prepared via prepareFormData() (from src/shared/formDataPreparation), which resolves ${path} placeholders against the full card interpolation context.

Validation happens authoritatively in the SDK before persistence and before any event/webhook emission, so CLI/API/MCP/UI callers all share the same rules. After a successful submit, the SDK also appends a system card log entry that records the submitted payload under payload for audit/debug visibility.

Kind: instance method of KanbanSDK
Returns: The canonical persisted payload and event context. result.data is always the full merged and validated object (never a partial snapshot).
Throws:

  • Error If the card or form cannot be found, or if validation fails.
Param Description
input The form submission input.
input.cardId ID of the card that owns the target form.
input.formId Resolved form ID/name to submit.
input.data Submitted field values to merge over the resolved base payload.
input.boardId Optional board ID. Defaults to the workspace default board.

Example

const result = await sdk.submitForm({
  cardId: '42',
  formId: 'bug-report',
  data: { severity: 'high', title: 'Crash on save' }
})
console.log(result.data.severity) // 'high'

kanbanSDK.triggerAction(cardId, action, boardId) ⇒

Triggers a named action for a card by POSTing to the global actionWebhookUrl configured in .kanban.json.

The payload sent to the webhook is:

{ "action": "retry", "board": "default", "list": "in-progress", "card": { ...sanitizedCard } }

Kind: instance method of KanbanSDK
Returns: A promise resolving when the webhook responds with 2xx.
Throws:

  • Error If no actionWebhookUrl is configured in .kanban.json.
  • Error If the card is not found.
  • Error If the webhook responds with a non-2xx status.
Param Description
cardId The ID of the card to trigger the action for.
action The action name string (e.g. 'retry', 'sendEmail').
boardId Optional board ID. Defaults to the workspace's default board.

Example

await sdk.triggerAction('42', 'retry')
await sdk.triggerAction('42', 'sendEmail', 'bugs')

kanbanSDK.moveCard(cardId, newStatus, position, boardId) ⇒

Moves a card to a different status column and/or position within that column.

The card's fractional order key is recalculated based on the target position. If the status changes, the underlying file is moved to the corresponding subdirectory and completedAt is updated accordingly.

Kind: instance method of KanbanSDK
Returns: A promise resolving to the updated Card card.
Throws:

  • Error If the card is not found.
Param Description
cardId The ID of the card to move.
newStatus The target status/column ID.
position Optional zero-based index within the target column. Defaults to the end of the column.
boardId Optional board ID. Defaults to the workspace's default board.

Example

// Move card to 'in-progress' at position 0 (top of column)
const card = await sdk.moveCard('42', 'in-progress', 0)

// Move card to 'done' at the end (default)
const done = await sdk.moveCard('42', 'done')

kanbanSDK.deleteCard(cardId, boardId) ⇒

Soft-deletes a card by moving it to the deleted status column. The file remains on disk and can be restored.

Kind: instance method of KanbanSDK
Returns: A promise that resolves when the card has been moved to deleted status.
Throws:

  • Error If the card is not found.
Param Description
cardId The ID of the card to soft-delete.
boardId Optional board ID. Defaults to the workspace's default board.

Example

await sdk.deleteCard('42', 'bugs')

kanbanSDK.permanentlyDeleteCard(cardId, boardId) ⇒

Permanently deletes a card's markdown file from disk. This cannot be undone.

Kind: instance method of KanbanSDK
Returns: A promise that resolves when the card file has been removed from disk.
Throws:

  • Error If the card is not found.
Param Description
cardId The ID of the card to permanently delete.
boardId Optional board ID. Defaults to the workspace's default board.

Example

await sdk.permanentlyDeleteCard('42', 'bugs')

kanbanSDK.getCardsByStatus(status, boardId) ⇒

Returns all cards in a specific status column.

This is a convenience wrapper around listCards that filters by a single status value.

Kind: instance method of KanbanSDK
Returns: A promise resolving to an array of Card cards in the given status.

Param Description
status The status/column ID to filter by (e.g., 'todo', 'in-progress').
boardId Optional board ID. Defaults to the workspace's default board.

Example

const inProgress = await sdk.getCardsByStatus('in-progress')
console.log(`${inProgress.length} cards in progress`)

kanbanSDK.getUniqueAssignees(boardId) ⇒

Returns a sorted list of unique assignee names across all cards on a board.

Cards with no assignee are excluded from the result.

Kind: instance method of KanbanSDK
Returns: A promise resolving to a sorted array of unique assignee name strings.

Param Description
boardId Optional board ID. Defaults to the workspace's default board.

Example

const assignees = await sdk.getUniqueAssignees('bugs')
// ['alice', 'bob', 'charlie']

kanbanSDK.getUniqueLabels(boardId) ⇒

Returns a sorted list of unique labels across all cards on a board.

Kind: instance method of KanbanSDK
Returns: A promise resolving to a sorted array of unique label strings.

Param Description
boardId Optional board ID. Defaults to the workspace's default board.

Example

const labels = await sdk.getUniqueLabels()
// ['bug', 'enhancement', 'frontend', 'urgent']

kanbanSDK.getLabels() ⇒

Returns all label definitions from the workspace configuration.

Label definitions map label names to their color and optional group. Labels on cards that have no definition will render with default gray styling.

Kind: instance method of KanbanSDK
Returns: A record mapping label names to LabelDefinition objects.
Example

const labels = sdk.getLabels()
// { bug: { color: '#e11d48', group: 'Type' }, docs: { color: '#16a34a' } }

kanbanSDK.setLabel(name, definition)

Creates or updates a label definition in the workspace configuration.

If the label already exists, its definition is replaced entirely. The change is persisted to .kanban.json immediately.

Kind: instance method of KanbanSDK

Param Description
name The label name (e.g. 'bug', 'frontend').
definition The label definition with color and optional group.

Example

sdk.setLabel('bug', { color: '#e11d48', group: 'Type' })
sdk.setLabel('docs', { color: '#16a34a' })

kanbanSDK.deleteLabel(name)

Removes a label definition from the workspace configuration and cascades the deletion to all cards by removing the label from their labels array.

Kind: instance method of KanbanSDK

Param Description
name The label name to remove.

Example

await sdk.deleteLabel('bug')

kanbanSDK.renameLabel(oldName, newName)

Renames a label in the configuration and cascades the change to all cards.

Updates the label key in .kanban.json and replaces the old label name with the new one on every card that uses it.

Kind: instance method of KanbanSDK

Param Description
oldName The current label name.
newName The new label name.

Example

await sdk.renameLabel('bug', 'defect')
// Config updated: 'defect' now has bug's color/group
// All cards with 'bug' label now have 'defect' instead

kanbanSDK.getLabelsInGroup(group) ⇒

Returns a sorted list of label names that belong to the given group.

Labels without an explicit group property are not matched by any group name (they are considered ungrouped).

Kind: instance method of KanbanSDK
Returns: A sorted array of label names in the group.

Param Description
group The group name to filter by (e.g. 'Type', 'Priority').

Example

sdk.setLabel('bug', { color: '#e11d48', group: 'Type' })
sdk.setLabel('feature', { color: '#2563eb', group: 'Type' })

sdk.getLabelsInGroup('Type')
// ['bug', 'feature']

kanbanSDK.filterCardsByLabelGroup(group, boardId) ⇒

Returns all cards that have at least one label belonging to the given group.

Looks up all labels in the group via getLabelsInGroup, then filters cards to those containing any of those labels.

Kind: instance method of KanbanSDK
Returns: A promise resolving to an array of matching Card cards.

Param Description
group The group name to filter by.
boardId Optional board ID. Defaults to the workspace's default board.

Example

const typeCards = await sdk.filterCardsByLabelGroup('Type')
// Returns all cards with 'bug', 'feature', or any other 'Type' label

kanbanSDK.addAttachment(cardId, sourcePath, boardId) ⇒

Adds a file attachment to a card.

The source file is copied into the card's directory (alongside its markdown file) unless it already resides there. The attachment filename is added to the card's attachments array if not already present.

Kind: instance method of KanbanSDK
Returns: A promise resolving to the updated Card card.
Throws:

  • Error If the card is not found.
Param Description
cardId The ID of the card to attach the file to.
sourcePath Path to the file to attach. Can be absolute or relative.
boardId Optional board ID. Defaults to the workspace's default board.

Example

const card = await sdk.addAttachment('42', '/tmp/screenshot.png')
console.log(card.attachments) // ['screenshot.png']

kanbanSDK.removeAttachment(cardId, attachment, boardId) ⇒

Removes an attachment reference from a card's metadata.

This removes the attachment filename from the card's attachments array but does not delete the physical file from disk.

Kind: instance method of KanbanSDK
Returns: A promise resolving to the updated Card card.
Throws:

  • Error If the card is not found.
Param Description
cardId The ID of the card to remove the attachment from.
attachment The attachment filename to remove (e.g., 'screenshot.png').
boardId Optional board ID. Defaults to the workspace's default board.

Example

const card = await sdk.removeAttachment('42', 'old-screenshot.png')

kanbanSDK.listAttachments(cardId, boardId) ⇒

Lists all attachment filenames for a card.

Kind: instance method of KanbanSDK
Returns: A promise resolving to an array of attachment filename strings.
Throws:

  • Error If the card is not found.
Param Description
cardId The ID of the card whose attachments to list.
boardId Optional board ID. Defaults to the workspace's default board.

Example

const files = await sdk.listAttachments('42')
// ['screenshot.png', 'debug-log.txt']

kanbanSDK.getAttachmentDir(cardId, boardId) ⇒

Returns the absolute path to the attachment directory for a card.

For the default markdown/localfs path this is typically {column_dir}/attachments/. Other providers may return a different local directory or null when attachments are not directly browseable on disk.

Kind: instance method of KanbanSDK
Returns: A promise resolving to the absolute directory path, or null if the card is not found.

Param Description
cardId The ID of the card.
boardId Optional board ID. Defaults to the workspace's default board.

Example

const dir = await sdk.getAttachmentDir('42')
// '/workspace/.kanban/boards/default/backlog/attachments'

kanbanSDK.listComments(cardId, boardId) ⇒

Lists all comments on a card.

Kind: instance method of KanbanSDK
Returns: A promise resolving to an array of Comment objects.
Throws:

  • Error If the card is not found.
Param Description
cardId The ID of the card whose comments to list.
boardId Optional board ID. Defaults to the workspace's default board.

Example

const comments = await sdk.listComments('42')
for (const c of comments) {
  console.log(`${c.author}: ${c.content}`)
}

kanbanSDK.addComment(cardId, author, content, boardId) ⇒

Adds a comment to a card.

The comment is assigned an auto-incrementing ID (e.g., 'c1', 'c2') based on the existing comments. The card's modified timestamp is updated.

Kind: instance method of KanbanSDK
Returns: A promise resolving to the updated Card card (including the new comment).
Throws:

  • Error If the card is not found.
Param Description
cardId The ID of the card to comment on.
author The name of the comment author.
content The comment text content.
boardId Optional board ID. Defaults to the workspace's default board.

Example

const card = await sdk.addComment('42', 'alice', 'This needs more investigation.')
console.log(card.comments.length) // 1

kanbanSDK.updateComment(cardId, commentId, content, boardId) ⇒

Updates the content of an existing comment on a card.

Kind: instance method of KanbanSDK
Returns: A promise resolving to the updated Card card.
Throws:

  • Error If the card is not found.
  • Error If the comment is not found on the card.
Param Description
cardId The ID of the card containing the comment.
commentId The ID of the comment to update (e.g., 'c1').
content The new content for the comment.
boardId Optional board ID. Defaults to the workspace's default board.

Example

const card = await sdk.updateComment('42', 'c1', 'Updated: this is now resolved.')

kanbanSDK.deleteComment(cardId, commentId, boardId) ⇒

Deletes a comment from a card.

Kind: instance method of KanbanSDK
Returns: A promise resolving to the updated Card card.
Throws:

  • Error If the card is not found.
Param Description
cardId The ID of the card containing the comment.
commentId The ID of the comment to delete (e.g., 'c1').
boardId Optional board ID. Defaults to the workspace's default board.

Example

const card = await sdk.deleteComment('42', 'c2')

kanbanSDK.getLogFilePath(cardId, boardId) ⇒

Returns the absolute path to the log file for a card.

The log file is stored as the card attachment <cardId>.log through the active attachment.storage provider. File-backed providers usually return a stable workspace path, while remote providers may return a materialized temporary local file path instead.

Kind: instance method of KanbanSDK
Returns: A promise resolving to the log file path, or null if the card is not found.

Param Description
cardId The ID of the card.
boardId Optional board ID. Defaults to the workspace's default board.

kanbanSDK.listLogs(cardId, boardId) ⇒

Lists all log entries for a card.

Reads the card's .log file and parses each line into a LogEntry. Returns an empty array if no log file exists.

Kind: instance method of KanbanSDK
Returns: A promise resolving to an array of LogEntry objects.
Throws:

  • Error If the card is not found.
Param Description
cardId The ID of the card whose logs to list.
boardId Optional board ID. Defaults to the workspace's default board.

Example

const logs = await sdk.listLogs('42')
for (const entry of logs) {
  console.log(`[${entry.source}] ${entry.text}`)
}

kanbanSDK.addLog(cardId, text, options, boardId) ⇒

Adds a log entry to a card.

Appends a new line to the card's .log attachment via the active attachment-storage capability. Providers may handle this with a native append hook when available, otherwise the SDK falls back to a safe read/modify/write cycle. If the file does not exist, it is created and automatically added to the card's attachments array. The timestamp defaults to the current time if not provided. The source defaults to 'default' if not provided.

Kind: instance method of KanbanSDK
Returns: A promise resolving to the created LogEntry.
Throws:

  • Error If the card is not found.
Param Description
cardId The ID of the card to add the log to.
text The log message text. Supports inline markdown.
options Optional log entry parameters.
options.source Source/origin label. Defaults to 'default'.
options.timestamp ISO 8601 timestamp. Defaults to current time.
options.object Optional structured data to attach as JSON.
boardId Optional board ID. Defaults to the workspace's default board.

Example

const entry = await sdk.addLog('42', 'Build started')
const entry2 = await sdk.addLog('42', 'Deploy complete', {
  source: 'ci',
  object: { version: '1.2.3', duration: 42 }
})

kanbanSDK.clearLogs(cardId, boardId) ⇒

Clears all log entries for a card by deleting the .log file.

The log attachment reference is removed from the card's attachments array. When a local/materialized file exists, it is deleted best-effort as well. New log entries recreate the log attachment automatically.

Kind: instance method of KanbanSDK
Returns: A promise that resolves when the logs have been cleared.
Throws:

  • Error If the card is not found.
Param Description
cardId The ID of the card whose logs to clear.
boardId Optional board ID. Defaults to the workspace's default board.

Example

await sdk.clearLogs('42')

kanbanSDK.getBoardLogFilePath(boardId) ⇒

Returns the absolute path to the board-level log file for a given board.

The board log file is located at .kanban/boards/<boardId>/board.log, at the same level as the column folders.

Kind: instance method of KanbanSDK
Returns: The absolute path to board.log for the specified board.

Param Description
boardId Optional board ID. Defaults to the workspace's default board.

Example

const logPath = sdk.getBoardLogFilePath()
// '/workspace/.kanban/boards/default/board.log'

kanbanSDK.listBoardLogs(boardId) ⇒

Lists all log entries from the board-level log file.

Returns an empty array if the log file does not exist yet.

Kind: instance method of KanbanSDK
Returns: A promise that resolves to an array of LogEntry objects, oldest first.

Param Description
boardId Optional board ID. Defaults to the workspace's default board.

Example

const logs = await sdk.listBoardLogs()
// [{ timestamp: '2024-01-01T00:00:00.000Z', source: 'api', text: 'Card created' }]

kanbanSDK.addBoardLog(text, options, boardId) ⇒

Appends a new log entry to the board-level log file.

Creates the log file if it does not yet exist.

Kind: instance method of KanbanSDK
Returns: A promise that resolves to the created LogEntry.

Param Description
text The human-readable log message.
options Optional entry metadata: source label, ISO timestamp override, and structured object.
boardId Optional board ID. Defaults to the workspace's default board.

Example

const entry = await sdk.addBoardLog('Board archived', { source: 'cli' })

kanbanSDK.clearBoardLogs(boardId) ⇒

Clears all log entries for a board by deleting the board-level board.log file.

New log entries will recreate the file automatically. No error is thrown if the file does not exist.

Kind: instance method of KanbanSDK
Returns: A promise that resolves when the logs have been cleared.

Param Description
boardId Optional board ID. Defaults to the workspace's default board.

Example

await sdk.clearBoardLogs()

kanbanSDK.listColumns(boardId) ⇒

Lists all columns defined for a board.

Kind: instance method of KanbanSDK
Returns: An array of KanbanColumn objects in their current order.

Param Description
boardId Optional board ID. Defaults to the workspace's default board.

Example

const columns = sdk.listColumns('bugs')
// [{ id: 'triage', name: 'Triage', color: '#ef4444' }, ...]

kanbanSDK.addColumn(column, boardId) ⇒

Adds a new column to a board.

The column is appended to the end of the board's column list.

Kind: instance method of KanbanSDK
Returns: The full updated array of KanbanColumn objects for the board.
Throws:

  • Error If the board is not found.
  • Error If a column with the same ID already exists.
  • Error If the column ID is 'deleted' (reserved for soft-delete).
Param Description
column The column definition to add.
column.id Unique identifier for the column (used as status values on cards).
column.name Human-readable display name.
column.color CSS color string for the column header.
boardId Optional board ID. Defaults to the workspace's default board.

Example

const columns = sdk.addColumn(
  { id: 'blocked', name: 'Blocked', color: '#ef4444' },
  'default'
)

kanbanSDK.updateColumn(columnId, updates, boardId) ⇒

Updates the properties of an existing column.

Only the provided fields (name, color) are updated; the column's id cannot be changed.

Kind: instance method of KanbanSDK
Returns: The full updated array of KanbanColumn objects for the board.
Throws:

  • Error If the board is not found.
  • Error If the column is not found.
Param Description
columnId The ID of the column to update.
updates A partial object with the fields to update.
updates.name New display name for the column.
updates.color New CSS color string for the column.
boardId Optional board ID. Defaults to the workspace's default board.

Example

const columns = sdk.updateColumn('in-progress', {
  name: 'Working On',
  color: '#f97316'
})

kanbanSDK.removeColumn(columnId, boardId) ⇒

Removes a column from a board.

The column must be empty (no cards currently assigned to it). This operation cannot be undone.

Kind: instance method of KanbanSDK
Returns: A promise resolving to the updated array of KanbanColumn objects.
Throws:

  • Error If the board is not found.
  • Error If the column is not found.
  • Error If the column still contains cards.
  • Error If the column ID is 'deleted' (reserved for soft-delete).
Param Description
columnId The ID of the column to remove.
boardId Optional board ID. Defaults to the workspace's default board.

Example

const columns = await sdk.removeColumn('blocked', 'default')

kanbanSDK.cleanupColumn(columnId, boardId) ⇒

Moves all cards in the specified column to the deleted (soft-delete) column.

This is a non-destructive operation — cards are moved to the reserved deleted status and can be restored or permanently deleted later. The column itself is not removed.

Kind: instance method of KanbanSDK
Returns: A promise resolving to the number of cards that were moved.
Throws:

  • Error If the column is 'deleted' (no-op protection).
Param Description
columnId The ID of the column whose cards should be moved to deleted.
boardId Optional board ID. Defaults to the workspace's default board.

Example

const moved = await sdk.cleanupColumn('blocked')
console.log(`Moved ${moved} cards to deleted`)

kanbanSDK.purgeDeletedCards(boardId) ⇒

Permanently deletes all cards currently in the deleted column.

This is equivalent to "empty trash". All soft-deleted cards are removed from disk. This operation cannot be undone.

Kind: instance method of KanbanSDK
Returns: A promise resolving to the number of cards that were permanently deleted.

Param Description
boardId Optional board ID. Defaults to the workspace's default board.

Example

const count = await sdk.purgeDeletedCards()
console.log(`Permanently deleted ${count} cards`)

kanbanSDK.reorderColumns(columnIds, boardId) ⇒

Reorders the columns of a board.

The columnIds array must contain every existing column ID exactly once, in the desired new order.

Kind: instance method of KanbanSDK
Returns: The reordered array of KanbanColumn objects.
Throws:

  • Error If the board is not found.
  • Error If any column ID in the array does not exist.
  • Error If the array does not include all column IDs.
Param Description
columnIds An array of all column IDs in the desired order.
boardId Optional board ID. Defaults to the workspace's default board.

Example

const columns = sdk.reorderColumns(
  ['backlog', 'todo', 'blocked', 'in-progress', 'review', 'done'],
  'default'
)

kanbanSDK.getMinimizedColumns(boardId) ⇒

Returns the minimized column IDs for a board.

Kind: instance method of KanbanSDK
Returns: Array of column IDs currently marked as minimized.

Param Description
boardId Board to query (uses default board if omitted).

kanbanSDK.setMinimizedColumns(columnIds, boardId) ⇒

Sets the minimized column IDs for a board, persisting the state to the workspace config file. Stale or invalid IDs are silently dropped.

Kind: instance method of KanbanSDK
Returns: The sanitized list of minimized column IDs that was saved.

Param Description
columnIds Column IDs to mark as minimized.
boardId Board to update (uses default board if omitted).

kanbanSDK.getSettings() ⇒

Returns the global card display settings for the workspace.

Display settings control which fields are shown on card previews (e.g., priority badges, assignee avatars, due dates, labels).

Kind: instance method of KanbanSDK
Returns: The current CardDisplaySettings object.
Example

const settings = sdk.getSettings()
console.log(settings.showPriority) // true

kanbanSDK.updateSettings(settings)

Updates the global card display settings for the workspace.

The provided settings object fully replaces the display settings in the workspace configuration file (.kanban.json).

Kind: instance method of KanbanSDK

Param Description
settings The new CardDisplaySettings to apply.

Example

sdk.updateSettings({
  showPriority: true,
  showAssignee: true,
  showDueDate: false,
  showLabels: true
})

kanbanSDK.migrateToSqlite(dbPath) ⇒

Migrates all card data from the current storage engine to SQLite.

Cards are scanned from every board using the active engine, then written through the configured sqlite compatibility provider. After all data has been copied the workspace .kanban.json is updated with storageEngine: 'sqlite' and sqlitePath so that subsequent SDK instances resolve the same compatibility provider.

The existing markdown files are not deleted; they serve as a manual backup until the caller explicitly removes them.

Kind: instance method of KanbanSDK
Returns: The total number of cards migrated.
Throws:

  • Error If the current engine is already 'sqlite'.
Param Description
dbPath Path to the SQLite database file. Relative paths are resolved from the workspace root. Defaults to '.kanban/kanban.db'.

Example

const count = await sdk.migrateToSqlite()
console.log(`Migrated ${count} cards to SQLite`)

kanbanSDK.migrateToMarkdown() ⇒

Migrates all card data from the current sqlite compatibility provider back to markdown files.

Cards are scanned from every board in the SQLite database and written as individual .md files under .kanban/boards/<boardId>/<status>/. After migration the workspace .kanban.json is updated to remove the storageEngine/sqlitePath overrides so the default markdown engine is used by subsequent SDK instances.

The SQLite database file is not deleted; it serves as a manual backup.

Kind: instance method of KanbanSDK
Returns: The total number of cards migrated.
Throws:

  • Error If the current engine is already 'markdown'.

Example

const count = await sdk.migrateToMarkdown()
console.log(`Migrated ${count} cards to markdown`)

kanbanSDK.setDefaultBoard(boardId)

Sets the default board for the workspace.

Kind: instance method of KanbanSDK
Throws:

  • Error If the board does not exist.
Param Description
boardId The ID of the board to set as the default.

Example

sdk.setDefaultBoard('sprint-2')

kanbanSDK.listWebhooks() ⇒

Lists all registered webhooks.

Delegates to the resolved kl-webhooks-plugin provider. Throws if no webhook.delivery provider is installed.

Kind: instance method of KanbanSDK
Returns: Array of Webhook objects.
Throws:

  • Error When kl-webhooks-plugin is not installed.

kanbanSDK.createWebhook(webhookConfig) ⇒

Creates and persists a new webhook.

Delegates to the resolved kl-webhooks-plugin provider. Throws if no webhook.delivery provider is installed.

Kind: instance method of KanbanSDK
Returns: The newly created Webhook.
Throws:

  • Error When kl-webhooks-plugin is not installed.
Param Description
webhookConfig The webhook configuration.

kanbanSDK.deleteWebhook(id) ⇒

Deletes a webhook by its ID.

Delegates to the resolved kl-webhooks-plugin provider. Throws if no webhook.delivery provider is installed.

Kind: instance method of KanbanSDK
Returns: true if deleted, false if not found.
Throws:

  • Error When kl-webhooks-plugin is not installed.
Param Description
id The webhook ID to delete.

kanbanSDK.updateWebhook(id, updates) ⇒

Updates an existing webhook's configuration.

Delegates to the resolved kl-webhooks-plugin provider. Throws if no webhook.delivery provider is installed.

Kind: instance method of KanbanSDK
Returns: The updated Webhook, or null if not found.
Throws:

  • Error When kl-webhooks-plugin is not installed.
Param Description
id The webhook ID to update.
updates Partial webhook fields to merge.

KanbanSDK._authStorage

Kind: static property of KanbanSDK
Internal: Async-scoped auth carrier. Installed per request scope via runWithAuth.


KanbanSDK._runWithScopedAuth()

Kind: static method of KanbanSDK
Internal:


KanbanSDK._getScopedAuth()

Kind: static method of KanbanSDK
Internal:


KanbanSDK._cloneMergeValue()

Kind: static method of KanbanSDK
Internal:


KanbanSDK._deepMerge()

Recursively deep-merges source into a shallow copy of target.

  • Plain objects are merged recursively; later keys override earlier keys at every depth.
  • Arrays, primitives, and class instances in source replace the corresponding value in target (no concatenation of arrays).
  • target itself is never mutated; the caller receives the merged clone.

Kind: static method of KanbanSDK
Internal:


_isPlainObject()

Returns true when value is a plain-object merge candidate.

Accepts {} literals and Object.create(null) objects. Rejects arrays, class instances, primitives, and null. Used by KanbanSDK._deepMerge.

Kind: global function
Internal:


Types

AuthError

Typed error thrown by the SDK authorization seam when a policy plugin denies an action.

Host surfaces should catch this to return appropriate error responses (HTTP 403, CLI error output, MCP tool error) without leaking token material.

Kind: global class


CardStateError

Typed public error for card-state availability and identity failures.

ERR_CARD_STATE_IDENTITY_UNAVAILABLE means a configured auth.identity provider did not yield an actor. ERR_CARD_STATE_UNAVAILABLE means no active card.state backend is available.

Kind: global class


CARD_FORMAT_VERSION

Current card frontmatter schema version. Increment when the format changes.

Kind: global variable


DEFAULT_COLUMNS

The default set of five kanban columns provided when no custom columns are configured: Backlog, To Do, In Progress, Review, and Done.

Kind: global variable
Example

// Use as the initial column configuration
const config = { columns: [...DEFAULT_COLUMNS] }

ERR_CARD_STATE_IDENTITY_UNAVAILABLE

Stable machine-readable error for configured-auth card-state calls without a resolved identity.

Kind: global variable


ERR_CARD_STATE_UNAVAILABLE

Stable machine-readable error for card-state calls when no provider is active.

Kind: global variable


CARD_STATE_DEFAULT_ACTOR_MODE

Stable mode name for the auth-absent card-state default actor contract.

Kind: global variable


DEFAULT_CARD_STATE_ACTOR

Shared default actor contract for auth-absent card-state mode.

This actor is only valid when no real auth.identity provider is configured. All host surfaces should treat this as a stable public contract for both the built-in file-backed builtin backend and first-party compatibility backends such as sqlite.

Kind: global variable


CARD_STATE_UNREAD_DOMAIN

Stable built-in domain name for unread/read cursor persistence.

Kind: global variable


CARD_STATE_OPEN_DOMAIN

Stable built-in domain name for explicit actor-scoped open-card state persistence.

Kind: global variable


getTitleFromContent(content) ⇒

Extracts a title from markdown content by finding the first # heading. Falls back to the first non-empty line if no heading is found, or 'Untitled' if the content is empty.

Kind: global function
Returns: The extracted title string.

Param Description
content Raw markdown string to extract the title from.

Example

getTitleFromContent('# My Card\nSome body text')
// => 'My Card'

Example

getTitleFromContent('Just a line of text')
// => 'Just a line of text'

generateSlug(title) ⇒

Creates a filename-safe slug from a title string.

The slug is lowercased, stripped of special characters, limited to 50 characters, and falls back to 'card' if the result would be empty.

Kind: global function
Returns: A URL/filename-safe slug string.

Param Description
title The human-readable title to slugify.

Example

generateSlug('Build Dashboard UI')
// => 'build-dashboard-ui'

Example

generateSlug('Hello, World!!!')
// => 'hello-world'

formatFormDisplayName(formKey) ⇒

Converts a stable form key such as 'bug-report' into a human-friendly display name such as 'Bug Report'.

This is used as the default display name for reusable config-backed forms when FormDefinition.name is omitted.

Kind: global function
Returns: A human-readable title-cased name.

Param Description
formKey Stable config form key or resolved form identifier.

generateCardFilename(id, title) ⇒ id

Generates a card filename from an incremental numeric ID and a title.

The filename is composed of the ID prefix followed by a slugified title (e.g. '42-build-dashboard').

Kind: global function
Returns: id - A filename string in the format '-{slug}'.

Param Description
id The numeric card ID.
title The human-readable card title.

Example

generateCardFilename(42, 'Build Dashboard')
// => '42-build-dashboard'

extractNumericId(filenameOrId) ⇒

Extracts the numeric ID prefix from a filename or card ID string.

Looks for a leading sequence of digits optionally followed by a hyphen (e.g. '42-build-dashboard' yields 42).

Kind: global function
Returns: The parsed numeric ID, or null if no numeric prefix is found.

Param Description
filenameOrId A filename or card ID string such as '42-build-dashboard'.

Example

extractNumericId('42-build-dashboard')
// => 42

Example

extractNumericId('no-number')
// => null

sanitizeCard(card) ⇒

Strips the filePath property from a card before exposing it in webhook payloads or API responses. The file path is an internal implementation detail that should not be leaked externally.

Kind: global function
Returns: A copy of the card without the filePath field.

Param Description
card The card object to sanitize.

Example

const safe = sanitizeCard(card)
// safe.filePath is undefined

Configuration

DEFAULT_CONFIG

Default configuration used when no .kanban.json file exists or when fields are missing from an existing config. Includes a single 'default' board with the standard five columns.

Kind: global variable


CONFIG_FILENAME

The filename used for the kanban configuration file: '.kanban.json'.

Kind: global variable


configPath(workspaceRoot) ⇒

Returns the absolute path to the .kanban.json config file for a workspace.

Kind: global function
Returns: Absolute path to the config file.

Param Description
workspaceRoot Absolute path to the workspace root directory.

Example

configPath('/home/user/my-project')
// => '/home/user/my-project/.kanban.json'

readConfig(workspaceRoot) ⇒

Reads the kanban config from disk. If the file is missing or unreadable, returns the default config. If the file contains a v1 config, it is automatically migrated to v2 format and persisted back to disk.

Kind: global function
Returns: The parsed (and possibly migrated) kanban configuration.

Param Description
workspaceRoot Absolute path to the workspace root directory.

Example

const config = readConfig('/home/user/my-project')
console.log(config.defaultBoard) // => 'default'

writeConfig(workspaceRoot, config)

Writes the kanban config to disk as pretty-printed JSON.

Kind: global function

Param Description
workspaceRoot Absolute path to the workspace root directory.
config The kanban configuration to persist.

Example

const config = readConfig('/home/user/my-project')
config.defaultBoard = 'sprint-1'
writeConfig('/home/user/my-project', config)

getDefaultBoardId(workspaceRoot) ⇒

Returns the default board ID from the workspace config.

Kind: global function
Returns: The default board ID string (e.g. 'default').

Param Description
workspaceRoot Absolute path to the workspace root directory.

Example

const boardId = getDefaultBoardId('/home/user/my-project')
// => 'default'

getBoardConfig(workspaceRoot, boardId) ⇒

Returns the configuration for a specific board. If boardId is omitted, the default board is used.

Kind: global function
Returns: The board configuration object.
Throws:

  • Error If the resolved board ID does not exist in the config.
Param Description
workspaceRoot Absolute path to the workspace root directory.
boardId Optional board ID. Defaults to the workspace's default board.

Example

const board = getBoardConfig('/home/user/my-project', 'sprint-1')
console.log(board.name) // => 'Sprint 1'

Example

// Uses default board
const board = getBoardConfig('/home/user/my-project')

allocateCardId(workspaceRoot, boardId) ⇒

Allocates the next card ID for a board by reading and incrementing the board's nextCardId counter. The updated config is persisted to disk.

Kind: global function
Returns: The newly allocated numeric card ID.
Throws:

  • Error If the resolved board ID does not exist in the config.
Param Description
workspaceRoot Absolute path to the workspace root directory.
boardId Optional board ID. Defaults to the workspace's default board.

Example

const id = allocateCardId('/home/user/my-project')
// => 1 (first call), 2 (second call), etc.

syncCardIdCounter(workspaceRoot, boardId, existingIds)

Synchronizes the board's nextCardId counter to be greater than all existing card IDs. This prevents ID collisions when cards have been created outside the normal allocation flow (e.g. manual file creation).

Does nothing if existingIds is empty or the counter is already ahead.

Kind: global function

Param Description
workspaceRoot Absolute path to the workspace root directory.
boardId The board ID to synchronize.
existingIds Array of numeric card IDs currently present on the board.

Example

syncCardIdCounter('/home/user/my-project', 'default', [1, 5, 12])
// Board's nextCardId is now at least 13

configToSettings(config) ⇒

Extracts CardDisplaySettings from a KanbanConfig by picking out the global display-related fields.

Kind: global function
Returns: A CardDisplaySettings object with the current display preferences.

Param Description
config The kanban configuration to extract settings from.

Example

const config = readConfig('/home/user/my-project')
const settings = configToSettings(config)
console.log(settings.compactMode) // => true

settingsToConfig(config, settings) ⇒

Merges CardDisplaySettings back into a KanbanConfig, returning a new config object with the display fields updated.

Kind: global function
Returns: A new KanbanConfig with the display settings applied.

Param Description
config The existing kanban configuration to update.
settings The display settings to merge into the config.

Example

const config = readConfig('/home/user/my-project')
const updated = settingsToConfig(config, { ...configToSettings(config), compactMode: true })
writeConfig('/home/user/my-project', updated)

normalizeAuthCapabilities()

Normalizes auth capability selections into a complete runtime capability map.

Omitted auth providers default to the noop compatibility ids. When the external kl-auth-plugin package is installed those ids resolve there; otherwise core keeps a built-in compatibility fallback so behavior is unchanged when auth is not configured.

The input object is never mutated.

Kind: global function


normalizeCardStateCapabilities()

Normalizes card-state capability selections into a complete runtime capability map.

card.state is first-class and defaults to the built-in provider contract when omitted from .kanban.json.

The input object is never mutated.

Kind: global function


normalizeStorageCapabilities()

Normalizes legacy storage settings plus capability-based plugin selections into a complete runtime capability map.

Precedence:

  1. Explicit plugins[namespace]
  2. Legacy storageEngine / sqlitePath for card.storage
  3. Backward-compatible defaults (markdown + localfs)

Explicit built-in attachment.storage providers such as sqlite and mysql remain opt-in. Omitting attachment.storage never auto-switches it away from the legacy localfs default.

The input object is never mutated.

Kind: global function


normalizeWebhookCapabilities()

Normalizes webhook capability selections into a complete runtime capability map.

When no explicit provider is configured, defaults to { provider: 'webhooks' }, which maps to the kl-webhooks-plugin external package via WEBHOOK_PROVIDER_ALIASES. Core no longer provides a built-in webhook delivery fallback; hosts must install that package anywhere webhook CRUD or runtime delivery is expected to work.

The input object is never mutated.

Kind: global function


Parser

parseCardFile(content, filePath) ⇒

Parses a markdown file with YAML frontmatter into a Card object.

The file is expected to have a YAML frontmatter block delimited by --- at the top, followed by the card body content. Additional --- delimited blocks after the body are parsed as comment sections (if they contain comment: true), otherwise they are treated as part of the body content.

Kind: global function
Returns: The parsed Card object, or null if no valid frontmatter block is found.

Param Description
content The raw string content of the markdown file.
filePath The absolute file path, used to extract the card ID from the filename if no id field is present in the frontmatter.

serializeCard(card) ⇒

Serializes a Card object back to markdown with YAML frontmatter.

Produces a string with a --- delimited YAML frontmatter block containing all card metadata, followed by the card body content. Any comments attached to the card are appended as additional --- delimited sections at the end of the file.

Kind: global function
Returns: The complete markdown string ready to be written to a .md file.

Param Description
card The Card object to serialize.

File Utilities

findWorkspaceRootSync(startDir) ⇒

Synchronously walks up from startDir looking for a workspace root.

Preference order:

  1. A directory containing .git (authoritative project root)
  2. The nearest directory containing .kanban.json
  3. The nearest directory containing package.json

This ensures monorepo package folders do not shadow the actual repository root when a .git directory exists higher up the tree.

Kind: global function
Returns: The detected workspace root, or startDir on no match.

Param Description
startDir Directory to start scanning from.

resolveWorkspaceRoot(startDir, configFilePath) ⇒

Resolves the workspace root from either an explicit config file path or the current directory tree.

Kind: global function
Returns: The absolute workspace root path.

Param Description
startDir Optional directory to start scanning from. Defaults to process.cwd().
configFilePath Optional path to a specific .kanban.json file.

resolveKanbanDir(startDir, configFilePath) ⇒

Resolves the kanban directory without an explicit path by locating the workspace root, then reading kanbanDirectory from the effective .kanban.json file (defaults to '.kanban').

Kind: global function
Returns: The absolute path to the kanban directory.

Param Description
startDir Optional directory to start scanning from. Defaults to process.cwd().
configFilePath Optional path to a specific .kanban.json file.

getCardFilePath(kanbanDir, status, filename) ⇒

Constructs the full file path for a card markdown file.

Kind: global function
Returns: The absolute path to the card file, including the .md extension.

Param Description
kanbanDir The root kanban directory (e.g., .kanban).
status The status subdirectory name (e.g., backlog, in-progress).
filename The card filename without the .md extension.

ensureDirectories(kanbanDir) ⇒

Creates the kanban directory if it does not already exist.

Kind: global function
Returns: A promise that resolves when the directory has been created or already exists.

Param Description
kanbanDir The root kanban directory path to ensure exists.

ensureStatusSubfolders(kanbanDir, statuses) ⇒

Creates subdirectories for each status column under the kanban directory.

Kind: global function
Returns: A promise that resolves when all status subdirectories have been created.

Param Description
kanbanDir The root kanban directory containing status subdirectories.
statuses An array of status names to create as subdirectories.

moveCardFile(currentPath, kanbanDir, newStatus, attachments) ⇒

Moves a card file to a new status directory, handling name collisions by appending a numeric suffix (e.g., card-1.md, card-2.md). Optionally co-moves attachment files from the source directory to the target directory.

Kind: global function
Returns: A promise that resolves to the new absolute path of the moved card file.

Param Description
currentPath The current absolute path of the card file.
kanbanDir The root kanban directory.
newStatus The target status subdirectory to move the card into.
attachments Optional array of attachment filenames to co-move alongside the card.

renameCardFile(currentPath, newFilename) ⇒

Renames a card file in place within its current directory.

Kind: global function
Returns: A promise that resolves to the new absolute path of the renamed card file.

Param Description
currentPath The current absolute path of the card file.
newFilename The new filename without the .md extension.

getStatusFromPath(filePath, kanbanDir) ⇒

Extracts the status from a card's file path by examining the directory structure.

Expects the file to be located at {kanbanDir}/{status}/{filename}.md. If the relative path does not match this two-level structure, returns null.

Kind: global function
Returns: The status string extracted from the path, or null if the path structure is unexpected.

Param Description
filePath The absolute path to the card file.
kanbanDir The root kanban directory used to compute the relative path.

Auth Plugin Contracts

WORKSPACE_ROOT

The pnpm workspace root directory, resolved once at module load time.

  • Inside the monorepo checkout: the absolute path to the repository root (contains pnpm-workspace.yaml).
  • Outside the monorepo (standalone npm install): null.

Used by the plugin loader to probe packages/{name} as the primary workspace-local resolution path during the staged monorepo migration.

Kind: global variable
Internal:


RBAC_USER_ACTIONS

Actions available to the user role.

Covers non-destructive card-interaction operations: form submission, comments, attachments, action triggers, and card-level log writes.

Kind: global variable


RBAC_MANAGER_ACTIONS

Actions available to the manager role (includes all user actions).

Adds card lifecycle mutations (create, update, move, transfer, delete), board-action triggers, card-log clearing, and board-level log writes.

Kind: global variable


RBAC_ADMIN_ACTIONS

Actions available to the admin role (includes all manager and user actions).

Adds all destructive and configuration operations: board create/update/delete, settings, webhooks, labels, columns, board-action config edits, board-log clearing, migrations, default-board changes, and deleted-card purge.

Kind: global variable


RBAC_ROLE_MATRIX

Fixed RBAC role matrix keyed by RbacRole.

Each entry maps to the complete set of canonical action names that the role is permitted to perform. This is the single canonical source of truth consumed by the shipped rbac auth provider pair and by host tests that verify denial semantics. Hosts must not replicate or extend this matrix locally.

Kind: global variable
Example

// Check whether a resolved role may perform an action:
const allowed = RBAC_ROLE_MATRIX['manager'].has('card.create') // true
const denied  = RBAC_ROLE_MATRIX['user'].has('board.delete')   // false

NOOP_IDENTITY_PLUGIN

No-op identity provider resolved from kl-auth-plugin when available.

Kind: global variable


NOOP_POLICY_PLUGIN

No-op policy provider resolved from kl-auth-plugin when available.

Kind: global variable


RBAC_IDENTITY_PLUGIN

RBAC identity provider resolved from kl-auth-plugin when available.

Kind: global variable


RBAC_POLICY_PLUGIN

RBAC policy provider resolved from kl-auth-plugin when available.

Kind: global variable


PROVIDER_ALIASES

Maps short user-facing provider ids to their installable npm package names.

The ids sqlite and mysql are compatibility aliases that keep the familiar user-visible provider id in .kanban.json while delegating implementation ownership to standalone, versioned packages. When a provider id is listed here and no built-in implementation is registered, the resolver loads the mapped package name and issues install hints that reference it.

Install targets:

  • sqlitenpm install kl-sqlite-storage
  • mysqlnpm install kl-mysql-storage

Both packages must export cardStoragePlugin and attachmentStoragePlugin with CJS entry dist/index.cjs.

Kind: global variable


CARD_STATE_PROVIDER_ALIASES

Maps short card.state provider ids to their installable npm package names.

  • sqlitenpm install kl-sqlite-card-state

External packages must export createCardStateProvider(context) or a cardStateProvider/default object with a manifest that provides 'card.state'.

Kind: global variable


WEBHOOK_PROVIDER_ALIASES

Maps short webhook provider ids to their installable npm package names.

  • webhooksnpm install kl-webhooks-plugin

External packages must export webhookProviderPlugin (or a default export) with a manifest that provides 'webhook.delivery' and CRUD methods.

Kind: global variable


AUTH_PROVIDER_ALIASES

Maps built-in auth compatibility ids to the external auth package.

  • noopnpm install kl-auth-plugin
  • rbacnpm install kl-auth-plugin

Kind: global variable


BUILTIN_ATTACHMENT_IDS

Set of provider ids that are handled as built-in attachment plugins.

Kind: global variable


FALLBACK_NOOP_IDENTITY_PLUGIN

Built-in compatibility no-op identity provider. Always resolves to null (anonymous).

Kind: global constant


FALLBACK_NOOP_POLICY_PLUGIN

Built-in compatibility no-op policy provider. Always returns { allowed: true } (allow-all).

Kind: global constant


BUILTIN_CARD_PLUGINS

Registry of built-in card.storage plugins keyed by provider id.

Kind: global constant


findWorkspaceRoot()

Walks up from startDir looking for a pnpm-workspace.yaml file that marks the workspace root. Returns the first matching ancestor directory, or null when running outside the monorepo (e.g., after a standalone npm install by a user).

Kind: global function
Internal:


createRbacIdentityPlugin(principals)

Creates a runtime-validated RBAC identity plugin backed by a host-supplied principal registry.

Tokens are treated as opaque strings and looked up in principals. A token present in the map resolves to the associated principal entry; any token absent from the map resolves to null (anonymous / deny). Roles are taken from the registry entry and are never inferred from token text.

Token values and principal material — including role assignments — must remain in host/runtime configuration only and must never appear in .kanban.json, diagnostics, or log output.

Kind: global function

Param Description
principals Map of opaque token → RbacPrincipalEntry, owned and populated by the host at startup.

canUseDefaultCardStateActor()

Returns true only when the auth configuration permits the stable default single-user card-state actor.

Any non-noop auth.identity provider disables the fallback, even if the provider later resolves no caller for a specific request.

Kind: global function


tryLoadWorkspacePackage()

Tries to load an external plugin from the workspace-local packages/ directory (monorepo layout). Requires WORKSPACE_ROOT to be discovered; throws MODULE_NOT_FOUND when the path does not exist so the caller can distinguish "not present in monorepo" from other errors.

Kind: global function
Internal:


tryLoadGlobalPackage()

Tries to load an external plugin from the global npm node_modules directory. The global prefix is derived from the Node.js binary path (process.execPath). On Unix-like systems the global node_modules directory is {prefix}/lib/node_modules; on Windows it is {prefix}/node_modules.

Kind: global function
Internal:


tryLoadSDKExtensionPlugin()

Attempts to load an optional sdkExtensionPlugin export from an active package. Returns null silently when the export is absent or does not satisfy the SDKExtensionPlugin contract so that missing extensions never prevent capability bag resolution.

Kind: global function
Internal:


resolveSDKExtensions(capabilities, authCapabilities, webhookCapabilities) ⇒

Collects SDK extension contributions from all active external packages by probing each for the optional sdkExtensionPlugin named export.

Kind: global function
Returns: De-duplicated list of resolved SDK extension entries.
Internal:

Param Description
capabilities Resolved storage capability selections.
authCapabilities Resolved auth capability selections.
webhookCapabilities Resolved webhook capability selections, or null.

loadExternalCardPlugin()

Lazily loads an external npm card-storage plugin. Returns a deterministic, actionable error when the package is not installed rather than letting Node throw a confusing MODULE_NOT_FOUND.

Kind: global function
Internal:


loadExternalAttachmentPlugin()

Lazily loads an external npm attachment-storage plugin. Returns a deterministic, actionable error when the package is not installed.

Kind: global function
Internal:


isValidSDKEventListenerPlugin()

Type guard for SDKEventListenerPlugin — validates that plugin has the register / unregister lifecycle and a valid manifest.

Kind: global function
Internal:


loadWebhookPluginPack()

Lazily loads an external npm webhook provider plugin.

Accepts packages that export:

  • webhookProviderPlugin (or a default): CRUD webhook provider.
  • webhookListenerPlugin (optional): a SDKEventListenerPlugin for runtime delivery.
  • WebhookListenerPlugin (optional): a class export constructed with the workspace root when the runtime listener needs workspace-local config.

Returns a deterministic, actionable error when the package is not installed or does not export the expected shape.

Kind: global function
Internal:


resolveWebhookPlugins()

Attempts to resolve a webhook provider and its runtime delivery listener from a normalized ProviderRef.

Listener resolution priority:

  1. webhookListenerPlugin: SDKEventListenerPlugin named export from package.
  2. WebhookListenerPlugin class export constructed with the workspace root.
  3. null — no webhook runtime listener is available.

Returns null when the package is simply not installed yet (not-installed error). Throws for any other loading or validation error.

Kind: global function
Internal:


createBuiltinAuthListenerPlugin(authIdentity, authPolicy, getAuthContext) ⇒

Creates the built-in auth event listener plugin that enforces authorization during the before-event phase.

The listener resolves identity from the active request-scoped auth carrier, evaluates the configured policy for BeforeEventPayload.event, emits auth.allowed / auth.denied, and throws AuthError when a mutation must be vetoed.

Kind: global function
Returns: A registered SDKEventListenerPlugin for the auth runtime seam.

Param Description
authIdentity Resolved identity provider used to establish the caller.
authPolicy Resolved policy provider used to authorize each action.
getAuthContext Optional accessor for the active scoped auth context.

collectActiveExternalPackageNames(config) ⇒

Collects the canonical set of external npm package names that should be probed for plugin extension contributions (e.g. cliPlugin, standaloneHttpPlugin) from a raw workspace config object.

Applies the same alias translations used by the standalone HTTP plugin discovery path (collectStandaloneHttpPackageNames), and reads both the normalized plugins key and the legacy webhookPlugin key so that webhook-only configurations deterministically activate the webhook package for all surfaces.

When no explicit webhook provider is configured, falls through to the default 'webhooks''kl-webhooks-plugin' alias, matching the behaviour of normalizeWebhookCapabilities and the standalone discovery path so that both surfaces activate the same set of packages.

Kind: global function
Returns: Deduplicated list of external npm package names to probe for extensions.

Param Description
config Raw workspace config. Only the consumed fields need to be present.

resolveMcpPlugins()

Resolves optional MCP tool plugins from the canonical active-package set.

Reuses collectActiveExternalPackageNames so MCP follows the same activation model as CLI and standalone HTTP discovery.

Kind: global function


resolveCapabilityBag(capabilities, kanbanDir, authCapabilities, webhookCapabilities)

Resolves a fully typed ResolvedCapabilityBag from a normalized ResolvedCapabilities map.

Attachment storage fallback precedence:

  1. Explicit provider in capabilities['attachment.storage'] (built-in or external)
  2. Card storage engine's explicit built-in attachment provider
  3. Built-in localfs

Auth plugins default to the noop compatibility providers (anonymous identity, allow-all policy) when authCapabilities is not supplied, preserving the current open-access behavior.

Kind: global function

Param Description
capabilities Normalized provider selections from normalizeStorageCapabilities.
kanbanDir Absolute path to the .kanban directory.
authCapabilities Optional normalized auth provider selections from normalizeAuthCapabilities. Defaults to noop providers.
webhookCapabilities Optional normalized webhook provider selections from normalizeWebhookCapabilities. When omitted, webhook provider resolution is skipped and bag.webhookProvider is null.

Data Storage

Cards are stored as markdown files with YAML frontmatter:

.kanban/
  boards/
    default/
      backlog/
        1-implement-auth.md
        2-setup-ci.md
      todo/
      in-progress/
      review/
      done/
    bugs/
      new/
      investigating/
      fixed/
  .kanban.json          # Board config, forms, labels, settings, and webhook definitions

Each card file contains YAML frontmatter (id, status, priority, assignee, dates, labels, order) followed by markdown content and optional comment sections.


Error Handling

All SDK methods throw standard Error objects with descriptive messages:

Error Cause
Card not found: {id} No card matches the given ID
Board not found: {id} Board ID doesn't exist in config
Board already exists: {id} Duplicate board ID on create
Cannot delete the default board: {id} Attempted to delete default board
Cannot delete board "{id}": N card(s) still exist Board has cards
Column not found: {id} Column ID doesn't exist
Column already exists: {id} Duplicate column ID on add
Cannot remove column "{id}": N card(s) still in this column Column has cards
Must include all column IDs when reordering Missing columns in reorder
Comment not found: {id} Comment ID doesn't exist