Serving an application interface
A capability can supply its own UI or HTTP API. The host decides which addresses the child may serve. Protocols 3 and 4 place the chosen address in Startup.serve_host.
from skulk_capability_sdk.serving import (
advertised_host, bind_hosts, peer_allowed,
)
hosts = bind_hosts(startup)
public_host = advertised_host(startup)
# Bind each returned host separately.
# Check peer_allowed(remote_address) at your connection boundary.
Bind and advertise
bind_hosts() returns loopback and, when supplied, the host-selected serving address. Bind them separately. Binding every interface would also expose the application on networks the host did not choose.
advertised_host() chooses the reachable host for the surface URL and brackets IPv6 addresses appropriately. Without a serving address, the interface is loopback-only and needs a browser on that host.
Caller admission
peer_allowed() accepts loopback and the configured Tailscale address ranges, handles IPv4-mapped IPv6, and refuses malformed or other addresses. Tailscale’s own access policy decides which peers can reach the serving address. These helpers do not authenticate an application user or grant permission to mutate state; apply the host and application’s authorization contract too.
Publish readiness
Declare a surface URL and readiness through the managed integration. Discovery alone does not make the URL reachable or the application healthy. Update readiness when the application cannot serve its declared workflow.