flowlayer
// Official Client v1.0.0

FlowLayer Client

Terminal UI for FlowLayer. The official terminal client connects to a running server over WebSocket and provides a deterministic local view of service state, live logs, and runtime controls.

Terminal Observability Client

The TUI connects over WebSocket to a running FlowLayer server and provides a local view of service state, live logs, and runtime controls. It is a thin client — all business truth stays in the server.

check Observer of server state (snapshot + live events + replay)
check Keyboard-first operator surface for start/stop/restart
check Reconnects automatically with exponential backoff
close Not an orchestrator — does not embed service logic
close Not a log archive — in-memory working window only

Two ways to connect

Pass -addr and -token directly, or use -config to read session.addr and session.token.

FlowLayer TUI Connected
S Start All X Stop
tab switch panel · ↑↓ navigate/scroll · / filter · esc close filter · i conn info · q quit
Services
Filter: —
— all logs
  billing ready
  ping failed
  users ready
Logs
Filter: —

16:23:50 ping [stderr] Commands:

16:23:50 ping [stderr] attach Attach local standard input, output, and error streams to a running container

16:23:50 ping [stderr] build Build an image from a Dockerfile

16:23:50 ping [stderr] exec Run a command in a running container

16:23:50 ping [stderr] images List images

16:23:50 ping [stderr] run Run a command in a new container

16:23:51 billing > billing@0.0.1 start:dev

16:23:51 billing > nest start --watch --preserveWatchOutput

16:23:52 billing [4:23:52 PM] Starting compilation in watch mode...

16:23:52 billing [4:23:52 PM] Found 0 errors. Watching for file changes.

16:23:52 billing [Nest] LOG [NestFactory] Starting Nest application...

16:23:52 billing [Nest] LOG [InstanceLoader] AppModule dependencies initialized +6ms

16:23:52 billing [Nest] LOG [RoutesResolver] AppController {/}: +2ms

16:23:52 billing [Nest] LOG [RouterExplorer] Mapped {/health, GET} route +2ms

16:23:52 billing [Nest] LOG [RouterExplorer] Mapped {/healthz, GET} route +0ms

16:23:52 billing [Nest] LOG [RouterExplorer] Mapped {/, GET} route +1ms

16:23:52 billing [Nest] LOG [NestApplication] Nest application successfully started +1ms

16:23:52 billing ready http: http://localhost:3002/healthz

16:23:56 ping failed_start: ready tcp: process exited before ready

16:23:56 users > users@0.0.1 start:dev

16:23:56 users > nest start --watch --preserveWatchOutput

16:23:56 users [4:23:56 PM] Starting compilation in watch mode...

16:23:58 users [4:23:58 PM] Found 0 errors. Watching for file changes.

16:23:58 users [Nest] LOG [NestFactory] Starting Nest application...

16:23:58 users [Nest] LOG [InstanceLoader] AppModule dependencies initialized +7ms

16:23:58 users [Nest] LOG [NestApplication] Nest application successfully started +1ms

16:23:58 users ready http: http://localhost:3003/healthz

16:23:58 [flowlayer] boot: startup ok: 2 running, 0 oneshot succeeded, 1 failed_start, 0 blocked

connected flowlayer.tech · since 2026 58-109 / 109 100%

Installation

download Download binary

Download the prebuilt binary for your platform from GitHub Releases. Binaries are available for Linux, macOS, and Windows on amd64 and arm64.

# Download and run directly

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

Go to Download page arrow_forward

code Run from source

For development or contributions. Requires Go.

# Run from source (server already running)

go run . -addr 127.0.0.1:6999 -token <token>

Connecting to the Server

The TUI supports two connection modes: Direct with -addr and -token, or Config with -config (reads session.addr and session.token).

1

Start the server

Run the server first. The TUI only connects after the Session API is already up.

2

Copy the token from the server logs

Read the token from the server startup log line and keep that exact value.

3

Connect with -addr / -token or -config

Pass flags directly, or use -config to read connection values from the server config.

verified

Standard usage

The flow is always the same: start the server, copy the token from the server logs, then connect the TUI with -addr and -token.

# 1. Start the server

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

# 2. Copy the token from the server logs

[flowlayer] boot: session token: fl_abc123

# 3. Connect the TUI with -addr and -token

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

tune

Flags reference

-addr <host:port>

Address of the running server. Required.

-token <token>

Session token printed by the server at startup. Copy it from the server logs and pass it here.

-config <path>

Path to a FlowLayer config file. The TUI reads session.addr and session.token.

-h, --help

Print help and exit.

--version

Print flowlayer-client-tui 1.0.0 and exit.

Bare invocation launches the TUI. Unknown flags or positional arguments print an error and the help, exit 2. NO_COLOR disables red error coloring.

description

Configuration file

Use -config to load connection values from JSONC.

{

  "session": {

    "addr": "127.0.0.1:6999",

    "token": "change-me"

  }

}

Use session.addr for TUI connections.

# Launch with config

flowlayer-client-tui -config flowlayer.jsonc

Keybindings

navigation
↑ ↓ Navigate services / scroll logs
Tab Switch focus between panels
Page ↑ ↓ Scroll log panel by page
filter & info
/ Start filter on focused panel
Esc Close filter or modal
i Connection info (address, token, status)
service control
s Start / restart selected service
x Stop selected service
q Quit the TUI

Connection & Message Flow

The TUI keeps local UI state only (selection, filters, busy hints, footer messages). Service truth comes entirely from server messages.

session lifecycle
1.
TUI connects to ws://<addr>/ws with bearer token
2.
Server sends hello (protocol version, capabilities)
3.
Server sends snapshot (full service state)
4.
TUI consumes live events: service_status, log
5.
TUI sends commands via the same WebSocket

hub State model

The TUI uses snapshot for the full initial state, then applies service_status events as incremental updates. The server is the single authority. Command results provide user feedback only — they do not invent state.

bolt Available commands

start_service / stop_service / restart_service

start_all / stop_all

get_logs — used for initial load and replay after reconnect

Additional protocol capabilities such as get_snapshot exist for custom clients. See Protocol reference.

info No HTTP/SSE path

All communication uses the single WebSocket connection at /ws. There is no HTTP polling or SSE path in the current TUI.

Log Model

Logs are an ordered stream, not a static dataset. The TUI merges live events with historical replay into a continuous operator view.

sort Sequence cursor (seq)

Every log entry has a globally unique, monotonically increasing seq. The TUI tracks lastSeq as the highest sequence seen across both live events and replay responses. This is the high-water mark for log continuity.

merge Deduplication

The same log entry can arrive via live log event and via get_logs replay. The TUI deduplicates by seq, maintaining a seen-set to prevent duplicate rows when replay overlaps with live delivery.

memory Buffer size (effective_limit)

The TUI never computes log limits locally. It sends get_logs without a limit field, receives effective_limit from the server, and uses that value to trim its local buffer. All retention decisions are server-driven.

warning Best-effort delivery

Live log events are best-effort. If the TUI is slow, the server may drop log events silently. The TUI uses get_logs with after_seq to recover gaps after reconnection.

log continuity pattern
1.On initial load: send get_logs (optionally with service filter)
2.Store effective_limit from the response for buffer management
3.Track lastSeq = max seq seen (from both get_logs and live log events)
4.Append live log events as they arrive; deduplicate by seq
5.On reconnect: after snapshot, send get_logs with after_seq=lastSeq
6.Merge replayed entries; deduplicate; trim buffer to effective_limit

Reconnect Behavior

The server does not persist sessions. A reconnection is a completely new session — the TUI performs a full handshake and replays logs from lastSeq.

Backoff schedule

500ms → 1s → 2s → 5s (max)

All pending commands are invalidated on disconnect. The server has no mechanism to deliver responses across sessions.

reconnect sequence
1.

Exponential backoff

Wait, then attempt reconnect. 500ms → 1s → 2s → 5s max.

2.

Full handshake

Wait for hello, then snapshot.

3.

Log replay

If lastSeq > 0: send get_logs with after_seq=lastSeq.

4.

Merge & deduplicate

Merge replayed entries with any live events received in the meantime. Deduplicate by seq.

!

Pending commands are dropped

Commands awaiting ack or result are orphaned at disconnect. The TUI marks them as failed and does not auto-retry.

What the TUI Is Not

close

Not an orchestrator

The TUI does not start or manage services itself. All orchestration logic stays in the FlowLayer server.

close

Not a log archive

Maintains an in-memory working window bounded by effective_limit. For durable log retention, use logs.dir on the server.

close

Not a source of truth

Service state is server-owned. The TUI never invents state from command results — it only displays what the server reports.

close

Not a source of config truth

The TUI only reads connection values from config via -config: session.addr and session.token. It does not read or apply service definitions or server settings.

Contributing

code

Source exploration

The TUI is open source. Read the code to understand how log deduplication, reconnect backoff, and state merging work in practice.

github.com/FlowLayer/tui open_in_new
palette

UI contributions

Improvements to layout, keybindings, log display, or status presentation are welcome. Open an issue to discuss first.

Open an issue open_in_new
build

Alternative clients

The FlowLayer protocol is public. You can build your own client — a web UI, a plugin, an IDE integration — using the same WebSocket protocol. The only requirements are a WebSocket library and a JSON parser.

Protocol reference arrow_forward