npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@subshell-ai/plugin-headscale

v1.0.0

Published

Headscale network plugin for Subshell

Readme

@subshell-ai/plugin-headscale

Reach this server over your own self-hosted tailnet.

Headscale is the open-source control server for the Tailscale protocol. This plugin drives the tailscale client binary (the same one the Tailscale plugin drives, at the same install locations; there is no headscale package to install on a client machine) pointed at a control server you run. It implements the type: "network" contract (spec 2026-09-15 § 4): it describes argv, parses output and names a required setting; the control-plane host is what executes, bounds and audits every act.

What it needs

  • The tailscale client installed (Settings → Networking prints the copyable daemon-install steps; installing the client is privileged, so the server never runs it).
  • A Control server URL saved under Settings → Networking → Headscale. Without it the join refuses: a bare tailscale up would not be "unset", it would enroll this machine into Tailscale's SaaS instead of your tailnet.
  • An interactive join is finished by an admin (headscale nodes register … on the control server), so the needs-login row says so. A pre-auth (tskey-…) key joins without a human on either end.

One machine, one tailnet: the pick-one rule

A machine can be on one tailnet at a time. With both the Tailscale and the Headscale plugins enabled, each row reads the same daemon, and tailscale status --json cannot see --login-server after the fact (no LoginServer key, measured on CLI 1.102.4). Since 2026-09-16 the rows do not have to guess: tailscale debug prefs reports the daemon's own ControlURL, and each row checks it. This row answers joined only when that URL canonicalizes to your configured Control server URL; a daemon reporting Tailscale's own service, or any other control server, reports needs-login here instead, and its serve config is never read, so a foreign machine can neither phantom-"Join" nor phantom-"Publish" (the measured case that forced this). What stays ambiguous is what the read cannot answer: a CLI too old for debug prefs, a refused read or an unparseable body leaves a Running daemon reading joined on whichever row asks, exactly as before: the fail-open the rule lives on. Nothing else can make the two rows agree on one daemon, because a Headscale configured at https://controlplane.tailscale.com would not be a Headscale. Enable both if you switch machines between tailnets; expect one green row per machine.

Publishing

Publish tries tailscale serve --bg --http=80 http://127.0.0.1:<port> (reset first). Whether Serve works against a given Headscale is UNMEASURED (design spec 2026-09-15 § 10.3), and this plugin shipped with that measurement still open. If the CLI refuses, publish returns an honest refusal that names the unmeasured section and points at the plain http://<DNSName>:<port> address the status already lists; it never reports a published state it did not create. Headscale tailnets issue no HTTPS certificates (juanfont/headscale#2527), so every address here is http with secureContext: false; passkeys and Secure cookies will not work on them.

Where the code came from

src/cli.ts, status.ts, join.ts, publish.ts and hints.ts are copied from @subshell-ai/plugin-tailscale (the inline route spec 2026-09-16 § 4 names first, tsdown noExternal, cannot carry them: the tailscale package exports only its factory and manifest, and inlining its module graph would parse tailscale's own manifest at load). The shared argv constants are pinned by a containment test in src/__tests__/headscale.test.ts so the two plugins cannot silently disagree about one binary.