diff --git a/Driver/internal/control/page.go b/Driver/internal/control/page.go
index 5915900..8486668 100644
--- a/Driver/internal/control/page.go
+++ b/Driver/internal/control/page.go
@@ -1,3 +1,4 @@
+// Modified for Goblin Skiff integration on 2026-09-19.
 package control
 
 const page = `<!doctype html><html lang="en"><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Goblin Modem · Radio network</title>
@@ -9,9 +10,9 @@ const page = `<!doctype html><html lang="en"><meta charset="utf-8"><meta name="v
 <main><section class="panel"><h2>Connection</h2><label for="target">Computer</label><select id="target"></select><label for="device">Radio serial port</label><div class="row"><select id="device"></select><button class="secondary" id="scan" style="margin:0;max-width:90px">Rescan</button></div><label for="name">Computer name · blank uses hostname</label><input id="name" maxlength="32" placeholder="e.g. naamah"><label for="gid">Radio identity (GID)</label><input id="gid" inputmode="numeric">
 <div class="sharing"><label><input id="internet" type="checkbox">Share Internet</label><p>Use this computer’s Internet connection — Wi-Fi, modem, or Ethernet — as a gateway for other radios. Leave this off on computers without an Internet uplink.</p></div>
 <label for="priority">Gateway priority · lower wins</label><input id="priority" type="number" min="0" max="65535" value="100"><label for="preferred">Preferred gateway</label><select id="preferred"><option value="0">Automatic · priority, then hops</option></select>
-<p class="hint">Closing this browser leaves the radio connected. Use Disconnect to stop it. A Mosh command reconnects using the settings saved on the computer where it runs.</p><div class="row"><button id="connect">Connect</button><button id="disconnect" class="secondary">Disconnect</button></div><button id="apply" class="secondary">Apply Internet settings</button>
+<p class="hint">Closing this browser leaves the radio connected. Use Disconnect to stop it. A Skiff command reconnects using the settings saved on the computer where it runs.</p><div class="row"><button id="connect">Connect</button><button id="disconnect" class="secondary">Disconnect</button></div><button id="apply" class="secondary">Apply Internet settings</button>
 <details><summary>Network and connection settings</summary><label for="key">Shared network key</label><input id="key" type="password" autocomplete="off"><p class="hint">Use the same 64-character key on all N radios, and a different GID for each radio.</p><label for="socks">Local SOCKS5 port</label><input id="socks" type="number" min="1024" max="65535"><label for="pacing">Minimum delay after a radio send (ms)</label><input id="pacing" type="number" min="100" max="60000"><label for="hops">Discovery radius (link traversals)</label><input id="hops" type="number" min="1" max="6"><label><input id="native" type="checkbox"> Create an IP interface (requires privilege)</label><button id="save" class="secondary">Save settings</button></details>
-</section><section class="panel"><h2>Link status</h2><div id="addresses" class="muted">Connect a radio to begin.</div><div class="stats"><div><small>RADIO MESSAGES SENT</small><div class="metric" id="tx">0</div></div><div><small>RADIO MESSAGES RECEIVED</small><div class="metric" id="rx">0</div></div><div><small>SELECTED INTERNET GATEWAY</small><div id="gateway" class="metric">—</div></div><div><small>DISCARDED / SEND REJECTIONS</small><div class="metric" id="dropped">0 / 0</div></div></div><p class="hint" id="radioqueue"></p><p class="hint">Discarded packets and filtered background traffic are separate counts, not an over-the-air loss rate. Send rejections are retried with backoff.</p><h2>Other computers</h2><label for="sshuser">SSH user on the destination</label><input id="sshuser" autocomplete="username" placeholder="Your login name"><label for="bootstrap">SSH setup</label><select id="bootstrap"><option value="existing">Existing network · local radio test</option><option value="radio">Radio only · experimental</option></select><p id="peerwarning"></p><p class="hint" id="peercontext"></p><table><thead><tr><th>Computer and mesh addresses</th><th>Connection</th></tr></thead><tbody id="peers"></tbody></table><div id="connecthelp" hidden><h2 style="margin-top:22px" id="commandtitle">Connect with Mosh</h2><textarea id="moshcommand" rows="5" readonly></textarea><button id="copycommand" class="secondary">Copy Mosh command</button><p class="hint" id="moshhint"></p></div><p class="hint">Gateways advertise periodically. Automatic selection changes when a gateway withdraws sharing or its advertisement expires. Existing TCP sessions may need to reconnect.</p><p class="hint">SOCKS5 supports TCP and UDP. Goblin Mosh can use --socks5-proxy=127.0.0.1:1080. The computer’s default route is unchanged.</p><div id="error" role="status"></div></section></main>
+</section><section class="panel"><h2>Link status</h2><div id="addresses" class="muted">Connect a radio to begin.</div><div class="stats"><div><small>RADIO MESSAGES SENT</small><div class="metric" id="tx">0</div></div><div><small>RADIO MESSAGES RECEIVED</small><div class="metric" id="rx">0</div></div><div><small>SELECTED INTERNET GATEWAY</small><div id="gateway" class="metric">—</div></div><div><small>DISCARDED / SEND REJECTIONS</small><div class="metric" id="dropped">0 / 0</div></div></div><p class="hint" id="radioqueue"></p><p class="hint">Discarded packets and filtered background traffic are separate counts, not an over-the-air loss rate. Send rejections are retried with backoff.</p><h2>Other computers</h2><label for="sshuser">SSH user on the destination</label><input id="sshuser" autocomplete="username" placeholder="Your login name"><label for="bootstrap">SSH setup</label><select id="bootstrap"><option value="existing">Existing network · local radio test</option><option value="radio">Radio only · experimental</option></select><p id="peerwarning"></p><p class="hint" id="peercontext"></p><table><thead><tr><th>Computer and mesh addresses</th><th>Connection</th></tr></thead><tbody id="peers"></tbody></table><div id="connecthelp" hidden><h2 style="margin-top:22px" id="commandtitle">Connect with Skiff</h2><textarea id="moshcommand" rows="5" readonly></textarea><button id="copycommand" class="secondary">Copy Skiff command</button><p class="hint" id="moshhint"></p></div><p class="hint">Gateways advertise periodically. Automatic selection changes when a gateway withdraws sharing or its advertisement expires. Existing TCP sessions may need to reconnect.</p><p class="hint">SOCKS5 supports TCP and UDP. Goblin Skiff can use --socks5-proxy=127.0.0.1:1080. The computer’s default route is unchanged.</p><div id="error" role="status"></div></section></main>
 <script>
 const el=id=>document.getElementById(id);let token='CONTROL_TOKEN',configs={},busy=false,loadingTarget=false,selection=0,moshLauncher='',radioError='',controllerError='';
 function error(e){el('error').textContent=e?.message||String(e||'')}
