Hosts & deployment

Flowdrome splits management from execution:

  • The Nucleus is the control plane. Workflow registry, credentials vault, users & roles, the host fleet, deployments, the approvals inbox. It never executes a workflow.
  • A host is the data plane: a machine running the host agent, with the same engine the editor uses embedded inside it. Deployed workflows are served by that engine. Hosts keep running if the Nucleus is unreachable; they dial home for secrets at run start and for management actions.

The split is the architecture’s load-bearing wall. The control plane can restart, upgrade, or sit on the other side of a flaky link without taking a single workflow down — and a host can be a 300 MB live-ISO VM that does nothing but run apps. The screen-by-screen tour of both sides (fleet view, host dashboard, approvals inbox, run drawer) is the Hosts guide.

Enrolling a host

Install a host (four artifacts: single exe, Docker image, Proxmox LXC template, live ISO), then connect it: Hosts → Enroll in the Nucleus issues a join token; the agent takes it via CLI (--join), environment (FLOWDROME_JOIN_*) or its GUI Connect to Nucleus screen. Authorized hosts appear in the fleet view, grouped by environment, with live status, an open-host link, and per-host deployments. De-authorizing a host stops it from receiving anything.

Deploying a workflow

From a workflow’s Deploy action, pick a host — that’s the whole decision. The Nucleus pushes the exact flowdrome.workflow.v1 document you tested (no conversion, no compile step), stamped with its saved version and deploy time, plus a scoped resolve token for secrets leasing. The host persists the deploy envelope (it survives restarts) and registers the workflow with its embedded engine — the unified hosted runtime: one engine and one worker pool per host, shared by every workflow deployed to it.

The host’s serve layer takes over the triggers: HTTP webhooks, schedules (interval and cron), HTML forms, web chat, WebSocket, Telegram (long-poll and webhook), Slack events, and WhatsApp. Runs execute on the embedded engine with the same envelope capture you saw in the editor. Stopping a deployment is intentional and distinct from a crashed one; removing it uninstalls the document.

x64 note: the host’s engine worker is compiled with Bun’s standard build, which requires AVX2. On Proxmox set the VM CPU type to host — a kvm64-class vCPU kills it at launch (exit 132).

Sub-workflows come along

A workflow that runs sub-workflows installs self-contained. On deploy the Nucleus walks the whole dependency tree and:

  • Checks everything exists first — every sub-workflow it uses (transitively), plus the variables and credentials it and its subs reference. Anything missing blocks the deploy with the exact list, so a workflow never installs only to fail on its first run.
  • Inlines the sub-workflows into the deployed document. Each Execute Workflow node is expanded into the master graph, so the host serves one workflow: every node runs — and is tracked — in a single run history, and the sub-workflows never appear as separate deployments cluttering the fleet.

The Deploy action previews what an install brings along (“…brings along 3 sub-workflows, embedded to run inline”). Secrets are still never baked in — the host dial-homes for their values at run start; the dependency check only confirms they’re defined.

The same self-contained artifact comes from Export → Self-contained (or GET /api/workflows/{id}/export?bundle=1) — a single file that installs anywhere with nothing else to bring.

Deploy carries a frozen copy

Sub-workflows aren’t the only dependencies that ride along. A deploy walks the workflow for the tables it reads or writes and the interfaces whose pages run it, and freezes a copy of each:

  • Tables deploy with their schema pinned at the deploy-time version. The host serves rows against that frozen schema, so a column dropped or retyped in the Nucleus tomorrow can’t break a running app.
  • Interface pages that call the workflow deploy with the workflow, at their current content version, and are served from the host.

The deploy manifest lists all of it up front — the same “checks everything exists first” gate that covers sub-workflows now includes tables and interfaces, each with the exact version being pinned:

GET /api/workflows/{id}/dependencies
  → { ok, subWorkflows[], variables[], credentials[],
      tables:[{id,name,version,present}], interfaces:[{id,title,slug,version}] }

Editing the live table or interface afterwards mints a new version (its version history records it), but active deployments keep serving their pinned copy — they don’t drift out from under you. The change reaches a host only when you redeploy. Until then the table/interface’s Where used view flags each lagging deployment stale, so the impact of a schema or content edit is visible before you commit it — the same version-badge drift you see for the workflow document itself.

Watching the fleet

  • Workflows view — each workflow row expands to its deployments across hosts (matched by workflow id, so renames don’t orphan deployments), with status, a version badge (v3 in teal when the deployment matches the current saved version, orange when it has drifted behind a newer save), and a logs drawer streaming output through the Nucleus.
  • Hosts view — fleet health at a glance; each host’s own dashboard shows apps, queues, the run ledger and a Resources tab with per-app CPU/memory/disk telemetry.
  • Approvals inbox — every pending approval gate across every authorized host, in the Nucleus header, with approve/reject in place.
A host dashboard with running apps and a pending approval
A live host's own dashboard: six running apps, a pending approval panel, and the selected app's run statistics — the data plane managing itself.

The host upgrade story

Host state lives in one data directory; the agent is replaceable around it.

  • Bare exe / Docker: replace the binary or image, keep the data directory / volume.

  • Proxmox LXC: run flowdrome-upgrade <new-template.tar.gz> inside the container (in-place, the template doubles as the upgrade artifact) — or, with /data on its own mount point, create a new CT from the new template and pct move-volume the data volume across.

  • Live ISO appliance: the OS is the ISO — upgrading is swapping the attached ISO and rebooting. At boot the appliance adopts its data disk by label:

    1. A filesystem labelled FLOWDROME_DATA → mounted as the data directory. Never reformatted.
    2. Otherwise, the first provably blank disk (no filesystem signatures, no partition table; removable/optical/read-only devices excluded) → formatted exactly once, labelled FLOWDROME_DATA.
    3. No candidate disk → the host runs ephemeral and says so on the console.

    Host identity, apps and run data ride the data disk across ISO swaps. OS-level changes (including passwords) live on the boot overlay and reset every reboot — that is the appliance contract.

Scale expectations

The management plane is light: a host comfortably manages 100 deployed workflows on its shared runtime (monitoring round-trips under 50 ms, restarts in the hundreds of milliseconds). Deploys are pushes of a JSON document — provisioning many hosts is bound by your network, not by a build step.