# Command reference UART0 and authenticated `admin` SSH sessions use the same registered command implementations through one serialized dispatcher. Admin SSH exposes the full operational registry, including interactive prompts, network diagnostics, reboot, and HTTPS/SSH material mutation. Create the first administrator through normal `user add admin` on physical UART0; explicit recovery of an unavailable database is UART0-only. Admin SSH also rejects generating a replacement password for its own account so the one-time value cannot be lost when the session is revoked. Run `help` for root commands and ` help` for a group summary. Configuration changes are RAM-only unless explicitly saved. Browser admin uses the same dispatcher with a [narrower parsed frontend policy](web_administration.md#browser-shell-policy), independent of typed Settings permissions. It supports bounded deferred `reboot`, `web stop`, exact `web certificate rotate --force` and owner-relative `exit`. Drain (up to ten seconds plus 200 ms) is best-effort application-buffer acknowledgement, not peer receipt or an execution deadline; pending input is discarded. Certificate work runs on the existing dispatcher through the shared service-before-identity reservation, commits before stop/restart and never rolls back a committed identity after lifecycle failure. Failed stop retains ownership and skips start. Verify changed trust through UART0 `web certificate info`, recover with UART0/admin SSH `web stop` / `web start`, then sign in freshly. HTTPS-only actions leave SSH/native USB/UART0 independent; reboot affects every transport and loses unsaved RAM. Browser `web` allows only status/stop/exact forced certificate rotation; `wifi`/`mdns` allow status only. Browser `user` allows status/list/show and interactive add/password plus forced role/delete for **other accounts**, not self/generated/key/recovery commands. Restricted SSH stop/disconnect/reset/host-key mutation remains unavailable in the browser shell. Typed Accounts/Network/SSH settings separately provide their documented bounded workflows; this is not shell parity. See [web administration](web_administration.md) for lifecycle/API ownership and uncertainty. ## System | Command | Description | |---|---| | `memory` | Show free memory, minimum free memory, and largest blocks for internal RAM, DMA-capable RAM, and PSRAM. | | `reboot` | Drain console output briefly and restart the ESP32. | | `exit` | Close the current administrative SSH or browser session after its acknowledgement drains; unavailable on UART0. Browser `exit` leaves serial connected. Ctrl+D on an empty administrative command line does the same. | ## Role-based users | Command | Description | |---|---| | `user status` / `user list` | Show database generation, capacity, administrator count, and all secret-free account summaries. | | `user show ` | Show one account's role, ID, authentication generation, and SSH-key fingerprints. | | `user add ` | Create an account using a bounded no-echo password and confirmation prompt. | | `user add --generate` | Create an account with a generated password displayed once. | | `user delete --force` | Delete an account; the final administrator is protected. | | `user role --force` | Change a role; the final administrator cannot be demoted. | | `user password ` | Set and confirm a new password without echo. | | `user password --generate` | Replace a password with a generated value displayed once. | | `user key add ` | Prompt on UART0 or authenticated admin SSH for one bounded OpenSSH public-key line. | | `user key add ` | Import a key non-interactively; intended for authenticated admin SSH and also accepted on UART0. | | `user key delete <0..2> --force` | Delete one key by the index shown by `user show`. | | `user key clear --force` | Delete all public keys for an account. | | `user recover --force` | When normal user-database initialization failed, explicitly replace only its blob with an empty database; UART0-only, refuses a healthy database. | Usernames must match `[a-z][a-z0-9_-]{0,15}`. Passwords contain 12–64 printable ASCII characters. The fixed database supports eight users and three SSH keys per user; initial key types are `ssh-ed25519` and `ecdsa-sha2-nistp256`. A key may be assigned to multiple accounts but cannot be duplicated within one account. Password verifiers, salts, raw key blobs, and passwords are absent from ordinary status output. `Ctrl-C` cancels a password or key prompt, and generated passwords are shown once. Missing `user_db/database` storage is committed empty. On UART0 run `user add admin`, optionally with `--generate`, to create the first administrator. There is no bootstrap command, imported shared credential, or synchronization with HTTPS material. Existing valid v1 user databases load unchanged, including previously migrated role-`user` accounts; no account is silently promoted. `user recover --force` is destructive and succeeds only while the database is unavailable. It rebuilds only the user blob empty, importing no credentials; then create an administrator with normal `user add` on UART0. It refuses a healthy initialized database, including a healthy empty one, and does not erase unrelated NVS data. Successful password, role, key and delete operations invalidate only that username's outstanding tickets and active web/SSH sessions; unrelated users remain connected. ## Local display | Command | Description | |---|---| | `display status` | Show the runtime aging settings and OLED service state. | | `display set dim-seconds <0..86400>` | Set the RAM inactivity delay before contrast drops to `1`; `0` disables dimming. | | `display set off-seconds <0..86400>` | Set the RAM inactivity delay before the OLED switches off; `0` disables automatic off. | | `display save` / `display load` | Save the working aging settings to NVS or load them. | | `display defaults` / `display reset` | Apply 300/600-second defaults in RAM, or save defaults first and then apply them. | When both transitions are enabled, `off-seconds` must be greater than `dim-seconds`. Applying settings counts as local UI activity. At normal boot, an initialized OLED shows a bounded five-second identity animation before the status UI begins; it scrolls the device name in yellow and draws the compact upright-terminal logo in blue. A missing OLED remains nonfatal; after reconnecting it safely, one new button press requests a bounded reprobe and is consumed without navigating. Display settings require an available local UI task, not an attached panel. CLI and browser **Settings → Display** share the public configuration owner; concurrent mutations can report busy, and browser operations reject an intervening configuration edit rather than overwrite it. Save persists working RAM, not browser drafts. Load selects defaults when saved storage is absent/incompatible without rewriting NVS. Reset storage failure leaves RAM unchanged (commit-before-publication, no RAM rollback). Browser timeout/navigation does not cancel already-admitted work; Check Result and Refresh before retrying. [Display settings contract](web_administration.md#serial-and-display). ## Serial service | Command | Description | |---|---| | `serial status` | Show UART1 state, configuration, modem signals, and ownership. | | `serial start` / `serial stop` | Start or release the physical UART1 service. | | `serial set ` | Change the working serial configuration and safely restart a running service. | | `serial save` / `serial load` | Save the working configuration to NVS or load it. | | `serial defaults` / `serial reset` | Apply defaults in RAM, or apply and persist them. | | `serial counters` / `serial clear-counters` | Show or clear serial counters. | Defaults are 115200 baud, 8 data bits, no parity, one stop bit, no flow control, and inactive DTR. Supported values: baud `110`–`1000000`; data bits `7` or `8`; parity `none`, `even`, or `odd`; stop bits `1` or `2`; flow `none` or `rts-cts`; DTR `inactive`, `active`, or `on-connect`; and RTS threshold `1`–`127` bytes. The broker exclusively owns serial data access. ## Session broker | Command | Description | |---|---| | `broker status` / `broker clients` | Show broker state or connected clients. | | `broker counters` / `broker clear-counters` | Show global totals plus active-client ID/type/pending/HWM/UART/queued/read/dropped; clear counters and seed HWM from current pending bytes without draining output. | | `broker connect ` / `broker disconnect ` | Create or remove a console test client. | | `broker request-writer ` / `broker release-writer ` | Request or relinquish the single writer lease. | | `broker force-writer ` | Administratively assign or clear the writer lease. | | `broker send-hex ` | Send hexadecimal bytes through a writer client. | | `broker read [maximum-bytes]` | Read queued serial output for a client. | | `broker events ` | Show ownership and connection events for a client. | Each client has a generation-safe ID. There can be one writer and multiple observers; a slow observer loses only its own queued output. HWM is bounded by 4,096 bytes; read counts transport handoff, not peer receipt. Disconnected client rows disappear, while global totals retain traffic and unread-output discards until cleared. Capture counters before disconnect. `broker read` consumes queued data and must not be used as a throughput diagnostic probe. See [Web throughput diagnostics](web_throughput_diagnostics.md). ## Native USB CDC-ACM | Command | Description | |---|---| | `usb` / `usb help` | Show USB command usage. | | `usb status` | Show CDC connection, broker role, and runtime state. | | `usb counters` / `usb clear-counters` | Show or clear USB counters. | | `usb request-writer` / `usb release-writer` | Request or release USB writer ownership. | Opening `/dev/ttyACM*` with DTR asserted creates the `usb-cdc` broker client, starts UART1 if needed, and requests writer ownership. It becomes an observer if another client is writer. USB data is binary-transparent. The host's CDC line coding is shown by `usb status` for diagnostics only; it does not alter UART1. Configure physical baud rate, framing, flow control, and DTR explicitly with `serial` commands and persist them with `serial save`. ## Wi-Fi | Command | Description | |---|---| | `wifi status` / `wifi profiles` | Show Wi-Fi state or configured station profiles. | | `wifi start` / `wifi stop` / `wifi reconnect` | Start, stop, or reconnect Wi-Fi. | | `wifi next-profile` | Queue a switch to the enabled station profile after the currently active profile in priority order; wraps safely. | | `wifi profile set ` | Set a station profile. | | `wifi profile secret ` | Set a profile password through a no-echo prompt. | | `wifi profile enable|disable|delete ` | Manage a station-profile slot. | | `wifi ap policy ` | Configure fallback AP behavior. | | `wifi ap ssid ` / `wifi ap channel <1..11>` | Set the AP name or channel. | | `wifi ap secret` / `wifi ap show-secret` | Set or reveal the AP password. | | `wifi save|load|defaults|reset` | Persist, restore, reset in RAM, or reset and persist configuration. | | `wifi counters|clear-counters` | Show or clear Wi-Fi counters. | | `wifi ping [count]` | Send 1–20 IPv4 or IPv6 ICMP probes. | | `wifi nslookup ` | Resolve and display unique IPv4/IPv6 addresses. | | `wifi traceroute [max-hops]` | Run IPv4 ICMP traceroute with up to 30 hops. | `ping`, `nslookup`, and `traceroute` are root aliases. The four station-profile slots use lower priority values first. Edits to a disabled profile's SSID, priority, security mode, or secret are staged in RAM and do not interrupt the current Wi-Fi connection. Enabling or disabling a profile, changing an enabled profile, or changing AP policy/configuration applies the new radio policy and may reconnect Wi-Fi. Use `wifi save` to persist working changes. Passwords are not displayed by ordinary status output. ## mDNS | Command | Description | |---|---| | `mdns status` | Show the configured `sak-.local` hostname and announcement state. | | `mdns suffix ` | Set a 1–55-character lowercase hostname suffix in RAM. | | `mdns save` / `mdns load` | Save the working suffix to its independent NVS record or load it. | | `mdns defaults` / `mdns reset` | Restore the MAC-derived suffix in RAM, or restore and persist it. | When the Wi-Fi station receives an IPv4 address, the Wi-Fi manager announces `sak-.local`. The default suffix is the lower-case hexadecimal STA MAC address. Suffixes may contain lowercase ASCII letters, digits, and internal hyphens only. Changing a suffix while online causes a best-effort reannouncement; mDNS failures do not stop Wi-Fi, UART0, UART1, or native USB access. ## HTTPS web terminal | Command | Description | |---|---| | `web` / `web help` | Show web-service command usage. | | `web status` | Show HTTPS and WebSocket state. | | `web start` / `web stop` | Start or stop HTTPS service. | | `web counters` / `web clear-counters` | Show or clear ordinary HTTPS/serial WebSocket counters, independently of performance capture. | | `web diagnostics enable\|disable\|show\|clear` | Independent opt-in admission tracing and post-TLS occupancy; not serial throughput timing. | | `web performance enable\|disable\|show\|clear` | Default-disabled per-slot binary TX timing/count aggregates. Disable freezes; enable resumes; clear preserves enabled state. Each control operation fences in-flight samples with a new epoch. All actions print a snapshot. | | `web certificate info` | Display certificate identity and fingerprint. | | `web certificate rotate --force` | Replace the HTTPS certificate and private key. Browser admin defers commit and HTTPS restart; both browser routes close and new certificate trust/relogin is required. UART0/admin SSH behavior is unchanged. | | `web reset --force` | Explicitly replace HTTPS certificate/private key only, including missing, incompatible or damaged material; never changes users. | Use UART0 for quiet throughput captures (authenticated admin SSH also exposes these commands). Performance output includes current-epoch pending age and count/sum/estimated-average/max timings for queue entry to callback entry, synchronous send, and completion to drain return. These are not peer acknowledgements or scheduler-only measurements; nonempty intervals may include idle. No secrets or serial payloads are printed. See [Web throughput diagnostics](web_throughput_diagnostics.md) for exact semantics, saturation limits and the reset/burst/drain/disable/capture-before-disconnect recipe. HTTPS listens on port 443 only. Authenticate with any current user-database username/password; both `user` and `admin` roles receive the existing status and browser-terminal interface. The device serves vendored xterm.js without Internet access. Browser sessions use one-time account-bound tickets, binary WebSocket frames, and the broker's one-writer rule. The combined **Connect**/**Disconnect** control closes the current WebSocket and pauses automatic reconnect when active; after a user-paused disconnect, it changes to **Connect** to resume connection attempts. Account mutations revoke only that account's tickets and sessions. ## SSH serial transport | Command | Description | |---|---| | `ssh` / `ssh help` | Show SSH command usage. | | `ssh status` | Show service state and resource information. | | `ssh start` / `ssh stop` | Start or stop the SSH server. | | `ssh sessions` | List active SSH sessions with account, user role, authentication method, route, broker role where applicable, and admin-worker state. | | `ssh disconnect ` | Disconnect one SSH session. | | `ssh counters` / `ssh clear-counters` | Show or clear SSH counters. | | `ssh host-key info` | Display the OpenSSH host-key fingerprint. | | `ssh host-key rotate --force` | Replace the persistent SSH host key. | | `ssh reset --force` | Explicitly replace invalid or missing SSH material. | SSH listens on port 22 and accepts user-database passwords plus stored `ssh-ed25519` and `ecdsa-sha2-nistp256` public keys. wolfSSH verifies key possession after the database authorizes the username/key pair; unsigned key probes do not complete authentication. A `user` receives the broker-backed UART1 serial stream. An `admin` receives the administration shell instead, does not become a broker client, and cannot acquire a UART1 writer lease. UART0 and admin SSH submit to one bounded queue, and one dispatcher task is the sole caller of `esp_console_run()`. Consequently, SSH commands execute the canonical UART0 handlers and produce the same status and mutation behavior rather than using a second command implementation. Remote output is routed into the authenticated session's bounded output ring; only the SSH transport task accesses wolfSSH. UART0 and admin SSH use shared whole-line Tab completion. A unique/common prefix expands inline; a Tab that cannot extend an ambiguous prefix prints the matching candidates and redraws the unchanged input line instead of cycling candidates. Admin SSH additionally supports four-entry per-session command history with Up/Down, inline cursor editing with Left/Right, Home/End (including Pos1/Ende terminal sequences), Backspace/Delete, Ctrl-C, and visible or no-echo interactive prompts. Its history is RAM-only, private to the session, and wiped on disconnect. Ping callbacks enqueue bounded typed results so all formatting remains on the dispatcher task. `exit`, `reboot`, `ssh stop`, session disconnect, and SSH host-key reset/rotation use bounded deferred control. The firmware waits on a best-effort basis for the administration output ring and transport TX buffer to drain before acting; this is not confirmation that the peer received the acknowledgement. The shell stops accepting another command while such an action is pending. SSH host-key replacement or service stop closes all SSH sessions; reconnect and verify the new fingerprint where applicable. TLS certificate management, Wi-Fi secrets, and interactive user passwords/keys are available to authenticated administrators and must therefore be treated as remotely accessible administrative material. `user recover --force` remains UART0-only; `user bootstrap` and all `web credentials` commands are removed. A connected administrator also cannot generate its own replacement password remotely, preventing the one-time password from being lost during self-revocation. SSH does not provide `exec`, SFTP, SCP, forwarding, or subsystems. ## Hardware diagnostics | Command | Description | |---|---| | `debug status` | Show MAX3243 driver, receiver, VLD, and shutdown states. It requires UART1 to be stopped. | | `debug transceiver ` | Enable or shut down the MAX3243. | | `debug drivers ` | Drive static TX, DTR, and RTS logic levels for measurement. | | `debug loopback-a` / `debug loopback-b` | Test MAX3243 driver/receiver loopback configurations. | | `debug valid-test` | Verify valid RS-232 voltage detection. | | `debug uart-loopback [8N1|8E1|8O1|8N2|7E1|7O1] [bytes]` | Run a parameterized UART loopback test. | | `debug uart-suite` | Test supported baud rates and frame formats. | | `debug cts-flow-test` / `debug rts-flow-test` | Verify hardware transmit gating or receive backpressure. | | `debug display status` | Show the current display diagnostic state. | | `debug display probe` | Probe the expected OLED addresses 7-bit `0x3c` and `0x3d`, initially using 100 kHz I²C. The tested module responds at `0x3c`. | | `debug display scan --force` | Scan usable 7-bit addresses `0x08`–`0x77` at 100 kHz; use only on this dedicated local-UI bus. | | `debug display init [address]` | Initialize the OLED at 7-bit `0x3c`/`0x3d`, or their 8-bit write/read aliases: `0x78`/`0x79` and `0x7a`/`0x7b`. | | `debug display off` | Turn off the initialized OLED. | | `debug display pattern ` | Draw a full-screen electrical and geometry test pattern; `layout` renders separate status- and content-panel text. | | `debug display row <0..63>` | Draw the selected one-pixel display row for addressing and color-boundary checks. | | `debug display contrast <0..255>` | Set the OLED contrast to the specified bounded value. | | `debug display invert ` | Enable or disable OLED pixel inversion. | | `debug buttons status` | Show the current active-low state of previous/back GPIO10, select/confirm GPIO13, and next GPIO14. | | `debug buttons test [seconds]` | Run the bounded button event test for 1–30 seconds; the default is 10 seconds. | Follow the exact wiring in [Electrical tests](electrical_tests.md) before invoking diagnostics. The OLED must be powered from 3.3 V because module I²C pull-ups may connect to `VCC`; verify that all external pull-ups also terminate at 3.3 V. Display diagnostics probe the standard SSD1315-compatible 7-bit `0x3c`/`0x3d` addresses. The currently tested module acknowledges at `0x3c`, whose 8-bit write/read forms are `0x78`/`0x79`; an explicit `scan --force` is available only for the dedicated local-UI bus. Diagnostics initially run at 100 kHz and treat an absent display as nonfatal. RS-232 diagnostics that require UART1 refuse to use it until `serial stop` releases it. The RGB LED shows test state: blue idle, yellow/orange running, green passed, red failed. HTTPS storage migration preserves the exact TLS identity and commits TLS-only v2 before publication. Older v1-only firmware cannot read v2. Logical NVS replacement is not secure flash erasure; no factory erase is required. See [legacy removal](legacy_credential_removal.md).