Public SDK Protocol v1 Scope

This document classifies the current NodeTool protocol before new SDK operations are added. It is a scope boundary, not the final protocol reference.

The current automated and interactive gate status is recorded in docs/sdk/non-regression-baseline-2026-07-24.md.

Current public core

The initial public SDK profile contains:

  • compact workflow summaries;
  • graph-derived workflow interface v1;
  • bounded bulk workflow-interface retrieval;
  • bounded hybrid TypeScript/Python node-type inventory;
  • correlated read-only WebSocket RPC envelopes;
  • JSON HTTP responses;
  • MessagePack WebSocket frames.

The current public discovery operations are:

Operation HTTP WebSocket command
Workflow summaries GET /api/sdk/v1/workflows list_workflow_summaries
Workflow interface GET /api/workflows/:id/interface?version=1 get_workflow_interface
Workflow interfaces POST /api/sdk/v1/workflow-interfaces get_workflow_interfaces
Node-type inventory GET /api/sdk/v1/node-types get_node_type_inventory
Capabilities GET /api/sdk/v1/capabilities get_capabilities
Workflow preflight POST /api/sdk/v1/preflight preflight_workflow
Temporary input POST /api/sdk/v1/assets/temporary -

The same workflow-interface services and authorization rules back all transports.

Current transport behavior

MessagePack is the supported and default SDK encoding on /ws. The current server also accepts JSON-text commands, and a client can send set_mode to request JSON-text responses. That behavior is captured for regression and diagnostic coverage, but is not part of the initial public SDK guarantee. Correlated read-only SDK commands require a non-empty request_id.

Each WebSocket frame carries exactly one top-level message object. Binary frames contain one MessagePack object; text frames contain one UTF-8 JSON object. The connection starts in binary outbound mode. Sending {"command":"set_mode","data":{"mode":"text"}} selects JSON-text responses; using "binary" selects MessagePack again. The set_mode acknowledgement is encoded in the previous mode because the change takes effect after that acknowledgement is queued.

The baseline payloads are stored in packages/protocol/fixtures/sdk-v1-baseline.json. Tests validate the REST shapes, JSON text, and exact MessagePack bytes.

Generated contract artifacts

The current public discovery profile is published from the Zod source schemas as:

  • packages/protocol/schema/sdk-v1.discovery.schema.json;
  • packages/protocol/schema/sdk-v1.manifest.json.

The manifest records protocol version 1, the public and optional profiles, the default WebSocket encoding, and a SHA-256 digest for each artifact. npm run generate:sdk-protocol --workspace=packages/protocol regenerates the bundle. npm run check:sdk-protocol --workspace=packages/protocol and the protocol tests fail when committed artifacts are stale.

The bundle also contains draft OpenAPI 3.1 and AsyncAPI 3.0 documents for the current discovery profile. They remain marked draft while the wider job and asset profiles are still being designed.

The lifecycle vocabulary and state-machine semantics are defined in docs/sdk/lifecycle-v1-draft.md and generated as packages/protocol/schema/sdk-v1.lifecycle.schema.json. Capabilities, preflight, and temporary SDK input upload are additive and enabled by default. Deployments can disable lifecycle v1 with NODETOOL_DISABLE_SDK_LIFECYCLE_V1=1; later job operations remain explicitly marked planned. AsyncAPI lifecycle entries are marked partial because their union contains both implemented and planned commands.

Errors and correlation

Public SDK errors share these required fields:

  • code: stable machine-readable identifier;
  • message: safe human-readable summary;
  • retryable: whether retrying without changing the request may succeed.

HTTP discovery errors retain detail during migration. Correlated WebSocket errors retain apiCode and trpcCode. Those compatibility fields must not be used as the portable error contract.

Expected SDK errors use an allowlisted public message. Unexpected HTTP and WebSocket failures return INTERNAL_ERROR with Internal server error; the internal exception is logged server-side and is not placed on the wire. Protocol v1 does not expose stack traces, database errors, credentials, provider responses, or arbitrary exception details.

Every read-only WebSocket RPC request requires a non-empty, client-generated request_id. The server echoes it unchanged in exactly one rpc_response. Clients should not reuse a request ID while an earlier request with that ID is pending.

Additive compatibility

Generated request schemas reject unknown fields. A new request shape or command therefore requires a protocol version or advertised capability.

Generated response schemas allow additional fields at every object level. Clients must ignore response fields they do not understand. Event consumers must likewise ignore an unknown event type after safely advancing its stream position; they must not reinterpret it as a known event. Required fields are not removed or repurposed within protocol v1.

Authentication boundary

Current local discovery behavior is preserved by default. When NodeTool’s server authentication is enabled, SDK discovery always uses the normal authentication hook. NODETOOL_REQUIRE_SDK_AUTH_V1=1 can additionally require that hook in a local deployment. Trusted loopback behavior remains controlled by NodeTool’s existing local-trust settings.

The Fastify-to-Web-API bridge strips caller-supplied x-user-id and forwards only the server-authenticated identity. Missing and inaccessible workflows both return WORKFLOW_NOT_FOUND, so discovery does not reveal whether another user owns a requested workflow.

Feature flags

Flag Default Owner Protected behavior
NODETOOL_DISABLE_SDK_WORKFLOW_INTERFACE_V1 Enabled unless exactly 1 WebSocket/API server Emergency kill switch for SDK workflow summaries, interfaces, and node-type inventory
NODETOOL_REQUIRE_SDK_AUTH_V1 Disabled unless exactly 1 Fastify authentication hook Require verified identity for SDK discovery even when the server otherwise runs in local mode
NODETOOL_DISABLE_SDK_LIFECYCLE_V1 Enabled unless exactly 1 WebSocket/API server Emergency kill switch for capabilities, preflight, and temporary SDK input upload; later job-lifecycle operations remain unregistered

The two additive SDK profiles are available without special server startup. Their kill switches preserve the existing non-SDK workflow, execution, asset, web, Electron, CLI, and agent behavior. Authentication and deployment policy remain server-owned and cannot be enabled by a client.

Optional profiles

These areas require separate versioning or capability advertisement before they become public SDK behavior:

  • acknowledged job submission, snapshots, replay, and cancellation;
  • durable canonical asset retention, leases/cleanup, and result manifests;
  • agent chat and tool-call transport;
  • offline workflow/model bundles.

Internal implementation

The following are not public SDK contracts:

  • Python bridge messages and process lifecycle;
  • database schemas and Drizzle models;
  • tRPC router internals;
  • editor and ReactFlow state;
  • provider-specific request objects;
  • in-memory queue and runner implementation details;
  • legacy full-workflow responses used by the current editor.

Public endpoints extend the existing validation, workflow, runner, job, and asset services. They do not introduce a second execution engine.

Readiness adapters follow least-authority boundaries:

  • node-package requirements use exact provenance recorded by registry loaders and registrars; namespaces are not package identities;
  • model availability reads cache/local inventory, and download readiness may read immutable snapshots of already-tracked downloads;
  • remote-worker readiness may read persisted worker rows, but does not refresh provider status, reconcile, attach, resume, or provision;
  • preflight does not install packages, download models, reserve capacity, create jobs, or call paid inference operations.

Compatibility policy

Current NodeTool behavior must remain operational while the SDK profile grows. New routes and commands are additive and initially opt-in. Existing run_job and current discovery routes remain available until current clients migrate and their cutover tests pass.

The SDK does not promise compatibility with retired NodeTool server releases.