Wheelhouse docs

The commands Wheelhouse runs#

The agent is a separate program that drives the router over its documented HTTP API. It does not link against the router's code, and it does not shell out. Everything it knows comes from the reads on this page, and everything it changes goes through /configure.

If you are wondering what an idle Wheelhouse box is doing to your router, this is the whole list.

The router API endpoints it posts to#

EndpointUsed forClient timeout
/retrieveshowConfig, in JSON and in the native format30 s
/showevery operational read30 s
/configureset, delete, commit, commit-confirm, confirm3 minutes
/config-filesave and load3 minutes
/container-imagepulling and deleting images15 minutes
/imageadd, delete, set_default, show system image15 minutes
/traceroutethe diagnostics traceroute15 minutes
/reboot, /poweroffpower actions15 minutes

Three timeout tiers because one figure cannot be right for all of it. A read that hangs should not hold a dashboard for a minute; a commit on slow hardware legitimately runs past fifteen seconds, and timing out mid-commit leaves the caller unable to tell whether it landed; an image pull is bounded by the uplink, and the router keeps pulling after the agent hangs up.

Two encodings, and the reason is the router's own parser: most calls are form-encoded, but its form parser requires a path field on every command — so operations that have none (confirm) and fields it does not read (confirm_time) go as JSON instead.

Operational reads#

Every one of these is show <path> through /show. This is the complete list; nothing else is read.

CommandBehind
show versionSystem, Dashboard, /api/version, the fleet health check
show system uptimeSystem, Dashboard
show system memorySystem, Dashboard
show system storageSystem, Dashboard
show system processesDiagnostics
show system imageSystem — boot images
show system commitSystem — the revision list
show system commit diff <rev>System — one revision's diff
show system loggingwarmed by the primer
show hardware cpuSystem, Dashboard
show interfacesInterfaces, the Dashboard's stream, the throughput sampler
show interfaces <kind> <name>Interfaces — per-interface detail, and the QoS page's qdisc
show interfaces wireguardWireGuard
show interfaces openvpn <mode>OpenVPN, once per configured mode
show ip routeRoutes
show arpNeighbours
show lldp neighborsHigh availability, LLDP
show vrrpHigh availability
show wan-load-balanceHigh availability — the load balancer's own verdict
show firewall statisticsFirewall — hit counters
show nat source statistics, show nat destination statisticsNAT — hit counters
show conntrack table ipv4Sessions
show conntrack statisticsSessions — per-CPU health
show dhcp server leasesDHCP
show dns forwarding statisticsDNS
show dns dynamic statusDynamic DNS
show ntpSystem
show pkiCertificates
show containerApps
show container imageApps — is the image already here
show container log <name>One app's log
show host lookup <host>Diagnostics
show log tail <n>Logs
show configuration commandsEvery CLI panel, and /api/config/commands
show vpn ipsec sa, show vpn ipsec connectionsIPsec

Re-derive it:

bash
grep -ohE 'showText\([^,]*, [^)]*\)' agent/*.go | sort -u

Configuration subtrees it reads#

Through /retrieve with showConfig. The whole tree (an empty path) is read too — by the reconcile diff, and by the Config tree page.

container                     protocols               service dhcp-server
container name                protocols bgp           service dns
container network             protocols ospf          service dns dynamic
firewall                      protocols static        service lldp
firewall group                qos                     service ntp
firewall ipv4                 system                  service suricata
high-availability             pki                     service conntrack-sync
interfaces                    policy                  vpn ipsec
interfaces openvpn            load-balancing          nat
interfaces wireguard          service

Re-derive it:

bash
grep -ohE 'configOf\(vyos, [^)]*\)|configTag\(vyos, [^)]*\)' agent/*.go | sort -u

What it writes#

Only through /configure, and only as set and delete operations whose path the operator has seen. The staging endpoint refuses anything else:

json
[{"op":"set","path":["service","dns","forwarding","cache-size","10000"]},
 {"op":"delete","path":["nat","destination","rule","10"]}]

For a set, the last path element is the value — the router's own convention, and why an empty path element is refused where the request can still say which operation is wrong.

Commit-confirm is the router's native mechanism: confirm_time on the commit, and a later confirm operation to cancel it. Miss the window and the router reboots into the previous configuration. That reboot is the rollback — it is how the configuration backend implements the feature, and it is what makes a WAN or firewall change survivable.

Rollback is not an operation at all. The router's HTTP API has no rollback; the CLI command works by loading the archived configuration file for that revision, so POST /api/rollback loads /config/archive/config.boot.<N>.gz through /config-file and commits it.

What it costs the router#

Every call into the router's HTTP API forks a shell helper on the router, so the agent budgets calls, not intervals.

ActivityCost
The throughput samplerone show interfaces every 5 s — one call for every interface
An open Dashboardone uncached show interfaces every 2 s, for the stream
Operational readscached for 3 seconds, served stale-while-revalidating
Per-interface detailcached for 20 seconds
Configuration readscached for an hour, and invalidated by the agent's own commits
The primerone warm-up pass at start, and one configuration-only pass every 10 s and after each commit

Idle, that is roughly a dozen calls a minute.

The router serialises its HTTP API: concurrent reads are no faster than sequential, and each read is in the region of 150 to 800 milliseconds. That is why the cache exists, why the primer does not stagger its calls — spacing them out would not lower the peak, only lengthen the warm-up — and why the primer does not refresh operational reads on a timer.

Reads that bypass the cache#

Three, and each for a reason:

ReadWhy
The telemetry stream's show interfacesA stream that replays a cached answer is not live.
The throughput sampler's countersRate arithmetic needs genuinely new counters.
The reconcile diff's showConfigThe cache is invalidated by the agent's own commits only, so a change made over SSH — the thing drift detection exists to notice — would stay invisible for up to an hour.

GET /api/apps/plan also reads show container image uncached, because it is asked right after a pull and the three-second cache would answer with the list from before it.

Two cautions#

See also#

Checked against#

agent/vyos.go (post, postJSON, clientFor, ShowConfig, ShowConfigCommands, ShowConfigUncached, ShowConfigRaw, Show, ShowTTL, ShowUncached, Configure, ConfigureConfirm, Confirm, LoadConfig, SaveConfig, AddContainerImage, Image, Traceroute, Reboot, Poweroff, routerBudget), agent/cache.go (configTTL, opModeTTL, interfaceDetailTTL), agent/primer.go, agent/opmode.go, agent/main.go (handleStream, handleRollback, archiveDir, handleStage), agent/apps.go (showTextUncached, imagePresent), agent/metrics.go (History.collect), agent/wan.go, docs/api-cookbook.md, docs/deploy.md "What the agent costs the router", PLAN.md §3.

Updated 2026-09-02 vyos op-mode commands api