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.json for metadata, Model.js for data parsing, and Panel.qml for UI rendering
  • The Wi-Fi panel parses nmcli output via parseNetworkStatus and maps signal strength to icons using wifiIconFor in shell/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 filterIPv4 and filterIPv6, displaying peer information through peerFromStatus
  • Background updates are handled by Service.qml spawning tailscale status --json and tailscale exit-node list via Quickshell.execDetached
  • Users enable panels via omarchy plugin enable and 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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →