How Omarchy Manages Network Panels: Wi-Fi Bandwidth and Tailscale Integration
Omarchy network panels are first-party plugins under shell/plugins/panels/ that render Wi-Fi status, bandwidth metrics, and Tailscale mesh networks through reactive QML interfaces backed by JavaScript data models parsing CLI outputs like nmcli and tailscale status --json.
The omacom/omarchy repository implements network monitoring through modular panel plugins located in shell/plugins/panels/. These Omarchy network panels transform raw command-line output from NetworkManager and Tailscale into interactive UI components. Each panel follows a standardized architecture separating data processing from presentation.
Plugin Architecture for Network Monitoring
Core Components
Every network panel consists of three mandatory files and one optional service layer:
- manifest.json: Declares the plugin ID, description, and default UI placement
- Model.js: Implements data-processing logic and state management
- Panel.qml: Renders the QML interface binding to model properties
- Service.qml (optional): Executes background commands and pushes updates to the model
Wi-Fi and General Network Panel
Located at shell/plugins/panels/network/, this panel aggregates omarchy-network-status output (wrapping nmcli and iw) to display connectivity states, bandwidth information, and Wi-Fi signal strength.
Parsing Connection Status
The parseNetworkStatus function in Model.js converts tab-delimited CLI output into structured objects:
// https://github.com/omacom/omarchy/blob/quattro/shell/plugins/panels/network/Model.js#L1-L8
function parseNetworkStatus(raw) {
var parts = String(raw || "disconnected\t\t\t").replace(/\r?\n+$/, "").split("\t")
return { kind: parts[0] || "disconnected", label: parts[1] || "", signalStrength: parts[2] ? parseInt(parts[2], 10) : -1, frequency: parts[3] || "" }
}
Signal Strength Visualization
The wifiIconFor function maps 0-100% signal strength to Unicode icons:
// https://github.com/omacom/omarchy/blob/quattro/shell/plugins/panels/network/Model.js#L11-L15
function wifiIconFor(strength) {
var icons = ["","","","",""]; var index = Math.max(0, Math.min(4, Math.ceil(strength/20)-1)); return icons[index];
}
Frequency Band Formatting
Functions like formatHeaderFreq and bandLabel convert raw MHz values into human-readable bands (2.4 GHz, 5 GHz, 6 GHz):
// https://github.com/omacom/omarchy/blob/quattro/shell/plugins/panels/network/Model.js#L46-L55
function formatHeaderFreq(mhz) { var v = parseFloat(mhz); if (!v) return ""; if (v>=2400&&v<2500) return "2.4ghz"; … return (v/1000).toFixed(1)+"ghz"; }
QML UI Implementation
shell/plugins/panels/network/Panel.qml binds the model to a ListView, using connectionIcon to display captive-portal or limited-connectivity states:
// https://github.com/omacom/omarchy/blob/quattro/shell/plugins/panels/network/Panel.qml#L30-L42
Icon { source: model.connectionIcon(network.kind, network.signalStrength, network.connectivity) }
ListView { model: wifiRows; delegate: WifiRowDelegate { … } }
Tailscale Network Panel
The Tailscale panel at shell/plugins/panels/tailscale/ consumes tailscale status --json and tailscale exit-node list to visualize mesh networks, peer devices, and VPN exit nodes including Mullvad integration.
IP Address Filtering
The model filters for Tailscale-specific ranges using filterIPv4 and filterIPv6:
// https://github.com/omacom/omarchy/blob/quattro/shell/plugins/panels/tailscale/Model.js#L1-L8
function filterIPv4(ips){…if(/^100\./.test(ip)) result.push(ip)…}
function filterIPv6(ips){…if(/^fd7a:115c:a1e0:/i.test(ip)) result.push(ip)…}
Peer Normalization
peerFromStatus constructs UI-friendly objects, detecting Mullvad peers and exposing Taildrop capabilities:
// https://github.com/omacom/omarchy/blob/quattro/shell/plugins/panels/tailscale/Model.js#L99-L116
function peerFromStatus(id, peer){ return { id, HostName: displayHostName(...), OS: String(peer.OS||""), Mullvad: isMullvadPeer(peer), … }; }
Status and Authentication
parseStatus decodes JSON state, extracting backend status and login requirements:
// https://github.com/omacom/omarchy/blob/quattro/shell/plugins/panels/tailscale/Model.js#L23-L68
function parseStatus(raw){ … var data = JSON.parse(text); var backendState = String(data.BackendState||"Unknown"); … return { ok:true, running:backendState==="Running", needsLogin:backendState==="NeedsLogin", … }; }
Exit Node Management
parseExitNodeList processes the text table from tailscale exit-node list, grouping Mullvad nodes by region:
// https://github.com/omacom/omarchy/blob/quattro/shell/plugins/panels/tailscale/Model.js#L25-L73
function parseExitNodeList(raw){ … var byHost = {}; … byHost[host] = { … ExitNode: status!=="-" , … }; … }
Background Service Execution
Service.qml spawns detached processes via Quickshell.execDetached to update the model continuously:
// https://github.com/omacom/omarchy/blob/quattro/shell/plugins/panels/tailscale/Service.qml#L145-L174
statusProcess.command = ["tailscale","status","--json"]
mullvadExitNodesProcess.command = ["tailscale","exit-node","list"]
Quickshell.execDetached(["omarchy-tailscale-send", target])
Connecting to Exit Nodes
When a user selects an exit node, the service executes the set command:
exitNodeProcess.command = ["tailscale","set","--exit-node=" + target]
Enabling and Configuring Panels
Plugin Registration
Each panel's manifest.json declares its ID for the Omarchy plugin system:
// https://github.com/omacom/omarchy/blob/quattro/shell/plugins/panels/network/manifest.json
{ "id": "omarchy.network", "description": "Network status and Wi-Fi scanner" }
Enable via CLI:
omarchy plugin enable omarchy.network
omarchy plugin enable omarchy.tailscale
Bar Layout Configuration
Panels integrate into ~/.config/omarchy/omarchy-bar.jsonc. Users can position them in left, center, or right sections:
// https://github.com/omacom/omarchy/blob/quattro/default/omarchy/omarchy-menu.jsonc#L240-L250
"center": [{ "id": "omarchy.clock" }, { "id": "omarchy.weather" }, { "id": "omarchy.network" }, { "id": "omarchy.tailscale" }]
Reposition using:
omarchy bar move omarchy.network right
Summary
- Omarchy network panels follow a three-tier architecture:
manifest.jsonfor metadata, Model.js for data parsing, and Panel.qml for UI rendering - The Wi-Fi panel parses
nmclioutput viaparseNetworkStatusand maps signal strength to icons usingwifiIconForinshell/plugins/panels/network/Model.js - Frequency bands are humanized through
formatHeaderFreq, supporting 2.4 GHz, 5 GHz, and 6 GHz identification - The Tailscale panel filters CGNAT and IPv6 addresses via
filterIPv4andfilterIPv6, displaying peer information throughpeerFromStatus - Background updates are handled by Service.qml spawning
tailscale status --jsonandtailscale exit-node listviaQuickshell.execDetached - Users enable panels via
omarchy plugin enableand position them through the bar configuration file or CLI commands
Frequently Asked Questions
How does Omarchy display Wi-Fi signal strength?
The wifiIconFor function in shell/plugins/panels/network/Model.js divides the 0-100% signal range into five tiers, returning specific Unicode icons for each tier to indicate connection quality visually in the panel.
Can I use the Tailscale panel without Mullvad exit nodes?
Yes. The panel's parseStatus function handles standard Tailscale mesh networks independently. Mullvad-specific logic in parseExitNodeList only activates when exit nodes are configured, filtering non-Mullvad peers through the standard peerFromStatus pipeline.
What CLI commands power the network panels?
The Wi-Fi panel executes omarchy-network-status (wrapping nmcli and iw), while the Tailscale panel runs tailscale status --json, tailscale exit-node list, and tailscale switch --list --json. These execute via Quickshell.execDetached in each panel's Service.qml.
How do I reposition the network panels in the Omarchy bar?
Run omarchy bar move omarchy.network [left|center|right] or edit ~/.config/omarchy/omarchy-bar.jsonc directly, placing the panel IDs in your desired array position within the "center", "left", or "right" sections.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →