1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
|
#+TITLE: Net Panel — Tailscale, VPN, and WireGuard Interfaces
#+AUTHOR: Craig Jennings
#+DATE: 2026-07-02
#+TODO: TODO | DONE
#+TODO: DRAFT READY DOING | IMPLEMENTED SUPERSEDED CANCELLED
* IMPLEMENTED Status
:PROPERTIES:
:ID: 79a1075a-4b56-4f25-a861-b69f120a636a
:END:
- [2026-07-02 Thu] IMPLEMENTED — all six phases shipped (dotfiles 2d9d060,
21db05a, 31ba056, b4010bf, b5c8442; archsetup 0389790 + the wireguard
import script): probes, panel Tunnels view, diagnose/doctor route
awareness, bar badge, installer swap + operator, velox config migration.
Residual human steps filed under todo.org "Manual testing and
validation": proton CLI sign-in (per machine) and the first live
badge/tunnel round-trip. Ratio picks up the import + package swap on its
trip.
- [2026-07-02 Thu] DOING — decomposed into six build phases under the
todo.org parent (:SPEC_ID: bound); build started same evening per Craig
("tunnels build now + audio-panel spec alongside").
- [2026-07-02 Thu] READY — fused review passed the gate: 4/4 decisions
resolved, phases decomposable, claims re-verified live (proton-vpn-cli
1.0.1 in extra, binary =/usr/bin/protonvpn=, no package conflict with the
GTK app; =tailscale status --json= shape confirmed on velox — Self/Peer/
CurrentTailnet.Name/MagicDNSSuffix; zero NM wireguard connections yet,
seven configs in assets awaiting the phase 6 import).
- [2026-07-02 Thu] DRAFT — initial spec from the roam capture "other network
interfaces (tailscale, VPNs, wireguard)" filed in todo.org 2026-07-02.
* Metadata
| Field | Value |
|--------+---------------------------------------------------|
| Status | implemented |
|--------+---------------------------------------------------|
| Owner | Craig Jennings |
|--------+---------------------------------------------------|
| Repo | dotfiles (net module); archsetup (packages) |
|--------+---------------------------------------------------|
| Parent | Waybar network module spec (2026-06-29), V2 panel |
|--------+---------------------------------------------------|
* Problem
The net panel's Connections tab shows what NetworkManager knows: WiFi networks
and wired links. The machines also run overlay and tunnel interfaces the panel
is blind to:
- Tailscale (tailscaled, both daily drivers; the tailnet is how the machines
reach each other; not an NM device)
- WireGuard configs (assets/wireguard-config/ carries Proton VPN configs;
importable as NM connections of type wireguard or run via wg-quick)
- Commercial VPN clients (Proton VPN GTK app is installed on velox; owns its
own tunnel device)
When one of these is up it changes routing, DNS, and reachability — exactly
the things the Diagnostics tab reasons about — yet the panel neither shows nor
controls them, and the doctor can misattribute a VPN-caused failure to the
underlying link.
* Goals
1. Visibility: the Connections tab shows overlay/tunnel interfaces with live
state (up/down, address, and for tailscale the tailnet peers summary).
2. Control: bring each up or down from the panel row, same interaction shape
as Join/Disconnect on WiFi rows (no terminals — V2 contract).
3. Diagnostics awareness: diagnose/doctor know when a tunnel owns the default
route or DNS, name it in evidence rows, and stop misattributing its
failures to the physical link.
Non-goals (this iteration): installing or configuring VPN providers, tailnet
ACL management, exit-node selection UI (a "use exit node" affordance can ride
a later pass), kill-switch management (tracked separately in the spec's
failure catalog).
* Design sketch
** Data sources — one probe per backend, engine-side
New GTK-free module net/src/net/overlays.py with one probe per backend,
each returning the same small dict shape ({kind, name, state, addr, detail,
can_toggle}):
- tailscale: =tailscale status --json= (rich: self, peers, exit node, health
messages). Daemon down → state "stopped". Binary absent → backend absent.
- wireguard-nm: =nmcli -t connection show= filtered to type wireguard —
up/down via the existing nmcli wrapper (activate/deactivate connection).
The seven Proton configs in assets/wireguard-config/ import cleanly
(=nmcli connection import type wireguard file <conf>=, then
=connection.autoconnect no= immediately — imports default to autoconnect
yes). They use only PrivateKey/Address/DNS + PublicKey/AllowedIPs/Endpoint,
no PostUp/PostDown anywhere, so no wg-quick path is needed at all
(Craig, 2026-07-02). All are full-tunnel (AllowedIPs 0.0.0.0/0) — the
panel should treat them as mutually exclusive.
- proton: drive the official proton-vpn-cli (Arch extra repo, v1.0.x,
stable since 2026-04) — connect/disconnect/status verbs. It drives NM
underneath (python-proton-vpn-network-manager), so the panel still sees
connection events through NM. Runtime-exclusive with the GTK app, which
gets dropped from the install. The imported NM wireguard configs remain
a raw fallback when the CLI/API path is down; the CLI stays primary
because the raw configs lack kill switch, port forwarding, and server
rotation.
** Panel
A fourth Connections group "Tunnels" (after Saved / Available now / Wired)
using the existing group-header + row machinery. Row: glyph per kind, name,
state caption; primary action Up/Down where can_toggle, else Open app.
Tailscale row detail (subtitle or tooltip): tailnet name, peer count online,
exit node if any.
** Privileged path
- tailscale up/down: needs root or operator — =tailscale set --operator= at
install time (archsetup) makes the user an operator, so no sudo needed at
runtime. Fallback: the V2 net-priv helper gains tailscale-up/down verbs.
- NM wireguard connections: no privilege needed (NM polkit default for the
active user).
** Diagnostics awareness
- diag gains an "overlay owns default route/DNS" detection step: when the
default route or resolv.conf points at a tunnel interface, evidence names
it ("default route via tailscale0") and failure classification runs the
physical-link checks against the underlying device instead.
- doctor: a tunnel-caused egress failure (VPN up but its endpoint dead)
classifies fixable with next_action "bring the tunnel down / reconnect",
not a WiFi reset.
** Bar indicator
Part of v1 (Craig, 2026-07-02 — "shouldn't be optional"): a small overlay
badge on the net glyph when a tunnel owns the default route. Rides the same
route/DNS-ownership detection the diagnostics step adds.
* Decisions (Craig)
** DONE Which backends ship in the first pass?
CLOSED: [2026-07-02 Thu]
Approved (Craig, 2026-07-02): tailscale + NM-managed wireguard. Craig asked
whether the wireguard configs can be ported to NM so wg-quick drops out
entirely — yes: all seven configs in assets/wireguard-config/ use only the
six directives NM imports cleanly (verified 2026-07-02; import command and
autoconnect caveat now in the design sketch). wg-quick is out of the spec,
not deferred. Proton control is CLI-driven per the Proton decision below,
superseding the detection-only recommendation here.
** DONE Tailscale control path: operator flag at install vs net-priv verbs?
CLOSED: [2026-07-02 Thu]
Approved (Craig, 2026-07-02): =tailscale set --operator=$USER= in archsetup's
tailscale step (declarative, no sudo at runtime); net-priv verbs only if
operator mode proves insufficient (e.g. up with flags).
** DONE Does "Tunnels" belong in Connections or its own tab?
CLOSED: [2026-07-02 Thu]
Approved (Craig, 2026-07-02): a Connections group. A fourth top tab dilutes
the V2 nav for three rows.
** DONE Proton VPN: detect-only or drive its CLI?
CLOSED: [2026-07-02 Thu]
Decided (Craig, 2026-07-02): drive it through a CLI. Research (2026-07-02):
Proton shipped an official Linux CLI — first release 2025-11, stable v1.0.0
2026-04, packaged in Arch extra as proton-vpn-cli (1.0.1 at check time),
with kill switch, port forwarding, NetShield, server selection, and a
status command. It drives NM underneath, so the panel sees its connections
through the existing NM event path. Spec changes: the proton backend calls
protonvpn connect/disconnect/status instead of device-detection
(can_toggle true); archsetup installs proton-vpn-cli and drops
proton-vpn-gtk-app (the two can't run concurrently per the project README —
untested locally); the imported NM wireguard configs stay as a raw fallback.
Sources: [[https://protonvpn.com/support/linux-cli][Proton Linux CLI guide]],
[[https://protonvpn.com/support/release-notes-linux-cli][CLI release notes]],
[[https://github.com/ProtonVPN/proton-vpn-cli][proton-vpn-cli repo]].
* Implementation phases
1. overlays.py probes (tailscale JSON, nmcli wireguard filter, proton-vpn-cli
status) — pure engine, TDD with fake binaries; =net status= grows an
overlays section.
2. Panel Tunnels group + Up/Down wiring through the worker thread; AT-SPI
smoke extension.
3. Diagnose/doctor overlay awareness (route/DNS ownership step, classifier
rows, evidence text) — TDD against the diag harness.
4. waybar-net tunnel badge on the net glyph (v1 per the bar-indicator
decision), riding phase 3's route-ownership detection; suite coverage.
5. archsetup: tailscale operator flag in the tailscale install step;
proton-vpn-cli replaces proton-vpn-gtk-app in the package list; VM test
assertions.
6. One-time per-machine migration: import the seven assets/wireguard-config
configs into NM with autoconnect off (scriptable; both daily drivers).
|