@@ -60,9 +61,9 @@ async function copy(value,button){try{await navigator.clipboard.writeText(value)
 function showMosh(peer,status){
  const user=el('sshuser').value.trim(),name=peer.dnsName||('radio-'+peer.gid.toString(16).padStart(12,'0')+'.mesh');
  let ssh='ssh -o ConnectTimeout=180';if(peer.name)ssh+=' -o HostKeyAlias='+quote(peer.name);
- const bin=el('target').value==='local'?'/usr/bin/':'/opt/homebrew/opt/goblin-mosh/bin/';
- const server="/bin/sh -c 'for p in /opt/homebrew/opt/goblin-mosh/bin/goblin-mosh-server /usr/local/opt/goblin-mosh/bin/goblin-mosh-server /usr/bin/goblin-mosh-server /usr/local/bin/goblin-mosh-server; do if [ -x \"$p\" ]; then exec \"$p\" \"$@\"; fi; done; exec goblin-mosh-server \"$@\"' goblin-mosh-server";
- el('moshcommand').value=bin+'goblin-mosh --client='+bin+'goblin-mosh-client --socks5-proxy='+quote(status.socks)+' --ssh='+quote(ssh)+' --server='+quote(server)+' -- '+quote((user?user+'@':'')+name);
+ const bin=el('target').value==='local'?'/usr/bin/':'/opt/homebrew/opt/goblin-skiff/bin/';
+ const server="/bin/sh -c 'for p in /opt/homebrew/opt/goblin-skiff/bin/goblin-skiff-server /usr/local/opt/goblin-skiff/bin/goblin-skiff-server /usr/bin/goblin-skiff-server /usr/local/bin/goblin-skiff-server; do if [ -x \"$p\" ]; then exec \"$p\" \"$@\"; fi; done; exec goblin-skiff-server \"$@\"' goblin-skiff-server";
+ el('moshcommand').value=bin+'goblin-skiff --client='+bin+'goblin-skiff-client --socks5-proxy='+quote(status.socks)+' --ssh='+quote(ssh)+' --server='+quote(server)+' -- '+quote((user?user+'@':'')+name);
  if(el('bootstrap').value==='existing'){
   const launcher=el('target').value==='local'?moshLauncher:'/usr/local/libexec/goblin-radio-mosh';
   el('moshcommand').value=quote(launcher)+' --ipv6 --proxy='+quote(status.socks)+' --peer='+quote(name)+' -- '+quote((user?user+'@':'')+(peer.name||peer.ipv6));
@@ -81,7 +82,7 @@ function peerRow(peer,status){
  const buttons=document.createElement('div');buttons.className='peer-actions';
  for(const [label,value] of [['Copy IPv4',peer.ipv4],['Copy IPv6',peer.ipv6],['Copy name',name]]){const button=document.createElement('button');button.textContent=label;button.className='secondary';button.onclick=()=>copy(value,button);buttons.append(button)}addresses.append(buttons);
  const availability=document.createElement('p');availability.className='hint';availability.textContent=peer.nativeInterface?'Peer IP interface on. SSH and Mosh must be installed on this computer.':'Peer IP interface is not advertised. Enable it on this computer to receive SSH/Mosh connections.';connection.append(availability);
- const button=document.createElement('button');button.textContent='Mosh command';button.className='secondary';button.disabled=!peer.nativeInterface||status.state==='stopping'||(el('bootstrap').value==='radio'&&status.state!=='up');button.onclick=()=>showMosh(peer,status);connection.append(button);
+ const button=document.createElement('button');button.textContent='Skiff command';button.className='secondary';button.disabled=!peer.nativeInterface||status.state==='stopping'||(el('bootstrap').value==='radio'&&status.state!=='up');button.onclick=()=>showMosh(peer,status);connection.append(button);
  tr.append(addresses,connection);return tr;
 }
 async function refresh(){
diff --git a/Makefile b/Makefile
index da96f8e..b11467d 100644
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,6 @@
-VERSION ?= 0.1.0+20260918.1
-MAC_VERSION ?= 0.1.0.20260918.1
+# Modified for Goblin Skiff integration on 2026-09-19.
+VERSION ?= 0.1.0+20260919.1
+MAC_VERSION ?= 0.1.0.20260919.1
 ARCH ?= amd64
 GO ?= go
 OUTPUT ?= $(CURDIR)/dist
@@ -32,5 +33,5 @@ site-publish: site-check
 linux-install: linux-deb
 	sudo apt install '$(OUTPUT)/goblin-modem_$(VERSION)_$(ARCH).deb'
 macos-install: macos-pkg
-	brew install goblinreactor/tap/goblin-mosh python@3.14
+	brew install goblinreactor/tap/goblin-skiff python@3.14
 	sudo installer -pkg '$(OUTPUT)/goblin-modem-$(MAC_VERSION)-arm64.pkg' -target /
diff --git a/RADIO.md b/RADIO.md
index bf102a5..34c80a3 100644
--- a/RADIO.md
+++ b/RADIO.md
@@ -1,3 +1,4 @@
+<!-- Modified for Goblin Skiff integration on 2026-09-19. -->
 # goTenna Mesh radios
 
 `goblin-radio` is the shared macOS/Linux driver. On macOS, Goblin Modem's
@@ -20,9 +21,9 @@ cd ~/dev/goblin-modem
 Open <http://127.0.0.1:8777>. Choose **This Linux computer** or **wopr · SSH**,
 select the radio, and connect. **Other computers** lists authenticated computer names, IPv4 and
 IPv6 addresses, gateway role, hop count and peer-interface availability. Copy
-an address/name directly, or choose **Mosh command**; its heading says which
+an address/name directly, or choose **Skiff command**; its heading says which
 computer should run the command. On the Mac, **Radios & addresses… → Radio**
-shows the same list with an **Open Mosh** button that opens Terminal.
+shows the same list with an **Open Skiff** button that opens Terminal.
 
 A SOCKS-only computer can make outgoing connections but needs its **Create an
 IP interface** option enabled to receive SSH/Mosh connections from peers.
@@ -106,7 +107,7 @@ JSON line from stdin, followed by role-update JSON lines; EOF stops the driver.
 Receive captures contain raw radio bytes and should be kept private and rotated
 for long-running installations.
 
-## Applications and Goblin Mosh
+## Applications and Goblin Skiff
 
 The local SOCKS5 proxy supports CONNECT and UDP ASSOCIATE:
 
@@ -116,10 +117,10 @@ curl --socks5-hostname 127.0.0.1:1080 --max-time 150 -I http://example.com
 ./Scripts/radio-mosh.sh --ipv6 wopr
 ```
 
-`radio-mosh.sh` connects the local radio from its saved GUI profile if needed, waits for the destination's discovery, then starts `goblin-mosh-server` over management SSH. It reads the destination's
-discovered peer mesh IP from the local driver, and runs the local `goblin-mosh-client` through SOCKS5. **Only
+`radio-mosh.sh` connects the local radio from its saved GUI profile if needed, waits for the destination's discovery, then starts `goblin-skiff-server` over management SSH. It reads the destination's
+discovered peer mesh IP from the local driver, and runs the local `goblin-skiff-client` through SOCKS5. **Only
 the bootstrap uses management SSH; terminal UDP travels over the radios.**
-It requires the destination computer's IP interface to be enabled, and Goblin Mosh on both
+It requires the destination computer's IP interface to be enabled, and Goblin Skiff on both
 computers. `--peer NAME` selects a mesh peer separately from the management
 SSH host, for custom SSH aliases or renamed computers. Options include `--proxy HOST:PORT`, `--server PATH`, and a command
 after the SSH host. Disconnected test servers expire after 180 seconds by
@@ -202,7 +203,7 @@ hashed IPv4 alias conflicts. The advertised hostname must also be a working
 management SSH hostname; use the shell launcher with `--peer` for other SSH aliases.
 
 The optional **Radio only · experimental** mode uses
-`/usr/local/bin/goblin-mosh`, explicit client/server paths, and the selected
+`/usr/local/bin/goblin-skiff`, explicit client/server paths, and the selected
 computer's local proxy. Setup can still be slow on this link; this mode has not passed an
 end-to-end hardware test. `HostKeyAlias`
 reuses the known SSH host key for the advertised hostname; normal SSH host-key
@@ -245,7 +246,7 @@ wire vectors using the original Python implementation.
 
 Hardware checks on 2026-09-17 used Mac MX18211952 and Linux MX18210440/MX18211700:
 three-peer discovery, DNS and HTTP through the Mac gateway, switching to the
-second gateway with the GUI, and interactive Goblin Mosh request/reply over
+second gateway with the GUI, and interactive Goblin Skiff request/reply over
 both IPv4 and IPv6 on the native Mac IP interface. Clean disconnect, independence
 from PPP disconnect, and helper-crash cleanup/restart were also exercised.
 See the driver tests for simulated packet-loss
@@ -268,8 +269,8 @@ interactive response remain slow on a busy radio link.
 
 ## Radio startup reliability
 
-Goblin Mosh now defaults to a 120-second initial connection timeout. Both
-`goblin-mosh` and `goblin-mosh-client` accept `--connect-timeout=SECONDS`
+Goblin Skiff now defaults to a 120-second initial connection timeout. Both
+`goblin-skiff` and `goblin-skiff-client` accept `--connect-timeout=SECONDS`
 (1–3600); the wrapper also passes it to its SSH proxy setup. This does not
 change established-session timeouts. `goblin-radio-mosh` exposes the same
 option and keeps an unconnected server alive beyond that startup window.
@@ -308,11 +309,11 @@ terminal-owned mode for debugging. Background mode uses systemd (the native
 variant runs as the invoking user with `CAP_NET_ADMIN`), and lasts until
 stopped or the computer restarts. Run the launcher again after a restart.
 
-A normal local-test Mosh command now connects a stopped radio using the
+A normal local-test Skiff command now connects a stopped radio using the
 profile saved in that computer's GUI, then waits for fresh peer discovery
 before starting SSH/Mosh. On Linux it also starts the background controls
 if necessary. It does not change the radio's identity, key, or Internet role.
-The Mac menu offers **Connect**, and a retained peer's **Connect & open Mosh**
+The Mac menu offers **Connect**, and a retained peer's **Connect & open Skiff**
 uses the same launcher as a copied command. Both GUI Connect and the launcher
 submit the same connection request to the local controller; connection
 progress and errors therefore appear in the GUI. A hardware error or an
@@ -325,7 +326,7 @@ The Mac GUI adopts a newly connected or externally changed active profile,
 including changes made from Linux. Selecting a Mac in the Linux GUI
 loads its most recent helper profile when available, so the displayed Internet role matches the driver.
 Closing the Mac with **Quit & restore** still disconnects the radio. A later
-Mosh command connects it again from the saved profile.
+Skiff command connects it again from the saved profile.
 
 Recovery regression tests: `python3 Scripts/test-radio-mosh.py`.
 
@@ -341,7 +342,7 @@ a stopped controller/native radio and reported an absent peer within the
 requested timeout. The Mac launcher submitted its saved profile to the helper
 and correctly reported the missing USB device. After the radio was power-cycled,
 the GUI connected Mac MX18211952 and discovered `naamah.mesh`. The GUI then
-disconnected it, and its generated Mosh command (default 120-second startup
+disconnected it, and its generated Skiff command (default 120-second startup
 wait) automatically reconnected from the saved profile and waited for fresh
 peer discovery. A real login shell returned the typed `GOBLIN-RECOVERY-OK`
 marker over IPv6 radio UDP after 137 seconds. The GUI reflected the launcher’s
@@ -367,10 +368,10 @@ negotiates radio mode on both Mosh endpoints. The command itself is unchanged:
 /usr/local/libexec/goblin-radio-mosh --ipv6 --proxy=127.0.0.1:1080 --peer=naamah.mesh -- adam@naamah
 ```
 
-Use updated Goblin Mosh client/server binaries on both computers. The launcher
+Use updated Goblin Skiff client/server binaries on both computers. The launcher
 requires the server's `MOSH RADIO single-frame-v1` confirmation and invokes the
 client's `--radio` option. Its startup message confirms radio mode. This applies
-to the Mac **Open Mosh** action and Linux **Mosh command** through the same
+to the Mac **Open Skiff** action and Linux **Skiff command** through the same
 installed launcher, including automatic connection from the saved GUI profile.
 
 Previously, IPv6 datagrams could reach 1,216 bytes (several radio fragments),
diff --git a/modem-review/goblin-modem-0.1.0-20260919.1/SKIFF_RELEASE.md b/SKIFF_RELEASE.md
new file mode 100644
index 0000000..e4e0953
--- /dev/null
+++ b/SKIFF_RELEASE.md
@@ -0,0 +1,11 @@
+# Goblin Modem Skiff integration — 2026-09-19
+
+This distribution derives from the published 0.1.0-20260918.1 source snapshot
+(SHA-256 12186690ec747f8023574019275369acfe6ba07889b057b99f44c3cc20c8b335).
+It updates the packaged client/server paths and package dependencies to Goblin
+Skiff, the radio launcher's local configuration variables, and visible command
+labels. MOSH CONNECT, capability banners, MOSH_KEY and server-facing variables
+keep their existing protocol meanings. No radio configuration or keys change.
+
+Goblin Skiff is an independent fork of Mosh. Mosh is a registered trademark of
+Keith Winstein. See the Skiff source's TRADEMARKS.md for the notice.
diff --git a/Scripts/radio-mosh.py b/Scripts/radio-mosh.py
index d88de98..e208380 100755
--- a/Scripts/radio-mosh.py
+++ b/Scripts/radio-mosh.py
@@ -1,4 +1,5 @@
 #!/usr/bin/env python3
+# Modified for Goblin Skiff integration on 2026-09-19.
 """Bootstrap over management SSH; carry the Mosh session over radio SOCKS5."""
 import argparse
 import json
@@ -147,7 +148,7 @@ def main():
     parser.add_argument('--connect-timeout', type=int, default=120, help='Radio/discovery and initial Mosh UDP waits in seconds (1..3600; default: 120)')
     parser.add_argument('--peer', help='Discovered mesh name or GID; defaults to the SSH hostname')
     parser.add_argument('--client-arg', action='append', default=[])
-    parser.add_argument('--server', help='Remote server executable; defaults to the packaged Goblin Mosh')
+    parser.add_argument('--server', help='Remote server executable; defaults to the packaged Goblin Skiff')
     parser.add_argument('host', help='Management SSH host, such as wopr')
     parser.add_argument('command', nargs=argparse.REMAINDER)
     args = parser.parse_args()
@@ -156,25 +157,25 @@ def main():
     if not re.fullmatch(r'[A-Za-z0-9_@.:-]+', args.host) or args.host.startswith('-'):
         parser.error('invalid SSH host')
     # Prefer the managed package over older manual /usr/local installations.
-    candidates = (['/opt/homebrew/opt/goblin-mosh/bin/goblin-mosh-client',
-                   '/usr/local/opt/goblin-mosh/bin/goblin-mosh-client']
-                  if platform.system() == 'Darwin' else ['/usr/bin/goblin-mosh-client'])
+    candidates = (['/opt/homebrew/opt/goblin-skiff/bin/goblin-skiff-client',
+                   '/usr/local/opt/goblin-skiff/bin/goblin-skiff-client']
+                  if platform.system() == 'Darwin' else ['/usr/bin/goblin-skiff-client'])
     client = next((p for p in candidates if os.access(p, os.X_OK)), None)
-    client = client or shutil.which('goblin-mosh-client')
-    if not client and os.access('/usr/local/bin/goblin-mosh-client', os.X_OK):
-        client = '/usr/local/bin/goblin-mosh-client'
+    client = client or shutil.which('goblin-skiff-client')
+    if not client and os.access('/usr/local/bin/goblin-skiff-client', os.X_OK):
+        client = '/usr/local/bin/goblin-skiff-client'
     if not client:
-        parser.error('goblin-mosh-client is required locally')
+        parser.error('goblin-skiff-client is required locally')
     ssh = ['ssh', '-T', '-o', 'BatchMode=yes', '-o', 'ConnectTimeout=8', args.host]
     host = (args.peer or args.host.rsplit('@', 1)[-1]).lower().removesuffix('.local')
     radio, peer = wait_for_peer(RadioControl(), host, args.connect_timeout)
     address = peer['ipv6' if args.ipv6 else 'ipv4']
     server = [args.server] if args.server else ['/bin/sh', '-c',
-        'for server in /opt/homebrew/opt/goblin-mosh/bin/goblin-mosh-server '
-        '/usr/local/opt/goblin-mosh/bin/goblin-mosh-server /usr/bin/goblin-mosh-server '
-        '/usr/local/bin/goblin-mosh-server; do '
+        'for server in /opt/homebrew/opt/goblin-skiff/bin/goblin-skiff-server '
+        '/usr/local/opt/goblin-skiff/bin/goblin-skiff-server /usr/bin/goblin-skiff-server '
+        '/usr/local/bin/goblin-skiff-server; do '
         'if [ -x "$server" ]; then exec "$server" "$@"; fi; done; '
-        'exec goblin-mosh-server "$@"', 'goblin-radio-server']
+        'exec goblin-skiff-server "$@"', 'goblin-radio-server']
     command = ['env', 'MOSH_SERVER_NETWORK_TMOUT=' + str(max(120, args.connect_timeout + 60)),
                'MOSH_CLIENT_CAPS=keepalive-v1,link-budget-v1,radio-v1',
                'MOSH_CLIENT_TERM=' + os.environ.get('TERM', 'xterm-256color')] + server + ['new',
@@ -187,23 +188,23 @@ def main():
                             capture_output=True, timeout=30)
     match = re.search(r'^MOSH CONNECT (\d+) ([A-Za-z0-9+/=]+)\s*$', result.stdout, re.M)
     if result.returncode or not match:
-        raise RuntimeError('Mosh server did not start: ' + result.stderr.strip())
+        raise RuntimeError('Skiff server did not start: ' + result.stderr.strip())
     port, key = match.groups()
     env = dict(os.environ, MOSH_KEY=key)
-    # Match the normal Goblin Mosh wrapper: enable only the capabilities
+    # Match the normal Goblin Skiff wrapper: enable only the capabilities
     # confirmed by this server, never flags inherited from another session.
     negotiated = set(result.stdout.splitlines())
     if not {'MOSH RADIO single-frame-v1', 'MOSH CAPS keepalive-v1', 'MOSH LINK budget-v1'} <= negotiated:
-        raise RuntimeError('Update goblin-mosh-server on ' + args.host + ': radio pacing support is required.')
-    for name in ('MOSH_DIRECTORY', 'MOSH_FILES', 'MOSH_SIXEL_STATE',
-                 'MOSH_CLIPBOARD', 'MOSH_DOWNLOADS'):
+        raise RuntimeError('Update goblin-skiff-server on ' + args.host + ': radio pacing support is required.')
+    for name in ('GOBLIN_SKIFF_DIRECTORY', 'GOBLIN_SKIFF_FILES', 'GOBLIN_SKIFF_SIXEL_STATE',
+                 'GOBLIN_SKIFF_CLIPBOARD', 'GOBLIN_SKIFF_DOWNLOADS'):
         env[name] = '0'
-    for name in ('MOSH_STATE_ZSTD_DICT', 'MOSH_RELAY_KEYS'):
+    for name in ('MOSH_STATE_ZSTD_DICT', 'GOBLIN_SKIFF_RELAY_KEYS'):
         env.pop(name, None)
     compact = 'MOSH CAPS keepalive-v1' in negotiated
-    env['MOSH_COMPACT_KEEPALIVE'] = '1' if compact else '0'
-    env['MOSH_LINK_BUDGET'] = '1' if compact and 'MOSH LINK budget-v1' in negotiated else '0'
-    print('Goblin Mosh: {}:{} through radio proxy {}'.format(address, port, args.proxy),
+    env['GOBLIN_SKIFF_COMPACT_KEEPALIVE'] = '1' if compact else '0'
+    env['GOBLIN_SKIFF_LINK_BUDGET'] = '1' if compact and 'MOSH LINK budget-v1' in negotiated else '0'
+    print('Goblin Skiff: {}:{} through radio proxy {}'.format(address, port, args.proxy),
           file=sys.stderr, flush=True)
     print('Radio mode: 128-byte datagrams, paced transmission, extended retransmission waits.',
           file=sys.stderr, flush=True)
diff --git a/Scripts/test-radio-mosh.py b/Scripts/test-radio-mosh.py
index c82f4ad..a533430 100644
--- a/Scripts/test-radio-mosh.py
+++ b/Scripts/test-radio-mosh.py
@@ -1,4 +1,5 @@
 #!/usr/bin/env python3
+# Modified for Goblin Skiff integration on 2026-09-19.
 """Exercise launcher recovery without starting SSH or touching a real radio."""
 import contextlib
 import importlib.util
@@ -44,13 +45,13 @@ class RecoveryTests(unittest.TestCase):
         output = 'MOSH CONNECT 60000 TESTKEY\nMOSH CAPS keepalive-v1\nMOSH LINK budget-v1\nMOSH RADIO single-frame-v1\n'
         with mock.patch.object(radio_mosh.sys, 'argv', ['goblin-radio-mosh', '--peer=workstation.mesh', '--', 'adam@workstation']), \
              mock.patch.object(radio_mosh, 'wait_for_peer', return_value=({}, PEER)), \
-             mock.patch.object(radio_mosh.shutil, 'which', return_value='/test/goblin-mosh-client'), \
+             mock.patch.object(radio_mosh.shutil, 'which', return_value='/test/goblin-skiff-client'), \
              mock.patch.object(radio_mosh.subprocess, 'run', return_value=mock.Mock(returncode=0, stdout=output)) as run, \
              mock.patch.object(radio_mosh.os, 'execvpe') as execute, contextlib.redirect_stderr(io.StringIO()):
             radio_mosh.main()
             self.assertIn('MOSH_CLIENT_CAPS=keepalive-v1,link-budget-v1,radio-v1', run.call_args.args[0][-1])
             self.assertIn('--radio', execute.call_args.args[1])
-            self.assertEqual(execute.call_args.args[2]['MOSH_LINK_BUDGET'], '1')
+            self.assertEqual(execute.call_args.args[2]['GOBLIN_SKIFF_LINK_BUDGET'], '1')
             run.return_value.stdout = output.replace('MOSH RADIO single-frame-v1\n', '')
             execute.reset_mock()
             with self.assertRaisesRegex(RuntimeError, 'radio pacing support is required'):
diff --git a/Sources/GoblinModem/AppModel.swift b/Sources/GoblinModem/AppModel.swift
index 15264d6..21e7731 100644
--- a/Sources/GoblinModem/AppModel.swift
+++ b/Sources/GoblinModem/AppModel.swift
@@ -1,3 +1,4 @@
+// Modified for Goblin Skiff integration on 2026-09-19.
 import Foundation
 import SwiftUI
 import Combine
@@ -188,7 +189,7 @@ final class AppModel: ObservableObject {
             try FileManager.default.setAttributes([.posixPermissions: 0o700], ofItemAtPath: url.path)
             guard NSWorkspace.shared.open(url) else {
                 try? FileManager.default.removeItem(at: url)
-                throw HelperClient.ClientError.refused("Could not open Terminal. Use Copy Mosh command instead.")
+                throw HelperClient.ClientError.refused("Could not open Terminal. Use Copy Skiff command instead.")
             }
         }
     }
diff --git a/Sources/GoblinModem/RadioTab.swift b/Sources/GoblinModem/RadioTab.swift
index 4564e3c..b571e6c 100644
--- a/Sources/GoblinModem/RadioTab.swift
+++ b/Sources/GoblinModem/RadioTab.swift
@@ -1,3 +1,4 @@
+// Modified for Goblin Skiff integration on 2026-09-19.
 import SwiftUI
 import ModemKit
 
@@ -53,10 +54,10 @@ struct RadioTab: View {
                             if peer.nativeInterface == true {
                                 let command = peer.moshCommand(proxy: status.socks, user: sshUser, localTest: localTest)
                                 HStack {
-                                    Button(status.state == "up" ? "Open Mosh" : "Connect & open Mosh") { model.openRadioMosh(command) }
-                                    Button("Copy Mosh command") { model.copyRadioText(command) }
+                                    Button(status.state == "up" ? "Open Skiff" : "Connect & open Skiff") { model.openRadioMosh(command) }
+                                    Button("Copy Skiff command") { model.copyRadioText(command) }
                                 }.disabled(status.state == "stopping" || (!localTest && status.state != "up"))
-                                Text("Peer IP interface is available. SSH and goblin-mosh-server must be installed on \(peer.displayName).")
+                                Text("Peer IP interface is available. SSH and goblin-skiff-server must be installed on \(peer.displayName).")
                                     .font(.caption).foregroundStyle(.secondary)
                             } else {
                                 Text("Peer IP interface is not advertised. Enable it on \(peer.displayName) before connecting to its SSH/Mosh server.")
diff --git a/Sources/ModemKit/RadioProfile.swift b/Sources/ModemKit/RadioProfile.swift
index baeecfd..58cbf60 100644
--- a/Sources/ModemKit/RadioProfile.swift
+++ b/Sources/ModemKit/RadioProfile.swift
@@ -1,3 +1,4 @@
+// Modified for Goblin Skiff integration on 2026-09-19.
 import Foundation
 
 /// A radio can run alongside a PPP modem. Its Internet gateway role shares
@@ -75,8 +76,8 @@ public struct RadioPeer: Codable, Sendable {
         var ssh = "ssh -o ConnectTimeout=180"
         if let name, !name.isEmpty { ssh += " -o HostKeyAlias=" + quoted(name) }
         let destination = user.isEmpty ? meshName : user + "@" + meshName
-        let server = "/bin/sh -c 'for p in /opt/homebrew/opt/goblin-mosh/bin/goblin-mosh-server /usr/local/opt/goblin-mosh/bin/goblin-mosh-server /usr/bin/goblin-mosh-server /usr/local/bin/goblin-mosh-server; do if [ -x \"$p\" ]; then exec \"$p\" \"$@\"; fi; done; exec goblin-mosh-server \"$@\"' goblin-mosh-server"
-        return "/opt/homebrew/opt/goblin-mosh/bin/goblin-mosh --client=/opt/homebrew/opt/goblin-mosh/bin/goblin-mosh-client --socks5-proxy=" + quoted(proxy) + " --ssh=" + quoted(ssh) + " --server=" + quoted(server) + " -- " + quoted(destination)
+        let server = "/bin/sh -c 'for p in /opt/homebrew/opt/goblin-skiff/bin/goblin-skiff-server /usr/local/opt/goblin-skiff/bin/goblin-skiff-server /usr/bin/goblin-skiff-server /usr/local/bin/goblin-skiff-server; do if [ -x \"$p\" ]; then exec \"$p\" \"$@\"; fi; done; exec goblin-skiff-server \"$@\"' goblin-skiff-server"
+        return "/opt/homebrew/opt/goblin-skiff/bin/goblin-skiff --client=/opt/homebrew/opt/goblin-skiff/bin/goblin-skiff-client --socks5-proxy=" + quoted(proxy) + " --ssh=" + quoted(ssh) + " --server=" + quoted(server) + " -- " + quoted(destination)
     }
 }
 
diff --git a/html/README.md b/modem-original/goblin-modem-0.1.0-20260918.1/html/README.md
deleted file mode 100644
index b07e32b..0000000
--- a/html/README.md
+++ /dev/null
@@ -1,11 +0,0 @@
-# Goblin Modem website
-
-Static files served at https://modem.goblinreactor.com/.
-Preview: `python3 -m http.server 8080 --directory html` from the project root.
-Publish only the site files with `make site-publish`; default destination is
-`hail::distribution/modem.goblinreactor.com/`.
-
-The SSH demo is a real Ghostty capture at 80 columns by 25 rows, connecting to
-naamah and typing into Goblin Purrfect. `tools/record-session.py` records the
-session workflow. The video uses the existing network, not a radio link.
-No configuration profiles or network keys belong in this directory.
diff --git a/html/assets/goblin.png b/modem-original/goblin-modem-0.1.0-20260918.1/html/assets/goblin.png
deleted file mode 100644
index c08a138..0000000
Binary files a/html/assets/goblin.png and /dev/null differ
diff --git a/html/assets/ssh-purrfect-poster.png b/modem-original/goblin-modem-0.1.0-20260918.1/html/assets/ssh-purrfect-poster.png
deleted file mode 100644
index 7fe3138..0000000
Binary files a/html/assets/ssh-purrfect-poster.png and /dev/null differ
diff --git a/html/assets/ssh-purrfect.mp4 b/modem-original/goblin-modem-0.1.0-20260918.1/html/assets/ssh-purrfect.mp4
deleted file mode 100644
index c74fa1f..0000000
Binary files a/html/assets/ssh-purrfect.mp4 and /dev/null differ
diff --git a/html/assets/ssh-purrfect.vtt b/modem-original/goblin-modem-0.1.0-20260918.1/html/assets/ssh-purrfect.vtt
deleted file mode 100644
index d236449..0000000
--- a/html/assets/ssh-purrfect.vtt
+++ /dev/null
@@ -1,16 +0,0 @@
-WEBVTT
-
-00:00.000 --> 00:07.000
-An 80-by-25 SSH session to naamah opens Goblin Purrfect.
-
-00:07.000 --> 00:13.000
-Type a short heading: A small link. A real workspace.
-
-00:13.000 --> 00:19.000
-Alt-F9, then 6, 1, 9 opens the equation editor.
-
-00:19.000 --> 00:29.000
-Build a fraction with a plus-or-minus sign, square root, and superscript.
-
-00:29.000 --> 00:42.000
-The quadratic formula is committed to the document and saved.
diff --git a/html/demo-transcript.html b/modem-original/goblin-modem-0.1.0-20260918.1/html/demo-transcript.html
deleted file mode 100644
index cec08eb..0000000
--- a/html/demo-transcript.html
+++ /dev/null
@@ -1 +0,0 @@
-<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><meta name="theme-color" content="#f5f4ee"><meta name="description" content="Transcript of a real 80-by-25 SSH session to naamah running Goblin Purrfect and creating a quadratic formula."><meta property="og:title" content="SSH demo transcript — Goblin Modem"><meta property="og:image" content="https://modem.goblinreactor.com/assets/goblin.png"><link rel="canonical" href="https://modem.goblinreactor.com/demo-transcript.html"><link rel="icon" href="assets/goblin.png"><link rel="stylesheet" href="style.css"><title>SSH demo transcript — Goblin Modem</title></head><body><a class="skip" href="#main">Skip to content</a><header class="wrap masthead"><a class="brand" href="./">goblin modem<span>_</span></a><nav aria-label="Main navigation"><a href="index.html#connections">The project</a><a href="install.html">Install</a><a href="link.html">Make a link</a><a href="index.html#demo">Watch the demo</a></nav></header><main id="main"><section class="wrap page-heading"><p class="eyebrow">Demo / Accessible transcript</p><h1>A formula,<br><em>over a shell.</em></h1><p class="lede">A real SSH connection to naamah in an 80 × 25 Ghostty terminal. Keystrokes are scripted; the editor and graphics are live. This capture uses the existing network, not the goTenna radio.</p></section><section class="wrap section"><ol class="steps"><li>The SSH prompt reads <code>adam@naamah:demo$</code>.</li><li>Run <code>goblin-purrfect edit RADIO-MATH.WP --kitty --theme hercules</code>.</li><li>Type “A small link. A real workspace.” into the document.</li><li>Press Alt-F9, then 6, 1, 9 to open the equation editor.</li><li>Type the quadratic formula source below. Its fraction, plus-or-minus sign, superscript and square root appear in the live preview.</li><li>Press F7 to commit the equation, then Ctrl-S to save.</li></ol><div class="code-block"><button class="copy" type="button" aria-label="Copy equation source">Copy</button><pre><code>x = {-b plusminus SQRT {b^2 - 4ac}} OVER {2a}</code></pre></div><p>The result is x = (−b ± √(b² − 4ac)) / (2a).</p><p><a href="index.html#demo">Back to the video</a> · <a href="assets/ssh-purrfect.mp4">Download the MP4</a> · <a href="link.html">Set up Mosh across goTenna</a></p></section></main><footer><div class="wrap footer"><a class="brand" href="./">goblin modem<span>_</span></a><p>Small links. Useful computers.</p><div><a href="https://goblinreactor.com/">Goblin Reactor ↗</a><a href="https://brew.goblinreactor.com/sources/goblin-modem-0.1.0-20260918.1.tar.gz">Source ↗</a><a href="https://inkline.goblinreactor.com/">Inkline ↗</a></div></div></footer><p id="copy-status" class="sr-only" role="status"></p><script src="site.js" defer></script></body></html>
\ No newline at end of file
diff --git a/html/index.html b/modem-original/goblin-modem-0.1.0-20260918.1/html/index.html
deleted file mode 100644
index 1b1adca..0000000
--- a/html/index.html
+++ /dev/null
@@ -1,8 +0,0 @@
-<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><meta name="theme-color" content="#f5f4ee"><meta name="description" content="Wi-Fi, modem and goTenna radio connections. Discover mesh peers, share selected Internet uplinks, and run Goblin Mosh between Mac and Linux."><meta property="og:title" content="Goblin Modem — Small links. Useful computers."><meta property="og:image" content="https://modem.goblinreactor.com/assets/goblin.png"><link rel="canonical" href="https://modem.goblinreactor.com/"><link rel="icon" href="assets/goblin.png"><link rel="stylesheet" href="style.css"><title>Goblin Modem — Small links. Useful computers.</title></head><body><a class="skip" href="#main">Skip to content</a><header class="wrap masthead"><a class="brand" href="./">goblin modem<span>_</span></a><nav aria-label="Main navigation"><a href="index.html#connections">The project</a><a href="install.html">Install</a><a href="link.html">Make a link</a><a href="index.html#demo">Watch the demo</a></nav></header><main id="main">
-<section class="wrap hero"><div><p class="eyebrow"><span class="dot"></span> Wi-Fi · Modem · Radio</p><h1>A small link.<br><em>A real connection.</em></h1><p class="lede">Bring your computer along, even when the connection is slow. Goblin Modem gives you controls for your links, a goTenna mesh for nearby computers, and a shell that travels with you.</p><div class="actions"><a class="button" href="install.html">Install Goblin Modem ↓</a><a class="text-link" href="link.html">Connect a Mac and Linux machine ↗</a></div><p class="release">Development preview <span>/</span> macOS + Linux</p></div><figure class="mascot"><img src="assets/goblin.png" width="1254" height="1254" alt="Goblin, a fluffy black and white Silkie chicken drawn in ink" fetchpriority="high"><figcaption>A little bandwidth. A lot of possibility.</figcaption></figure></section>
-<div class="spec-strip"><div class="wrap"><span>Apple Silicon / macOS Tahoe</span><span>Debian + Ubuntu / amd64</span><span>goTenna Mesh</span><span>SOCKS5 for selected apps</span></div></div>
-<section class="wrap section" id="connections"><div class="section-heading"><p class="eyebrow">01 / Your connection, your choice</p><h2>Know the connection.<br><em>Choose what uses it.</em></h2><p class="intro">Wi-Fi is Wi-Fi. A modem is a modem. Your connection controls should not depend on which satellite service happens to be behind them.</p></div><div class="cards"><article><span class="number">01</span><h3>Wi-Fi</h3><p>Use an existing network: a hotspot, a tether, or your ordinary Wi-Fi. The Mac app can apply traffic rules to a chosen interface and gateway.</p></article><article><span class="number">02</span><h3>Modem</h3><p>Bring up a serial PPP connection on the Mac, with the port, dial string and initialization commands your modem needs. Manage it alongside your radio.</p></article><article><span class="number">03</span><h3>Radio</h3><p>Plug a goTenna Mesh radio into each computer. Mac and Linux share the radio driver, compressed IP transport, peer discovery and local SOCKS5 proxy.</p></article></div><p class="note">The Mac has a native menu bar app with Wi-Fi/network, modem and radio controls. Linux has a browser GUI and desktop launcher for radio networking; configure its Wi-Fi or modem uplink with the operating system’s usual tools.</p></section>
-<section class="tinted"><div class="wrap section mesh-layout"><div><p class="eyebrow">02 / A network without a central router</p><h2>Many radios.<br><em>A few ways out.</em></h2><p>Give the radios one shared network key and distinct identities. Computers discover names and addresses locally. There is no DHCP server to find first.</p><p>Have N radios and M Internet connections? Turn on <strong>Share Internet</strong> on those M computers. Other radios can use an advertised gateway through SOCKS5, for the applications you choose.</p><p>Sharing starts off. Gateway priority, then discovered hop count, determines the automatic choice; you can also prefer a particular gateway.</p><a class="text-link" href="link.html#gateways">Choose your Internet gateways ↗</a></div><div class="mesh-diagram" role="img" aria-label="A Mac and a Linux computer use goTenna radios to join a mesh. The Linux computer optionally shares its Wi-Fi or modem Internet connection."><div class="diagram-label">One mesh. Your choice of uplink.</div><div class="node"><span class="node-icon">⌘</span><strong>Mac</strong><small>Local SOCKS5 · wopr.mesh</small></div><div class="radio-line"><span>goTenna</span><i></i><span>goTenna</span></div><div class="node"><span class="node-icon">&gt;_</span><strong>Linux</strong><small>Local SOCKS5 · naamah.mesh</small></div><div class="uplink"><span>↑</span><strong>Optional Internet gateway</strong><small>Wi-Fi, modem, or Ethernet</small></div></div></div></section>
-<section class="wrap section" id="demo"><div class="section-heading"><p class="eyebrow">03 / A small terminal, doing real work</p><h2>A shell.<br><em>A little mathematics.</em></h2><p class="intro">An 80 × 25 terminal. An SSH session to naamah. Goblin Purrfect turns editable equation source into a live mathematical preview.</p></div><figure class="demo"><div class="terminal-bar"><span class="terminal-dots" aria-hidden="true">● ● ●</span><span>adam@naamah · SSH · 80 × 25</span><span>Goblin Purrfect</span></div><video controls playsinline preload="none" poster="assets/ssh-purrfect-poster.png" width="1044" height="604" aria-label="SSH demonstration of creating a quadratic formula in Goblin Purrfect"><source src="assets/ssh-purrfect.mp4" type="video/mp4"><track kind="captions" src="assets/ssh-purrfect.vtt" srclang="en" label="English" default>Your browser cannot play this video. <a href="assets/ssh-purrfect.mp4">Download the recording</a>.</video><figcaption>A real SSH recording over the existing network, with scripted keystrokes. It demonstrates the application and terminal graphics; it is not a radio speed test. <a href="demo-transcript.html">Read the transcript</a> · <a href="assets/ssh-purrfect.mp4" download>Download MP4</a></figcaption></figure><div class="two-col"><div><h3>What happens in the recording</h3><p>Open a document, type a heading, enter the equation editor, and build the quadratic formula. The fraction and square root update as the source is typed. Finish the equation and save the document.</p></div><div><h3>Next, put the shell on the radio.</h3><p>Our walkthrough uses normal SSH to start Mosh, then sends terminal traffic through goTenna. Begin with a small text command; graphics and file transfers need more patience on a narrow radio link.</p><a class="text-link" href="link.html#mosh">Run Mosh between the radios ↗</a></div></div></section>
-<section class="tinted"><div class="wrap section two-col"><div><p class="eyebrow">04 / Ready to try it?</p><h2>Two computers.<br><em>Two radios.</em></h2><p>Packages include the GUI, radio driver, helper tools and radio Mosh launcher. Homebrew and APT bring in the runtime dependencies.</p><div class="actions"><a class="button" href="install.html">Choose your platform ↓</a><a class="text-link" href="link.html">Follow the setup guide ↗</a></div></div><div class="status"><h3>A working preview</h3><p>Package installs are checked on Apple Silicon / macOS 26 and five Debian/Ubuntu releases. The radio path has been exercised between a Mac and Linux workstation.</p><p>goTenna is a narrow link. Discovery and startup can take time, and radio-only SSH setup remains experimental. Keep the initial test on an existing SSH connection.</p><a href="https://brew.goblinreactor.com/goblin-modem.html">Mac build records ↗</a><br><a href="https://apt.goblinreactor.com/goblin-modem.html">Linux build records ↗</a></div></div></section>
-</main><footer><div class="wrap footer"><a class="brand" href="./">goblin modem<span>_</span></a><p>Small links. Useful computers.</p><div><a href="https://goblinreactor.com/">Goblin Reactor ↗</a><a href="https://brew.goblinreactor.com/sources/goblin-modem-0.1.0-20260918.1.tar.gz">Source ↗</a><a href="https://inkline.goblinreactor.com/">Inkline ↗</a></div></div></footer><p id="copy-status" class="sr-only" role="status"></p><script src="site.js" defer></script></body></html>
\ No newline at end of file
diff --git a/html/install.html b/modem-original/goblin-modem-0.1.0-20260918.1/html/install.html
deleted file mode 100644
index 2b90bac..0000000
--- a/html/install.html
+++ /dev/null
@@ -1,48 +0,0 @@
-<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><meta name="theme-color" content="#f5f4ee"><meta name="description" content="Install the Mac menu bar app or Linux browser GUI with Homebrew and APT. Includes drivers, helper tools, Python and Goblin Mosh."><meta property="og:title" content="Install Goblin Modem — Mac and Linux"><meta property="og:image" content="https://modem.goblinreactor.com/assets/goblin.png"><link rel="canonical" href="https://modem.goblinreactor.com/install.html"><link rel="icon" href="assets/goblin.png"><link rel="stylesheet" href="style.css"><title>Install Goblin Modem — Mac and Linux</title></head><body><a class="skip" href="#main">Skip to content</a><header class="wrap masthead"><a class="brand" href="./">goblin modem<span>_</span></a><nav aria-label="Main navigation"><a href="index.html#connections">The project</a><a href="install.html">Install</a><a href="link.html">Make a link</a><a href="index.html#demo">Watch the demo</a></nav></header><main id="main"><section class="wrap page-heading"><p class="eyebrow">Install / Development preview</p><h1>Everything for<br><em>your end of the link.</em></h1><p class="lede">Install Goblin Modem on each computer attached to a radio. Then connect them with the <a href="link.html">Mac-to-Linux setup guide</a>.</p><div class="actions"><a class="button" href="#mac">Mac ↓</a><a class="button outline" href="#linux">Linux ↓</a></div></section><section class="wrap section" id="mac"><p class="eyebrow">01 / macOS</p><h2>The menu bar app.</h2><p>Apple Silicon, macOS 26 Tahoe. Start with <a href="https://brew.sh/">Homebrew</a>, then run these commands as your normal user:</p><div class="code-block"><button class="copy" type="button" aria-label="Copy commands">Copy</button><pre><code>brew tap goblinreactor/tap https://brew.goblinreactor.com/homebrew-tap.git
-brew update
-brew install --cask goblinreactor/tap/goblin-modem
-open /Applications/GoblinModem.app</code></pre></div><div class="two-col"><div><h3>What gets installed</h3><p>GoblinModem.app, the privileged launchd helper, the radio driver, the Mosh launcher and helper repair/removal tools. Homebrew installs Python 3.14 and the radio-capable Goblin Mosh package.</p></div><div><h3>First launch</h3><p>The installer asks for administrator authentication. Open the menu bar app and choose <strong>Radios &amp; addresses…</strong>. If its helper is missing, choose <strong>Install or repair helper…</strong>.</p><p class="note">This preview is ad-hoc signed; the installer is not Developer ID signed or Apple-notarized. Install through the cask so the package checksum and dependencies are checked.</p></div></div></section><section class="wrap section" id="linux"><p class="eyebrow">02 / Linux</p><h2>The browser GUI.</h2><p>amd64 on Ubuntu 22.04, 24.04 or 26.04, and Debian 12 or 13. A desktop session needs a browser and a polkit authentication agent. Add the repository once:</p><div class="code-block"><button class="copy" type="button" aria-label="Copy commands">Copy</button><pre><code>sudo apt update
-sudo apt install ca-certificates curl gnupg
-
-(
-  set -eu
-  . /etc/os-release
-  case &quot;$ID:$VERSION_CODENAME&quot; in
-    ubuntu:jammy|ubuntu:noble|ubuntu:resolute|debian:bookworm|debian:trixie) ;;
-    *) echo &quot;This OS release is not supported.&quot; &gt;&amp;2; exit 1 ;;
-  esac
-  test &quot;$(dpkg --print-architecture)&quot; = amd64 || {
-    echo &quot;Goblin Modem currently requires amd64.&quot; &gt;&amp;2; exit 1;
-  }
-  goblin_keydir=$(mktemp -d)
-  trap &#x27;rm -rf &quot;$goblin_keydir&quot;&#x27; EXIT
-  curl -fsSL https://apt.goblinreactor.com/goblinreactor-archive-keyring.gpg \
-    -o &quot;$goblin_keydir/keyring.gpg&quot;
-  goblin_fingerprint=$(gpg --batch --show-keys --with-colons \
-    &quot;$goblin_keydir/keyring.gpg&quot; | awk -F: &#x27;$1 == &quot;fpr&quot; {print $10; exit}&#x27;)
-  test &quot;$goblin_fingerprint&quot; = B7B61E8CB85A9270530364F23273CB62402FC793
-  sudo install -d -m 0755 /etc/apt/keyrings
-  sudo install -m 0644 &quot;$goblin_keydir/keyring.gpg&quot; \
-    /etc/apt/keyrings/goblinreactor.gpg
-  printf &#x27;%s\n&#x27; \
-    &#x27;Types: deb&#x27; \
-    &#x27;URIs: https://apt.goblinreactor.com/&#x27; \
-    &quot;Suites: $VERSION_CODENAME&quot; \
-    &#x27;Components: main&#x27; \
-    &#x27;Architectures: amd64&#x27; \
-    &#x27;Signed-By: /etc/apt/keyrings/goblinreactor.gpg&#x27; \
-    | sudo tee /etc/apt/sources.list.d/goblinreactor.sources &gt;/dev/null
-)
-sudo apt update
-sudo apt install goblin-modem
-goblin-modem</code></pre></div><p>If the Goblin APT repository is already configured for this OS release, use only the final three commands. Open <strong>Goblin Modem</strong> from the Applications menu, or run <code>goblin-modem</code>. Authenticate to start the controller; it opens <a href="http://127.0.0.1:8777">127.0.0.1:8777</a>.</p><p>APT installs the driver, desktop launcher, serial permissions, privileged launcher, Python, OpenSSH client/server and Goblin Mosh. Internet sharing remains off. Closing the browser leaves the controller running; use Disconnect or <code>goblin-modem --stop</code> to stop it.</p></section><section class="tinted"><div class="wrap section"><p class="eyebrow">03 / Keep it current</p><h2>Update, rebuild, or remove.</h2><div class="two-col"><div><h3>Mac</h3><div class="code-block"><button class="copy" type="button" aria-label="Copy commands">Copy</button><pre><code>brew update
-brew upgrade goblinreactor/tap/goblin-mosh
-brew upgrade --cask goblinreactor/tap/goblin-modem
-# Remove the app and helper:
-brew uninstall --cask goblinreactor/tap/goblin-modem</code></pre></div></div><div><h3>Linux</h3><div class="code-block"><button class="copy" type="button" aria-label="Copy commands">Copy</button><pre><code>sudo apt update
-sudo apt upgrade
-# Remove Goblin Modem:
-sudo apt remove goblin-modem</code></pre></div></div></div><p>The September 18 preview was rebuilt in place for the Wi-Fi / Modem labels, at the same version. If you installed the earlier build, refresh it explicitly:</p><div class="two-col"><div><div class="code-block"><button class="copy" type="button" aria-label="Copy commands">Copy</button><pre><code>brew reinstall --cask goblinreactor/tap/goblin-modem</code></pre></div></div><div><div class="code-block"><button class="copy" type="button" aria-label="Copy commands">Copy</button><pre><code>sudo apt update
-sudo apt install --reinstall goblin-modem</code></pre></div></div></div><p>User profiles and keys are retained on removal. The Mac uninstaller stops its helper and restores managed filtering. The Linux uninstaller stops package controllers.</p><h3>Build from source</h3><p><a href="https://brew.goblinreactor.com/sources/goblin-modem-0.1.0-20260918.1.tar.gz">Download the complete source archive</a>, including vendored Go dependencies. Use Go 1.26.3 or newer; Mac app builds also need current Apple Command Line Tools. The source Makefile provides:</p><div class="code-block"><button class="copy" type="button" aria-label="Copy commands">Copy</button><pre><code>make test
-make linux-deb       # Linux .deb in dist/
-make macos-pkg       # Mac .pkg in dist/; run on macOS</code></pre></div><p>Build details, checksums and dependency sources are on the <a href="https://brew.goblinreactor.com/goblin-modem.html">Homebrew</a> and <a href="https://apt.goblinreactor.com/goblin-modem.html">APT</a> package sites.</p><a class="button" href="link.html">Next: make the radio link →</a></div></section></main><footer><div class="wrap footer"><a class="brand" href="./">goblin modem<span>_</span></a><p>Small links. Useful computers.</p><div><a href="https://goblinreactor.com/">Goblin Reactor ↗</a><a href="https://brew.goblinreactor.com/sources/goblin-modem-0.1.0-20260918.1.tar.gz">Source ↗</a><a href="https://inkline.goblinreactor.com/">Inkline ↗</a></div></div></footer><p id="copy-status" class="sr-only" role="status"></p><script src="site.js" defer></script></body></html>
\ No newline at end of file
diff --git a/html/link.html b/modem-original/goblin-modem-0.1.0-20260918.1/html/link.html
deleted file mode 100644
index e6011f8..0000000
--- a/html/link.html
+++ /dev/null
@@ -1,8 +0,0 @@
-<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><meta name="theme-color" content="#f5f4ee"><meta name="description" content="A complete walkthrough: install Goblin Modem, pair mesh settings, discover addresses, choose Internet gateways, and run Mosh over goTenna."><meta property="og:title" content="A Mac, a Linux computer, two goTennas — Goblin Modem"><meta property="og:image" content="https://modem.goblinreactor.com/assets/goblin.png"><link rel="canonical" href="https://modem.goblinreactor.com/link.html"><link rel="icon" href="assets/goblin.png"><link rel="stylesheet" href="style.css"><title>A Mac, a Linux computer, two goTennas — Goblin Modem</title></head><body><a class="skip" href="#main">Skip to content</a><header class="wrap masthead"><a class="brand" href="./">goblin modem<span>_</span></a><nav aria-label="Main navigation"><a href="index.html#connections">The project</a><a href="install.html">Install</a><a href="link.html">Make a link</a><a href="index.html#demo">Watch the demo</a></nav></header><main id="main"><section class="wrap page-heading"><p class="eyebrow">Setup guide / Mac ↔ Linux</p><h1>Two radios.<br><em>One useful link.</em></h1><p class="lede">This first test connects a Mac named <code>wopr</code> to a Linux workstation named <code>naamah</code>. SSH uses your existing network to start the session. Mosh then carries the terminal traffic over goTenna.</p><p>Substitute your own hostnames and login. You need two powered-on goTenna Mesh radios, two USB data cables, both packages installed, and working SSH from the Mac to Linux.</p><nav class="guide-nav" aria-label="Guide steps"><a href="#prepare">1 Prepare</a><a href="#profiles">2 Configure</a><a href="#discover">3 Discover</a><a href="#mosh">4 Mosh</a><a href="#gateways">5 Gateways</a></nav></section>
-<section class="wrap guide-step" id="prepare"><span class="step-number">01</span><div><h2>Install both ends.<br><em>Check the ordinary SSH path.</em></h2><p>Follow the <a href="install.html">installation instructions</a> on each computer. Plug in one radio per computer. On Linux, ensure the SSH service is running:</p><div class="code-block"><button class="copy" type="button" aria-label="Copy commands">Copy</button><pre><code>sudo systemctl enable --now ssh</code></pre></div><p>From the Mac, test your existing network connection:</p><div class="code-block"><button class="copy" type="button" aria-label="Copy commands">Copy</button><pre><code>ssh adam@naamah</code></pre></div><p>Accept a host key only after checking it belongs to your workstation. If the name is not resolvable, use its LAN address or an SSH config alias. Log out before continuing. For connections in the opposite direction, enable <strong>Remote Login</strong> in the Mac’s System Settings.</p></div></section>
-<section class="wrap guide-step" id="profiles"><span class="step-number">02</span><div><h2>Give the radios<br><em>a shared network.</em></h2><p>On the Mac, open Goblin Modem → <strong>Radios &amp; addresses… → Radio</strong>. On Linux, run <code>goblin-modem</code> and choose <strong>This Linux computer</strong>.</p><div class="table-wrap"><table><thead><tr><th>Setting</th><th>Mac</th><th>Linux</th></tr></thead><tbody><tr><td>Computer name</td><td><code>wopr</code></td><td><code>naamah</code></td></tr><tr><td>Radio / serial port</td><td>Select the attached radio</td><td>Select the attached radio; Rescan if needed</td></tr><tr><td>Radio identity (GID)</td><td>Keep this radio’s unique identity</td><td>Use a different identity from the Mac</td></tr><tr><td>Shared network key</td><td colspan="2">The same 64 hexadecimal characters on both</td></tr><tr><td>Create an IP interface</td><td>On</td><td>On, so the workstation can receive Mosh</td></tr><tr><td>SOCKS5 port</td><td><code>1080</code></td><td><code>1080</code> on this computer</td></tr><tr><td>Share Internet</td><td>Off for the first local test</td><td>Off for the first local test</td></tr></tbody></table></div><p>The apps generate fresh keys, but independently generated keys will not match. Generate one for this collection and paste it into both GUIs:</p><div class="code-block"><button class="copy" type="button" aria-label="Copy commands">Copy</button><pre><code>python3 -c &#x27;import secrets; print(secrets.token_hex(32))&#x27;</code></pre></div><p>Keep this key private. Leave the discovery radius at six link traversals and leave pacing at its default. Save the settings, then Connect on each computer. Connection settings require disconnecting before edits; Internet settings can be applied while connected.</p></div></section>
-<section class="wrap guide-step" id="discover"><span class="step-number">03</span><div><h2>Find the other computer.<br><em>No address book required.</em></h2><p>Wait for <strong>Other computers</strong> to list the peer. On the Mac you should see <code>naamah.mesh</code>, its IPv4 and IPv6 addresses, and whether it has an IP interface. Linux should see <code>wopr.mesh</code>.</p><p>Addresses derive from the shared network key and radio identity. The mesh name resolves inside the local SOCKS proxy; it is not a general DNS name for the browser or your normal SSH client. Use IPv6 or the copied mesh name if the GUI reports an IPv4 collision.</p><div class="callout"><strong>No peer yet?</strong><p>Check that both radios are connected, keys match, identities differ, and the peer’s IP interface is enabled. Allow time for discovery. If USB has disappeared, Rescan after reconnecting or power-cycling the radio, then Connect again.</p></div></div></section>
-<section class="wrap guide-step" id="mosh"><span class="step-number">04</span><div><h2>Open Mosh.<br><em>Let the radio carry the shell.</em></h2><p>In the Mac peer list, set the destination SSH user to <code>adam</code>, leave <strong>SSH setup → Existing network · local radio test</strong> selected, and click <strong>Open Mosh</strong> beside naamah. The Linux GUI’s <strong>Mosh command</strong> button supplies the equivalent command for the selected computer.</p><p>For the example names, this is the Mac command with a generous five-minute startup timeout:</p><div class="code-block"><button class="copy" type="button" aria-label="Copy commands">Copy</button><pre><code>/usr/local/libexec/goblin-radio-mosh --ipv6 --connect-timeout=300 \
-  --proxy=127.0.0.1:1080 --peer=naamah.mesh -- adam@naamah</code></pre></div><p>The launcher connects the saved radio profile if needed, waits for authenticated peer discovery, starts the server through ordinary SSH, and sends Mosh UDP through the local radio proxy. Keep the existing SSH network available during setup. Type a short command:</p><div class="code-block"><button class="copy" type="button" aria-label="Copy commands">Copy</button><pre><code>printf &#x27;hello over goTenna\n&#x27;
-hostname</code></pre></div><p>Watch the radio counters and queues in both GUIs. Expect seconds of latency. Radio mode uses small packets and conservative pacing; repeatedly launching new sessions or flooding large output makes diagnosis harder. Exit the remote shell normally when finished.</p><details><summary>Connected radios, but Mosh does not open?</summary><p>Confirm that <code>ssh adam@naamah</code> still works and that both packages have the current Goblin Mosh dependency. Check the destination advertises an IP interface and that its firewall allows the Mosh UDP port on the mesh interface (normally 60000–61000). Check the GUI error and retry counters; “discarded” also includes filtering and is not a measured radio loss rate.</p><p>The separate <strong>Radio only · experimental</strong> setting also carries SSH setup through the radio. Start with the existing-network test above; the SSH handshake is expensive on this link.</p></details></div></section>
-<section class="tinted" id="gateways"><div class="wrap guide-step"><span class="step-number">05</span><div><h2>A few Internet links.<br><em>One collection of radios.</em></h2><p>For N radios with M Internet-connected computers, enable <strong>Share Internet</strong> on those M computers only. Their uplinks can be Wi-Fi, modem, or Ethernet. Keep sharing off elsewhere.</p><p>Other computers discover the gateway advertisements and select by priority, then hops, then GID. A lower priority number wins. <strong>Preferred gateway</strong> lets you choose one explicitly while it is available.</p><p>Point selected applications at their own computer’s SOCKS5 proxy. For an HTTP check through the advertised gateway:</p><div class="code-block"><button class="copy" type="button" aria-label="Copy commands">Copy</button><pre><code>curl --socks5-hostname 127.0.0.1:1080 --max-time 150 -I http://example.com</code></pre></div><p>Sharing permits access to destinations reachable by the gateway, including its LAN. Share the network key only with computers you intend to admit. Goblin Modem does not move your computer’s ordinary default route to the radio.</p><a class="text-link" href="index.html#demo">Watch a small terminal do real work ↗</a></div></div></section></main><footer><div class="wrap footer"><a class="brand" href="./">goblin modem<span>_</span></a><p>Small links. Useful computers.</p><div><a href="https://goblinreactor.com/">Goblin Reactor ↗</a><a href="https://brew.goblinreactor.com/sources/goblin-modem-0.1.0-20260918.1.tar.gz">Source ↗</a><a href="https://inkline.goblinreactor.com/">Inkline ↗</a></div></div></footer><p id="copy-status" class="sr-only" role="status"></p><script src="site.js" defer></script></body></html>
\ No newline at end of file
diff --git a/html/site.js b/modem-original/goblin-modem-0.1.0-20260918.1/html/site.js
deleted file mode 100644
index 3e5a561..0000000
--- a/html/site.js
+++ /dev/null
@@ -1 +0,0 @@
-document.querySelectorAll('.copy').forEach(button=>button.addEventListener('click',async()=>{const code=button.parentElement.querySelector('code');try{await navigator.clipboard.writeText(code.textContent);button.textContent='Copied';document.querySelector('#copy-status').textContent='Commands copied.';setTimeout(()=>button.textContent='Copy',1800)}catch{const range=document.createRange();range.selectNodeContents(code);const selection=window.getSelection();selection.removeAllRanges();selection.addRange(range);document.querySelector('#copy-status').textContent='Commands selected. Copy with your keyboard.'}}));
\ No newline at end of file
diff --git a/html/style.css b/modem-original/goblin-modem-0.1.0-20260918.1/html/style.css
deleted file mode 100644
index 3f6e6d6..0000000
--- a/html/style.css
+++ /dev/null
@@ -1,3 +0,0 @@
-
-:root{--paper:#f5f4ee;--ink:#242822;--muted:#676b60;--accent:#456544;--line:#d6d9cd;--wash:#e8ecdf;--mono:ui-monospace,"DejaVu Sans Mono",monospace;--serif:Georgia,"Times New Roman",serif;color-scheme:light}*{box-sizing:border-box}html{scroll-behavior:smooth;scroll-padding-top:24px}body{margin:0;color:var(--ink);background:var(--paper);font:16px/1.7 system-ui,-apple-system,sans-serif}a{color:inherit;text-underline-offset:5px}a:hover{color:var(--accent)}a:focus-visible,button:focus-visible,summary:focus-visible{outline:3px solid var(--accent);outline-offset:5px}img,video{max-width:100%;height:auto}.wrap{max-width:1220px;margin:auto;padding-left:38px;padding-right:38px}.masthead{min-height:112px;display:flex;justify-content:space-between;align-items:center;gap:28px}.brand{font:600 21px/1.3 var(--mono);text-decoration:none;white-space:nowrap}.brand span{color:var(--accent)}nav{display:flex;gap:26px;flex-wrap:wrap}nav a{font-size:13px;text-decoration:none}.hero{display:grid;grid-template-columns:1.12fr 1fr;align-items:center;gap:32px;padding-top:70px;padding-bottom:85px}.eyebrow{font:500 11px/1.6 var(--mono);letter-spacing:.14em;text-transform:uppercase;color:var(--accent);margin:0 0 24px}.dot{display:inline-block;width:7px;height:7px;border-radius:50%;background:var(--accent);margin-right:9px}h1,h2,h3{font-family:var(--serif);font-weight:400;letter-spacing:-.04em;line-height:1.09;margin:0 0 24px}h1{font-size:clamp(48px,5.5vw,76px)}h2{font-size:clamp(35px,4vw,53px)}h3{font-size:28px;letter-spacing:-.025em;margin-bottom:14px}em{font-weight:400;color:var(--accent)}p{margin:0 0 20px}.lede{font-size:18px;line-height:1.8;max-width:580px;color:#50574b}.actions{display:flex;align-items:center;gap:22px;flex-wrap:wrap;margin:30px 0}.button{display:inline-flex;align-items:center;justify-content:center;padding:13px 21px;background:var(--ink);color:var(--paper);border:1px solid var(--ink);text-decoration:none;border-radius:3px;font-size:13px;font-weight:600}.button:hover{background:var(--accent);color:white}.button.outline{background:transparent;color:var(--ink)}.text-link{font-size:13px;font-weight:600}.release,.note,figcaption{font-size:12px;line-height:1.7;color:var(--muted)}.release span{padding:0 12px;color:#abb19e}.mascot{margin:0;text-align:center}.mascot img{display:block;mix-blend-mode:multiply;width:100%;max-width:500px;margin:auto}.mascot figcaption{font-family:var(--serif);font-style:italic;font-size:15px;margin-top:-12px}.spec-strip{border-block:1px solid var(--line)}.spec-strip>.wrap{display:flex;justify-content:space-between;gap:20px;flex-wrap:wrap;padding-block:21px;font:11px var(--mono);color:var(--muted)}.section{padding-top:96px;padding-bottom:96px}.section-heading{max-width:720px;margin-bottom:45px}.intro{font-size:17px;color:#59604f;max-width:680px}.cards{display:grid;grid-template-columns:repeat(3,1fr);gap:38px}.cards article{border-top:1px solid var(--line);padding-top:28px}.number{font:11px var(--mono);color:var(--accent);display:block;margin-bottom:24px}.cards p{font-size:14px;color:#565e4e}.note{max-width:850px;margin-top:22px}.tinted{background:var(--wash)}.mesh-layout,.two-col{display:grid;grid-template-columns:1fr 1fr;gap:80px;align-items:start}.mesh-layout>div>p,.two-col p{max-width:520px}.mesh-diagram{padding:30px;border:1px solid #b9c4af;border-radius:5px;background:#f5f6ef;display:grid;grid-template-columns:1fr 1fr;gap:20px;text-align:center}.diagram-label{grid-column:1/-1;font:10px var(--mono);color:var(--muted);padding-bottom:10px}.node{display:flex;flex-direction:column;align-items:center;gap:5px}.node-icon{font:22px var(--mono);border:1px solid var(--line);border-radius:8px;padding:12px 16px;margin-bottom:5px}.node strong,.uplink strong{font-size:13px}.node small,.uplink small{font:10px/1.6 var(--mono);color:var(--muted)}.radio-line{grid-column:1/-1;grid-row:3;display:flex;align-items:center;gap:15px;font:11px var(--mono);color:var(--accent)}.radio-line i{flex:1;border-bottom:2px dotted #93a685}.uplink{grid-column:1/-1;display:flex;flex-direction:column;gap:6px;border-top:1px solid var(--line);padding-top:15px}.uplink>span{font:30px var(--mono);color:var(--accent)}.demo{margin:0 0 35px;border:1px solid #30382c;border-radius:9px;overflow:hidden;background:#101b26}.terminal-bar{color:#c8d0c2;display:flex;justify-content:space-between;gap:10px;padding:14px 20px;font:10px var(--mono);background:#242d25}.terminal-dots{color:#849a79;letter-spacing:3px}.demo video{display:block;width:100%}.demo figcaption{padding:17px 22px;background:var(--paper)}.two-col{margin-top:35px}.status{border-top:1px solid #b8c2ad;padding-top:25px}.status p{font-size:14px}.status a{font-size:12px}.page-heading{padding-top:70px;padding-bottom:50px;max-width:1220px}.page-heading .lede{max-width:740px}.code-block{position:relative;margin:25px 0;border:1px solid var(--line);background:#eeeee6;border-radius:4px;min-width:0}.copy{position:absolute;right:12px;top:10px;border:1px solid #c1c8b7;border-radius:3px;padding:5px 9px;font:10px var(--mono);cursor:pointer;background:var(--paper);color:var(--accent)}pre{margin:0;padding:46px 22px 24px;overflow:auto;font:12px/1.9 var(--mono);tab-size:2}code{font-family:var(--mono);font-size:.86em;overflow-wrap:anywhere}pre code{font-size:inherit;overflow-wrap:normal}.guide-nav{margin-top:34px;border-top:1px solid var(--line);padding-top:22px;gap:24px}.guide-step{display:grid;grid-template-columns:90px minmax(0,1fr);padding-top:65px;padding-bottom:65px;border-top:1px solid var(--line);gap:20px}.guide-step>div{max-width:930px}.step-number{font:14px var(--mono);color:var(--accent);padding-top:8px}.guide-step h2{font-size:42px}.guide-step p{max-width:810px}.table-wrap{overflow:auto;margin:30px 0}table{border-collapse:collapse;width:100%;font-size:13px;min-width:580px}th,td{padding:15px;text-align:left;border-bottom:1px solid var(--line);vertical-align:top}th{font:11px var(--mono);color:var(--accent)}.callout{padding:24px;border-left:3px solid var(--accent);background:var(--wash);margin:26px 0}.callout p{margin:10px 0 0}details{padding:22px 0;border-top:1px solid var(--line)}summary{cursor:pointer;font-weight:600;margin-bottom:18px}.steps li{padding-bottom:15px}.footer{display:flex;justify-content:space-between;align-items:center;gap:25px;padding-block:40px}.footer p{margin:0;font-family:var(--serif);font-style:italic;color:var(--muted)}.footer>div{display:flex;gap:18px;font-size:11px}footer{border-top:1px solid var(--line)}.skip{position:absolute;left:10px;top:-100px;z-index:2;background:var(--paper);padding:12px}.skip:focus{top:10px}.sr-only{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%)}@media(max-width:900px){.masthead{flex-direction:column;align-items:flex-start;padding-top:27px;padding-bottom:22px;gap:20px}.hero{padding-top:45px;gap:12px}.hero h1{font-size:52px}.lede{font-size:16px}.mesh-layout,.two-col{gap:35px}.footer{flex-wrap:wrap}.guide-step{grid-template-columns:45px minmax(0,1fr)}}@media(max-width:650px){.wrap{padding-left:23px;padding-right:23px}.masthead nav{gap:18px}.hero{grid-template-columns:1fr;padding-bottom:50px}.hero h1{font-size:53px}.mascot{max-width:340px;margin:10px auto 0}.hero .actions{align-items:flex-start;flex-direction:column}.spec-strip>.wrap{font-size:10px;gap:15px}.section{padding-block:58px}.cards,.mesh-layout,.two-col{grid-template-columns:1fr;gap:32px}.cards article{padding-top:22px}.section-heading{margin-bottom:30px}.page-heading{padding-top:38px}.guide-step{display:block;padding-block:45px}.step-number{display:block;margin-bottom:18px}.guide-step h2{font-size:36px}.terminal-bar{font-size:8px;padding:12px}.terminal-bar>span:last-child{display:none}.footer{display:block}.footer>p{margin:20px 0}.footer>div{flex-wrap:wrap}.copy{top:8px}pre{font-size:11px;padding-inline:14px}}@media(prefers-reduced-motion:reduce){html{scroll-behavior:auto}}
-.hero>div,.two-col>div,.mesh-layout>div,.cards>article{min-width:0}
diff --git a/html/tools/check-site.py b/modem-original/goblin-modem-0.1.0-20260918.1/html/tools/check-site.py
deleted file mode 100644
index 4b202bb..0000000
--- a/html/tools/check-site.py
+++ /dev/null
@@ -1,26 +0,0 @@
-#!/usr/bin/env python3
-"""Check static pages, local assets, fragments and video before publication."""
-from html.parser import HTMLParser
-from pathlib import Path
-from urllib.parse import urlsplit, unquote
-root=Path(__file__).resolve().parents[1]
-class Page(HTMLParser):
- def __init__(self,p):super().__init__();self.path=p;self.links=[];self.ids=set();self.feed(p.read_text())
- def handle_starttag(self,tag,attrs):
-  attrs=dict(attrs)
-  if 'id' in attrs:self.ids.add(attrs['id'])
-  for a in ('href','src','poster'):
-   if attrs.get(a):self.links.append(attrs[a])
-  if tag=='img':assert attrs.get('alt'),self.path
-pages={p:Page(p) for p in root.glob('*.html')}
-for p,page in pages.items():
- for url in page.links:
-  u=urlsplit(url)
-  if u.scheme or u.netloc:continue
-  target=(p.parent/unquote(u.path)).resolve() if u.path else p
-  if target.is_dir():target=target/'index.html'
-  assert target.is_relative_to(root) and target.exists(),(p.name,url)
-  if u.fragment and target in pages:assert u.fragment in pages[target].ids,(p.name,url)
-assert (root/'assets/ssh-purrfect.mp4').stat().st_size>100_000
-assert (root/'assets/ssh-purrfect.vtt').read_text().startswith('WEBVTT')
-print('PASS: four pages, local links/fragments, mascot, video, captions and transcript')
diff --git a/html/tools/modem.nginx.conf b/modem-original/goblin-modem-0.1.0-20260918.1/html/tools/modem.nginx.conf
deleted file mode 100644
index 39f90b3..0000000
--- a/html/tools/modem.nginx.conf
+++ /dev/null
@@ -1,24 +0,0 @@
-server {
-    listen 80;
-    listen [::]:80;
-    server_name modem.goblinreactor.com;
-
-    add_header X-Content-Type-Options "nosniff" always;
-    add_header X-Frame-Options "DENY" always;
-    add_header Referrer-Policy "strict-origin-when-cross-origin" always;
-    add_header Cache-Control "no-cache" always;
-    add_header Cloudflare-CDN-Cache-Control "no-store" always;
-
-    location / {
-        proxy_pass http://192.168.1.11:8888/modem.goblinreactor.com/;
-        proxy_http_version 1.1;
-        proxy_set_header Connection "";
-        proxy_set_header Host $host;
-        proxy_set_header X-Real-IP $remote_addr;
-        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
-        proxy_set_header X-Forwarded-Proto $scheme;
-        proxy_connect_timeout 5s;
-        proxy_send_timeout 120s;
-        proxy_read_timeout 120s;
-    }
-}
diff --git a/html/tools/record-session.py b/modem-original/goblin-modem-0.1.0-20260918.1/html/tools/record-session.py
deleted file mode 100644
index ba65aa0..0000000
--- a/html/tools/record-session.py
+++ /dev/null
@@ -1,44 +0,0 @@
-#!/usr/bin/env python3
-"""Record real SSH I/O in a private 80x25 Ghostty terminal; no synthetic frames."""
-import fcntl,os,pty,select,signal,struct,subprocess,sys,termios,time,tty
-root='/tmp/goblin-modem-video-20260918'
-subprocess.run(['ssh','-o','BatchMode=yes','naamah','mkdir -p '+root],check=True)
-master,slave=pty.openpty()
-fcntl.ioctl(slave,termios.TIOCSWINSZ,struct.pack('HHHH',25,80,1040,600))
-command=['ssh','-tt','-o','BatchMode=yes','naamah',"cd "+root+" && env TERM=xterm-kitty LC_ALL=C.UTF-8 PATH=/home/adam/.local/bin:/usr/local/bin:/usr/bin:/bin PS1='adam@naamah:demo$ ' /bin/bash --noprofile --norc -i"]
-process=subprocess.Popen(command,stdin=slave,stdout=slave,stderr=slave,start_new_session=True);os.close(slave)
-original=termios.tcgetattr(0);tty.setraw(0)
-# Human-readable typing with full terminal responses forwarded to the SSH PTY.
-events=[]
-def type_at(t,text,delay=.065):
- for i,c in enumerate(text):events.append((t+i*delay,c.encode()))
- return t+len(text)*delay
-end=type_at(2,'goblin-purrfect edit RADIO-MATH.WP --kitty --theme hercules');events.append((end+.4,b'\r'))
-t=end+3
-end=type_at(t,'A small link. A real workspace.',.08);events.append((end+.4,b'\r\r'))
-events.extend([(end+2,b'\x1b[20;3~'),(end+2.8,b'6'),(end+3.5,b'1'),(end+4.2,b'9')])
-formula='x = {-b plusminus SQRT {b^2 - 4ac}} OVER {2a}'
-end=type_at(end+6,formula,.13)
-events.extend([(end+7,b'\x1b[18~'),(end+9,b'\x13')])
-finish=end+15
-start=time.monotonic();n=0
-log=open('/tmp/goblin-site-tools/ssh-demo.tty','wb')
-try:
- while time.monotonic()-start<finish and process.poll() is None:
-  elapsed=time.monotonic()-start
-  while n<len(events) and events[n][0]<=elapsed:
-   os.write(master,events[n][1]);n+=1
-  ready,_,_=select.select([master,0],[],[],.02)
-  if master in ready:
-   try:data=os.read(master,262144)
-   except OSError:break
-   log.write(data);os.write(1,data)
-  if 0 in ready:
-   data=os.read(0,65536)
-   if data:os.write(master,data)
-finally:
- log.close();termios.tcsetattr(0,termios.TCSANOW,original)
- open('/tmp/goblin-site-tools/demo-duration.txt','w').write(str(finish))
- # Keep the final frame visible for the recorder; SSH exits only after capture.
- time.sleep(8)
- process.terminate();os.close(master)
diff --git a/packaging/README.md b/packaging/README.md
index 9730f02..929b578 100644
--- a/packaging/README.md
+++ b/packaging/README.md
@@ -1,15 +1,16 @@
+<!-- Modified for Goblin Skiff integration on 2026-09-19. -->
 # Goblin Modem distribution packages
 
 The Mac package includes the menu bar app, privileged launchd helper, radio
 IP/SOCKS driver, helper repair/removal tools, and radio Mosh launcher. Its
-Homebrew cask installs Python 3.14 and the radio-capable Goblin Mosh package.
+Homebrew cask installs Python 3.14 and the radio-capable Goblin Skiff package.
 The initial binary target is Apple Silicon on macOS 26 Tahoe. The app is
 ad-hoc signed; the installer is not Developer ID signed or notarized.
 Use the Homebrew cask to install the package and its dependencies.
 
 The Linux package includes the browser GUI, desktop entry, radio IP/SOCKS
 driver, udev permissions, polkit launcher and radio Mosh launcher. APT installs
-Python, OpenSSH client/server, Goblin Mosh, systemd and polkit dependencies.
+Python, OpenSSH client/server, Goblin Skiff, systemd and polkit dependencies.
 The first binary target is amd64 on Ubuntu 22.04/24.04/26.04 and Debian 12/13.
 The Linux GUI needs a graphical login with a browser and a polkit agent.
 On a headless machine use `goblin-radio` directly or forward the loopback GUI
@@ -32,14 +33,14 @@ The Mac runtime dependencies are installed with:
 
 ```
 brew tap goblinreactor/tap https://brew.goblinreactor.com/homebrew-tap.git
-brew install goblinreactor/tap/goblin-mosh python@3.14
+brew install goblinreactor/tap/goblin-skiff python@3.14
 ```
 
-For reproducible Linux Mosh dependencies, build the matching Goblin Mosh
+For reproducible Linux Mosh dependencies, build the matching Goblin Skiff
 source with its `packaging/debian/build-release.sh` inside each target
 suite's native build environment. Its source and binary packages are published
 alongside Goblin Modem, with the same archive signature. Goblin Modem requires
-Goblin Mosh 1.4.0+goblin20260918.1 or newer.
+Goblin Skiff 1.4.0+goblin20260919.1 or newer.
 
 ## Install and use
 
@@ -64,8 +65,8 @@ On both computers choose the USB radio, share a freshly generated network key
 between your devices, and enable the peer IP interface if this computer should
 receive Mosh connections. Internet sharing defaults off; enable it only on
 computers that should advertise themselves as Internet gateways. Save and
-Connect. Wait for the other computer in the peer list, then choose **Open Mosh**
-(Mac) or **Mosh command** (Linux). The default test uses management SSH to start
+Connect. Wait for the other computer in the peer list, then choose **Open Skiff**
+(Mac) or **Skiff command** (Linux). The default test uses management SSH to start
 the session and sends terminal traffic over the radio. Enable macOS Remote
 Login in System Settings if it must accept incoming SSH setup connections.
 
@@ -76,7 +77,7 @@ a source checkout. A missing Mac helper can be repaired from the app menu.
 ## Upgrade and remove
 
 ```
-brew upgrade goblinreactor/tap/goblin-mosh
+brew upgrade goblinreactor/tap/goblin-skiff
 brew upgrade --cask goblinreactor/tap/goblin-modem
 brew uninstall --cask goblinreactor/tap/goblin-modem
 
diff --git a/packaging/debian/build.sh b/packaging/debian/build.sh
index 1b53453..43ed20f 100755
--- a/packaging/debian/build.sh
+++ b/packaging/debian/build.sh
@@ -1,8 +1,9 @@
 #!/bin/bash
+# Modified for Goblin Skiff integration on 2026-09-19.
 set -euo pipefail
 umask 022
 cd "$(dirname "$0")/../.."
-version=${VERSION:-0.1.0+20260918.1}
+version=${VERSION:-0.1.0+20260919.1}
 arch=${ARCH:-amd64}
 case $arch in amd64|arm64) ;; *) echo 'ARCH must be amd64 or arm64' >&2; exit 2;; esac
 out=${OUTPUT:-$PWD/dist}
@@ -35,7 +36,7 @@ Section: net
 Priority: optional
 Architecture: $arch
 Maintainer: Adam DePrince <adam.deprince@gmail.com>
-Depends: goblin-mosh (>= 1.4.0+goblin20260918.1), python3 (>= 3.9), openssh-client, openssh-server, systemd, udev, util-linux, xdg-utils, pkexec | policykit-1, polkitd | policykit-1
+Depends: goblin-skiff (>= 1.4.0+goblin20260919.1), python3 (>= 3.9), openssh-client, openssh-server, systemd, udev, util-linux, xdg-utils, pkexec | policykit-1, polkitd | policykit-1
 Recommends: firefox | firefox-esr | chromium, polkit-kde-agent-1 | policykit-1-gnome
 Homepage: https://apt.goblinreactor.com/goblin-modem.html
 Description: goTenna radio IP, SOCKS proxy and graphical controls
diff --git a/packaging/homebrew/goblin-modem.rb b/packaging/homebrew/goblin-modem.rb
index da5387d..bcda19d 100644
--- a/packaging/homebrew/goblin-modem.rb
+++ b/packaging/homebrew/goblin-modem.rb
@@ -1,15 +1,16 @@
+# Modified for Goblin Skiff integration on 2026-09-19.
 cask "goblin-modem" do
-  version "0.1.0.20260918.1"
-  sha256 "d33179d5bf382e7b63d689d9bc5e909587634ab393c45da5c1b5c1d05b671b8d"
+  version "0.1.0.20260919.1"
+  sha256 "b3989f26135091eb45a7a6fd336d480107e06089202a35a94f072e479ce61772"
 
   url "https://brew.goblinreactor.com/releases/goblin-modem-#{version}/goblin-modem-#{version}-arm64.pkg"
   name "Goblin Modem"
-  desc "Modem and goTenna radio controls, mesh discovery, SOCKS5 and radio Mosh"
+  desc "Modem and goTenna radio controls, mesh discovery, SOCKS5 and radio Skiff"
   homepage "https://brew.goblinreactor.com/goblin-modem.html"
 
   depends_on arch: :arm64
   depends_on macos: :tahoe
-  depends_on formula: "goblinreactor/tap/goblin-mosh"
+  depends_on formula: "goblinreactor/tap/goblin-skiff"
   depends_on formula: "python@3.14"
 
   pkg "goblin-modem-#{version}-arm64.pkg"
diff --git a/packaging/homebrew/goblin-mosh.rb b/modem-original/goblin-modem-0.1.0-20260918.1/packaging/homebrew/goblin-mosh.rb
deleted file mode 100644
index 38688bb..0000000
--- a/packaging/homebrew/goblin-mosh.rb
+++ /dev/null
@@ -1,136 +0,0 @@
-class GoblinMosh < Formula
-  desc "Mobile shell and file transfers optimized for low-bandwidth links"
-  homepage "https://mosh.goblinreactor.com/"
-  url "https://brew.goblinreactor.com/sources/goblin-mosh-1.4.0-goblin20260918.1.tar.gz"
-  version "1.4.0-goblin20260918.1"
-  sha256 "f065136b4c71b546874cd3f0e4b5fb6f1e6979b2c8946bfc0b378f6fe44161a4"
-  license all_of: ["GPL-3.0-or-later", "ISC"]
-
-  bottle do
-    root_url "https://brew.goblinreactor.com/bottles"
-    sha256 arm64_tahoe: "0f6423e600890fc6f3b9e9423d0d6d7f71d34033c79dbaf927f987b02d92b43e"
-  end
-
-  # The archive is a reviewed release snapshot, not the moving source branch.
-  livecheck do
-    skip "Release snapshots are published by the Goblin Reactor maintainer"
-  end
-
-  depends_on "autoconf" => :build
-  depends_on "automake" => :build
-  depends_on "pkgconf" => :build
-  depends_on "python@3.14" => :test
-  depends_on "abseil"
-  depends_on "djvulibre"
-  depends_on "libpng"
-  depends_on "librsync"
-  depends_on :macos
-  depends_on "ncurses"
-  depends_on "openssl@3"
-  depends_on "protobuf"
-  depends_on "webp"
-  depends_on "zstd"
-
-  # Core tests open Unix sockets; the installed test also uses loopback UDP.
-  # Homebrew counts both as network access. No test contacts an external host.
-  allow_network_access! [:build, :test]
-
-  # Homebrew 7 allows Unix sockets only inside its temporary directory.
-  patch :DATA
-
-  def install
-    system "autoreconf", "-fi"
-    system "./configure", *std_configure_args,
-           "--docdir=#{doc}",
-           "--disable-completion", "--disable-ufw", "--without-utempter",
-           "--with-crypto-library=apple-common-crypto",
-           "--with-zstd", "--with-librsync", "--with-fips-crypto",
-           "--without-libraptorq", "--enable-compile-warnings=yes"
-    system "make"
-    system "sh", "packaging/check-prebuilt-fec.sh", "./src/moshcp/goblin-moshcp"
-    # Keep Unix socket paths short on macOS and never share a live session's
-    # runtime directory. Tests use local Unix sockets and loopback UDP.
-    Dir.mktmpdir("gc-", ENV.fetch("TMPDIR", "/tmp")) do |runtime|
-      ENV["XDG_RUNTIME_DIR"] = runtime
-      tests = %w[
-        ocb-aes encrypt-decrypt fips-crypto base64 nonce-incr fec-codecs
-        bulk-datagram moshcp-protocol bulk-loss-sim transport-compression session-version
-        state-samples osc52-parse kitty-graphics terminal-geometry
-        terminal-display tmux-control control-panel mascot file-transfer
-        link-budget sixel-state terminal-extensions download download-forward
-        udp-relay udp-jump-wrapper.test
-      ]
-      system "make", "check", "TESTS=#{tests.join(" ")}"
-    end
-    system "make", "install"
-    bash_completion.install "conf/bash-completion/completions/goblin-mosh"
-    doc.install "README.md", "GOBLIN_DOWNLOAD_PROTOCOL.md", "SIXEL_STATE.md",
-                "AUDIO.md", "UDP_RELAY.md", "debian/copyright"
-    (pkgshare/"tests").install "src/tests/control-panel-integration.py"
-    (pkgshare/"tests").install "packaging/check-prebuilt-fec.sh"
-    (pkgshare/"verification").install "src/tests/test-suite.log"
-  end
-
-  def caveats
-    <<~EOS
-      Install goblin-mosh on both endpoints, then run:
-        goblin-mosh user@server
-      For UDP jump relays, install this release on each jump host too:
-        goblin-mosh -J user@jump user@server
-      Open the file/control menu with Ctrl-^ (usually Ctrl-Shift-6), then 0.
-      This package does not replace stock mosh or a manual /usr/local install.
-      Existing sessions keep running; open a new session after an upgrade.
-      --fips-crypto requires a configured FIPS provider; this is not a FIPS
-      certification. Source, licenses and setup: https://brew.goblinreactor.com/
-    EOS
-  end
-
-  test do
-    system "sh", pkgshare/"tests/check-prebuilt-fec.sh", bin/"goblin-moshcp"
-    assert_match "goblin-mosh-client", shell_output("#{bin}/goblin-mosh-client --version 2>&1")
-    assert_match "goblin-mosh-server", shell_output("#{bin}/goblin-mosh-server --version 2>&1")
-    assert_path_exists man1/"goblin-mosh.1"
-    ENV["GOBLIN_TEST_CLIENT"] = bin/"goblin-mosh-client"
-    ENV["GOBLIN_TEST_SERVER"] = bin/"goblin-mosh-server"
-    system formula_opt_bin("python@3.14")/"python3.14",
-           pkgshare/"tests/control-panel-integration.py", "--files"
-    # Four independently authenticated hops add substantial overhead at the
-    # simulated lossy link's conservative startup rate. Keep all loss, input
-    # responsiveness and integrity assertions; allow longer file completion.
-    # Copy the fixture so testing never modifies files in the installed keg.
-    relay_test = testpath/"relay-integration.py"
-    cp pkgshare/"tests/control-panel-integration.py", relay_test
-    inreplace relay_test, "(300 if speed else 60)", "(300 if speed or udp_hops else 60)"
-    system formula_opt_bin("python@3.14")/"python3.14", relay_test, "--udp-relay"
-  end
-end
-
-__END__
---- a/src/tests/bulk-datagram.cc
-+++ b/src/tests/bulk-datagram.cc
-@@ -36,11 +36,11 @@
- void backpressure_test()
- {
-   struct Runtime {
--    char path[40] = "/tmp/goblin-bulk-queue.XXXXXX";
-+    std::string path = std::string( getenv( "TMPDIR" ) ? getenv( "TMPDIR" ) : "/tmp" ) + "/gbq.XXXXXX";
-     bool existed = getenv( "XDG_RUNTIME_DIR" );
-     std::string previous = existed ? getenv( "XDG_RUNTIME_DIR" ) : "";
--    Runtime() { require( mkdtemp( path ), "queue-test runtime directory" ); setenv( "XDG_RUNTIME_DIR", path, 1 ); }
--    ~Runtime() { if ( existed ) { setenv( "XDG_RUNTIME_DIR", previous.c_str(), 1 ); } else { unsetenv( "XDG_RUNTIME_DIR" ); } rmdir( path ); }
-+    Runtime() { require( mkdtemp( &path[0] ), "queue-test runtime directory" ); setenv( "XDG_RUNTIME_DIR", path.c_str(), 1 ); }
-+    ~Runtime() { if ( existed ) { setenv( "XDG_RUNTIME_DIR", previous.c_str(), 1 ); } else { unsetenv( "XDG_RUNTIME_DIR" ); } rmdir( path.c_str() ); }
-   } runtime;
-   Network::Bulk::ControlServer server( "test" );
-   Network::Bulk::ControlClient client( server.socket_path() );
---- a/src/tests/control-panel-integration.py
-+++ b/src/tests/control-panel-integration.py
-@@ -99,7 +99,7 @@
-     client = os.environ.get("GOBLIN_TEST_CLIENT", str((build / "../frontend/goblin-mosh-client").resolve()))
-     server = os.environ.get("GOBLIN_TEST_SERVER", str((build / "../frontend/goblin-mosh-server").resolve()))
-     # Keep session socket paths below sockaddr_un.sun_path on macOS too.
--    with tempfile.TemporaryDirectory(prefix="goblin-panel-", dir="/tmp") as root:
-+    with tempfile.TemporaryDirectory(prefix="gp-", dir=os.environ.get("TMPDIR", "/tmp")) as root:
-         directory = Path(root)
-         runtime = directory / "runtime"
-         runtime.mkdir(mode=0o700)
diff --git a/modem-review/goblin-modem-0.1.0-20260919.1/packaging/homebrew/goblin-skiff.rb b/packaging/homebrew/goblin-skiff.rb
new file mode 100644
index 0000000..47d654a
--- /dev/null
+++ b/packaging/homebrew/goblin-skiff.rb
@@ -0,0 +1,93 @@
+# Modified for Goblin Skiff on 2026-09-19.
+class GoblinSkiff < Formula
+  desc "Fork of Mosh optimized for bandwidth-constrained links"
+  homepage "https://skiff.goblinreactor.com/"
+  url "https://brew.goblinreactor.com/sources/goblin-skiff-1.4.0-goblin20260919.2.tar.gz"
+  version "1.4.0-goblin20260919.2"
+  sha256 "b3db69c56ad12c1ac672aba0c171732658a4841b42e5de232e3f2c6f850c5924"
+  license all_of: ["GPL-3.0-or-later", "ISC"]
+
+  # The archive is a reviewed release snapshot, not the moving source branch.
+  livecheck do
+    skip "Release snapshots are published by the Goblin Reactor maintainer"
+  end
+
+  depends_on "autoconf" => :build
+  depends_on "automake" => :build
+  depends_on "pkgconf" => :build
+  depends_on "python@3.14" => :test
+  depends_on "abseil"
+  depends_on "djvulibre"
+  depends_on "libpng"
+  depends_on "librsync"
+  depends_on :macos
+  depends_on "ncurses"
+  depends_on "openssl@3"
+  depends_on "protobuf"
+  depends_on "webp"
+  depends_on "zstd"
+
+  # Core tests open Unix sockets; the installed test also uses loopback UDP.
+  # Homebrew counts both as network access. No test contacts an external host.
+  allow_network_access! [:build, :test]
+
+  def install
+    system "autoreconf", "-fi"
+    system "./configure", *std_configure_args,
+           "--docdir=#{doc}",
+           "--disable-completion", "--disable-ufw", "--without-utempter",
+           "--with-crypto-library=apple-common-crypto",
+           "--with-zstd", "--with-librsync", "--with-fips-crypto",
+           "--without-libraptorq", "--enable-compile-warnings=yes"
+    system "make"
+    system "sh", "packaging/check-prebuilt-fec.sh", "./src/moshcp/goblin-skiffcp"
+    # Keep Unix socket paths short on macOS and never share a live session's
+    # runtime directory. Tests use local Unix sockets and loopback UDP.
+    Dir.mktmpdir("gc-", ENV.fetch("TMPDIR", "/tmp")) do |runtime|
+      ENV["XDG_RUNTIME_DIR"] = runtime
+      tests = %w[
+        ocb-aes encrypt-decrypt fips-crypto base64 nonce-incr fec-codecs
+        bulk-datagram skiffcp-protocol bulk-loss-sim transport-compression session-version
+        state-samples osc52-parse kitty-graphics terminal-geometry
+        terminal-display tmux-control control-panel mascot file-transfer
+        link-budget sixel-state terminal-extensions download download-forward
+        udp-relay udp-jump-wrapper.test connect-timeout.test
+      ]
+      system "make", "check", "TESTS=#{tests.join(" ")}"
+    end
+    system "make", "install"
+    bash_completion.install "conf/bash-completion/completions/goblin-skiff"
+    doc.install "README.md", "GOBLIN_DOWNLOAD_PROTOCOL.md", "SIXEL_STATE.md",
+                "AUDIO.md", "UDP_RELAY.md", "debian/copyright"
+    (pkgshare/"tests").install "src/tests/control-panel-integration.py"
+    (pkgshare/"tests").install "packaging/check-prebuilt-fec.sh"
+    (pkgshare/"verification").install "src/tests/test-suite.log"
+  end
+
+  def caveats
+    <<~EOS
+      Install goblin-skiff on both endpoints, then run:
+        goblin-skiff user@server
+      For UDP jump relays, install this release on each jump host too:
+        goblin-skiff -J user@jump user@server
+      Open the file/control menu with Ctrl-^ (usually Ctrl-Shift-6), then 0.
+      This package does not replace stock mosh or a manual /usr/local install.
+      Existing sessions keep running; open a new session after an upgrade.
+      --fips-crypto requires a configured FIPS provider; this is not a FIPS
+      certification. Source, licenses and setup: https://brew.goblinreactor.com/
+    EOS
+  end
+
+  test do
+    system "sh", pkgshare/"tests/check-prebuilt-fec.sh", bin/"goblin-skiffcp"
+    assert_match "goblin-skiff-client", shell_output("#{bin}/goblin-skiff-client --version 2>&1")
+    assert_match "goblin-skiff-server", shell_output("#{bin}/goblin-skiff-server --version 2>&1")
+    assert_path_exists man1/"goblin-skiff.1"
+    ENV["GOBLIN_SKIFF_TEST_CLIENT"] = bin/"goblin-skiff-client"
+    ENV["GOBLIN_SKIFF_TEST_SERVER"] = bin/"goblin-skiff-server"
+    system formula_opt_bin("python@3.14")/"python3.14",
+           pkgshare/"tests/control-panel-integration.py", "--files"
+    system formula_opt_bin("python@3.14")/"python3.14",
+           pkgshare/"tests/control-panel-integration.py", "--udp-relay"
+  end
+end
diff --git a/packaging/macos/build.sh b/packaging/macos/build.sh
index 19c0142..d916999 100755
--- a/packaging/macos/build.sh
+++ b/packaging/macos/build.sh
@@ -1,8 +1,9 @@
 #!/bin/bash
+# Modified for Goblin Skiff integration on 2026-09-19.
 set -euo pipefail
 cd "$(dirname "$0")/../.."
 [[ $(uname -s) == Darwin ]] || { echo 'Build the macOS package on macOS.' >&2; exit 1; }
-version=${VERSION:-0.1.0.20260918.1}
+version=${VERSION:-0.1.0.20260919.1}
 out=${OUTPUT:-$PWD/dist}
 mkdir -p "$out"
 out=$(cd "$out" && pwd)
diff --git a/packaging/macos/preinstall b/packaging/macos/preinstall
index b107284..09aaefd 100644
--- a/packaging/macos/preinstall
+++ b/packaging/macos/preinstall
@@ -1,9 +1,10 @@
 #!/bin/bash
+# Modified for Goblin Skiff integration on 2026-09-19.
 set -euo pipefail
 # Cask dependencies must be present before modifying the application/helper.
 test -x /opt/homebrew/opt/python@3.14/bin/python3.14 || { echo 'Install python@3.14 with Homebrew first.' >&2; exit 1; }
-radio_help=$(/opt/homebrew/opt/goblin-mosh/bin/goblin-mosh-client 2>&1 || true)
+radio_help=$(/opt/homebrew/opt/goblin-skiff/bin/goblin-skiff-client 2>&1 || true)
 if ! grep -q -- '--radio uses negotiated' <<< "$radio_help"; then
-    echo 'Install or upgrade goblinreactor/tap/goblin-mosh before Goblin Modem.' >&2
+    echo 'Install or upgrade goblinreactor/tap/goblin-skiff before Goblin Modem.' >&2
     exit 1
 fi
