CLI command

skarbiec serve

Run the host's one Skarbiec process: the HTTP API, the capability listener, and one replication component for every bond the vault pulls.

Invocation#

Shell
skarbiec serve [--port <port> | --no-http] [--socket <unix-socket-path>]

Purpose#

Run the host's one Skarbiec process: the HTTP API, the capability listener, and one replication component for every bond the vault pulls.

Required inputs and options#

  • The HTTP listener is loopback-only. --no-http runs the same process without it, for a hardened capability host that allows no TCP at all; it then requires a capability socket. --socket or SKARBIEC_CAP_SOCKET enables capability redemption using the configured workload trust and routes. Replication takes no arguments: every serve-channel bond that records --token-file and --interval (bond-add) is pulled, so every host runs the same command.

Output and state effects#

  • Runs its components as threads, never as child services. Each replication component journals replication-start, pulls at start and then at the bond's interval, and reads the bearer file on every pull. HTTP mutations and replica pulls persist through the normal vault operations. A component that exits or panics fails the owning command instead of leaving a partially functioning HTTP service running. An accept error that belongs to one connection - a client that reset while it waited in the listen queue (ECONNABORTED), ECONNRESET, EINTR, or a network error Linux hands back from accept - ends only that connection; any other accept error ends the listener and with it the process, which launchd restarts. A request that fails with EBADF on the socket the process itself just accepted ends the process the same way: no client can close a descriptor inside the process, so no answer it writes could be trusted to reach its caller, and launchd starts a clean one instead of keeping an active unit that answers nothing. Every other request failure - a client that resets, stalls or abandons its request - is printed as request error: <cause> and ends only that request. Started by launchd as com.wisent.always-on.skarbiec, serve first takes over the Skarbiec units it replaces (com.wisent.compute.service.skarbiec-replica-sync, com.wisent.compute.service.skarbiec-control-plane, com.wisent.skarbiec and com.wisent.compute.service.com.wisent.skarbiec-weles) whose launch agent is in the user's ~/Library/LaunchAgents: it records the removed sync-daemon's --token-file and --consumer on that bond's serve channel, notes the loopback ports each unit was listening on, boots the unit out, removes its launch agent, journals unit-retired, and then listens on those ports as well as its own, so a consumer still using an old port reaches the one process. The ports are kept beside the vault in <vault>.inherited-ports.json, and every later start as that unit answers on them again; a host converged before the record existed has it rebuilt from the journal's unit-retired entries on its next start. As that unit it also compares the file it was started from with what is installed there before each connection it accepts: once an install has renamed a new executable over it, it journals serve-replaced and ends, so launchd starts the installed release. A retired unit's port that another process holds is reported on stderr and skipped; a replica daemon whose bond cannot be recorded is kept and said to be. Run by hand or by a test, serve retires nothing, binds only its own port and keeps running the image it was started from.

Refusals#

  • Refuses an occupied TCP listener, a capability path that is not a socket, or a capability socket already served by another process. Only a disconnected stale socket is replaced. `serve --no-http binds no port; drop --port` and `serve --no-http requires --socket or SKARBIEC_CAP_SOCKET: it would serve nothing` refuse before anything is bound. A failed or refused pull does not stop the service: it is printed to stderr and journalled as replication-failed with the detail, and bond status shows the stale bond.