Repository navigation
Release Notes v0.12.0
Released: 2026-10-25
The big addition in 0.12.0 is mouse and touch input across the whole TUI, so unifly tui can run on a touchscreen kiosk. Most of the rest is correctness work. In unifly-api, commands no longer hang on dead connections, network updates are no longer silently dropped, and the CSRF token is kept current. Config handling no longer loses profiles or leaks secrets. --demo now actually hides PII. CLI output and exit codes have been tightened, and rustls is bumped to fix four security advisories.
🌟 Highlights
✨ Mouse and Touch Input in the TUI
You can now click or tap tabs, list rows, key hints, dialogs and dashboard panels. One tap selects a row and a second tap opens it. An open device detail follows a tap on another device and stays on the same tab, so you can step from switch to switch and stay on their ports. Key hints work as buttons, including help, settings, quit and search in the status bar. Confirmations accept y/n taps, a tap outside an overlay closes it, and a tap dismisses a notification. The mouse wheel scrolls lists and the event feed (scrolling back pauses a live feed), zooms the topology and moves through the theme picker. Dragging pans the topology map. You still need a keyboard to type text.
🐛 Config Files No Longer Lose Profiles
Before this release, a single typo in config.toml (for example timeout = "thirty") made config set, config use, config init, cloud switch and TUI saves fall back to defaults and write them over every profile. These commands now stop with an error that names the file and the bad key, and leave the file untouched. config init adds a profile instead of replacing the file. The TUI edits the session's profile instead of always editing default. Saves are atomic: they write an owner-only staging file and rename it into place.
🔒 Secrets Stay Masked
config show now masks api_key, password, totp_command arguments and credentials embedded in URLs in every output format. Before, only the table view masked them. vpn servers and vpn tunnels no longer print pre-shared keys in clear text. The session cookie cache is now created owner-only under a unique name and renamed into place, which closes a symlink and race window.
🐛 --demo Now Hides Real Data
CLI controller and cloud commands in demo mode now exit 5 before connecting, because only the TUI sanitizes output. In the TUI, dialogs, toasts, the status bar, SSIDs/BSSIDs, event messages and the WAN details in the Gateway panel now use the same stand-ins as the lists. MACs, clock times and Rust paths no longer get turned into fake IPv6 addresses.
🐛 API Client Fixes
Commands sent while disconnected now fail right away instead of waiting forever. Calling connect() again no longer makes the next disconnect() hang. Network updates now apply subnet and DHCP changes. A NAT rule the controller rejects (an HTTP 200 response with an error body) is no longer reported as created.
🖥️ TUI Fixes
- The tab bar draws all nine tabs from 74 columns up. Before, the WiFi tab (and Stats at some widths) was cut off on common terminal sizes.
- Typing in the Networks edit form stays in the form.
Tab, digits andqno longer switch screens or quit.Ctrl+Cstill quits. - An
Escthat closes part of a screen (network detail, WiFi channel map, roaming focus) stays on that screen. Tabin a client detail switches the type filter.- Firewall policy moves now reach the controller. Before,
J/Kon the Policies tab only swapped rows on screen. A move now reads the zone pair's ordering, steps the policy once and writes it to the controller. Moving past the system-defined block jumps over all of it, and the toast says so. - Lists keep their scroll position past the first page.
- Search keeps its filter on
Enterand clears it onEsc./only opens search on Devices, Clients and WiFi. - The WiFi client detail and roam history follow the selected client, and retry failed fetches every 15 seconds.
- Roam history loads under
--demowith MAC redaction on. - The Stats screen reloads the period it shows and resizes its charts when you switch periods.
- A paused Events feed holds still when new events arrive.
- Clicks in the Settings form redraw immediately.
- The status bar says "connecting" on the first connect and names the real cause of a failure.
- The help overlay only lists keys that work everywhere. The Firewall hint bar no longer advertises
Enter detail.
🔧 API Correctness (unifly-api)
last_full_refresh(),last_ws_event()anddata_age()now return real values. Late subscribers see the correct connection state, and a failed connect reportsFailed.- A non-ASCII response body no longer panics the error preview builder, which could crash the TUI's refresh task.
- Network DHCP ranges show their end address. Turning DHCP off keeps range, lease and DNS settings. Turning DHCP on without a range is refused with a clear error.
- NAT, WireGuard, VPN and
unifly apirequests now pick up rotated CSRF tokens and surface errors the controller returns with HTTP 200. - Platform detection probes now honor the configured TLS mode and
--timeout, and run concurrently. - Timeout errors now report the configured
--timeoutvalue instead of "0s".
💻 CLI Output and Errors
- YAML output stays valid and reads the same in YAML 1.1 parsers such as PyYAML. Apostrophes, booleans like
off, nulls,1_000, dates,<<and=are now quoted correctly. events watch -o yamlemits one---document per event.acl reorder -o yamlemits a YAML list.wifi channelsrenders data from multiple countries as one document, withcountryandcountry_codeon each row.topology -o jsonand-o yamlnow emit structured data (gateway, devices with their clients, and clients with no uplink). Before, they printed the ASCII tree.- A malformed
--filteris now a usage error (exit 2) that shows the accepted syntax. -qsilences the "Showing N of M results" hint.UNIFI_INSECUREand--insecureaccept1/0,yes/noandon/off.- Missing credentials exit 3 with a hint specific to what is missing (
config set-password,config setor--api-key). wifi getreports the actual failure type instead of always saying "not found".- Error hints name commands that exist and the profile in use.
- Unusable controller URLs (
foo:bar,ftp://...) are now configuration errors (exit 2), with any password in the URL masked. UNIFI_DEMOandUNIFI_DEMO_SEEDno longer collide with the[demo]table and hide every profile.- Setup wizards store keyring secrets only after the last prompt, and put the old ones back if the save fails.
🔒 Security
rustlsbumped to 0.23.46 for RUSTSEC-2026-0346 through 0349: TLS secrets exposed byDebugimpls, data sent after an ECH rejection, a 1 GiB allocation during Brotli certificate decompression before authentication, and a ServerHello downgrade to classical key exchange.
📝 Documentation
- The README now plays the 0.11 promo at the top. The tour GIF (
docs/images/tui-tour.gif) has been removed. - The TUI, CLI, configuration, cloud and troubleshooting references and the agent skill files in
crates/unifly/skill/have been updated to match current behavior. This adds theUfirmware-upgrade key, removes a promised PoE power cycle that no key triggers, and corrects what cloud mode allows.
⚠️ Breaking Changes
- VPN JSON/YAML output no longer duplicates raw keys. Fields the typed record already has (
localNetworks,peerIp,pskand similar) are no longer repeated under their raw names. Scripts should read the typed fields. - A broken
config.tomlstops every command, even when the controller and API key come from flags or environment variables. The command exits 2 and names the file and the problem. - Cloud fleet commands with no profile and no
--api-keyexit 1 (configuration error) instead of 3. - Demo mode now blocks CLI controller and cloud commands with exit 5.
config,skill,completionsand--demo-fleetstill run. - A malformed
--filternow exits 2 instead of matching nothing and exiting 0. - Invalid profile values and unusable controller URLs exit 2 instead of 1.
🔨 Upgrade Notes
- Check that
config.tomlparses cleanly. A typo that older versions ignored will now stop every command until you fix it. - Update scripts that read the raw duplicate keys from
vpn servers/vpn tunnelsJSON or YAML. - Review CI or wrapper scripts that check exit codes for cloud commands,
--filter, and invalid config or URL values. - If you set
UNIFI_DEMOor[demo] enabled = truein environments that also run CLI commands, turn demo mode off for those runs. - If you scripted
networks update --from-filewithsubnetordhcp_enabled, those fields now take effect. Make sure the values are what you intend.