flowlayer
// Server Runtime v1.1.1

FlowLayer Server

The FlowLayer server runtime: single binary that loads your config, orchestrates services, exposes the Session API, and streams logs and state in real time.

Quickstart

flowlayer-server -c flowlayer.jsonc -s 127.0.0.1:6999

flowlayer-client-tui -addr 127.0.0.1:6999 -token <token>

flowlayer-client-tui -config flowlayer.jsonc

The Orchestration Engine

The FlowLayer server is a single binary that reads a JSONC config, builds a dependency graph, launches services in the correct order, and exposes a live Session API.

Source of truth for process state, orchestration, and logs
Exposes Session API (/ws, /health) for clients
Engine source is closed; protocol and config reference are public
Does not restart crashed services automatically
Not a production supervisor — designed for development sessions

Two-binary architecture

Server flowlayer-server

Orchestration engine. Owns service state, lifecycle, logs, and Session API.

TUI flowlayer-client-tui

Official client. Connects over WebSocket. Observer and control surface. Separate binary.

Protocol: WebSocket V1 — public spec, open to custom clients

Config: JSONC — see Configuration for full reference

CLI Usage

FlowLayer is invoked as a single command. All flags are optional — the binary auto-discovers a config file in the current directory when no path is specified.

synopsis
flowlayer-server [-c <path>] [--config <path>] [<path>] [-s <bind>] [-token <value>] [--no-color] [-h|--help] [--version]

Session API bind — -s <bind>

Enables the Session API. Accepts host:port, :port, or a bare port number. CLI overrides session.bind from config.

-s 6999→ 127.0.0.1:6999 (localhost)
-s :6999→ :6999 (all interfaces)
-s 192.168.1.10:6999→ specific interface

Token — -token <value>

Bearer token override. Overrides session.token from config. When the Session API is enabled but no token is set via CLI or config, the server auto-generates one.

Token priority: -token flagsession.token configauto-generated fl_<uuid>

Color output — --no-color

--no-color Disables ANSI color output.
NO_COLOR Environment variable. Any non-empty value disables color.

If neither is set, color is enabled only when stdout is a TTY.

Version — --version

--version Prints flowlayer-server 1.1.1 and exits immediately. No config file is required.

Help — -h / --help

-h --help flowlayer-server with no arguments and flowlayer-server -h / --help print the same onboarding help and exit with code 0.

Error behavior

Error: <message> Invalid CLI/config input prints Error: <message>, then the full help, and exits with code 2.

Config Path Resolution

Priority order

Resolved in descending priority. Using both -c and --config simultaneously is an error. More than one positional argument is an error.

1. -c <path>
2. --config <path>
3. Positional argument
4. Auto-discovery (see right)

Auto-discovery order

Scans the current directory in this order when no explicit path is given:

1.flowlayer.jsonc
2.flowlayer.json
3.flowlayer.config.jsonc
4.flowlayer.config.json

If no config is found, FlowLayer exits with code 2.

Configuration

The Session API is configured in your JSONC file via session.bind and session.token.

{

  "session": {

    "bind": "127.0.0.1:6999",

    "token": "change-me"

  }

}

Open configuration reference

Session API

When enabled through -s or session.bind, the server exposes two authenticated endpoints. The HTTP server starts during boot, before services are launched.

GET /health

Liveness endpoint. Returns {'\"ok\": true'} when the server is running.

Requires: Authorization: Bearer <token>

GET /ws

Upgrades to a WebSocket session using the FlowLayer V1 protocol. On connection the server sends hello then snapshot.

See Protocol for the full message spec

Session API lifecycle

Activation

CLI -s takes precedence over session.bind. If neither is set, no Session API is started.

Startup

HTTP server starts before service wave execution. If the bind address is unavailable, FlowLayer exits immediately with an error.

Shutdown

On SIGINT/SIGTERM, the HTTP server stops first (2-second grace for in-flight requests), then services are torn down in reverse dependency order.

Bearer Token Auth

Every Session API request requires a bearer token. There are no public endpoints — authentication is enforced on all routes including /health and /ws.

Token priority

1. -token CLI flag

2. session.token config value

3. Auto-generated: fl_<uuid>

The token is ephemeral and printed in boot logs. It is a session-level gate for a development tool, not a production credential.

Request header

Authorization: Bearer <token>
auth responses
Condition HTTP Status
No Authorization header401 Unauthorized
Header present, token does not match403 Forbidden
Valid tokenRequest proceeds
$ flowlayer-server -c flowlayer.jsonc
[flowlayer] boot: session token: fl_d4e5f6a7-b8c9-4d0e-a1b2-c3d4e5f6a7b8
[flowlayer] boot: session API: 127.0.0.1:6999 (/ws, /health)

DAG + Wave Execution

At boot, FlowLayer validates the config, builds a dependency graph, and prints the execution plan before starting any service. Same config always produces the same order.

boot.output

$ flowlayer-server -c flowlayer.jsonc

[flowlayer] boot: validating config and graph...

[flowlayer] boot: session API: 127.0.0.1:6999 (/ws, /health)

[flowlayer] boot: DAG computed — 3 nodes, 2 waves

[flowlayer] boot: wave 0 │ billing → starting

[flowlayer] boot: wave 0 │ ping → starting

[flowlayer] boot: wave 0 │ billing → ready (http :3002/healthz)

[flowlayer] boot: wave 0 │ ping → ready (tcp :8088)

[flowlayer] boot: wave 1 │ users → starting

[flowlayer] boot: wave 1 │ users → ready (http :3003/healthz)

STARTUP COMPLETE — runtime active

DAG

Built from dependsOn declarations. Cycles cause immediate failure. Validated once at boot — never recomputed at runtime.

Waves

Services in the same wave start concurrently. The next wave begins only after all services in the current wave reach their terminal startup state (running or ready).

Runtime commands

After boot, clients can send start_service, stop_service, and restart_service via the WebSocket API. See Protocol for the full command reference.

Shutdown Behavior

Graceful shutdown sequence

01.

Session HTTP server stops. 2-second grace period for in-flight requests.

02.

Services torn down in reverse dependency order.

03.

Per-service: if stopCmd is defined, it runs instead of SIGTERM.

04.

If no stopCmd: SIGTERM sent to the process group. 8-second wait for I/O flushing.

05.

Any remaining processes receive SIGKILL.

stopCmd

Accepts string | string[]. When present, FlowLayer runs this command instead of sending SIGTERM to the process group. Runs with the same effective environment as cmd, including service env overrides. Useful for Docker Compose and similar runtimes that need an explicit stop command.

Trigger

Graceful shutdown is triggered by SIGINT or SIGTERM received by the FlowLayer process.

Track-Only Guarantee

FlowLayer maintains a registry of every process it spawns and will only ever signal processes in that registry. External processes are never touched. This guarantee prevents accidental interference with other running processes on the machine.

TRACKED

Signals and lifecycle management apply only to registered PIDs.

EXTERNAL

Unregistered processes remain untouched and unaware.

Runtime principles

  • Deterministic

    Same config, same order, every time. The execution plan is computed once and printed at boot.

  • Explicit

    Commands are executed directly — no shell is invoked. Shell operators (&&, |, redirections) are not interpreted. To use shell features, invoke a shell explicitly: ["sh", "-c", "..."]. See Configuration → cmd for details.

  • No automatic restart

    FlowLayer does not restart crashed services. An unexpected daemon exit transitions the service to failed.

Participation

Bug reports, feature requests, and roadmap discussion happen on GitHub Issues. The engine source is not public, but the protocol and config reference are, and alternative clients are welcome.