SDK Reference
Complete API reference for the @scrydon/sdk-authoring/integrations SDK
Installation
bun add -d @scrydon/sdk-authoring/integrations zodnpm install --save-dev @scrydon/sdk-authoring/integrations zodImport Paths
The SDK uses explicit subpath exports — there is no root barrel import.
// Definition helpers (all define* functions)
import {
defineVendor, defineProduct, defineTool, defineBlock, defineTriggerBlock,
defineCapabilityLLM, defineCapabilitySTT, defineCapabilityTTS,
defineCapabilityEmbedding, defineCapabilityVideo, defineCapabilityOCR,
defineCapabilityWebhook, defineCapabilityDiscovery,
} from "@scrydon/sdk-authoring/integrations/define";
// Runtime types (used in execute() signatures)
import type {
PureContext, PureContextAuth, ToolResponse, ExecutorResult,
RealtimeSession, RealtimeMessage,
} from "@scrydon/sdk-authoring/integrations/context";
// Credential narrowing helpers (throw CredentialKindError on kind mismatch)
import {
requireOAuthToken, requireOAuth,
requireApiKey, requireBasicAuth, requireBotToken,
} from "@scrydon/sdk-authoring/integrations/context";
// Manifest types (for advanced use cases)
import type { ManifestSchema } from "@scrydon/sdk-authoring/integrations/manifest";defineVendor(config)
Top-level container for an integration. The entry point's default export must be a defineVendor() result.
interface VendorInput {
/** Unique vendor ID — lowercase alphanumeric + hyphens, starts with letter */
id: string;
/** Display name */
name: string;
/** Semantic version (e.g. "1.0.0") */
version: string;
/** Short description */
description?: string;
/** Hex brand color (e.g. "#FF6B35") */
color?: string;
/** SVG icon as a string */
icon: string;
/** Vendor website URL */
website?: string;
/** Documentation URL */
docsUrl?: string;
/** Categories (e.g. ["tools"], ["llm"], ["database"]) */
categories?: string[];
/** Whether this vendor is enabled by default for new orgs */
defaultEnabled?: boolean;
/** Whether this vendor supports system-mode (client_credentials) */
supportsSystemMode?: boolean;
/** Whether this vendor requires external network connectivity */
connectivity?: "cloud" | "local" | "hybrid";
/** Authentication configuration */
auth: AuthConfig;
/** Admin-configurable fields (e.g. base URL for self-hosted services) */
configFields?: ConfigFieldInput[];
/** Vendor-level secrets (resolved per-invocation via Dapr Secret Store) */
secrets?: SecretInput[];
/** One or more products */
products: ProductDefinition[];
/** Optional protocol definitions */
protocols?: ProtocolDefinition[];
/** LLM provider configuration (for AI model vendors) */
llm?: VendorLLMDef;
}Authentication Config
The auth field defines which credential types your vendor supports:
auth: {
credentials: {
none: { type: "none" },
},
default: "none",
}auth: {
credentials: {
apiKey: {
type: "apiKey",
label: "API Key",
description: "Your service API key",
headerName: "Authorization", // HTTP header name
headerPrefix: "Bearer", // Prefix before the key value
},
},
default: "apiKey",
}auth: {
credentials: {
oauth: {
type: "oauth",
label: "Connect Account",
authorizationUrl: "https://example.com/oauth/authorize",
tokenUrl: "https://example.com/oauth/token",
scopes: ["read", "write"],
pkce: true,
useBasicAuth: false,
supportsRefreshTokenRotation: true,
},
},
default: "oauth",
}auth: {
credentials: {
botToken: {
type: "botToken",
label: "Bot Token",
description: "Your bot authentication token",
headerName: "Authorization",
headerPrefix: "Bot",
},
},
default: "botToken",
}You can define multiple credential types and let the user choose:
auth: {
credentials: {
oauth: { type: "oauth", /* ... */ },
apiKey: { type: "apiKey", /* ... */ },
},
default: "oauth", // Which one to show first
}Config Fields
For vendors that need admin-configured settings (e.g. a self-hosted base URL):
configFields: [
{
key: "baseUrl",
label: "Base URL",
placeholder: "https://your-instance.example.com",
description: "The base URL of your self-hosted instance",
required: true,
type: "url",
},
],Secrets
For vendor-level secrets that are stored in the Dapr Secret Store:
secrets: [
{
key: "WEBHOOK_SIGNING_SECRET",
label: "Webhook Signing Secret",
description: "Used to verify incoming webhook payloads",
required: true,
},
],Secrets are available at runtime via ctx.secrets["WEBHOOK_SIGNING_SECRET"].
defineProduct(config)
Groups tools and a block under a product that can be enabled/disabled per organization.
interface ProductInput {
/** Unique product ID within the vendor */
id: string;
/** Display name */
name: string;
/** Short description */
description?: string;
/** SVG icon as string (falls back to vendor icon if omitted) */
icon?: string;
/** Which credential from auth.credentials this product uses */
credentialRef?: string;
/** OAuth scopes required by this product */
credentialScopes?: string[];
/** Runtime capabilities */
capabilities: {
tools?: ToolDefinition[];
triggers?: TriggerDefinition[];
runtimes?: {
llm?: LLMCapability;
stt?: STTCapability;
tts?: TTSCapability;
embedding?: EmbeddingCapability;
video?: VideoCapability;
ocr?: OCRCapability;
};
webhooks?: WebhookCapability;
discovery?: DiscoveryCapability;
};
/** The block definition for the workflow editor */
block: BlockDefinition;
/** NPM package dependencies (for risk assessment at upload time) */
dependencies?: Array<{
type: "npm";
package: string;
version: string;
reason?: string;
}>;The dependencies array is for human-readable context — each entry includes a reason explaining why the dependency is needed. The CLI automatically generates a machine-readable SBOM (meta/sbom.cdx.json) that captures the complete set of bundled packages with versions and licenses. Both are complementary: declared dependencies explain intent, the SBOM provides the auditable inventory.
/** System-mode (client_credentials) configuration */
systemMode?: {
supported: boolean;
permissions?: string[];
resources?: Array<{
resourceType: string;
displayName: string;
description?: string;
required: boolean;
allowMultiple?: boolean;
}>;
};
}System Consent Extensions
OAuth credentials can declare manifest-safe extension points for provider-specific setup flows such as Microsoft admin consent. Keep this logic owned by the integration: the manifest should describe the provider URL shape, the required organization config fields, and the callback query parameters.
For most providers, implement system consent with a declarative redirect template. This is the supported path when the platform only needs to build a URL from runtime values:
auth: {
credentials: {
oauth: {
type: "oauth",
label: "Microsoft Account",
authorizationUrl: "https://login.microsoftonline.com/{tenantId}/oauth2/v2.0/authorize",
tokenUrl: "https://login.microsoftonline.com/{tenantId}/oauth2/v2.0/token",
requiredConfig: ["tenantId"],
supportsClientCredentials: true,
clientCredentialScopes: ["https://graph.microsoft.com/.default"],
extensions: {
systemConsent: {
kind: "redirect-template",
urlTemplate: "https://login.microsoftonline.com/{tenantId}/adminconsent",
params: {
client_id: "{clientId}",
redirect_uri: "{redirectUri}",
scope: "{scope}",
state: "{state}",
},
requiredConfig: ["tenantId"],
callback: {
successParam: "admin_consent",
tenantParam: "tenant",
},
},
},
},
},
}The platform substitutes these placeholders:
| Placeholder | Value |
|---|---|
{clientId} | OAuth client ID resolved for the organization |
{redirectUri} | Platform admin-consent callback URL |
{scope} | Space-joined clientCredentialScopes |
{state} | CSRF state generated by the platform |
Any requiredConfig key, such as {tenantId} | Organization provider config value |
If a provider cannot be represented as a URL template, declare a handler reference in the manifest and implement the referenced method in the vendor runtime. The method should be pure: accept resolved runtime values, validate any provider-specific config it requires, and return the redirect URL instead of hardcoding provider logic in the platform.
extensions: {
systemConsent: {
kind: "handler",
handlerRef: "microsoft.systemConsent.buildUrl",
callback: {
handlerRef: "microsoft.systemConsent.callback",
},
},
}type SystemConsentBuildUrlInput = {
clientId: string;
redirectUri: string;
state?: string;
scopes: string[];
providerConfig: Record<string, string | undefined>;
};
export async function buildUrl(input: SystemConsentBuildUrlInput): Promise<string> {
const tenantId = input.providerConfig.tenantId;
if (!tenantId) {
throw new Error("Microsoft admin consent requires tenantId");
}
const url = new URL(`https://login.microsoftonline.com/${tenantId}/adminconsent`);
url.searchParams.set("client_id", input.clientId);
url.searchParams.set("redirect_uri", input.redirectUri);
url.searchParams.set("scope", input.scopes.join(" "));
if (input.state) {
url.searchParams.set("state", input.state);
}
return url.toString();
}
type SystemConsentCallbackInput = {
query: Record<string, string | undefined>;
providerConfig: Record<string, string | undefined>;
};
export async function callback(input: SystemConsentCallbackInput) {
return {
approved: input.query.admin_consent === "True",
tenantId: input.query.tenant,
};
}Handler references are manifest metadata. Uploaded bundles should use
kind: "redirect-template" today unless the host application has explicitly
wired runtime execution for the referenced handler.
Multi-Product Vendors
Vendors like Google or Microsoft have multiple products. Each product gets its own block in the workflow editor and can be enabled independently:
export default defineVendor({
id: "acme",
// ...
products: [
defineProduct({
id: "acme-crm",
name: "Acme CRM",
block: crmBlock,
capabilities: { tools: [listContacts, createContact] },
}),
defineProduct({
id: "acme-email",
name: "Acme Email",
block: emailBlock,
capabilities: { tools: [sendEmail, listInbox] },
}),
],
});defineTool(config)
Defines the runtime logic for a tool. This is where your actual API calls, data transformations, or computations happen.
interface ToolInput<TInput, TOutput> {
/** Unique tool ID — convention: {vendor}:{product}:{action} */
id: string;
/** Display name */
name: string;
/** Semantic version */
version: string;
/** Description shown to users and LLM agents */
description?: string;
/** Zod schema for input validation */
input: z.ZodType<TInput>;
/** Zod schema for output validation */
output: z.ZodType<TOutput>;
/** Parameter metadata — controls visibility in the UI and to LLMs */
params?: Record<string, ParamDef>;
/** The function that runs when this tool is invoked */
execute: (input: TInput, ctx: PureContext) => Promise<ToolResponse<TOutput>>;
}
interface ParamDef {
type: string;
required?: boolean;
description?: string;
default?: unknown;
/** Controls where this parameter appears */
visibility?: "user-only" | "user-or-llm" | "hidden";
}Parameter Visibility
| Visibility | Who can provide the value | Use case |
|---|---|---|
user-or-llm | User sets it in the UI, or an AI agent generates it | Most parameters |
user-only | Only the user can configure it (hidden from LLM) | Connection settings, credentials |
hidden | Not shown in UI or to LLM — set programmatically | Internal IDs, computed values |
Execute Function
The execute function receives validated input and a PureContext:
import { requireOAuthToken } from "@scrydon/sdk-authoring/integrations/context";
async execute(input, ctx) {
// Use the logger (visible in workflow execution logs)
ctx.logger.info(`Processing request for org ${ctx.execution.orgId}`);
// Narrow on ctx.auth.kind before reading credential fields.
// This example assumes the vendor declares an OAuth credential —
// requireOAuthToken throws a CredentialKindError if the kind doesn't match.
const accessToken = requireOAuthToken(ctx.auth);
// Make authenticated API calls
const response = await fetch("https://api.example.com/data", {
headers: {
Authorization: `Bearer ${accessToken}`,
"Content-Type": "application/json",
},
body: JSON.stringify(input),
});
if (!response.ok) {
return {
success: false,
output: { error: `API returned ${response.status}` },
error: `HTTP ${response.status}: ${response.statusText}`,
};
}
const data = await response.json();
return {
success: true,
output: data,
metadata: { requestId: response.headers.get("x-request-id") },
};
},PureContext
The PureContext interface is the only interface between the platform and bundle code. It is injected into every execute() call at runtime:
/**
* Discriminated union of all credential shapes the platform can inject.
* Always narrow on `kind` before reading credential fields.
* Import narrowing helpers from @scrydon/sdk-authoring/integrations/context:
* requireOAuthToken(auth) → string (accessToken, throws on mismatch)
* requireOAuth(auth) → { accessToken, refreshToken?, tokenType?, expiresAt? }
* requireApiKey(auth) → string (apiKey)
* requireBasicAuth(auth) → { username, password }
* requireBotToken(auth) → string (botToken)
* Each helper throws a CredentialKindError with an actionable message on mismatch.
*/
type PureContextAuth =
| { kind: "oauth"; accessToken: string; refreshToken?: string; tokenType?: string; expiresAt?: number }
| { kind: "apiKey"; apiKey: string }
| { kind: "basicAuth"; username: string; password: string }
| { kind: "botToken"; botToken: string }
| { kind: "none" };
interface PureContext {
/** Credential resolved by the platform before invocation */
auth: PureContextAuth;
/** Execution metadata for logging and correlation */
execution: {
executionId: string; // Unique execution run ID
workflowId?: string; // Workflow ID (if running in a workflow)
nodeId?: string; // Block node ID in the workflow
orgId: string; // Organization ID
workspaceId?: string; // Workspace ID
userId?: string; // User who triggered the execution
};
/** Structured logger — console calls are intercepted in the sandbox */
logger: {
info(message: string, ...args: unknown[]): void;
warn(message: string, ...args: unknown[]): void;
error(message: string, ...args: unknown[]): void;
debug(message: string, ...args: unknown[]): void;
};
/** Vendor secrets configured by org admin (resolved per-invocation via Dapr Secret Store) */
secrets: Record<string, string>;
/** Present when executing via an Integration Profile — contains profile-specific overrides */
profileConfig?: Record<string, unknown>;
}PureContext is imported from @scrydon/sdk-authoring/integrations/context. The platform constructs it before each tool invocation — your code never needs to create one manually. All fields except auth and execution may be empty objects if not applicable. auth is a kind-discriminated union (PureContextAuth); always narrow on auth.kind or use a require* helper before accessing credential-specific fields. See Authentication Modes for the full per-mode shape reference.
ToolResponse
Every execute() must return a ToolResponse:
interface ToolResponse<T = unknown> {
/** Whether the tool execution succeeded */
success: boolean;
/** The typed output data */
output: T;
/** Error message (shown to user if success is false) */
error?: string;
/** Optional metadata (logged but not passed to downstream blocks) */
metadata?: Record<string, unknown>;
}defineBlock(config)
Defines the workflow editor UI — how the block appears, what form fields it has, and how data flows through it.
interface BlockInput {
/** Unique block type — lowercase with underscores (e.g. "acme_crm") */
type: string;
/** Display name in the block palette */
name: string;
/** Short description */
description?: string;
/** Block category — use "integration" for bundle blocks */
category: string;
/** Background color in hex */
bgColor?: string;
/** Auth mode: "none", "apiKey", "oauth", "botToken" */
authMode?: string;
/** Form fields displayed in the block panel */
subBlocks?: SubBlockInput[];
/** Which tools this block can invoke */
tools?: {
access: string[];
config?: {
/** Dynamic tool selection based on user input */
tool: (params: Record<string, any>) => string;
/** Parameter transformation before passing to tool */
params?: (params: Record<string, any>) => any;
};
};
/** Input connections from upstream blocks */
inputs?: Record<string, { type: string; description?: string }>;
/** Output connections to downstream blocks */
outputs?: Record<string, { type: string; description?: string }>;
/** Trigger configuration (for trigger blocks) */
triggers?: { enabled: boolean; available: string[] };
}SubBlock Types
SubBlocks are the form fields that appear when a user clicks on a block:
| Type | Description | Key Props |
|---|---|---|
short-input | Single-line text input | placeholder, password, readOnly, showCopyButton |
long-input | Multi-line textarea | placeholder |
code | Code editor with syntax highlighting | placeholder, mode |
dropdown | Select menu | options: [{ label, id }] |
combobox | Searchable dropdown | options, fetchOptions |
slider | Range slider | min, max, step |
switch | Toggle switch | defaultValue |
oauth-input | OAuth credential selector | serviceId, requiredScopes |
SubBlock Definition
interface SubBlockInput {
/** Unique field ID within the block */
id: string;
/** Field label */
title?: string;
/** SubBlock type */
type: string;
/** Layout: "full" (default) or "half" */
layout?: "full" | "half";
/** Whether this field is required */
required?: boolean;
/** Placeholder text */
placeholder?: string;
/** Mask input as password dots */
password?: boolean;
/** Default value */
defaultValue?: unknown;
/** Options for dropdown/combobox */
options?: Array<{ label: string; id: string }>;
/** Help text shown below the field */
description?: string;
/** Conditional visibility based on another field's value */
condition?: { field: string; value: string };
/** Whether the field is read-only */
readOnly?: boolean;
/** Show a copy-to-clipboard button */
showCopyButton?: boolean;
/** Hide this field from the UI */
hidden?: boolean;
}Dynamic Tool Selection
When a block has multiple tools, use tools.config.tool to select which one runs:
defineBlock({
// ...
subBlocks: [
{
id: "operation",
title: "Operation",
type: "dropdown",
options: [
{ label: "Create", id: "create" },
{ label: "Read", id: "read" },
{ label: "Update", id: "update" },
{ label: "Delete", id: "delete" },
],
},
// ... other fields
],
tools: {
access: ["acme_create", "acme_read", "acme_update", "acme_delete"],
config: {
tool: (params) => `acme_${params.operation}`,
},
},
});Conditional Visibility
Show or hide fields based on other field values:
subBlocks: [
{
id: "authType",
title: "Auth Type",
type: "dropdown",
options: [
{ label: "API Key", id: "apiKey" },
{ label: "Username/Password", id: "basic" },
],
},
{
id: "apiKey",
title: "API Key",
type: "short-input",
password: true,
condition: { field: "authType", value: "apiKey" },
},
{
id: "username",
title: "Username",
type: "short-input",
condition: { field: "authType", value: "basic" },
},
{
id: "password",
title: "Password",
type: "short-input",
password: true,
condition: { field: "authType", value: "basic" },
},
],defineTriggerBlock(config)
Defines a trigger block — a first-class workflow member that renders in the "Triggers" sidebar section and carries runtime metadata describing how it fires (webhook, polling, or both). The category is auto-set to "trigger".
interface TriggerBlockInput {
/** Unique block type */
type: string;
/** Display name */
name: string;
/** Description */
description?: string;
/** Background color in hex */
bgColor?: string;
/** Auth mode: "none", "apiKey", "oauth", "botToken" */
authMode?: string;
/** Form fields for trigger configuration */
subBlocks?: SubBlockInput[];
/** Which tools this trigger block can invoke */
tools?: {
access: string[];
config?: {
tool?: (params: Record<string, any>) => string;
params?: (params: Record<string, any>) => any;
};
};
/** Input connections */
inputs?: Record<string, { type: string; description?: string }>;
/** Output schema — what data the trigger emits */
outputs?: Record<string, { type: string; description?: string }>;
/** Provider identifier */
provider?: string;
/** Semantic version */
version?: string;
/** Runtime configuration — how events reach the workflow engine */
runtime?: {
webhook?: {
method?: "POST" | "GET" | "PUT" | "DELETE";
headers?: Record<string, string>;
};
polling?: PollingProvider;
};
}Secrets Management
Vendors can declare secrets that are stored encrypted at rest and resolved per-invocation. Secrets are scoped to the organization and vendor, so each org has its own isolated set of credentials.
Declaring Secrets
Define secret requirements in defineVendor() using the secrets array:
export default defineVendor({
id: "acme",
name: "Acme",
version: "1.0.0",
icon: acmeIcon,
auth: { credentials: { apiKey: { type: "apiKey", label: "API Key" } }, default: "apiKey" },
secrets: [
{
key: "WEBHOOK_SIGNING_SECRET",
label: "Webhook Signing Secret",
description: "Used to verify incoming webhook payloads",
required: true,
},
{
key: "ENCRYPTION_KEY",
label: "Encryption Key",
description: "AES key for encrypting sensitive payloads",
required: false,
},
],
products: [/* ... */],
});Each SecretInput has the following shape:
interface SecretInput {
/** Unique key within the vendor — must match ^[a-zA-Z0-9_-]+$ */
key: string;
/** Human-readable label shown in the admin UI */
label: string;
/** Help text describing what this secret is used for */
description?: string;
/** Whether the integration requires this secret to function */
required: boolean;
}Secret keys must contain only alphanumeric characters, hyphens, and underscores (^[a-zA-Z0-9_-]+$). Keys that do not match this pattern are rejected at save time.
Secret Key Format
Secrets are stored using a structured key that scopes them to the organization and vendor:
integration:{orgId}:{vendorId}:{key}For example, a secret with key WEBHOOK_SIGNING_SECRET for vendor acme in organization org_abc123 is stored as:
integration:org_abc123:acme:WEBHOOK_SIGNING_SECRETThis ensures complete isolation between organizations and between vendors within the same organization.
Encryption at Rest
All secret values are encrypted with AES-256-GCM before being persisted. The encryption key strategy is configured per organisation — LOCAL, BYOK, or HYOK. Secret values are never stored in plaintext. See Security → Secrets management for the full model.
Accessing Secrets at Runtime
When a tool executes, the platform resolves all declared secrets for the vendor and injects them into ctx.secrets as a flat Record<string, string>:
import { defineTool } from "@scrydon/sdk-authoring/integrations/define";
import { z } from "zod";
export const verifyWebhook = defineTool({
id: "acme:webhooks:verify",
name: "Verify Webhook",
version: "1.0.0",
input: z.object({ payload: z.string(), signature: z.string() }),
output: z.object({ valid: z.boolean() }),
async execute(input, ctx) {
const signingSecret = ctx.secrets["WEBHOOK_SIGNING_SECRET"];
if (!signingSecret) {
return { success: false, output: { valid: false }, error: "Webhook signing secret not configured" };
}
const valid = verifyHmac(input.payload, input.signature, signingSecret);
return { success: true, output: { valid } };
},
});The ctx.secrets object only contains secrets that have been set by the org admin. If a secret has not been configured, it will be absent from the record. Always check for the presence of required secrets before using them.
Admin UI
Organization administrators configure secrets through the integration settings UI under Settings > Integrations > [Vendor] > Secrets. The UI displays the declared secret fields from the vendor's secrets array.
Secret values are write-only -- after a value is saved, it is never displayed again. The UI only shows which keys have been configured (with a masked indicator) and allows admins to update or delete them.
API Endpoints
The platform exposes three internal admin endpoints for secret management:
| Endpoint | Purpose |
|---|---|
/integrations/admin/bundle-secret-set | Create or update a secret value |
/integrations/admin/bundle-secret-delete | Delete a secret |
/integrations/admin/bundle-secret-list | List configured secret keys (values are never returned) |
These endpoints are internal (service-to-service) and require the caller to be an authorized internal service. They are not directly accessible from client applications.
Build CLI
# Build a bundle
sdk-authoring integrations build [--entry src/index.ts] [--outDir dist]
# Test a bundle
sdk-authoring integrations test [--level static|sandbox|live] [--tool <id>]Build Output
my-vendor-1.0.0.bundle.tar.gz
├── manifest.json # Auto-generated metadata (JSON Schemas, UI defs)
├── dist/
│ └── index.js # Compiled, minified ESM (all deps inlined via esbuild)
├── meta/
│ ├── sbom.cdx.json # CycloneDX 1.6 SBOM (auto-generated)
│ └── metafile.json # esbuild dependency graph
└── assets/ # Optional icons
└── icon.svgThe build CLI inlines all npm dependencies into the single dist/index.js file and auto-generates a CycloneDX 1.6 SBOM at meta/sbom.cdx.json. There is no runtime npm install — the bundle is fully self-contained and deterministic.
Vendor ID Rules
- Lowercase alphanumeric characters and hyphens only
- Must start with a letter
- Pattern:
/^[a-z][a-z0-9-]*$/ - Examples:
acme,my-vendor,hello-world
Tool ID Convention
Tool IDs use the fully qualified format {vendorId}:{productId}:{action} at runtime:
hello-world:hello-world:say-hellogoogle:sheets:readslack:messaging:send-message
Shorthand: In authoring code you can use just the action part (e.g. "say-hello", "read"). The SDK auto-qualifies short IDs by prepending {vendorId}:{productId}: during defineVendor(). All first-party integrations use the short form. If you use the full form, the vendor/product prefix must match — the build CLI validates this.
Capability Helpers
Capability helpers wrap runtime configurations with a type tag so the manifest extractor can identify them. Each helper returns its config with a _capability tag used internally during build.
| Helper | Tag | Purpose |
|---|---|---|
defineCapabilityLLM(config) | llm | Full LLM provider (chat, completion, streaming) |
defineCapabilitySTT(config) | stt | Speech-to-text (batch and realtime) |
defineCapabilityTTS(config) | tts | Text-to-speech (batch and realtime) |
defineCapabilityEmbedding(config) | embedding | Vector embedding generation |
defineCapabilityVideo(config) | video | Video generation |
defineCapabilityOCR(config) | ocr | Document parsing / optical character recognition |
defineCapabilityWebhook(config) | webhook | Vendor-specific webhook handling |
defineCapabilityDiscovery(config) | discovery | Resource browsing, selectors, access scopes |
All helpers are imported from @scrydon/sdk-authoring/integrations/define:
import {
defineCapabilityLLM,
defineCapabilitySTT,
defineCapabilityTTS,
defineCapabilityEmbedding,
defineCapabilityVideo,
defineCapabilityOCR,
defineCapabilityWebhook,
defineCapabilityDiscovery,
} from "@scrydon/sdk-authoring/integrations/define";Capability configs are placed inside defineProduct({ capabilities: { runtimes: { ... } } }). The manifest extractor converts runtime functions to boolean flags and extracts model metadata (dimensions, benchmarks, pricing) into the manifest's capabilityMeta field. See Capabilities for full usage examples of each helper.
Manifest Schema
The build CLI auto-generates manifest.json from your defineVendor() call. The manifest is a JSON-serializable snapshot of your vendor's metadata, stripped of runtime functions. It follows manifestVersion: 1.
Top-Level Structure
{
"$schema": "...", // Optional JSON Schema URL
"manifestVersion": 1, // Always 1
"version": "1.0.0", // Vendor version (from defineVendor)
"vendor": { ... }, // Vendor metadata
"auth": { ... }, // Authentication config
"products": [ ... ], // Product definitions
"protocols": [ ... ], // Protocol definitions (optional)
"llm": { ... } // LLM provider config (optional)
}Vendor Section
Contains display metadata. Runtime code is excluded.
| Field | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Vendor ID (/^[a-z][a-z0-9-]*$/) |
name | string | Yes | Display name |
description | string | No | Short description |
color | string | No | Hex brand color |
icon | string | Yes | SVG icon as string |
website | string | No | Vendor website URL |
docsUrl | string | No | Documentation URL |
categories | string[] | No | Category tags |
defaultEnabled | boolean | No | Auto-enable for new orgs (default: false) |
supportsSystemMode | boolean | No | Supports client_credentials (default: false) |
connectivity | "cloud" | "local" | "hybrid" | No | Network requirements |
configFields | ConfigField[] | No | Admin-configurable fields |
secrets | Secret[] | No | Vendor-level secrets |
Product Section
Each product in the products array contains:
| Field | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Product ID |
name | string | Yes | Display name |
capabilities.tools | Tool[] | No | Tool definitions with JSON Schema input/output |
capabilities.triggers | Trigger[] | No | Trigger definitions |
capabilities.runtimes | object | No | Boolean flags for llm, stt, tts, embedding, video, ocr |
capabilities.capabilityMeta | object | No | Extracted model metadata (embedding dimensions, STT/TTS models, benchmarks) |
capabilities.webhooks | boolean | No | Whether the product handles webhooks |
capabilities.discovery | boolean | No | Whether the product supports resource discovery |
block | Block | No | Workflow editor block definition |
dependencies | Dependency[] | No | Declared NPM dependencies with reasons |
systemMode | object | No | System-mode (client_credentials) configuration |
How Runtime Code Becomes Manifest Data
The build CLI transforms runtime definitions into manifest-safe JSON:
| Source (defineProduct) | Manifest Output |
|---|---|
runtimes.llm (with executeRequest function) | runtimes.llm: true |
runtimes.embedding (with embed function, models with dimension) | runtimes.embedding: true + capabilityMeta.embeddingModels |
runtimes.stt (with transcribe function, models) | runtimes.stt: true + capabilityMeta.sttModels |
runtimes.tts (with synthesize function, models) | runtimes.tts: true + capabilityMeta.ttsModels |
Tool input/output (Zod schemas) | JSON Schema objects |
Tool execute function | Omitted (not serializable) |
Block tools.config.tool function | Omitted (serialized separately) |
The manifest is what the platform reads at boot time to populate the integration catalog. It contains no executable code -- only metadata, JSON Schemas, and UI definitions. Actual tool execution happens lazily when a tool is first invoked, loading the bundle's dist/index.js inside a sandboxed Worker Thread.