Skip to content

Show the tailnet's HTTPS services in the Tailscale panel - #10558

Open
Lethaquell wants to merge 2 commits into
omacom:quattrofrom
Lethaquell:tailscale-services
Open

Show the tailnet's HTTPS services in the Tailscale panel#10558
Lethaquell wants to merge 2 commits into
omacom:quattrofrom
Lethaquell:tailscale-services

Conversation

@Lethaquell

@Lethaquell Lethaquell commented Sep 6, 2026

Copy link
Copy Markdown

Two commits: the first binds the r refresh the panel's README has always
documented but nothing implemented, the second is the feature below.

The Tailscale panel answers "which machines do I have", but never "is the thing
I actually open still up". A tailnet can advertise services — svc:docs,
svc:wiki — that resolve inside it, and the panel had no idea they existed.

This adds a second tab listing them: the URL, the machine currently answering
for it, and the result of a reachability probe. Clicking a row opens it in the
browser.

Nothing to configure

The tab exists only while the tailnet advertises services to this node. A
tailnet without them sees the panel it always had — no chips, no section, and
no probe ever runs. There is no setting because there is no decision to make:
the tailnet already answered the question.

Where the data comes from

tailscale status --json already carries the services in the node's capability
map, and the panel already polls it for the machine list — so listing them
costs no second daemon call. Only reachability needs asking, and that is one
curl checking every URL in parallel.

Probing follows the panel: with it open the probe rides each status refresh;
with it closed, at most every five minutes, which is all the bar icon's dot
needs. The dot appears only when an advertised service is not answering, so an
unmarked icon still means there is nothing to look at.

Notes for review

  • curl exits non-zero as soon as any single transfer fails and still reports
    every URL it tried, so the probe reads its output rather than its exit
    status: one unreachable service is a row to colour red, not a failed probe.
  • Every probe flag is a refusal — no ~/.curlrc, no proxy, no plaintext, no
    redirects, no credentials, no unbounded wait — because it runs unattended on
    a timer against whatever the tailnet advertises.
  • A service name becomes a DNS label in a URL the panel opens, so a name that
    is not a valid label is skipped rather than turned into a URL.
  • Discovery, the probe command, its output parsing and the row join are pure
    functions in Model.js, so the whole feature is testable without a tailnet.

Testing

  • test/shell.d/tailscale-test.sh passes, with new assertions covering
    discovery, host selection, the probe command's flags, probe parsing and the
    join.
  • Verified live against a tailnet with three advertised services: both tabs,
    keyboard switching, and the degraded state (one service answering 502,
    another with no current host).
  • Checked the states that only look right by accident: an unprobed row is
    neutral rather than red, and the bar dot stays down until a probe has
    actually come back.
  • Verified with discovery stubbed out that a tailnet advertising no services
    renders exactly the panel that shipped before — no tabs, no section, no
    probe.

Credit

The discovery approach — reading the services/ capabilities, filtering to
tcp:443, and matching a service's addresses against peers' PrimaryRoutes
comes from digitalbase/omarchy-tailscale-services
(MIT), a third-party bar widget that shows this in a panel of its own. The
implementation here is written from scratch to fit Model.js and the existing
status poll, but the credit for working out where the data lives belongs there.

Preview

tailscale-services-tab

Lethaquell and others added 2 commits September 7, 2026 02:05
The panel's README has listed `r` as refresh since the widget landed, but
nothing ever bound the key: pressing it did nothing.
A tailnet can advertise services that resolve inside it, and until now the
panel had no idea they existed: the machine list answered "which machines do
I have", but never "is the thing I actually open still up".

The services ride the status poll that already runs. `tailscale status --json`
carries them in the node's capability map, so listing them costs no second
daemon call — only their reachability needs asking, and that is one curl
checking every URL in parallel.

There is nothing to configure. The second tab exists only while the tailnet
advertises services, so a tailnet without them sees the panel it always had
and never runs a probe. Probing follows the panel: with it open the probe
rides each status refresh, with it closed at most every five minutes, which
is all the icon's dot needs.

The dot in the bar icon appears only when an advertised service has been
probed and did not answer, so an unmarked icon still means there is nothing
to look at.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant