# How Omarchy Manages Network Panels: Wi-Fi Bandwidth and Tailscale Integration

> Learn how Omarchy manages network panels displaying Wi-Fi bandwidth and Tailscale integration. Discover its plugin architecture and data parsing methods.

- Repository: [Omacom/omarchy](https://github.com/omacom/omarchy)
- Tags: how-to-guide
- Published: 2026-09-10

---

**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`](https://github.com/omacom/omarchy/blob/main/Model.js) converts tab-delimited CLI output into structured objects:

```javascript
// 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:

```javascript
// 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):

```javascript
// 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:

```qml
// 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`:

```javascript
// 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:

```javascript
// 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:

```javascript
// 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:

```javascript
// 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:

```qml
// 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:

```qml
exitNodeProcess.command = ["tailscale","set","--exit-node=" + target]

```

## Enabling and Configuring Panels

### Plugin Registration

Each panel's [`manifest.json`](https://github.com/omacom/omarchy/blob/main/manifest.json) declares its ID for the Omarchy plugin system:

```json
// 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:

```bash
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:

```json
// 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:

```bash
omarchy bar move omarchy.network right

```

## Summary

- **Omarchy network panels** follow a three-tier architecture: [`manifest.json`](https://github.com/omacom/omarchy/blob/main/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`](https://github.com/omacom/omarchy/blob/main/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`](https://github.com/omacom/omarchy/blob/main/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.