Get started with c8ctl
The easiest way to run and manage Nano BPM — a single node or a whole cluster — is the c8ctl CLI with the c8ctl-plugin-nano plugin. The plugin ships a prebuilt Nano binary for your platform and installs it for you, so there is nothing to compile.
The one-liner (recommended)
The fastest way to go from zero to a running Nano Workforce — the engine, a supervised workforce of hired coding agents, and the Workforce app — is the one-command installer:
curl -fsSL https://nanobpm.io/install.sh | sh
It installs the Camunda 8 CLI and the c8ctl-plugin-nano plugin, lets you pick
which of your installed coding harnesses to hire (and with which model and how
many instances), composes a workforce manifest from those choices, brings the
engine and workforce up, then installs and runs the Workforce app. It never
runs sudo on your behalf — it installs the CLI with npm i -g, so where the
global package lands depends on your Node/npm setup (a user-owned prefix such as
nvm needs no elevation; a system-owned prefix may require you to fix your npm
prefix first).
Prefer to read the script before running it? Download, inspect, then run:
curl -fsSL https://nanobpm.io/install.sh -o install.sh
less install.sh
sh install.sh
https://nanobpm.io/install.sh always mirrors the script on main in the
nano-workforce
repository — the single source of truth.
The rest of this section sets up just the engine, by hand. Use it when you want a single node or a cluster without the workforce, or to understand exactly what the installer automates for you.
Prerequisites
Install these tools before you start.
- Node.js 22.18 or later. The Camunda 8 CLI runs on Node.js. Download Node.js from nodejs.org.
- The Camunda 8 CLI. Install the CLI with
npm i -g @camunda8/cli. This package provides thec8ctlcommand.
Verify each tool:
node --version
c8ctl --version
Then manage Nano with c8ctl:
# Load the plugin (installs the matching prebuilt binary for your OS/arch)
c8ctl load plugin c8ctl-plugin-nano
# Start a single-node cluster on port 8080
c8ctl nano start
# Start a 3-node cluster (ports 8080, 8081, 8082)
c8ctl nano start 3
# Start a 3-node Raft-replicated cluster (RF=3 enables replication automatically)
c8ctl nano start 3 --rf 3
# Show cluster status and per-node health
c8ctl nano status
# Tail a node's log (node ids are 0-indexed, so a single node is node 0)
c8ctl nano logs 0 --follow
# Simulate a node failing and recovering
c8ctl nano pause 0
c8ctl nano resume 0
# Stop the cluster (engine data retained); add --purge to delete engine data
c8ctl nano stop
c8ctl nano keeps your authoring assets (BPMN models and worker code) in a
shared workspace that survives stop and clean, separate from the throwaway
per-node engine data. It also wires every node's ports, ids, partitions,
replication, and data directories for you.
Once a cluster is up:
- Point any Camunda 8 v2 REST client (or the
Nano SDK) at
http://127.0.0.1:8080/v2. - Open the web console at
http://127.0.0.1:8080/console.
A demo process (processDefinitionId: "demo") is pre-deployed at startup, so you
have something to run immediately.
Compose and run a workforce by hand
The one-liner installer composes a workforce
manifest for you. To build one by hand — or to curate a fleet you can diff,
edit, and copy between machines — use the hire → workforce commands. A
workforce is a fleet of supervised coding-agent workers (each running a
harness such as copilot, claude, or qwen on your PATH) described by a
single manifest file. This needs a running engine (above) and at least one agent
harness installed.
1. Hire agent profiles. A profile is a reusable definition — a rank, the harness command, an optional model, and any launch args (the examples below set no model, so the harness uses its own default):
# Create a "copilot" senior profile that runs `copilot --allow-all`
c8ctl nano hire --name copilot --rank senior --command copilot --arg --allow-all
# Create a "qwen" profile that runs the `qwen` harness
c8ctl nano hire --name qwen --rank senior --command qwen
c8ctl nano hire --list
2. Compose the manifest with workforce add. --instances N spawns N copies
of a profile; --auto serves every deployed agent job type, or --roles a,b
scopes it to specific roles:
c8ctl nano workforce add copilot --instances 5 --auto
c8ctl nano workforce add qwen --instances 2 --roles pr-review,feature
The manifest is a portable JSON document at
<stateHome>/workforce/<name>.json (default.json unless you pass
--manifest <name>), where <stateHome> is c8ctl's OS-dependent state
directory (e.g. ~/.local/share/c8ctl-nano on Linux). It is meant to be read,
hand-edited, diffed, and copied between machines:
{
"version": 1,
"name": "default",
"workers": [
{ "profile": "copilot", "instances": 5, "roles": "auto" },
{ "profile": "qwen", "instances": 2, "roles": ["pr-review", "feature"] }
]
}
Each entry references a hired profile and sets instances (how many copies)
and roles — either "auto" (serve every agent job type, no capability gate) or
a list, each mapped to a <rank>:<role> job type. Optional fields: autoScope
(narrow --auto to a single bpmn:process id prefix — one app/network) and
args (verbatim flags appended to each worker).
3. Bring the whole fleet up under a supervisor with one command:
c8ctl nano workforce start # the default manifest
c8ctl nano workforce start --manifest review-only
start reconciles the running supervisor to the manifest using deterministic
wf-<manifest>-<profile>-<index> worker names, so re-running an unchanged
manifest starts, stops, and restarts nothing (it is idempotent).
4. Inspect and manage the fleet:
c8ctl nano workforce status --json # desired (manifest) joined with actual (live supervisor)
c8ctl nano workforce list
c8ctl nano workforce stop # bring the fleet down
The supervisor is a fleet runner, so you can also adjust individual workers without editing the manifest:
c8ctl nano supervisor add copilot --instances 3 --auto # or --roles pr-review,feature
c8ctl nano supervisor restart copilot
c8ctl nano supervisor status
c8ctl nano supervisor stop # stop the daemon and all its workers
GitHub authentication. Agent workers clone each task's repository over HTTPS, so every worker needs non-interactive GitHub credentials. Without them a job fails to provision with
fatal: could not read Username for 'https://github.com': terminal prompts disabled. Two ways to provide them:
- Recommended —
ghcredential helper. Rungh auth loginand enable the git integration (gh auth setup-git). This writes a credential helper into your global~/.gitconfig, which every worker'sgit clonepicks up automatically — nothing to export. Verify withgh auth status.- Or a token in the environment. Export a token in the shell that runs
workforce start; the supervisor and all its workers inherit it:export GITHUB_TOKEN="$(gh auth token)"(or any PAT withreposcope).
macOS + a remote engine over SSH (Local Network Privacy). If you run the fleet on a Mac over SSH against an engine on your LAN (e.g.
merlin.local:8080,192.168.x.x), workers may showrunningbut sit idle —listening on 0 job type(s), agenticdisconnected, logs spinning onactivateJobs failed: fetch failed/reconcile skipped — fetch failed. On macOS 15 Sequoia / 26 Tahoe the supervisor's session-independent LaunchAgent (installed so the fleet survives SSH logout) is a separate Local Network Privacy identity that is not granted LAN access — so it cannot reach a LAN engine, even though internet hosts and an interactive SSH shell work. The signature isEHOSTUNREACHto the engine's LAN IP from the service. Fix it with one of:
- Grant Node.js Local Network access on the Mac's GUI: System Settings → Privacy & Security → Local Network, enable the Node.js runtime entry (it may appear as “Node.js Foundation” / “App Background Activity”), then
c8ctl nano supervisor stop && c8ctl nano supervisor start.- Route over Tailscale — traffic over the
utuninterface is not treated as “local network”, so point the engine at the tailnet address (e.g.NANO_REST_URL=http://<host>.<tailnet>.ts.net:8080).- Run in the SSH session (
c8ctl nano supervisor uninstall) — inherits the Terminal grant, but then pin atmux/SSH session so it does not die on logout.See the c8ctl Nano plugin README (“Surviving SSH logout”) for the full explanation.