Wheelhouse docs

Every flag#

wheelhouse-agent registers 51 flags, all of them in one function — registerFlags() in agent/main.go. Every subcommand shares the whole set, so a flag that means nothing to plan is accepted and ignored rather than refused. The tables below are grouped the way the source groups them; the defaults are the literal third argument of each flag.*Var call.

Re-derive the list for the version you are running:

bash
grep -E '^\tflag\.(String|Bool|Int|Duration)Var' agent/main.go

Router connection#

FlagDefaultWhat it does
--api-urlhttps://127.0.0.1Base URL of the router's own HTTP API. A trailing slash is trimmed. On an appliance this is loopback, because first boot pins the router API to loopback.
--api-key$VYOS_API_KEYThe router API key. Root-equivalent on that router. Prefer the file form.
--api-key-fileFile holding the key. Required to exist when given: a missing file here is fatal, unlike the other four secret files.
--demofalseStart with no router credentials at all. Every router read then fails; the UI still loads. Also disables the cache primer.

Either --demo, or both a non-empty --api-url and a non-empty API key, are required. Without them the agent logs either --demo or both --api-url and --api-key are required and exits 2.

Listener#

FlagDefaultWhat it does
--addr127.0.0.1:8090Listen address. The shipped systemd unit overrides this to 0.0.0.0:8443 — every interface, including the WAN.
--ui-dirDirectory of built UI files. Empty means no GET / route at all: the API answers, the browser gets a 404. The package installs the UI at /usr/share/wheelhouse/ui.
--trust-proxyfalseTrust X-Forwarded-For and X-Forwarded-Proto. Only behind a reverse proxy you control — without it, a client could forge its own address into the audit log and around the per-address login rate limit. The last element of the header is used, because that is the only one the proxy vouches for.
--metrics-publicfalseServe GET /metrics with no authentication. Off by default, where the route needs the viewer role.

Data and state#

FlagDefaultWhat it does
--data-dir/config/wheelhouseEverything the agent persists: state.json, audit.jsonl, the self-signed certificate, initial-password. Created at mode 0700 if missing. On VyOS, /config survives an image upgrade and /var/lib does not.
--fleet-configJSON file listing other routers. Loaded whatever the licence says; the fleet endpoints answer 402 until a licence whose plan includes fleet is held. The file must be mode 0600 or the agent exits 1.

Only one agent may hold a data directory at a time. A second one exits 1 with another agent is running against this data dir.

TLS#

FlagDefaultWhat it does
--tls-certCertificate file. Must be given together with --tls-key; one without the other is a startup error.
--tls-keyPrivate key file.
--tls-self-signedfalseGenerate agent.crt / agent.key in the data directory when --tls-cert is not set and no usable pair is already there.

The generated certificate is a server leaf, not a CA: P-256 ECDSA, 398 days, DigitalSignature + ServerAuth, IsCA: false, with SANs for the host name, <host>.local, localhost, 127.0.0.1, ::1 and every non-loopback address on the box. An existing certificate is replaced on sight if it is unreadable, if it was generated as a CA by an older build, or if it expires within 30 days.

Serving on a non-loopback address with no certificate logs a warning naming the three fixes. See Ports and listeners.

Authentication and the first account#

FlagDefaultWhat it does
--admin-token$WHEELHOUSE_ADMIN_TOKENBreak-glass Bearer token, admin role, no account behind it. Prefer the file form.
--admin-token-fileFile holding it. A missing file degrades to "no break-glass" with a warning rather than aborting startup, because the shipped unit names the path unconditionally.
--initial-adminadminUser name created on the first start with an empty state file.
--initial-admin-password$WHEELHOUSE_INITIAL_PASSWORDPassword for that account. Empty means the agent generates one, logs it once and writes it to <data-dir>/initial-password at 0600.
--initial-admin-password-fileFile holding it; overrides the flag.

All three initial-account flags are read only when the state file has no users. Any non-empty password is accepted; an empty one, or one over 1024 characters, is refused. The account is flagged must change password either way.

Licensing#

FlagDefaultWhat it does
--license-key$WHEELHOUSE_LICENSEThe licence key. A key given here is also saved into the state file, so the next start without the flag still holds it.
--license-key-fileFile holding it.
--license-serverhttps://license.rhymelikedi.meWhere the daily refresh goes. An empty value disables the refresh entirely and runs on the offline path.

Without a usable licence every mutating endpoint answers 402 and every read keeps working. See Licence keys and states.

Single sign-on#

Everything here is optional. An agent with no issuer keeps password, TOTP, token and break-glass logins — a router that can only be entered through an identity provider is one provider outage from being unmanageable.

FlagDefaultWhat it does
--oidc-issuer$WHEELHOUSE_OIDC_ISSUERIssuer URL, e.g. https://auth.example.com/application/o/wheelhouse/. Must be an absolute http(s) URL.
--oidc-client-id$WHEELHOUSE_OIDC_CLIENT_IDClient id.
--oidc-client-secret$WHEELHOUSE_OIDC_SECRETClient secret. Prefer the file form.
--oidc-client-secret-fileFile holding the secret.
--oidc-redirect-urlderived per requestThe exact /api/oidc/callback URL registered at the provider. When given it must be a full URL ending in /api/oidc/callback.
--oidc-scopesopenid profile email groupsSpace-separated scopes to request.
--oidc-username-claimpreferred_usernameClaim used as the local user name when provisioning: preferred_username, email, name or sub.
--oidc-groups-claimgroupsClaim holding group membership.
--oidc-admin-groupsComma-separated groups mapped to the admin role. Empty means no group mapping at all.
--oidc-operator-groupsComma-separated groups mapped to the operator role.
--oidc-default-roleviewerRole for a provisioned user outside every mapped group. Must be viewer, operator or admin.
--oidc-provisiontrueCreate a local account on the first sign-on for an unknown identity.
--oidc-link-by-emailfalseLink an identity to an existing account by email — and only when the provider asserts email_verified.
--oidc-labelAuthentikProvider name shown on the login screen.
--oidc-ca-filePEM root CA to trust for the issuer instead of the system trust store.
--oidc-post-logout-redirectRegistered post-logout URI to send the browser to at the provider.

Single sign-on is "configured" only when both --oidc-issuer and --oidc-client-id are set. The agent exits 2 at startup on any of these:

  • --oidc-issuer without --oidc-client-id, or the reverse;
  • an issuer that is not an absolute http(s) URL;
  • a configured provider with no client secret;
  • a --oidc-redirect-url that does not end in /api/oidc/callback;
  • an invalid --oidc-default-role;
  • --oidc-provision together with --oidc-username-claim=sub, which would name every account after a UUID.

When it validates, the agent logs one line at start naming the issuer, client id, redirect URI, provisioning and default role — because a mismatch between that string and what is registered at the provider is the failure an operator has to diagnose.

Desired state (plan and apply)#

FlagDefaultWhat it does
--file<data-dir>/agent.yamlThe desired-state document. JSON or YAML, chosen by what the bytes look like rather than by the extension.
--fullfalseFull mode: also emit delete for live nodes the file does not declare.
--jsonfalseWith plan: emit a JSON document instead of command lines.
--commitfalseWith apply: commit instead of staging. Requires --confirm-minutes.
--confirm-minutes0The commit-confirm window for --commit. apply --commit refuses to run at 0.
--agent-urlWith apply: the running agent to stage through, e.g. https://127.0.0.1:8443. Needs --admin-token or --admin-token-file.

The reconcile loop#

Off unless --reconcile-file is set. It is a writer, so it obeys the same licence gate as the Commit Bar and pauses without one.

FlagDefaultWhat it does
--reconcile-fileKeep the router aligned with this desired-state file. Empty means the loop never runs.
--reconcile-modestagestage puts the difference in the Commit Bar and waits for a person; commit applies it. Any other value is a startup error (exit 2).
--reconcile-interval60sHow often the loop re-diffs. Values below the 10 s floor are clamped, with a warning naming what you asked for.
--reconcile-delay15sHow long after start the first pass waits, so boot can settle.
--reconcile-confirm2Commit-confirm minutes used in commit mode. At 0 or below, the loop commits without a confirm window.
--reconcile-fullfalseRun the loop in full mode, which deletes what the file does not declare.

Diagnostics#

FlagDefaultWhat it does
--log-levelinfodebug, info, warn or error. An unparseable value silently becomes info.
--versionfalsePrint wheelhouse-agent <version> and exit 0. Identical to the version subcommand.

What the shipped unit passes#

The appliance's systemd unit uses ten of these and nothing else:

--api-url https://127.0.0.1
--api-key-file /config/wheelhouse/api-key
--admin-token-file /config/wheelhouse/admin-token
--license-key-file /config/wheelhouse/license-key
--addr 0.0.0.0:8443
--tls-self-signed
--ui-dir /usr/share/wheelhouse/ui
--data-dir /config/wheelhouse
--log-level info

It sets no OIDC flags, so writing an oidc-secret file on its own configures nothing; turning single sign-on on means a drop-in that repeats ExecStart with the --oidc-* flags added. See systemd units.

See also#

Checked against#

agent/main.go (registerFlags, runDaemon, loadSecretFiles, bootstrapAdmin), agent/license.go (defaultLicenseServer), agent/oidc.go (validateOIDCFlags), agent/desired.go (runPlanApply), agent/tls.go, agent/auth.go (clientIP), agent/fleet.go, packaging/wheelhouse-agent.service, docs/deploy.md.

Updated 2026-09-02 cli flags agent