slancha-wire 0.17.0

Magic-wormhole for AI agents — bilateral signed-message bus over a mailbox relay
Documentation
# Fly.io app config for wire-relay-server.
#
# Deploy:
#   fly launch --no-deploy           # first time: creates the app
#   fly volumes create relay_state \
#       --size 1 --region iad        # 1 GB persistent volume; wire-state lives here
#   fly deploy                       # build + push + roll
#   fly status                       # health
#
# Cutover:
#   In Cloudflare DNS for wireup.net:
#     - CNAME relay → <app>.fly.dev  (proxied / orange-cloud for DDoS + caching)
#     - CNAME @ (apex) → <app>.fly.dev  OR keep apex on CF Pages for landing
#   Then point new clients at `https://relay.wireup.net` and let DNS
#   propagation drain old wireup.net traffic from Spark cloudflared tunnel.
#
# Pre-launch sanity:
#   curl https://<app>.fly.dev/healthz                                   # → ok
#   curl https://<app>.fly.dev/.well-known/agent-card.json?handle=test   # → 404 fine
#
# Cost @ v0.5 scale: $0 on Fly hobby plan (shared-cpu-1x 256MB + 1 GB volume covered).
# Bump memory / region count when you outgrow it.

app = "wireup-relay"
primary_region = "iad"   # change if your CF edge sits elsewhere (sjc / fra / etc.)

[build]
# Empty — Fly uses the repo-root Dockerfile.

[env]
# wire-relay-server reads WIRE_HOME for slot state. Already set in the
# Dockerfile, but re-stating here keeps Fly's config the single source
# of truth for environment.
WIRE_HOME = "/data"
RUST_LOG = "wire=info"

[http_service]
internal_port = 8770
force_https = true

# SSE / streaming: never auto-stop machines while subscribers are
# connected. min_machines_running = 1 keeps the relay warm.
auto_stop_machines = false
auto_start_machines = true
min_machines_running = 1

# Long timeouts so SSE keepalives don't disconnect.
# (Fly's default 60s idle timeout would kill our 30s-keepalive streams.)
#
# Concurrency: with `type = "requests"`, every long-lived SSE `/stream` holds a
# slot for its whole life, so the ceiling must cover (open streams + in-flight
# pulls) across ALL wire daemons, not peak RPS. At 250 the single instance
# saturated under the real federation fan-out — fly logged "reached hard limit
# of 250 concurrent requests" + "could not find a good candidate" (PR04), which
# surfaced to clients as the relay read-path hanging. Bumped to ~4x headroom;
# idle keepalive connections are cheap on the larger VM below.
[http_service.concurrency]
type = "requests"
soft_limit = 800
hard_limit = 1000

[[mounts]]
source = "relay_state"
destination = "/data"
# initial_size only applies on first attach; resize later with `fly volumes extend`.
initial_size = "1gb"

[[vm]]
# Bumped from shared-cpu-1x/256mb: the SSE subscriber count outgrew the
# >100 threshold noted previously, saturating the 250-request ceiling. 2x CPU +
# 512mb gives the headroom to actually hold the raised concurrency limit above.
size = "shared-cpu-2x"
memory = "512mb"
cpus = 1

[checks]
  [checks.healthz]
  type = "http"
  port = 8770
  path = "/healthz"
  interval = "15s"
  timeout = "5s"
  grace_period = "10s"
  method = "GET"