TypeScript plugin runtime
Build runnable nodes and reusable plugins with @octonode/plugin-runtime.
@octonode/plugin-runtime is the lower-level package that connects TypeScript handlers to the Octonode workflow runtime. The public @octonodes/sdk package in octonode-devtools owns cloud API access and typed plugin authoring.
It describes node contracts, dispatches invocations, and validates inputs and
outputs using its supported schema keywords. It supports Node.js 20.19+ and 22.12+
(^20.19.0 || >=22.12.0). Your handler code and dependencies must also support
the chosen runtime. The engine's octonode CLI used below requires Node 24.
Start with a runnable plugin
With the Octonode CLI installed:
octonode plugin create my-tools --lang typescript
cd my-tools
npm install
npm run build
npm testThe scaffold includes a package manifest, TypeScript build configuration,
octonode.yml, source, and a runnable IPC test. In an existing package, add
@octonode/plugin-runtime as a dependency with your package manager. Keep the SDK and CLI
versions compatible with your deployment.
Define a node contract
This complete octonode.yml declares a single greet node. Its command names the
compiled entry point and the node to invoke.
apiVersion: octonode.dev/settings/v1
plugin:
id: 7e780cd7-51bc-4ea8-b6bb-849b5bdc272d
name: My tools
version: 0.1.0
scope: [user]
nodes:
- id: df10592b-8eca-42d8-97f9-7517e1091b27
label: Greet someone
description: Return a greeting.
command: node dist/index.js df10592b-8eca-42d8-97f9-7517e1091b27
language: typescript
inputs:
type: object
properties:
name: { type: string }
required: [name]
defaults: { name: world }
outputs:
type: object
properties:
message: { type: string }
required: [message]inputs and outputs define the visible ports. defaults supplies default
input values. Keep IDs stable: workflows use them to identify nodes.
Implement the handler
For the scaffold's CommonJS build, put this in src/index.ts:
import { join } from "node:path";
import { definePlugin, loadPluginDefinition, startPlugin } from "@octonode/plugin-runtime";
startPlugin(
definePlugin(loadPluginDefinition(join(__dirname, "..")), {
"df10592b-8eca-42d8-97f9-7517e1091b27": async ({ name }: { name: string }) => ({ message: `Hello, ${name}!` }),
}),
);loadPluginDefinition reads the root settings file. definePlugin pairs each
declared node with a handler. startPlugin selects the node from the command,
validates the invocation, and writes the protocol result.
Handlers receive JSON-compatible input and return JSON-compatible output. Convert
dates to strings and adapt streams, class instances, or binary data explicitly.
Use console.error for diagnostics: stdout is reserved for the runtime protocol.
Build and test the node
npm run build
octonode run-node "node dist/index.js df10592b-8eca-42d8-97f9-7517e1091b27" --describe
octonode run-node "node dist/index.js df10592b-8eca-42d8-97f9-7517e1091b27" --input '{"name":"Ada"}'The invocation returns a result containing {"message":"Hello, Ada!"}. The
describe command shows the node contract without executing the handler.
Keep your scaffold's test expectations aligned with the contract if you change it.
From the destination workflow project, install the built plugin:
octonode plugin install /absolute/path/to/my-tools --projectIts node is addressed as 7e780cd7-51bc-4ea8-b6bb-849b5bdc272d/df10592b-8eca-42d8-97f9-7517e1091b27. Build after source edits so the configured
command executes current JavaScript.
Declare a service connection
For a plugin that calls a CRM, add these fields under plugin in the manifest:
permissions:
- { resource: secrets, access: read }
connections:
crm:
label: CRM account
fields:
CRM_TOKEN: { label: API token, secret: true, required: true }Add connections: [crm] to each node that requires that connection. The consumer
supplies CRM_TOKEN in its execution environment; read it inside the handler.
Required credentials are checked before the handler runs. The manifest declares
the requirement, never the credential value. This token belongs to the CRM;
an Octonode API token does not authenticate to that service.
Other runtime entry points
Existing single-node integrations can use defineNode and start. NodeError
represents an explicit node failure; NodeContext describes runtime context.
The runtime also exports PluginManifest, PluginNode, and PluginConnection
schemas and types for programmatic validation.
Use the plugin scaffold when starting a reusable integration, and see Nodes and plugins for marketplace attachment and generated adapters.
Installed app SDKs
This page describes the workflow plugin runtime. For workspace.block and
app.page contributions, use the app SDK reference, which
separates browser UI, the installation bridge, hosted backend verification,
and the general cloud API client.