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.
| Prompt | Default | Notes |
|---|---|---|
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):
- Shell environment variables
.env.localin the working directory~/.workplane/.env(written byworkplane-setup).envin the working directory
Server variables
| Variable | Default | Description |
|---|---|---|
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
| Variable | Default | Description |
|---|---|---|
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
| Variable | Description |
|---|---|
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
| Variable | Default | Description |
|---|---|---|
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.
| Adapter | Required tags | Modes |
|---|---|---|
| Shell | shell | batch |
| Ollama | ollama | batch |
| Aider | aider, git | batch |
| Codex | codex, git | batch, interactive |
| Claude Code | claude-code, git | batch, 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_TOKENon the server; all nodes must use the same value. - Operator token — required for the CLI to submit, retry, or cancel tasks. Set
WORKPLANE_OPERATOR_TOKENon 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:
| Provider | Requires |
|---|---|
anthropic | ANTHROPIC_API_KEY |
openai | OPENAI_API_KEY |
ollama | Ollama 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.
| Package | Purpose |
|---|---|
@workplane/workplans | Workplan DSL, sequential runner, inline providers, ScheduleBuilder |
@workplane/agent-skills | Pre-built skills, SkillRegistry, CanonicalSkillWorkflow interface |
@workplane/adapter-sdk | Build custom adapters — WorkAdapter, WorkContext, cancellable exec |
@workplane/types | Shared TypeScript types |
@workplane/core | Config, HTTP client, auth, git utilities |
@workplane/adapter-shell | Shell command adapter |
@workplane/adapter-ollama | Ollama inference adapter |
@workplane/adapter-aider | Aider coding agent adapter |
@workplane/adapter-harness | Base harness adapter (extended by codex/claude-code) |
@workplane/adapter-claude-code | Claude Code adapter (PTY interactive) |
@workplane/adapter-codex | Codex adapter (stdio interactive) |
@workplane/dbos | Optional 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