Install
A working Flowdrome setup is one Nucleus (the control plane, with Studio embedded) plus one or more hosts (the machines that execute workflows). For a first ride you can run both on the same machine.
Default ports: 48170 for the Nucleus, 48150 for a host. First boot creates an Owner login of
admin/admin— change it immediately (the console warns you until you do).
Run the Nucleus (from source)
The Nucleus is a .NET service with the Studio UI embedded. From a checkout of the Flowdrome repository:
# prerequisites: Node 22+, Bun, and the .NET 10 SDK
npm install
npm run build
dotnet run --project core/Niner.Control
Open http://localhost:48170, sign in as admin / admin, and change the password under
Admin → Users.
Useful environment variables:
| Variable | Default | Meaning |
|---|---|---|
NINER_NUCLEUS_PORT | 48170 | Listen port |
NINER_NUCLEUS_PUBLIC_URL | – | The URL hosts and deployed apps use to dial home. Set this to a routable address (e.g. http://10.1.1.246:48170) when hosts are on other machines — it is baked into deployments. |
NINER_BOOTSTRAP_USER / NINER_BOOTSTRAP_PASSWORD | admin / admin | First-boot Owner account |
NINER_REQUIRE_AUTH | 0 | 1 locks anonymous access out entirely. Without it, anonymous visitors get one built-in view-only principal. |
NINER_DATA | ./.niner | Data directory (DuckDB stores, encrypted secrets) |
Add a host
A host is a single self-contained agent. Pick the artifact that fits the machine; all three end at the same join flow (connect the host to your Nucleus with a join token).
Option A — Docker image
npm run docker:build
This produces the chiseled image niner/host-agent:latest (~157 MB, distroless .NET base,
non-root) and a portable tarball under dist/docker/. Move the tarball to any server with
Docker and load it:
docker load -i niner-host-agent-<sha>.tar.gz
docker run -d -p 48150:48150 -v niner-data:/data niner/host-agent:latest
The chiseled image runs compiled workflow executables directly.
Option B — the live ISO appliance (Proxmox / any VM)
npm run iso:build
This builds dist/iso/niner-host-live-<sha>.iso (~321 MB, Debian-based live image). The ISO
is the operating system:
- Boot from it every time — there is no installer and no install step. Keep the ISO attached; a freshly booted VM is a host in seconds.
- Persistence by disk adoption. At boot the appliance looks for a filesystem labelled
NINER_DATAand mounts it as the host’s data directory — it never reformats it. If none exists, the first provably blank disk (no filesystem signatures, no partitions) is formatted once and labelledNINER_DATA. With no data disk at all, the host runs ephemeral and the console banner says so — add a blank virtual disk to keep state. - The OS layer is immutable across reboots. Anything outside the data disk — including a
changed root password — does not survive a reboot. Only
NINER_DATApersists. Upgrading a host = swapping the ISO and rebooting; the data disk carries the identity and state forward. - On Proxmox set the VM CPU type to
host: compiled workflow executables use Bun’s standard x64 build, which requires AVX2. A defaultkvm64-class vCPU kills apps at launch (exit 132).
The console shows the host’s URL on boot (e.g. http://10.1.1.112:48150).
Option C — bare single file
pwsh scripts/publish-host.ps1 -Rid linux-x64 # or win-x64, osx-arm64, …
One self-contained executable (~58 MB on Windows, ~72 MB on Linux) with the host dashboard embedded. No .NET install needed on the target. Run it under your init system of choice.
Connect the host to the Nucleus
In the Nucleus go to Hosts → Enroll, create a join token, and give it to the agent — via the
CLI (--join), environment (NINER_JOIN_*), or the host GUI’s Connect to Nucleus screen.
Once authorized, the host appears in the fleet view and can receive deployments.