Codemation Docs

Plugin development

Scaffold a plugin package, run it against the real host, understand sandbox config, publish, and consume it from an app.

… stars

A plugin is an npm package that exports a default Codemation plugin object from codemation.plugin.ts (built to dist/). It registers nodes, credential types, and optional sandbox defaults so local development matches how a consumer app loads the same package from node_modules.

Use this page for the end-to-end plugin workflow. For reusable nodes and credentials themselves, follow the same guides as app-local extensions—see Nodes and credentials below.

Getting started

Scaffold the plugin template, install, and start the plugin dev server:

pnpm create codemation my-plugin --template plugin
cd my-plugin
pnpm install
pnpm dev

pnpm dev runs codemation dev:plugin, which boots the real host and UI against a synthetic codemation.config.ts generated next to your plugin (see Lifecycle with the host). Open the URL the CLI prints, create credentials as needed, and run the sample workflow.

To see all template ids (including plugin):

pnpm create codemation --list-templates

Framework package versions (0.0.x)

Scaffolded default and plugin projects list @codemation/* dependencies as 0.0.x. That semver range matches any 0.0.* patch release on npm, so you can run pnpm upgrade (or pnpm update) to move to newer 0.0.z builds without hand-editing versions each time. Pin stricter ranges once you are past pre-1.0 churn or need reproducible installs.

The plugin config file (codemation.plugin.ts)

The default export is built with definePlugin from @codemation/host. Typical shape:

import { createWorkflowBuilder, ManualTrigger } from "@codemation/core-nodes";
import { definePlugin, type CodemationConfig } from "@codemation/host";

const sandbox: CodemationConfig = {
  app: {
    auth: {
      kind: "local",
      allowUnauthenticatedInDevelopment: true,
    },
    database: {
      kind: "pglite",
      pgliteDataDir: ".codemation/pglite",
    },
    scheduler: {
      kind: "inline",
    },
    whitelabel: {
      productName: "Plugin sandbox",
    },
  },
  workflows: [
    createWorkflowBuilder({ id: "wf.plugin.hello", name: "Plugin Hello" })
      .trigger(new ManualTrigger("Start", [{ json: { message: "hello plugin" } }]))
      .then(new MyNodeConfig("Run node"))
      .build(),
  ],
};

export default definePlugin({
  credentialTypes: [
    /* optional declarative credential types */
  ],
  register(context) {
    context.registerNode(MyNode);
  },
  sandbox,
});

Sandbox (plugin.sandbox)

plugin.sandbox is an optional CodemationConfig fragment.

codemation dev:plugin uses it to synthesize a temporary consumer config for local development, so plugin authors can run the real host and UI against:

  • demo workflows
  • local auth defaults
  • embedded database (PGlite)
  • lightweight branding for the plugin sandbox

Plugin surface (definePlugin)

  • credentialTypes — optional list registered declaratively (alongside anything you register in register).
  • register — imperative registration: e.g. context.registerNode(...), container bindings, and other host hooks.
  • sandbox — optional; used by the dev:plugin flow so the generated config can merge your sandbox config and append the plugin automatically.

Lifecycle with the host

  1. Local plugin developmentcodemation dev:plugin (usually via pnpm dev in the template) uses PluginDevConfigFactory to write .codemation/plugin-dev/codemation.config.ts beside your package. That file:

    • imports your default plugin export;
    • reads plugin.sandbox ?? {};
    • merges that sandbox config into the root CodemationConfig;
    • appends your plugin to plugins.

    So you develop against the same host and runtime as a normal consumer, without publishing first.

  2. Consumer apps — When the CLI loads a consumer codemation.config.ts, it merges plugins from your config with plugins discovered under node_modules (see below). The host then runs registration, workflows, and the UI as usual.

Nodes and credentials

Implementing nodes and credential types in a plugin follows the same patterns as in an application: config classes, @node, CredentialType, constructor injection, and tests without heavy mocking.

One extra rule matters for custom nodes: defining the config class is not enough by itself. The plugin still needs to register the runtime node class in register(context):

export default definePlugin({
  register(context) {
    context.registerNode(MyNode);
  },
});

Start here:

Optional deeper reading:

  • Concepts — workflows, nodes, credentials, runs
  • Plugin developers — packaging nodes for AI agent tools (AgentToolFactory.asTool(...)) and stability notes for published surfaces

Publishing

  1. Build the package so codemation.plugin.ts compiles to the entry the manifest points at (the template uses tsdown):

    pnpm build
  2. Declare the plugin entry in package.json so the host can discover the package after install:

    {
      "name": "@acme/codemation-plugin-hello",
      "codemation": {
        "plugin": "./dist/codemation.plugin.js"
      }
    }
  3. Publish to npm (or your private registry) as you would any TypeScript library. Ensure files / exports include dist/ and that the plugin entry path is correct for consumers.

Using a plugin in a project

  1. Add the dependency to your Codemation consumer app:

    pnpm add @acme/codemation-plugin-hello
  2. Discovery — The host scans node_modules for packages whose package.json includes codemation.plugin as a string path and loads that module. You do not have to duplicate that import in codemation.config.ts unless you want an explicit reference.

  3. Explicit plugins — You can still add plugins to codemation.config.ts (for example a local file path while developing). Configured plugins are merged with discovered plugins; when the same published package appears both ways, the host dedupes by package identity.

  4. Run the apppnpm dev / codemation dev as usual. Your workflows can reference node types registered by the plugin.

See also

On this page