Back to list
Skywire Development Update — September 27, 2026
The twenty-seventh put a real settings surface on top of the previous day’s config API, restored mesh and clearnet browsing to real browser origins after an engine swap had quietly dropped the code that made either one work, and gave the resolving proxy per-domain routing and a second protocol on the same port. Away from the desk, an adaptive routing policy was found sharing its controller state across every route group of an app instead of keeping one per group, v1.3.97 shipped, and skychat picked up call-progress reporting with a ringback tone and a full-screen video viewer. The Android app rounded out the day with favorited servers, three VPN app-selection modes, and a hotspot-sharing feature that lets another device on a phone’s hotspot ride its SkyVPN tunnel.
Skywire: A Settings Page for skywire.conf
5208 and 5209 built the two front ends for the config API that landed the day before: a settings window in the desk for a browser tab’s own config, and a matching Settings tab in the native hypervisor UI, both listing one row per variable, letting an operator review every change before anything is written, and falling back to printing the equivalent autoconfig command when the file itself can’t be written directly — a root-owned /etc/skywire.conf, say. The desk’s version also groups the settings that do nothing in a browser tab, like the VPN router or the embedded dmsg server, apart from the ones that matter there. 5207 closed a side effect the config file’s new durability exposed: a flag recorded once for an attached boot was being read back and reapplied to every later boot regardless of whether that one was supposed to roam freely, pinning a roaming load to a WebSocket peer nobody was answering; an unattached boot now explicitly clears both flags rather than inheriting whatever a previous, different boot had written.
Skywire: Mesh and Clearnet Browsing on a Real Origin Again
5226 found that netscrape’s replacement of the desk’s old browsing engine had silently dropped the mechanism that gives a mesh site its own real browser origin with cookies, storage and a service worker, falling through instead to a sandboxed transcoder with none of that — the wasm-served desk had never even loaded the half of the code that handles the browser’s side of the handshake, and the part that was loaded tried to fetch through a visor reference the served desk doesn’t actually publish. The fix ports the origin-matching rules from the retired engine into netscrape’s own loader, verbatim enough that a site keeps the exact origin, and storage, it already had.
5228 found a similar loss on the clearnet side and a second bug alongside it: ordinary HTTPS and HTTP sites had been left on the sandboxed path because the rule that used to claim them for a real origin simply hadn’t been found and ported, and separately the browser’s own clearnet fetcher built a fresh HTTP transport per page and never closed it, so every page left its own connection and proxy stream open until the local proxy simply stopped answering after the first one.
5227 moved netscrape’s own request path onto the same resolving proxy a browser sitting beside a native visor already uses by default, rather than the patchwork of a direct skysocks dial for plain HTTP, the browse API for HTTPS, and hand-matched hostnames in JavaScript for mesh and status pages — which incidentally means per-domain routing rules and status.skywire now work inside netscrape too. Making that one path work inside a tab surfaced two bugs of its own: the resolver’s own forwarding dial couldn’t reach the page’s virtual loopback at all, and once it could, the SOCKS5 library it used panicked outright on the address type a virtual-network connection carries, taking the whole visor down with it. 5229 fixed a desk pointed at a deployed browse domain still advertising its own local listener’s port on every browse-origin frame, which nothing was serving at that address; only a .localhost suffix is served on the desk’s own listener now, and anything else correctly names an origin that lives behind a real reverse proxy on port 443.
Skywire: The Resolving Proxy Learns to Route and Speak HTTP
5222 gave the resolving proxies a per-domain routing table: a rule sends one domain and its subdomains to its own upstream SOCKS5 proxy, commonly a second skysocks-client pointed at a different exit, or marks it direct, ahead of whatever the default upstream would have handled it with — settable live, persisted in the config, and listed on the status page alongside whichever app is actually listening on each upstream.
5223 then let the same SOCKS5 port also answer plain HTTP proxy requests, reading the very first byte of a connection to tell which protocol it’s speaking and routing either one through the identical resolve-and-dial path — specifically because that’s the only protocol Android’s own VPN proxy setting and a typical browser’s HTTP proxy field can speak, making it the first step toward mesh browsing from the mobile VPN client itself.
5225 fixed MITM’d HTTPS traffic being decrypted correctly and then sent to port 443 on the destination visor, when every visor actually serves its site on port 80 and nothing on 443 at all, so every HTTPS mesh page had been falling through to the generic route-warming interstitial regardless of whether the route was actually ready.
Skywire: Who Holds a Route, and a Shell That Knows About the Proxy
5221 gave the status page a view of every route a visor is actually carrying rather than only the one proxy client’s own routes that status.skysocks already showed, naming each accepted route group after whichever app is listening on its port and labeling the visor’s own direct streams plainly as the visor’s. 5231 taught the desk’s own curl and got commands to read the standard proxy environment variables the way curl itself does, and gave a browser tab’s shell profile the matching exports pointing at its own resolving proxy — which is a smaller change than it sounds, since reaching that proxy from inside a tab exposed two further bugs: the got tool’s own proxy dial couldn’t reach the page’s virtual loopback at all, and it had no root certificate store to check a TLS connection against in the first place, since a browser tab has none of its own.
Skywire: An Adaptive Routing Policy That Forgot Which Route Group It Was
5233 found two defects in the adaptive routing policy after it collapsed in a browser visor, both of which affect native visors identically. The policy’s WASM engine had been a single global instance shared by every route group an app holds, so one group’s byte counters became another’s baseline and one group’s healthy ticks could reset a completely different group’s bad-primary streak, letting a group stay pinned to a multi-second-latency primary leg indefinitely; each route group now gets its own engine instance. The same audit found that dropping an active leg had never actually resent the data in flight on it, despite the code that drops a leg claiming it did, which could leave the receiver’s reorder gap open long enough for those sequences to age out of the sender’s own retransmit buffer and wedge the stream for good — a drop now flushes that in-flight data onto a surviving leg exactly the way a planned demotion already did.
Skywire: Release v1.3.97, and the Small Fixes Around It
5215 shipped v1.3.97, with a changelog entry backfilled for the previously unreleased v1.3.96 alongside it and the embedded wasm module re-staged from a clean tree so it no longer reports as built from modified sources. 5212 fixed every tagged release reporting itself with a trailing commit hash appended even when the release binary itself was built clean from that exact tag, which made v1.3.96 print as v1.3.96-a44e1e6e851d everywhere from cli version to a deployment service’s own health check.
5214 bumped skycoin to its latest development commit and ran a general dependency sweep across every build target, leaving gvisor deliberately pinned since its newer revisions ship without the generated files the build needs. 5211 cleared two unrelated CI failures blocking develop: a UI bundle built from node_modules that no longer matched its own lockfile, and a run of Windows-specific test failures that also caught a real resource leak, where killing an app had never closed its own pid file handle.
5210 simplified the Wisp server’s own on/off switch into no switch at all, since a native visor gains nothing from running it and a browser visor gains nothing from not running it; it now starts unconditionally on a browser visor and never on a native one. 5216 stopped a browser tab from auto-starting a VPN server or a skysocks server it cannot actually serve, since a tab can neither forward raw IP packets nor open a raw TCP socket, and the first of those had simply been erroring at boot while the second silently accepted connections it had no way to carry.
Skywire: Calls That Say What They’re Doing, and Video in skychat
5213 fixed a deleted, CXO-paired chat reliably coming back to life across a page reload, an app restart, or simply switching tabs and back, because three entirely separate places were still handing the deleted conversation back out — a pairing list that kept listing revoked records, a replay buffer that still held the peer’s old messages, and a restart-time resync that rebroadcast an entire pairing inbox from scratch with no idea any of it had since been revoked.
5217 gave a caller actual knowledge of what’s happening during a ring, rather than a static “Calling…” that looked identical whether the peer was offline, ringing, or had just pressed decline — a callee’s phone can now also offer a custom ringback tone the caller hears while waiting, fetched on its own connection so it can never delay the call being answered.
5218 gave chat videos a real full-screen viewer, since the browser’s native fullscreen control doesn’t exist on a recorded round video message and does nothing at all inside the Android app’s WebView. 5219 let a video message’s camera be switched mid-recording by drawing the camera feed into a canvas and recording that instead of the raw camera track, since a recorder tied directly to a camera track has no choice but to stop the instant the underlying track changes, and added the option to record a message as a square rather than only the original circular crop.
Skywire: Favorites, Per-App Tunneling, and a Hotspot for SkyVPN
5220 let a VPN or SOCKS proxy server be starred as a favorite directly from its row in the server list, kept locally on the phone and shown even when that server has dropped out of the current discovery listing, which is most of the point since finding a fast server in the first place is the slow part of using either feature at all. 5224 replaced SkyVPN’s all-or-nothing tunnel with three selectable modes — every app, only chosen apps, or every app except chosen ones — read by the VPN service every time it rebuilds its tunnel interface, with the app running the visor itself permanently excluded from every mode since its own traffic is what carries the tunnel in the first place. 5230 let a phone sharing its SkyVPN tunnel over its own hotspot carry a connected laptop’s traffic through that same tunnel via a small HTTP-and-SOCKS5 proxy bound to the hotspot interface specifically, since Android gives an app no way to pull tethered traffic into its own VPN tunnel without root privileges — a connection is accepted only if it genuinely arrived on a hotspot interface rather than, say, a café Wi-Fi network the phone itself joined as a client.