Documentation

Reference for setup, configuration, CLI commands, and fleet deployment. Node.js 20+ required.

Setup

The fastest way to get running is workplane-setup — an interactive wizard that configures tokens, picks a database, and runs migrations in one step.

npm install -g workplane
workplane-setup

The wizard prompts for five values. Press Enter to accept the default shown in brackets.

PromptDefaultNotes
DATABASE_URL sqlite://~/.workplane/workplane.db Change to postgres://… for Postgres
Server port 8787 Port workplane-server listens on
Server URL (for nodes) http://localhost:8787 What worker nodes use to reach the server
Node token auto-generated 64-char hex Shared secret between server and all nodes
Operator token auto-generated 64-char hex Required for mutating CLI commands

Config is written to ~/.workplane/.env. Re-run workplane-setup at any time — existing values appear as defaults, so you can update just what you need.

After setup

workplane-server    # terminal 1 — control plane
workplane-node      # terminal 2 — worker
workplane tasks     # verify connection

Configuration

All variables can be set via environment or in a .env file. Load priority (highest first — shell env vars always win):

  1. Shell environment variables
  2. .env.local in the working directory
  3. ~/.workplane/.env (written by workplane-setup)
  4. .env in the working directory

Server variables

VariableDefaultDescription
DATABASE_URL sqlite://~/.workplane/workplane.db Database connection. SQLite or postgres://…
WORKPLANE_SERVER_PORT 8787 Port the control plane HTTP server listens on
WORKPLANE_NODE_TOKEN If set, nodes must present this token to register and poll
WORKPLANE_OPERATOR_TOKEN If set, CLI must present this token for mutating commands
WORKPLANE_USE_DBOS false Set to true to enable DBOS workflow durability (Postgres required)
DBOS_APPLICATION_NAME Required when WORKPLANE_USE_DBOS=true
DBOS_CONDUCTOR_KEY Optional: DBOS Cloud observability key
WORKPLANE_SCHEDULER_ENABLED true Set to false to disable the background workplan scheduler
WORKPLANE_SCHEDULER_INTERVAL_MS 60000 How often the server checks for due workplan schedules (milliseconds)

Node variables

VariableDefaultDescription
WORKPLANE_SERVER_URL http://localhost:8787 URL the node uses to reach the control plane
WORKPLANE_NODE_TOKEN Must match the server's WORKPLANE_NODE_TOKEN
WORKPLANE_NODE_NAME local-node-1 Display name for this node
WORKPLANE_NODE_ID auto Stable node ID; auto-generated on first register if unset
WORKPLANE_NODE_CAPABILITIES shell,git,node,typescript,aider,ollama,codex,claude-code Comma-separated list of capability tags this node advertises
WORKPLANE_POLL_INTERVAL_MS 3000 How often the node polls for new tasks (milliseconds)

CLI variables

VariableDescription
WORKPLANE_SERVER_URL Control plane URL for CLI commands that talk to the server
WORKPLANE_OPERATOR_TOKEN Required for task submit, retry, cancel, and send-input
WORKPLANE_CODEX_BIN Path to the codex binary (default: resolved from PATH)
WORKPLANE_CLAUDE_CODE_BIN Path to the claude binary (default: resolved from PATH)
ANTHROPIC_API_KEY Required for workplan steps with provider: "anthropic"
OPENAI_API_KEY Required for workplan steps with provider: "openai"
OLLAMA_HOST Ollama base URL (default: http://localhost:11434)

Database

SQLite (default)

The server defaults to SQLite with WAL mode — no external database required. The file lives at ~/.workplane/workplane.db and is created automatically on first run.

SQLite is the right choice for a single-server fleet. It handles thousands of concurrent reads and writes on any modern NVMe drive.

# Default — no configuration needed
workplane-setup
workplane-server

Postgres

Recommended when running multiple server instances behind a load balancer, or when you need managed backups and replication.

# Switch to Postgres by re-running setup
workplane-setup
# DATABASE_URL [sqlite://~/.workplane/workplane.db]: postgres://user:pass@host:5432/workplane

Or set DATABASE_URL directly and run workplane-db-migrate. The migrate command creates the database if it doesn't exist (requires CREATE DATABASE permission).

Migrations

workplane-setup runs migrations automatically. For manual control:

workplane-db-migrate

The migrator is idempotent — safe to run multiple times. Applied migrations are tracked in a __drizzle_migrations table.

CLI reference

All commands that talk to the server read WORKPLANE_SERVER_URL (default: http://localhost:8787). Mutating commands also require WORKPLANE_OPERATOR_TOKEN.

Setup & migration

workplane-setup

Interactive first-run wizard. Prompts for database URL, server port, server URL, and auth tokens. Writes ~/.workplane/.env and runs migrations. Safe to re-run.

workplane-db-migrate

Apply database migrations for the configured DATABASE_URL. For Postgres, creates the database if it doesn't exist.

Fleet processes

workplane-server

Start the control plane API on WORKPLANE_SERVER_PORT (default: 8787). Reads DATABASE_URL for task/run state. Enable DBOS durability with WORKPLANE_USE_DBOS=true.

workplane-node

Start a worker node. Polls the server for queued tasks that match its capabilities. Set WORKPLANE_NODE_CAPABILITIES to control what work it accepts.

WORKPLANE_NODE_CAPABILITIES=shell,git,claude-code workplane-node

Skills

workplane skill list

List all registered skills.

workplane skill run <name> [options]

Run a skill inline on the local machine (no server or node required).

workplane skill run summarize-file --file ./README.md
workplane skill run code-review --repo . --model claude-haiku-4-5-20251001

Task submission

workplane task submit shell
workplane task submit shell \
  --command "npm test" \
  --repo https://github.com/you/repo.git \
  --requires shell,git
workplane task submit inference
workplane task submit inference \
  --model llama3.2 \
  --prompt "Summarise this codebase"
workplane task submit harness

Batch (one-shot) agent run:

workplane task submit harness \
  --harness claude-code \
  --repo git@github.com:you/app.git \
  --prompt "Refactor auth middleware" \
  --requires claude-code,git

Interactive (multi-turn PTY/stdin session):

workplane task submit harness \
  --harness claude-code \
  --repo git@github.com:you/app.git \
  --prompt "Start exploring the codebase" \
  --interactive \
  --requires claude-code,git

Interactive session input

workplane run input <runId>
workplane run input <runId> --stdin "Focus on the auth module"
workplane run input <runId> --signal SIGINT
workplane run input <runId> --resize 220x50

Inspection

workplane tasks [--status <status>]

List tasks. Filter by status: queued, assigned, running, succeeded, failed, cancelled.

workplane runs [--task-id <id>]

List runs, optionally filtered by task.

workplane run show <runId>

Show run detail.

workplane logs <runId>

Stream or print run logs.

workplane artifacts <runId>

List artifacts attached to a run.

Task control

workplane task retry <taskId>

Re-queue a failed task.

workplane task cancel <taskId>

Cancel a queued or running task. Sends SIGTERM to the running process (escalates to SIGKILL after 5 seconds).

Workplan scheduling

Schedule multi-step workplans (skills) on a cron expression. Requires a running server with the scheduler enabled (default). Mutating schedule commands require WORKPLANE_OPERATOR_TOKEN.

workplane schedule create <planId>

Create a cron schedule for a registered skill/workplan.

workplane schedule create hello \
  --cron "0 9 * * *" \
  --timezone UTC \
  --name "Daily hello" \
  --input message=hello

Cron supports five or six fields (second minute hour day month weekday). For sub-minute testing, use six fields (e.g. */20 * * * * *) and set WORKPLANE_SCHEDULER_INTERVAL_MS=10000 on the server.

workplane schedule list [--enabled <true|false>]

List schedules, optionally filtered by enabled state.

workplane schedule show <scheduleId>

Show schedule detail.

workplane schedule enable|disable|delete <scheduleId>

Enable, disable, or delete a schedule. Deleting detaches historical runs (sets schedule_id to null) rather than deleting run history.

workplane schedule run <scheduleId>

Trigger a schedule immediately (one-off run).

workplane schedule tick

Manually invoke the scheduler tick (process due schedules now).

workplane workplan-runs [--schedule-id <id>]

List workplan run records.

workplane workplan-run show <runId>

Show workplan run detail.

workplane workplan-run steps <runId>

List step results for a workplan run.

Workplan scheduling

v0.4.2 introduces cron-based scheduling for skills and custom workplans. The server loads the skill registry at startup and runs a background tick (default every 60 seconds) that enqueues due runs.

Quick example

workplane-server

workplane schedule create hello \
  --cron "0 9 * * *" \
  --timezone UTC \
  --input message=hello

workplane schedule list
workplane workplan-runs
workplane workplan-run show <runId>

The built-in hello skill runs a single shell echo — useful for verifying the scheduler without API keys.

Scheduler configuration

VariableDefaultDescription
WORKPLANE_SCHEDULER_ENABLED true Set to false to disable automatic scheduling
WORKPLANE_SCHEDULER_INTERVAL_MS 60000 Tick interval in milliseconds; use 10000 when testing sub-minute cron

After pulling new skills or code changes, restart workplane-server — plans are validated at startup.

Fleet deployment

Single machine

Run setup once, then start server and node side by side:

workplane-setup
workplane-server &
workplane-node

Multiple machines

Run the control plane on one always-reachable host. Workers on any machine that can reach it over your network (Tailscale, WireGuard, or LAN).

On the server machine:

workplane-setup
# Note the WORKPLANE_NODE_TOKEN and WORKPLANE_OPERATOR_TOKEN values
workplane-server

On each worker machine:

npm install -g workplane
workplane-setup
# SERVER URL: http://<server-ip>:8787
# NODE TOKEN:  <token from server machine>
workplane-node

Node capabilities

Nodes advertise capability tags. Tasks declare requires. The server assigns each task to a node whose capabilities are a superset of the requirement.

AdapterRequired tagsModes
Shellshellbatch
Ollamaollamabatch
Aideraider, gitbatch
Codexcodex, gitbatch, interactive
Claude Codeclaude-code, gitbatch, interactive
# Restrict a node to GPU inference only
WORKPLANE_NODE_CAPABILITIES=ollama workplane-node

# Full capabilities
WORKPLANE_NODE_CAPABILITIES=shell,git,ollama,aider,codex,claude-code workplane-node

Authentication

Both tokens are optional but recommended for any non-localhost deployment.

  • Node token — shared secret between the server and all worker nodes. Set WORKPLANE_NODE_TOKEN on the server; all nodes must use the same value.
  • Operator token — required for the CLI to submit, retry, or cancel tasks. Set WORKPLANE_OPERATOR_TOKEN on the server; CLI clients must use the same value.

Read-only CLI commands (tasks, logs, runs, …) work without the operator token.

Workplans

A workplan is an ordered sequence of steps. Each step specifies a provider (runs inline) or an adapter (dispatched to a capable fleet node). Output can be chained to the next step with dest: "next".

import { SequentialWorkplanRunner, LocalWorkplanContext } from "@workplane/workplans";

const plan = {
  id: "review",
  name: "Code Review",
  steps: [
    {
      id: "diff",
      adapter: "shell",
      provider: "shell",                      // inline — no fleet node
      payload: { command: "git diff HEAD~1", cwd: "./my-repo" },
      output: { dest: "next" },
    },
    {
      id: "summarize",
      adapter: "ollama",
      provider: "ollama",                     // inline via local Ollama
      model: "llama3",
      payload: { prompt: "Summarize these changes:\n{{prevOutput}}" },
      output: { dest: "next" },
    },
    {
      id: "critique",
      adapter: "anthropic",
      provider: "anthropic",                  // inline via Anthropic API
      model: "claude-haiku-4-5-20251001",
      payload: { prompt: "Review for correctness and security:\n{{prevOutput}}" },
    },
  ],
};

const result = await new SequentialWorkplanRunner().run(plan, new LocalWorkplanContext());

Inline providers

Steps with a provider field run without dispatching to a fleet node. Available inline providers:

ProviderRequires
anthropicANTHROPIC_API_KEY
openaiOPENAI_API_KEY
ollamaOllama running at OLLAMA_HOST
shell
file

Output chaining

Set output: { dest: "next" } on a step to pass its output to the next step. Use {{prevOutput}} in the next step's payload.prompt to reference it.

Skills

Skills are pre-built workplans bundled with workplane. Run them via the CLI or programmatically.

Built-in skills

code-review

Git diff → local summarize (Ollama) → frontier critique (Anthropic). Requires ANTHROPIC_API_KEY; Ollama is optional.

workplane skill run code-review \
  --repo . \
  --model claude-haiku-4-5-20251001
summarize-file

Read a file and summarize it with a configurable provider (default: Ollama).

workplane skill run summarize-file --file ./README.md
hello

Single shell echo — useful for scheduler smoke tests. No API keys required.

workplane skill run hello --message hello
workplane schedule create hello --cron "0 9 * * *" --timezone UTC --input message=hello

Programmatic usage

import { createDefaultRegistry } from "@workplane/agent-skills";
import { SequentialWorkplanRunner, LocalWorkplanContext } from "@workplane/workplans";

const registry = createDefaultRegistry();
const skill = registry.get("code-review");
const plan = skill.buildPlan({ repo: ".", model: "claude-haiku-4-5-20251001" });
const result = await new SequentialWorkplanRunner().run(plan, new LocalWorkplanContext());

Building custom skills

Implement CanonicalSkillWorkflow<TInput, TOutput> from @workplane/agent-skills:

import type { CanonicalSkillWorkflow } from "@workplane/agent-skills";
import { CanonicalSkillRunner } from "@workplane/agent-skills";

class MySkill implements CanonicalSkillWorkflow<MyInput, MyOutput> {
  async resolveInputs(raw: unknown): Promise<MyInput> { … }
  async buildContext(inputs: MyInput): Promise<MyContext> { … }
  async invokeAI(context: MyContext): Promise<MyOutput> { … }
  async persistOutput(output: MyOutput): Promise<void> { … }
}

const result = await new CanonicalSkillRunner().run(new MySkill(), rawInput);

Library packages

All packages are published under the @workplane npm org and can be used independently of the fleet CLI.

PackagePurpose
@workplane/workplansWorkplan DSL, sequential runner, inline providers, ScheduleBuilder
@workplane/agent-skillsPre-built skills, SkillRegistry, CanonicalSkillWorkflow interface
@workplane/adapter-sdkBuild custom adapters — WorkAdapter, WorkContext, cancellable exec
@workplane/typesShared TypeScript types
@workplane/coreConfig, HTTP client, auth, git utilities
@workplane/adapter-shellShell command adapter
@workplane/adapter-ollamaOllama inference adapter
@workplane/adapter-aiderAider coding agent adapter
@workplane/adapter-harnessBase harness adapter (extended by codex/claude-code)
@workplane/adapter-claude-codeClaude Code adapter (PTY interactive)
@workplane/adapter-codexCodex adapter (stdio interactive)
@workplane/dbosOptional DBOS durability layer

DBOS (optional)

DBOS adds crash-safe workflow durability to the server — if the server restarts mid-task, workflows replay from their last checkpoint. It is entirely opt-in; the server boots and routes work without it.

DBOS requires Postgres (it uses the same DATABASE_URL for its own system tables).

# Default — no DBOS, no system tables required
workplane-server

# With DBOS durability
WORKPLANE_USE_DBOS=true \
DBOS_APPLICATION_NAME=workplane-prod \
workplane-server

# Optional: DBOS Cloud observability
WORKPLANE_USE_DBOS=true \
DBOS_APPLICATION_NAME=workplane-prod \
DBOS_CONDUCTOR_KEY=<key> \
workplane-server

Without DBOS, the server uses plain async workflows (VanillaWorkflows). Task state and logs are still persisted in the database — DBOS only adds step-level checkpointing and replay.

Development

Clone the repository and use pnpm. Node.js 20+ required.

pnpm install
cp .env.example .env.local
# edit DATABASE_URL and tokens in .env.local

pnpm dev:db          # optional: docker Postgres
pnpm db:migrate      # apply schema
pnpm dev:server      # terminal 1
pnpm dev:node        # terminal 2

Local CLI

Use pnpm dev:cli to run the CLI against your local server. Do not insert -- between the script name and subcommands — pass arguments directly:

pnpm dev:cli schedule create hello --cron "*/20 * * * * *" --timezone UTC --input message=hello
pnpm dev:cli schedule list
pnpm dev:cli workplan-runs
pnpm dev:cli task submit shell --command "echo hello"

For sub-minute cron testing, set WORKPLANE_SCHEDULER_INTERVAL_MS=10000 on the server process.

Tests and build

pnpm test
pnpm build:libs
pnpm build