feat(gateway): robust Smithers Gateway manager + Tailscale exposure - #60
Merged
Conversation
Add scripts/smithers-gateway.sh — an idempotent manager for the Smithers
workspace Gateway that publishes it to a tailnet for token-free browser
access — plus a `gateway` config block in rig.schema.json and the example.
Why: the Gateway's token auth is Authorization-header only, so a token-gated
UI is unreachable from a browser (no query-param / cookie / Basic fallback).
The manager runs the Gateway on loopback (no token needed) and publishes it
over HTTPS via `tailscale serve`, making Tailscale device identity the auth
boundary while the Gateway stays unauthenticated on 127.0.0.1. It exports
SMITHERS_GATEWAY_TRUST_ANY_HOST=1 so the tailnet DNS name in the Host header
isn't rejected as a DNS-rebinding attempt.
Commands: up (default) / down / restart / status / url / discover.
- Auto-discovers Tailscale (ip, MagicDNS name, HTTPS certs) and picks the mode
(auto -> tailscale-serve when available, else loopback).
- Liveness is an HTTP console probe, not `smithers gateway status` (which can
report running:false for a serving, manually-started Gateway).
- Idempotent; graceful fallback to loopback when Tailscale is absent; explicit
`--insecure` opt-in for direct tailnet-IP binding.
Config: gateway.{port,mode,servePort,trustAnyHost}. install.sh already vendors
scripts/* into <target>/.claude/scripts/, so no installer change is needed.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TMUG7KT32tVitdDTjjyrgE
…sink Wire scripts/smithers-gateway.sh into rig-sync apply's `workflow` sink: after `smithers up ... --input`, run `smithers-gateway.sh up` so the durable run gets a browser-reachable console (loopback Gateway + Tailscale HTTPS when present) and report the console URL alongside the run id. Document the `gateway.*` config in the skill's Configuration section. rig-sync is the only skill that launches a durable Smithers run (rig-epic/rig-task are agent-orchestrated and don't `smithers up`), so this is the one apply flow that needs the wiring. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TMUG7KT32tVitdDTjjyrgE
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
scripts/smithers-gateway.sh— an idempotent manager for the Smithers workspace Gateway with Tailscale auto-discovery.gatewayconfig block inrig.schema.json+rig.config.example.json(gateway.{port,mode,servePort,trustAnyHost}).install.shalready vendorsscripts/*into<target>/.claude/scripts/(andchmod +x's.sh), so no installer change is needed.Why
The Gateway's token auth is
Authorization-header only — a browser navigating to a URL can't send that header, and there's no query-param / cookie / Basic-auth fallback, so a token-gated UI is simply unreachable from a browser. This bit us trying to reach the console over Tailscale.The manager runs the Gateway on loopback (no token) and publishes it to the tailnet over HTTPS via
tailscale serve— making Tailscale device identity the auth boundary while the Gateway stays unauthenticated on127.0.0.1where nothing else reaches it. It exportsSMITHERS_GATEWAY_TRUST_ANY_HOST=1so the tailnet DNS name in theHostheader isn't rejected as a DNS-rebinding attempt.Commands
up(default) ·down·restart·status·url·discoverauto→tailscale-servewhen available, elseloopback.smithers gateway status— the status tracker can reportrunning:falsefor a serving, manually-started/re-adopted Gateway (observed live).--insecureopt-in for direct tailnet-IP binding.Verification
Exercised live against a 0.32 gateway + real tailnet:
discover→ correct dns / ipv4 / https-cert detection.status→running(via probe) +serve: https :8443 → 127.0.0.1:7331 (active)(multi-linetailscale serve statusparsed correctly).up(idempotent) → detects healthy gateway + serve, mutates nothing, printshttps://<name>.ts.net:8443/console.bash -nclean; both JSON files validate; example fields match the schema.Mutating paths (fresh start / teardown) are covered by the same probe-based health logic used in the verified idempotent path.
🤖 Generated with Claude Code
https://claude.ai/code/session_01TMUG7KT32tVitdDTjjyrgE