Worker in Depth

The worker quickstart gets a worker running and paired. This page covers the rest: what the Desktop shows about a worker, the security model, day-to-day operation, phone pairing and the [worker] settings.

One window at a time

A worker has one remote window at a time. If you open the worker from a second Desktop, a browser, or with flightdeck connect, the newer one takes over. The first window shows Taken over by <device> with a Reconnect button (in a browser, Take it back), which takes the worker back. Its pairing stays valid.

If the worker is stopped, the window shows The worker stopped. and tells you to run flightdeck worker start on the machine, then Reconnect.

When no window is open, each Desktop keeps a status-only background link to its saved workers. Each row in the WORKERS section shows a status pill:

PillMeaning
connecting…The Desktop is dialling the worker.
onlineConnected. The row shows the worker's health (for example load 0.42 · 18 GB free · 3 agents), how many agents need you, and its version.
offlineUnreachable. The row shows when it was last seen, and the Desktop retries.
not pairedThis Desktop's token is gone. Connect to remote… pairs it again.
access revokedThe worker revoked this Desktop. Pair again with a new code.
update neededThe Desktop and the worker speak protocols too far apart. The row says which side to update.

A version differs badge means the worker runs a different FlightDeck version than the Desktop. Click a row to open that worker's window.

The Desktop raises OS notifications for the worker's agents (needs input, error, done), the way a local FlightDeck would. They are not posted while a window to that worker is open, because that window notifies instead. When several Desktop processes run on one machine, only one posts them. Background links carry no terminal output and can't send input, and they never cause a takeover.

Host messages (for example a refused merge or a failed clone) appear in the open window. While nothing is attached, the worker keeps the last 100. The next window shows them as N messages while you were away.

Security

  • The tailnet is the boundary. The worker listens only on Tailscale addresses, so your Tailscale ACLs decide who can even reach the port.
  • Codes need a shell on the box. A pairing code can only be minted through a control socket that only the worker account can reach. Getting a code already means being logged in as that account.
  • Tokens are per device and revocable. List them with flightdeck worker devices. Revoke one with flightdeck worker revoke <device>, by id, by label (case-insensitive) or by a unique id prefix. Its live connections close at once, and it must pair again to reconnect.
  • Uploads stay in the home folder. Uploading files writes only inside the worker account's home folder, never overwrites a file without asking, and only the window that holds the worker can do it.
  • Nothing leaves the WireGuard tunnel. The browser page also gets HTTPS when your tailnet allows it (below), and the worker never handles your agent or git logins.
flightdeck worker devices
flightdeck worker revoke mbp

devices prints a table with each paired device's id (a browser shows as, for example, Chrome on macOS (browser)), label, state (attached, background or offline; revoked ones are marked), when it paired, when it was last seen and its address. devices --json prints a bare array for scripts.

Whether agents run in containers or worktree isolation follows your normal configuration, with no worker-specific default.

HTTPS

The worker serves the browser page and the Desktop's connection on the same port. When it can, it also answers HTTPS there, with a certificate from Tailscale for the machine's name (box.tail1234.ts.net). That makes the page a secure context, so it can show notifications while its tab is in the background.

To turn it on, in the Tailscale admin console under DNS, enable MagicDNS and HTTPS Certificates. The worker notices within a minute, fetches a certificate with tailscale cert and renews it daily. flightdeck worker status shows the result:

Web:          https://box.tail1234.ts.net:7420 (certificate until 2027-02-09)

or, without a certificate, why not:

Web:          http://100.101.102.103:7420 (HTTPS unavailable: HTTPS certificates are not enabled for this tailnet …)

Without a certificate, the browser page is served over plain http:// on the worker's Tailscale address. It is still encrypted by Tailscale, but the browser treats it as insecure, so notifications are not offered. Once a certificate is loaded, an http:// link redirects to the https:// name. The Desktop always connects without TLS and is not affected.

To serve the page without HTTPS, set https = false under [worker]. To serve no browser page at all, set web = false. Run flightdeck worker restart after either change.

Pair the iPhone app

A worker can also pair the FlightDeck Remote iPhone app directly, over its Tailscale address. It is off by default, because a paired phone can type into agents and open a shell.

  1. Add phone = true under [worker] in the worker's ~/.flightdeck/config.toml and run flightdeck worker restart.
  2. In the Worker shell, run flightdeck worker pair --phone. It prints a QR code and a 4-digit code and waits until the phone has paired.

The phone lists the worker as <host> (worker). flightdeck worker devices and flightdeck worker status list paired phones, and flightdeck worker revoke <pairing id> unpairs one. The worker sends no phone notifications while a Desktop window is attached to it. See FlightDeck Remote for the app itself.

Operate the worker

Status

flightdeck worker status
flightdeck worker status --json

status shows whether the worker is running, its pid, uptime and version, the addresses it listens on (or why it isn't listening), paired devices, the attached device, background links, and every project with its agents and their status. When the worker is stopped, it shows the supervisor's last exit and, if it gave up, why. --json prints a stable shape for scripts.

Logs

flightdeck worker logs          # last 100 lines
flightdeck worker logs -n 500   # last 500 lines
flightdeck worker logs -f       # follow

The log is ~/.flightdeck/logs/worker.log, rotated at 10 MB with 5 files kept. It reads the file directly, so it works while the worker is down.

Stop and restart

flightdeck worker stop
flightdeck worker restart

stop shuts the worker down gracefully and saves state, so the next start resumes your agents. restart is stop then start. Agents relaunch with their resume command, as in the terminal UI. A turn that was in progress is lost.

Start on boot

flightdeck worker enable            # set it up and start the worker
flightdeck worker enable --dry-run  # show the file and commands, change nothing
flightdeck worker disable           # take it down (stops a worker it started)

enable writes ~/Library/LaunchAgents/agency.neworange.flightdeck.worker.plist (macOS) or ~/.config/systemd/user/flightdeck-worker.service (Linux). It needs no root. The service manager starts the worker's supervisor and never restarts it itself, so crash recovery works as described below, and flightdeck worker stop keeps the worker stopped until the next start, reboot or login. While it is set up, start and restart go through the service manager too. When they can't (on a Mac with nobody logged in at the screen, or on Linux without lingering) they start the worker directly and say why.

The worker gets your login shell's PATH, SHELL and LANG as they were when you ran enable. Nothing else from your shell profile is copied, so API keys exported there don't reach it. Run flightdeck worker enable again after installing tools in a new place, then flightdeck worker restart.

  • macOS: the worker starts when the account logs in at the screen. For an unattended Mac, turn on automatic login.
  • Linux: without lingering, systemd starts the worker only once you log in and stops it when you log out. enable prints the command to fix that: sudo loginctl enable-linger $USER.

flightdeck worker status has a Start on boot line (Start at login on a Mac) that says whether it is on. To dig deeper, use launchctl print gui/$(id -u)/agency.neworange.flightdeck.worker on a Mac, or systemctl --user status flightdeck-worker and journalctl --user -u flightdeck-worker on Linux.

Crash recovery

A small supervisor restarts the worker if it crashes, waiting longer after each crash (from 1 second up to 60). If the worker crashes 5 times within 10 minutes, the supervisor gives up. flightdeck worker status then shows Gave up: with the reason (for example 5 crashes within 10 minutes), and flightdeck worker logs shows the details. A run that lasts at least a minute resets the wait to 1 second. Fix the cause and run flightdeck worker start. The supervisor also gives up at once if the global config is invalid, or if another worker already runs for the account.

No Tailscale address

If the worker has no Tailscale address (Tailscale is down or logged out), it keeps running and your agents keep working. status reports Not listening: no Tailscale address. The worker checks every 5 seconds and starts listening as soon as an address appears, and rebinds if the address changes. Desktops reconnect on their own. Run tailscale up on the worker if it stays that way.

Update

On the worker, in the Worker shell or over SSH:

flightdeck update
flightdeck worker restart

The restart makes the worker and its supervisor run the new binary. Until then, status shows the running worker's version with a note that the CLI differs, and the Desktop shows a version differs badge in the launcher and a banner in the worker window: "This worker runs FlightDeck <worker>; this app was built with <app>. Update it from the worker shell: flightdeck update, then flightdeck worker restart." Updating from the Desktop is not available in this version. Start on boot doesn't need setting up again after an update: Homebrew and the installer both keep the binary's path.

The terminal UI on a worker machine

While a worker runs, starting the terminal UI or a local Desktop window on that machine refuses: "A FlightDeck worker is running on this machine and serving its projects. Control it from FlightDeck Desktop, or run flightdeck worker stop." Desktop remote windows on that machine are not affected.

Configuration

The worker reads a [worker] table from your global ~/.flightdeck/config.toml. A project's [worker] table is ignored. Every key is optional.

[worker]
port = 7420
projects_root = "~/flightdeck"
default_cols = 200
default_rows = 50
web = true
https = true
KeyDefaultMeaning
port7420TCP port served on each Tailscale address. 0 is rejected.
projects_root"~/flightdeck"Scanned two levels deep for repositories to offer, and where clones land. ~ and relative paths are relative to your home directory. Must not be empty.
default_cols200Terminal width for an agent started while no window has reported a size (20 to 1000).
default_rows50Terminal height in the same case (4 to 500).
phonefalseAllow pairing the iPhone app with flightdeck worker pair --phone. See Pair the iPhone app.
webtrueServe FlightDeck Web's page, so a browser can pair and drive the worker. false serves only the Desktop's connection.
httpstrueFetch a Tailscale certificate and answer HTTPS on the same port, when your tailnet has HTTPS certificates on. See HTTPS.

An attached window resizes terminals to fit its panes, so the defaults only apply when nothing is attached. An invalid [worker] table stops the worker from starting. Run flightdeck worker logs to see the message. These settings aren't in the configuration manager, so edit the file and run flightdeck worker restart.

To change other settings (agents, git, UI) for the worker's projects, open the configuration manager from the worker window: choose Open Configuration in the command palette. It edits the configuration on the worker, and it works in a remote window on any host, not only workers.