Skip to content

Server

// Server Runtimev1.1.1

flowlayer-server is the runtime engine that turns one config file into a live, controllable session. It validates config, computes startup order, launches services, exposes authenticated endpoints, and emits canonical state and logs to every client.

Terminal window
# Typical boot
flowlayer-server -c flowlayer.jsonc -s 127.0.0.1:6999
# Typical client attachment (official TUI)
flowlayer-client-tui -addr 127.0.0.1:6999 -token <token>
flowlayer-client-tui -config flowlayer.jsonc
DomainServer ownershipNot delegated to clients
Config intakeParse JSONC, validate schema, resolve config pathClients do not reinterpret config policy
Startup planningBuild DAG, compute waves, enforce dependency gatesClients cannot reorder service startup
Session surfaceStart and guard /health and /wsClients do not publish session endpoints
Runtime truthCanonical service states, events, command outcomes, logsClients only render or request
Shutdown policyReverse-order teardown, stopCmd or signal pathClients do not signal processes directly

This ownership model is why multiple clients can connect without creating divergent runtime behavior.

flowlayer-server

Server

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

flowlayer-client-tui

TUI Client

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

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

Behavior summary:

  • Running with no explicit config path triggers config auto-discovery in the current directory.
  • --help and -h print help and exit 0.
  • --version prints version and exits.
  • Invalid CLI/config combinations print Error: <message>, then help, then exit 2.
FlagPurposeNotes
-c <path>Primary explicit config pathHighest config-path precedence
--config <path>Alternate explicit config pathCannot be combined with -c
<path> (positional)Config path by positionMore than one positional arg is invalid
-s <bind>Enable Session API and set bindOverrides session.bind
-token <value>Session bearer token overrideOverrides session.token
--no-colorDisable ANSI color outputEquivalent effect to non-empty NO_COLOR
-h, --helpPrint help and exitSame output as bare help mode
--versionPrint binary version and exitNo config required

Accepted -s forms:

  • host:port
  • :port
  • bare port (interpreted as loopback bind)

Examples:

Terminal window
flowlayer-server -s 6999 -c ./services/flowlayer.jsonc
flowlayer-server -s :6999 -c ./services/flowlayer.jsonc
flowlayer-server -s 192.168.1.10:6999 -c ./services/flowlayer.jsonc

Resolution order (highest to lowest):

  1. -c <path>
  2. --config <path>
  3. positional <path>
  4. auto-discovery in current directory

Auto-discovery order:

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

Invalid combinations:

  • -c with --config in the same invocation
  • more than one positional config path
  • no discoverable config file and no explicit path

Failure mode: exit code 2 with help text.

Server behavior combines CLI and config values with strict precedence.

ConcernPrecedence chain
Config file path-c -> --config -> positional -> auto-discovery
Session bind-s -> session.bind -> Session API disabled
Session token-token -> session.token -> generated token (if Session API enabled)
Color output--no-color or NO_COLOR -> no ANSI color

Example session block:

{
"session": {
"bind": "127.0.0.1:6999",
"token": "change-me"
}
}

See Configuration for full schema.

The Session API listener is opt-in.

  • If neither -s nor session.bind is set, no Session API is started.
  • If enabled, listener startup happens during boot, before service wave execution.
  • Bind failure is fatal: the server exits rather than running in partial mode.

Operational guidance:

  • Prefer loopback binds (127.0.0.1:PORT) for local development.
  • Use :PORT or non-loopback interfaces only when intentionally exposing the API.

All Session API requests require bearer authentication.

Token source priority:

  1. -token
  2. session.token
  3. auto-generated token (fl_<uuid> pattern)
boot token output
$ flowlayer-server -c flowlayer.jsonc -s 127.0.0.1:6999[flowlayer] boot: session token: fl_d4e5f6a7-b8c9-4d0e-a1b2-c3d4e5f6a7b8[flowlayer] boot: session API: 127.0.0.1:6999 (/ws, /health)

Request header:

Authorization: Bearer <token>

Auth outcomes:

ConditionResult
Missing Authorization header401 Unauthorized
Header present but token mismatch403 Forbidden
Valid bearer tokenRequest proceeds

The generated token is a session credential for local/dev operation, not a full production identity system.

The runtime exposes two authenticated endpoints.

  • Method: GET
  • Auth: bearer token required
  • Purpose: liveness check of running session server
  • Response while live:
{"ok": true}
  • Method: GET (WebSocket upgrade)
  • Auth: bearer token required
  • Purpose: protocol transport for state, logs, and control commands

Handshake order on successful connect:

  1. hello
  2. snapshot
  3. incremental runtime events and command traffic

Protocol details: Protocol.

The server maintains canonical runtime state for all connected clients.

Runtime outputMeaning for clients
snapshotFull baseline state for newly connected client
status/lifecycle eventsIncremental changes after snapshot
command ack and resultRequest acceptance and completion outcome
log eventsLive merged stdout/stderr stream (best effort)

Service lifecycle interpretation is server-owned. Clients do not synthesize independent state from local assumptions.

Server log behavior in the session model:

  • Aggregates logs from tracked services into one timeline.
  • Emits live log events on the WebSocket stream.
  • Supports replay via get_logs for reconnect and catch-up flows.
  • Can persist canonical logs when server-side log persistence is configured.

Practical implications:

SituationServer behavior
Slow or disconnected clientClient may miss live events; replay fills gaps
Reconnect with high-water sequenceReplay can request after_seq continuity
Multiple clients connectedAll observe the same canonical log stream model

At boot, orchestration follows a strict sequence:

  1. Validate config and dependency graph.
  2. Compute DAG and startup waves.
  3. Start Session API listener (if configured).
  4. Launch wave 0 services concurrently.
  5. Advance to next wave only after current wave reaches terminal startup outcomes.
boot.output
$ flowlayer-server -c flowlayer.jsonc -s 127.0.0.1:6999[flowlayer] boot: validating config and graph…[flowlayer] boot: session API: 127.0.0.1:6999 (/ws, /health)[flowlayer] boot: session token: fl_d4e5f6a7-b8c9-4d0e-a1b2-c3d4e5f6a7b8[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

Control commands accepted through protocol path include:

  • start_service
  • stop_service
  • restart_service
  • start_all
  • stop_all

Clients request these actions; server policy validates and executes them.

Readiness is part of startup gating, not just a UI hint.

StageDescription
PlannedService included in validated DAG and wave
StartingProcess launch initiated by wave execution
Running or readyTerminal startup success condition for wave progression
Failed startupService fails before readiness, affecting dependents
BlockedDownstream service waits for upstream readiness/success

Illustrative flow:

config -> DAG/waves -> start wave N -> wait for startup outcomes -> unlock wave N+1

Shutdown begins when server receives SIGINT or SIGTERM.

Sequence:

  1. Stop Session HTTP server first.
  2. Apply short grace period for in-flight HTTP requests (2 seconds).
  3. Tear down services in reverse dependency order.
  4. For each service, use stopCmd if defined; otherwise signal process group.
  5. Wait for graceful process exit window.
  6. Force remaining processes with SIGKILL.
01.Session HTTP server stops. 2-second grace 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 to the process group. 8-second wait for I/O flushing.
05.Any remaining processes receive SIGKILL.

Timeouts from source behavior:

  • HTTP grace: 2 seconds
  • signal-based process wait: 8 seconds before forced kill path
AspectstopCmd pathSignal path
TriggerService defines stopCmdNo stopCmd defined
MechanismExecute explicit stop commandSend SIGTERM to tracked process group
EnvironmentSame effective env as service cmd, including service env overridesN/A (signal delivery)
Graceful intentRuntime-specific shutdown command (useful for wrappers)Generic process termination
FallbackIf process remains, eventual force-kill path still appliesSIGKILL after grace window

Use stopCmd for runtimes that need explicit shutdown semantics.

The server uses a track-only registry model:

  • It manages only processes it spawned and registered.
  • External/untracked processes are never signaled.
  • This prevents accidental interference with unrelated machine workloads.
TRACKED

Signals and lifecycle management apply only to processes spawned and registered by the server. External processes are never touched.

EXTERNAL

Unregistered processes remain untouched and unaware. This prevents accidental interference with unrelated machine workloads.

Execution model constraints:

  • Commands are executed directly.
  • Shell operators are not interpreted unless a shell is explicitly invoked.
  • For shell semantics, wrap explicitly (for example sh -c "...") in config command arrays.

Security posture in this runtime model:

  • Every request to /health and /ws is authenticated.
  • Token control is session-scoped, not user-account-scoped.
  • Bind address selection materially changes exposure.
  • Runtime action authority remains centralized in the server.

Operational baseline:

  1. Keep binds on loopback unless remote access is intentional.
  2. Treat session token as sensitive for the lifetime of the session.
  3. Rotate by restarting session when access scope changes.

Pattern A: local deterministic startup and attach

Section titled “Pattern A: local deterministic startup and attach”
Terminal window
flowlayer-server -c ./services/flowlayer.jsonc -s 127.0.0.1:6999
flowlayer-client-tui -addr 127.0.0.1:6999 -token <token>

Use when validating startup order and readiness gating quickly.

Terminal window
flowlayer-server -c ./services/flowlayer.jsonc
flowlayer-client-tui -config ./services/flowlayer.jsonc

Use when team workflow already stores session values in config.

Pattern C: investigate failed startup before restart loops

Section titled “Pattern C: investigate failed startup before restart loops”
  1. Review failure logs in client.
  2. Confirm dependency readiness conditions.
  3. Apply targeted restart_service only after cause is understood.

This avoids hiding root cause with blind restart cycles.

Collaboration paths aligned with the server page content:

  • Bug reports and feature requests go through project issue tracking.
  • Protocol and configuration surfaces are documented publicly.
  • Alternative clients remain possible through the public protocol contract.

Practical references:

  • Not a production supervisor for long-lived remote fleets.
  • No automatic restart policy for crashed services by default.
  • No implicit shell parsing for service command arrays.
  • No control over external processes outside tracked registry.
  • Session token model is intentionally lightweight for development sessions.