c8ctl-plugin-nano 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +493 -0
- package/c8ctl-plugin.js +1866 -0
- package/nanobpmn-binary.json +5 -0
- package/package.json +58 -0
- package/platforms.mjs +66 -0
package/README.md
ADDED
|
@@ -0,0 +1,493 @@
|
|
|
1
|
+
# c8ctl-plugin-nano
|
|
2
|
+
|
|
3
|
+
A [c8ctl](https://github.com/camunda/c8ctl) plugin that starts, inspects, and
|
|
4
|
+
stops a local Nano BPM (`nanobpmn`) cluster.
|
|
5
|
+
|
|
6
|
+
## About Nano BPM
|
|
7
|
+
|
|
8
|
+
**A Rust research engine exploring high-performance BPMN execution and Camunda 8
|
|
9
|
+
compatibility.**
|
|
10
|
+
|
|
11
|
+
Nano BPM (`nanobpmn`) is a single self-contained binary that runs BPMN processes
|
|
12
|
+
behind a **Camunda 8-compatible v2 REST API**. It embeds a deterministic,
|
|
13
|
+
event-sourced BPMN engine (`engine-core`), an append-only journal for crash
|
|
14
|
+
durability, an SQLite-backed read model, optional multi-node Raft replication,
|
|
15
|
+
and a built-in web console — all in one executable with no runtime dependencies.
|
|
16
|
+
|
|
17
|
+
It is an advanced research prototype: a place to explore what a faster, smaller,
|
|
18
|
+
faster-to-iterate-on process engine can do, while staying API-compatible with
|
|
19
|
+
existing Camunda 8 clients and tooling. This plugin is the easiest way to run and
|
|
20
|
+
manage it — single node or a whole cluster — shipping a prebuilt binary for your
|
|
21
|
+
platform so there is nothing to compile.
|
|
22
|
+
|
|
23
|
+
It adds a single `nano` command:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
c8ctl nano start|status|stop|restart|logs|clean|set|config
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
`nano start N` spawns **N** nanobpmn node processes wired to talk to each other
|
|
30
|
+
on `localhost` (round-robin partition ownership), tracks them in a state file,
|
|
31
|
+
and waits until every node is reachable.
|
|
32
|
+
|
|
33
|
+
## Usage
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
# Start a single-node cluster (port 8080)
|
|
37
|
+
c8ctl nano start
|
|
38
|
+
|
|
39
|
+
# Start a 3-node cluster (ports 8080, 8081, 8082)
|
|
40
|
+
c8ctl nano start 3
|
|
41
|
+
|
|
42
|
+
# Start a 3-node Raft-replicated cluster (RF=3 enables Raft automatically)
|
|
43
|
+
c8ctl nano start 3 --rf 3
|
|
44
|
+
|
|
45
|
+
# Choose a different base port (nodes -> 9000, 9001, 9002)
|
|
46
|
+
c8ctl nano start 3 --port 9000
|
|
47
|
+
|
|
48
|
+
# Override the partition count (default = node count)
|
|
49
|
+
c8ctl nano start 3 --partitions 6
|
|
50
|
+
|
|
51
|
+
# Show cluster status and per-node health
|
|
52
|
+
c8ctl nano status
|
|
53
|
+
|
|
54
|
+
# Inspect a cluster c8ctl did NOT start (queries /v2/topology on the given port)
|
|
55
|
+
c8ctl nano status --port 8080
|
|
56
|
+
|
|
57
|
+
# Tail a node's log (-f / --follow to stream)
|
|
58
|
+
c8ctl nano logs 1 --follow
|
|
59
|
+
|
|
60
|
+
# Simulate a node failing (freeze it) and recovering (resume it)
|
|
61
|
+
c8ctl nano pause 1
|
|
62
|
+
c8ctl nano resume 1
|
|
63
|
+
|
|
64
|
+
# Stop the cluster (engine data is retained)
|
|
65
|
+
c8ctl nano stop
|
|
66
|
+
|
|
67
|
+
# Stop the cluster and delete per-node engine data
|
|
68
|
+
c8ctl nano stop --purge
|
|
69
|
+
|
|
70
|
+
# Stop then start fresh
|
|
71
|
+
c8ctl nano restart 3
|
|
72
|
+
|
|
73
|
+
# Wipe journal/data + logs from disk (keeps models & workers)
|
|
74
|
+
c8ctl nano clean
|
|
75
|
+
|
|
76
|
+
# Persist settings
|
|
77
|
+
c8ctl nano set bin ~/workspace/nanobpmn/server/target/release/nanobpm-gateway-rest-server
|
|
78
|
+
c8ctl nano set model-dir ~/bpmn-workspace
|
|
79
|
+
|
|
80
|
+
# Show current configuration and on-disk locations
|
|
81
|
+
c8ctl nano config
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Persistent assets: models & workers
|
|
85
|
+
|
|
86
|
+
Nano BPM separates **persistent authoring assets** (BPMN models and worker code)
|
|
87
|
+
from **ephemeral engine data** (journal, snapshots, variable spill):
|
|
88
|
+
|
|
89
|
+
- **Workspace** (`NANOBPMN_WORKSPACE_DIR`) — holds `models/` and `workers/`. It is
|
|
90
|
+
the authoring source of truth, **shared by every node**, and is **never** deleted
|
|
91
|
+
by `stop` or `clean`.
|
|
92
|
+
- **Engine data** (`NANOBPMN_DATA_DIR`) — per-node journal/snapshots/spill. Ephemeral;
|
|
93
|
+
removed by `stop --purge` and `clean`.
|
|
94
|
+
|
|
95
|
+
The plugin points every node at one shared workspace so a model deployed once is
|
|
96
|
+
visible cluster-wide and survives restarts. By default it lives at
|
|
97
|
+
`<state home>/workspace`; change it with:
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
c8ctl nano set model-dir ~/bpmn-workspace
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
This creates `~/bpmn-workspace/models/` and `~/bpmn-workspace/workers/`. Restart a
|
|
104
|
+
running cluster for a workspace change to take effect.
|
|
105
|
+
|
|
106
|
+
## Cleaning up disk
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
c8ctl nano clean # remove engine data + logs (cluster must be stopped)
|
|
110
|
+
c8ctl nano clean --workspace # ALSO delete models & workers (destructive!)
|
|
111
|
+
c8ctl nano stop --purge # stop and remove engine data in one step
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
`clean` refuses to run while any node is alive.
|
|
115
|
+
|
|
116
|
+
## Configuration (`set` / `config`)
|
|
117
|
+
|
|
118
|
+
Persistent settings are stored in `<state home>/config.json`:
|
|
119
|
+
|
|
120
|
+
| Setting | Env mapping | Set with |
|
|
121
|
+
|---------------------|--------------------------|-----------------------------------|
|
|
122
|
+
| Binary path | (used to launch nodes) | `c8ctl nano set bin <path>` |
|
|
123
|
+
| Workspace directory | `NANOBPMN_WORKSPACE_DIR` | `c8ctl nano set model-dir <path>` |
|
|
124
|
+
|
|
125
|
+
Show the effective configuration and all on-disk locations with `c8ctl nano config`.
|
|
126
|
+
|
|
127
|
+
## Checking status
|
|
128
|
+
|
|
129
|
+
`c8ctl nano status` queries each node's always-on `GET /v2/topology`, which is the
|
|
130
|
+
authoritative cluster view. Because of this it works in three situations:
|
|
131
|
+
|
|
132
|
+
- **c8ctl-managed cluster** — shows per-node process liveness (PID), reachability,
|
|
133
|
+
and the live topology (partition leadership).
|
|
134
|
+
- **External cluster** — a Nano BPM cluster started outside c8ctl (e.g. by hand,
|
|
135
|
+
a script, or another tool). With no recorded state, status probes
|
|
136
|
+
`http://127.0.0.1:<port>/v2/topology` and reports what it finds, labelled
|
|
137
|
+
`(external — not started by c8ctl)`.
|
|
138
|
+
- **Nothing running** — reports `stopped`.
|
|
139
|
+
|
|
140
|
+
Point status at a specific endpoint with `--port`:
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
c8ctl nano status # default: managed cluster, else probe port 8080
|
|
144
|
+
c8ctl nano status --port 9000
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### Camunda vs Nano detection
|
|
148
|
+
|
|
149
|
+
Nano advertises itself in `GET /v2/topology` with a `nano` object
|
|
150
|
+
(`engine: "nanobpmn"`) — a superset of the Camunda Orchestration Cluster API.
|
|
151
|
+
A stock Camunda gateway answers the same endpoint without it, so `status` can
|
|
152
|
+
tell the two apart and prints a `product:` line (`Nano BPM` or `Camunda`) with
|
|
153
|
+
the version. If `status` finds a Camunda gateway on the probed port it says so
|
|
154
|
+
explicitly rather than pretending it is a Nano cluster.
|
|
155
|
+
|
|
156
|
+
For the same reason, `c8ctl nano start` refuses to launch on top of an existing
|
|
157
|
+
gateway. If any chosen port is already serving a Camunda (or Nano) endpoint it
|
|
158
|
+
reports exactly what is running and exits without starting:
|
|
159
|
+
|
|
160
|
+
```
|
|
161
|
+
✗ Port 8080 is already serving a Camunda gateway (v8.6.0).
|
|
162
|
+
✗ Refusing to start Nano on top of a running Camunda instance.
|
|
163
|
+
Start on a free base port instead, e.g. "c8ctl nano start 1 --port 8180".
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
To run Nano alongside a local Camunda, give it a different base port
|
|
167
|
+
(`--port`); the collision check only applies to the ports Nano would bind.
|
|
168
|
+
|
|
169
|
+
## Fault injection: pause / resume a node
|
|
170
|
+
|
|
171
|
+
`c8ctl nano pause <nodeId>` and `c8ctl nano resume <nodeId>` let you simulate a
|
|
172
|
+
node failing and coming back online, to exercise Raft failover and recovery on a
|
|
173
|
+
local cluster:
|
|
174
|
+
|
|
175
|
+
```bash
|
|
176
|
+
c8ctl nano start 3 --rf 3 # 3-node Raft-replicated cluster
|
|
177
|
+
c8ctl nano pause 1 # freeze node 1 (SIGSTOP) — like a hang or partition
|
|
178
|
+
c8ctl nano status # node 1 shows "paused"; the cluster is "degraded"
|
|
179
|
+
c8ctl nano resume 1 # unfreeze node 1 (SIGCONT) — it rejoins
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
- **pause** sends `SIGSTOP`, which halts the process instantly and *cannot be
|
|
183
|
+
caught or ignored* — so the node stops responding without losing its PID or its
|
|
184
|
+
on-disk state, faithfully mimicking a hung/partitioned node.
|
|
185
|
+
- **resume** sends `SIGCONT`, and the process continues exactly where it left off.
|
|
186
|
+
- A paused node is reported as `paused` in `c8ctl nano status` and counts as
|
|
187
|
+
unhealthy, so the cluster shows `degraded`.
|
|
188
|
+
- `c8ctl nano stop` automatically resumes any paused node first, so it can shut
|
|
189
|
+
down gracefully rather than being force-killed.
|
|
190
|
+
|
|
191
|
+
## Trace capture for historical replay (`--capture`)
|
|
192
|
+
|
|
193
|
+
Start a cluster with `--capture` to record every instance's inputs so runs can be
|
|
194
|
+
replayed and analysed later:
|
|
195
|
+
|
|
196
|
+
```bash
|
|
197
|
+
c8ctl nano start 3 --capture
|
|
198
|
+
c8ctl nano status # shows "trace capture: on"
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
`--capture` sets `NANOBPMN_TRACE_STIMULI=1` on **every** node. That single flag
|
|
202
|
+
enables the Tier 2 recorded-input (stimuli) log *and* auto-enables Tier 1 variable
|
|
203
|
+
capture. It must be set on all nodes because each node's `TraceStore` only sees
|
|
204
|
+
instances on its own partitions.
|
|
205
|
+
|
|
206
|
+
Read a trace back from any node:
|
|
207
|
+
|
|
208
|
+
```
|
|
209
|
+
GET /console/api/traces/{instanceKey}
|
|
210
|
+
→ { creationVariables, stimuli[], <per-incident variables> }
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
Optional tuning is done with environment variables, which pass through from your
|
|
214
|
+
shell automatically (no dedicated flags):
|
|
215
|
+
|
|
216
|
+
| Env var | Default | Purpose |
|
|
217
|
+
|------------------------------------|---------|--------------------------------------|
|
|
218
|
+
| `NANOBPMN_TRACE_VARIABLES_MAX_BYTES` | 16384 | Max captured variable payload bytes |
|
|
219
|
+
| `NANOBPMN_TRACE_STIMULI_MAX` | 1024 | Max recorded stimuli per instance |
|
|
220
|
+
| `NANOBPMN_TRACE_CAPACITY` | 2000 | Max traced instances retained |
|
|
221
|
+
|
|
222
|
+
> Setting `NANOBPMN_TRACE_VARIABLES=1` alone enables only Tier 1 (variables); use
|
|
223
|
+
> `--capture` for full recorded-input replay.
|
|
224
|
+
|
|
225
|
+
## How nodes are configured
|
|
226
|
+
|
|
227
|
+
Each node is the single `nanobpmn` server binary, configured entirely through
|
|
228
|
+
environment variables. For `nano start 3` the plugin spawns:
|
|
229
|
+
|
|
230
|
+
| Node | `PORT` | `NANOBPMN_NODE_ID` | `NANOBPMN_NODES` |
|
|
231
|
+
|------|--------|--------------------|--------------------------------------------------------------------|
|
|
232
|
+
| 0 | 8080 | 0 | `http://127.0.0.1:8080,http://127.0.0.1:8081,http://127.0.0.1:8082` |
|
|
233
|
+
| 1 | 8081 | 1 | (same) |
|
|
234
|
+
| 2 | 8082 | 2 | (same) |
|
|
235
|
+
|
|
236
|
+
Additionally every node gets:
|
|
237
|
+
|
|
238
|
+
- `NANOBPMN_PARTITIONS` — total partitions (default = node count)
|
|
239
|
+
- `NANOBPMN_RF` — replication factor (default `1`)
|
|
240
|
+
- `NANOBPMN_RAFT=1` — set automatically when `RF > 1` (or via `--raft`)
|
|
241
|
+
- `NANOBPMN_DATA_DIR` — a per-node engine data directory
|
|
242
|
+
- `NANOBPMN_DURABILITY=async` — set by default for throughput; override by
|
|
243
|
+
exporting `NANOBPMN_DURABILITY` (e.g. `sync`) before `nano start`
|
|
244
|
+
- `NANOBPMN_REPLICATE_ACTIVATION=digest` — set by default so activated-job
|
|
245
|
+
state is observable across the cluster; override by exporting
|
|
246
|
+
`NANOBPMN_REPLICATE_ACTIVATION` before `nano start`
|
|
247
|
+
- `NANOBPMN_REPLICATION=leader-durable` — set by default; override by exporting
|
|
248
|
+
`NANOBPMN_REPLICATION` before `nano start`
|
|
249
|
+
- `NANOBPMN_WORKSPACE_DIR` — the shared workspace (models & workers)
|
|
250
|
+
- `NANOBPMN_TRACE_STIMULI=1` — set on every node when `--capture` is passed
|
|
251
|
+
|
|
252
|
+
Partition ownership is deterministic (`partition_id % num_nodes`), so the nodes
|
|
253
|
+
agree on the cluster map with no coordinator. With `RF=1` each partition lives on
|
|
254
|
+
one node and the others forward to it; with `RF>1` partitions are Raft-replicated
|
|
255
|
+
across nodes.
|
|
256
|
+
|
|
257
|
+
## Locating the binary
|
|
258
|
+
|
|
259
|
+
The plugin needs a built `nanobpmn` server binary. Resolution order:
|
|
260
|
+
|
|
261
|
+
1. `--binary <path>`
|
|
262
|
+
2. configured path (`c8ctl nano set bin <path>`)
|
|
263
|
+
3. `NANOBPMN_BINARY=<path>`
|
|
264
|
+
4. the matching **platform package** (`c8ctl-plugin-nano-<os>-<arch>`), installed
|
|
265
|
+
automatically as an `optionalDependency` when you install the plugin from npm
|
|
266
|
+
5. `release` build under the nanobpmn repo
|
|
267
|
+
6. `debug` build under the nanobpmn repo
|
|
268
|
+
|
|
269
|
+
Most users never need a local build: installing the plugin from npm pulls in the
|
|
270
|
+
prebuilt binary for their platform (step 4). Steps 5–6 are the local-dev path.
|
|
271
|
+
|
|
272
|
+
The repo root defaults to `~/workspace/nanobpmn` and can be overridden with
|
|
273
|
+
`NANOBPMN_REPO`. Build a binary with:
|
|
274
|
+
|
|
275
|
+
```bash
|
|
276
|
+
cd ~/workspace/nanobpmn && make release-gateway # API-only gateway
|
|
277
|
+
# or
|
|
278
|
+
cd ~/workspace/nanobpmn && make release # includes the web console
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
## State & data locations
|
|
282
|
+
|
|
283
|
+
State, config, logs, per-node data, and the workspace live under a per-user
|
|
284
|
+
directory (override with `C8CTL_NANO_HOME`):
|
|
285
|
+
|
|
286
|
+
- **macOS**: `~/Library/Application Support/c8ctl-nano`
|
|
287
|
+
- **Linux**: `$XDG_DATA_HOME/c8ctl-nano` (or `~/.local/share/c8ctl-nano`)
|
|
288
|
+
- **Windows**: `%LOCALAPPDATA%\c8ctl-nano`
|
|
289
|
+
|
|
290
|
+
```
|
|
291
|
+
<home>/config.json # persistent settings (binary path, workspace dir)
|
|
292
|
+
<home>/cluster.json # tracked cluster: nodes, pids, ports, config
|
|
293
|
+
<home>/data/node-<i>/ # per-node engine data (journal, spill, snapshots) — ephemeral
|
|
294
|
+
<home>/logs/node-<i>.log # per-node stdout/stderr
|
|
295
|
+
<home>/workspace/ # default shared workspace (models/, workers/) — persistent
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
`nano stop` removes the state file but keeps `data/` by default so you can stop a
|
|
299
|
+
cluster and keep your journals; pass `--purge` to delete engine data too. The
|
|
300
|
+
workspace is never removed except by `nano clean --workspace`.
|
|
301
|
+
|
|
302
|
+
## Flags
|
|
303
|
+
|
|
304
|
+
| Flag | Applies to | Description |
|
|
305
|
+
|----------------|------------|----------------------------------------------------------|
|
|
306
|
+
| `--port` | start | Base HTTP port; node *i* listens on `basePort+i` (8080) |
|
|
307
|
+
| `--partitions` | start | Total partitions across the cluster (default node count) |
|
|
308
|
+
| `--rf` | start | Replication factor; `>1` enables Raft (default `1`) |
|
|
309
|
+
| `--raft` | start | Force Raft on (default: on iff `rf>1`) |
|
|
310
|
+
| `--capture` | start | Enable trace capture (recorded-input replay) on every node |
|
|
311
|
+
| `--binary` | start | Path to the nanobpmn server binary (overrides `set bin`) |
|
|
312
|
+
| `--force` | start | Stop any existing cluster first |
|
|
313
|
+
| `--purge` | stop | Also delete per-node engine data |
|
|
314
|
+
| `--workspace` | clean | Also delete the workspace (models + workers) |
|
|
315
|
+
| `--follow`,`-f`| logs | Stream log output (`tail -F`) |
|
|
316
|
+
|
|
317
|
+
ProcessOS flags (`processos` command):
|
|
318
|
+
|
|
319
|
+
| Flag | Applies to | Description |
|
|
320
|
+
|----------------|------------|----------------------------------------------------------|
|
|
321
|
+
| `--port` | start | ProcessOS listen port (default 8090) |
|
|
322
|
+
| `--nano-url` | start | Target Nano BPM engine URL (default `http://localhost:8080`) |
|
|
323
|
+
| `--binary` | start | Path to the ProcessOS binary (overrides `set bin`) |
|
|
324
|
+
| `--spawn-nano` | start | Force spawning a pilot Nano engine (default on when a nano binary is available) |
|
|
325
|
+
| `--no-spawn-nano` | start | Don't spawn a pilot engine; reuse the `--nano-url` engine |
|
|
326
|
+
| `--force` | start | Stop any existing ProcessOS instance first |
|
|
327
|
+
| `--follow`,`-f`| logs | Stream log output (`tail -F`) |
|
|
328
|
+
|
|
329
|
+
## Managing ProcessOS (`processos`)
|
|
330
|
+
|
|
331
|
+
ProcessOS is the optimization-plane server that analyses a running Nano BPM
|
|
332
|
+
engine. The plugin can manage a single local ProcessOS instance with the same
|
|
333
|
+
start/stop/status/logs lifecycle as `nano`.
|
|
334
|
+
|
|
335
|
+
Unlike the Nano BPM server binary (which is distributed via npm — see below),
|
|
336
|
+
**the ProcessOS binary is downloaded manually**: grab the build for your
|
|
337
|
+
platform, then point the plugin at it.
|
|
338
|
+
|
|
339
|
+
```bash
|
|
340
|
+
# One-time: tell the plugin where the binary is
|
|
341
|
+
c8ctl processos set bin ~/Downloads/processos
|
|
342
|
+
|
|
343
|
+
# Start ProcessOS against the local Nano BPM engine (http://localhost:8080)
|
|
344
|
+
c8ctl processos start
|
|
345
|
+
|
|
346
|
+
# Or against a specific engine, on a specific port
|
|
347
|
+
c8ctl processos start --nano-url http://localhost:8080 --port 8090
|
|
348
|
+
|
|
349
|
+
# Inspect / stream logs / stop
|
|
350
|
+
c8ctl processos status
|
|
351
|
+
c8ctl processos logs --follow
|
|
352
|
+
c8ctl processos stop
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
On a successful `start` the summary leads with the landing page:
|
|
356
|
+
|
|
357
|
+
```
|
|
358
|
+
Start here http://127.0.0.1:8090/ (landing)
|
|
359
|
+
Cockpit http://127.0.0.1:8090/cockpit
|
|
360
|
+
Health http://127.0.0.1:8090/health
|
|
361
|
+
Target Nano http://localhost:8080
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
### Pilot engine (spawned by default)
|
|
365
|
+
|
|
366
|
+
ProcessOS uses a Nano engine in two roles: the **target** engine it analyses
|
|
367
|
+
(read-only, set with `--nano-url`), and its **own** internal "pilot" engine where
|
|
368
|
+
it runs experiments. **By default ProcessOS spawns its own pilot engine** as a
|
|
369
|
+
child process, so it never disturbs the target:
|
|
370
|
+
|
|
371
|
+
```bash
|
|
372
|
+
c8ctl processos start # spawns a pilot engine automatically
|
|
373
|
+
c8ctl processos start --no-spawn-nano # reuse the --nano-url engine for the pilot too
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
ProcessOS spawns its pilot engine from a Nano gateway binary given in
|
|
377
|
+
`PROCESSOS_NANO_BIN`. The plugin **auto-wires `PROCESSOS_NANO_BIN`** from the same
|
|
378
|
+
binary `c8ctl nano` uses (`--binary` / `nano set bin` / `$NANOBPMN_BINARY` / the
|
|
379
|
+
platform package / a repo build). A console-enabled nano build is required — the
|
|
380
|
+
npm-distributed binaries qualify. The spawned engine is torn down when ProcessOS
|
|
381
|
+
stops.
|
|
382
|
+
|
|
383
|
+
If no nano binary can be found, ProcessOS falls back to `--no-spawn-nano`
|
|
384
|
+
automatically (using the target engine as the pilot) and prints a warning. Force
|
|
385
|
+
the behaviour explicitly with `--spawn-nano` / `--no-spawn-nano`, override the
|
|
386
|
+
binary with `c8ctl processos set env PROCESSOS_NANO_BIN=<path>`, or set the mode
|
|
387
|
+
persistently with `c8ctl processos set env PROCESSOS_SPAWN_NANO=false`.
|
|
388
|
+
|
|
389
|
+
### ProcessOS configuration
|
|
390
|
+
|
|
391
|
+
Settings persist under a `processos` key in the same `config.json` as `nano`.
|
|
392
|
+
|
|
393
|
+
```bash
|
|
394
|
+
c8ctl processos set bin <path> # path to the downloaded ProcessOS binary
|
|
395
|
+
c8ctl processos set port <n> # listen port (default 8090)
|
|
396
|
+
c8ctl processos set nano-url <url> # target Nano BPM engine (default http://localhost:8080)
|
|
397
|
+
c8ctl processos set data-dir <path> # PROCESSOS_DATA_DIR (default <stateHome>/processos-data)
|
|
398
|
+
c8ctl processos set env KEY=VALUE # set any passthrough env var (e.g. PROCESSOS_LLM_MODEL)
|
|
399
|
+
c8ctl processos set env KEY= # unset a passthrough env var
|
|
400
|
+
c8ctl processos config # show current settings and on-disk paths
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
The binary is resolved in this order: `--binary` flag → `set bin` →
|
|
404
|
+
`$PROCESSOS_BINARY` → a local `processos/target/{release,debug}/processos` build.
|
|
405
|
+
Typed settings (`port`, `nano-url`, `data-dir`) always win over generic `env`
|
|
406
|
+
passthrough values when launching.
|
|
407
|
+
|
|
408
|
+
## Installing
|
|
409
|
+
|
|
410
|
+
```bash
|
|
411
|
+
c8ctl load plugin --from file:///path/to/c8ctl-nano
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
Then verify it shows up:
|
|
415
|
+
|
|
416
|
+
```bash
|
|
417
|
+
c8ctl help | grep nano
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
## Distribution & releasing
|
|
421
|
+
|
|
422
|
+
Releases are automated with **semantic-release** (`.github/workflows/release.yml`,
|
|
423
|
+
`release.config.cjs`). Pushing conventional commits to `main` cuts a version,
|
|
424
|
+
publishes to npm, and creates a GitHub Release.
|
|
425
|
+
|
|
426
|
+
### Platform packages
|
|
427
|
+
|
|
428
|
+
The server binary is shipped as a set of platform-specific npm packages, one per
|
|
429
|
+
target, gated by npm's `os`/`cpu` fields:
|
|
430
|
+
|
|
431
|
+
| package | os | cpu |
|
|
432
|
+
|----------------------------------|--------|-------|
|
|
433
|
+
| `c8ctl-plugin-nano-darwin-arm64` | darwin | arm64 |
|
|
434
|
+
| `c8ctl-plugin-nano-darwin-x64` | darwin | x64 |
|
|
435
|
+
| `c8ctl-plugin-nano-linux-x64` | linux | x64 |
|
|
436
|
+
| `c8ctl-plugin-nano-linux-arm64` | linux | arm64 |
|
|
437
|
+
| `c8ctl-plugin-nano-win32-x64` | win32 | x64 |
|
|
438
|
+
|
|
439
|
+
The root `c8ctl-plugin-nano` lists all five as `optionalDependencies` (pinned to
|
|
440
|
+
the exact release version, injected into the published tarball at release time).
|
|
441
|
+
npm installs only the one matching the host, so each user downloads a single
|
|
442
|
+
binary. The mapping lives in `platforms.mjs` — the single source of truth shared
|
|
443
|
+
by the build/publish scripts and the plugin's runtime resolution.
|
|
444
|
+
|
|
445
|
+
### Binary delivery contract (upstream CI)
|
|
446
|
+
|
|
447
|
+
This repo never builds or references the private Nano BPM source. Instead, the
|
|
448
|
+
upstream cross-compile pipeline uploads prebuilt binaries as assets on a rolling
|
|
449
|
+
GitHub Release named **`binaries`** in this repo. The release workflow downloads
|
|
450
|
+
them (`gh release download binaries`) and packs them into the platform packages.
|
|
451
|
+
|
|
452
|
+
Each asset must be named exactly (see `PLATFORMS[].asset` in `platforms.mjs`):
|
|
453
|
+
|
|
454
|
+
```
|
|
455
|
+
nanobpm-gateway-rest-server-darwin-arm64
|
|
456
|
+
nanobpm-gateway-rest-server-darwin-x64
|
|
457
|
+
nanobpm-gateway-rest-server-linux-x64
|
|
458
|
+
nanobpm-gateway-rest-server-linux-arm64
|
|
459
|
+
nanobpm-gateway-rest-server-win32-x64.exe
|
|
460
|
+
```
|
|
461
|
+
|
|
462
|
+
The upstream job needs a token with `contents: write` on this repo and can upload
|
|
463
|
+
with e.g. `gh release upload binaries <files> --clobber`.
|
|
464
|
+
|
|
465
|
+
### What triggers a release
|
|
466
|
+
|
|
467
|
+
The plugin's npm version is **decoupled** from the nanobpmn binary version, so
|
|
468
|
+
uploading new binaries does **not** by itself publish a new npm version —
|
|
469
|
+
`semantic-release` only releases on releasable commits to `main`.
|
|
470
|
+
|
|
471
|
+
To make a binary update ship, the upstream pipeline (after uploading the assets)
|
|
472
|
+
rewrites the tracked marker file **`nanobpmn-binary.json`** in this repo with the
|
|
473
|
+
new nanobpmn version/commit and pushes it as a `fix(binary): …` commit. That
|
|
474
|
+
commit triggers the release workflow, which downloads the just-uploaded binaries
|
|
475
|
+
and publishes a patch release. The marker is surfaced to users in `nano config`
|
|
476
|
+
(`bundled nano <version>`). The push is a no-op when the marker is unchanged.
|
|
477
|
+
|
|
478
|
+
```json
|
|
479
|
+
// nanobpmn-binary.json — overwritten by upstream CI; "0.0.0-dev" = local checkout
|
|
480
|
+
{ "version": "v1.4.2", "commit": "cdeb390", "updated": "2026-06-27T11:00:00Z" }
|
|
481
|
+
```
|
|
482
|
+
|
|
483
|
+
### OIDC / Trusted Publishing
|
|
484
|
+
|
|
485
|
+
The workflow is set up for npm **Trusted Publishing** (OIDC, `id-token: write`)
|
|
486
|
+
with provenance (`NPM_CONFIG_PROVENANCE: true`, requires this repo to be public).
|
|
487
|
+
Trusted Publishing is per-package and requires the package to already exist, so:
|
|
488
|
+
|
|
489
|
+
1. **Bootstrap** the first release with a granular-automation `NPM_TOKEN` secret —
|
|
490
|
+
it is used automatically and creates all six packages.
|
|
491
|
+
2. On npmjs.com, add a **Trusted Publisher** (this repo + `release.yml`) for the
|
|
492
|
+
root package and each of the five platform packages.
|
|
493
|
+
3. Remove the `NPM_TOKEN` secret; subsequent releases authenticate via OIDC.
|