Zero-configuration AI service discovery using mDNS/DNS-SD
Project description
Saturn
Discover and call any model on your network with one query.
Saturn is a protocol — mDNS/DNS-SD service type _saturn._tcp.local. — that lets any OpenAI-compatible AI endpoint announce itself on a LAN. Clients discover and call it with stock tools.
# 1. Discover Saturn endpoints on your LAN (macOS/Linux, no install)
$ dns-sd -B _saturn._tcp .local
Browsing for _saturn._tcp.local
Add 3 llama-3-8b._saturn._tcp.local.
Add 3 whisper-v3._saturn._tcp.local.
# 2. Resolve and call one — same shape as OpenAI
$ curl http://llama-3-8b.local:8080/v1/chat/completions \
-H 'content-type: application/json' \
-d '{"model":"default","messages":[{"role":"user","content":"hi"}]}'
{"id":"...","choices":[{"message":{"content":"Hello!"}}]}
AI agents and LLMs: read AGENTS.md. ML systems researchers: read docs/how-to/for-researchers.md.
This repository is the artifact of a master's thesis at UC Santa Cruz (Joey Perrello, advised by Adam Smith). Thesis: Saturn: Zero-Configuration AI Service Discovery (eScholarship, 2026).
Why Saturn
- Zero-config. No accounts, no per-app keys, no manual endpoint URLs. The same mechanism your laptop already uses to find printers.
- Transport-agnostic. Anything that can browse mDNS and speak HTTP is a conformant client —
dns-sd,avahi-browse, Go, Python, Rust, TS, Lua. - OpenAI-compatible by default. Discovered endpoints expose
/v1/health,/v1/models,/v1/chat/completions. Drop the URL into any tool that takes abase_url.
Same idea, other languages
Go
$ cd saturnd && go build -o saturnd ./cmd/saturnd
$ ./saturnd # browse + serve on :7827
$ curl http://localhost:7827/v1/agents # discovered Saturn instances
Python
$ pip install saturn-ai
$ saturn discover # print every advertised service
$ curl $(saturn endpoint)/v1/models # call the highest-priority one
TypeScript
import { createSaturn } from "ai-sdk-provider-saturn";
const saturn = createSaturn();
const services = await saturn.discover({ timeout: 2000 });
console.log(services[0].endpoint);
Full per-language details: docs/integrations/.
Implementations
Seven reference clients across five languages and four mDNS libraries, sharing no Saturn-specific code. Interoperability comes from the wire format alone (Saturn.md:976).
| Implementation | Language | mDNS library | What it does |
|---|---|---|---|
saturnd/ |
Go | grandcat/zeroconf |
Standalone discovery daemon; A2A/MCP surface |
saturn/ |
Python | python-zeroconf |
Reference package: discovery, server, beacon, CLI, Web UI |
saturn-router/ |
Rust | mdns-sd |
Router-edge build (~2 MB, runs on a $20 OpenWRT MIPS box) |
ai-sdk-provider-saturn/ |
TypeScript | multicast-dns |
Vercel AI SDK provider with circuit breaking + failover |
vlc_extension/ |
Lua + Python | dns-sd CLI |
Bridges Saturn into a non-AI-native host application |
saturn-mcp/ |
TypeScript | multicast-dns |
Discovery surfaced as MCP tools |
| Open WebUI plugin | Python | python-zeroconf |
Single-file backend swap for Open WebUI |
A post-thesis OpenCode fork (TypeScript, multicast-dns) demonstrates agentic workflow with tool calls and streaming; it lives outside the monorepo and is not part of the canonical seven.
TXT record (the wire artifact)
Saturn carries everything a client needs in one DNS-SD TXT record:
version=1 # protocol version — required
api_type=openai # api shape — required
deployment=cloud # local | cloud | network — required
priority=10 # lower preferred — required
api_base=https://openrouter.ai/api/v1 # cloud only
ephemeral_key=eyJhbGc... # short-lived JWT, cloud only
rotation_interval=300 # seconds; default 300
features=chat,tools,vision # capability hints
RFC 6763 §6.1 caps each TXT string at 255 bytes — JWTs fit, X.509 certs don't. That constraint shapes the credential design.
Full schema, RFC-style stability levels, and per-key prose: docs/reference/protocol/txt-keys.md.
Beacons and ephemeral keys
A Saturn beacon dispenses credentials for a cloud upstream and never proxies inference traffic:
- Mint a scoped sub-key against the upstream with a short expiration.
- Embed it in the
ephemeral_keyTXT field. - Rotate before expiry; clients re-read TXT.
- Clients call the upstream directly — the beacon never sees prompt or completion bytes.
The reference Python beacon defaults to a 10-minute key with a 5-minute rotation interval (Saturn.md:614–615). These are reference-implementation defaults, not protocol invariants. The design bounds the dominant secret-leakage failure mode — Meli et al. found 81% of GitHub-leaked secrets are never revoked; a short-lived sub-key is dead before any scanner reaches it.
Security posture. Beacon mode is for trusted local networks — the kind you'd plug a printer into. The sub-key's per-key spending cap is the actual security boundary; set
beacon.max_budget_usdlow if your threat model includes any device on the LAN. If that doesn't fit, use proxy mode — Saturn keeps the parent key server-side and proxies through its own authenticated/v1/*endpoints, gated bySATURN_RUNNER_TOKEN(CONFIG_FIELDS §A.2).
Full threat model, TLS posture, and X-Forwarded-For / SATURN_TRUSTED_PROXIES setup: docs/reference/protocol/security.md.
Roles
Saturn names three roles and concentrates configuration in exactly one of them.
- Administrator — deploys services, sets priorities, manages credentials. The only role that touches configuration.
- Application developer — calls
discover(); receives services with URLs and credentials populated. No auth logic, no billing integration. - End user — connects to the network. Nothing else.
The cognitive walkthrough in the thesis shows the application-developer step count drops 19 → 4 (−79%) and the end-user count drops 7 → 0 (−100%). Asymptotic form: 12 + 19N + 7M (traditional) → 14 + 4N + 0M (Saturn) over N developers and M end users. Methodology and threats to validity: docs/how-to/for-researchers.md.
Conformance
A Saturn implementation in any language is five steps:
- Browse
_saturn._tcp.local.with any DNS-SD library. - Resolve SRV + TXT for each instance.
- Validate
version=1and parse the TXT keys. - Sort by
priority; pick the lowest healthy (probeGET /v1/health). - Call the
/v1/*HTTP API atapi_base(cloud) or the SRVhost:port(local / network).
That is the entire protocol surface. The full 30-minute walk-through, including a working publisher and client in three languages, lives at docs/tutorial/. The proposed v2 schema redesign is at docs/spec/v0.2/wire-format.md.
Platform notes
- macOS.
dns-sdis part of the system; nothing to install. Beacon caveat: if you run a Saturn beacon on a laptop, keep it awake (caffeinate -i saturn run <name>) — the Bonjour Sleep Proxy can serve a stale TXT after the host sleeps and the publishedephemeral_keyexpires. See docs/concepts/mdns-background.md#addendum-bonjour-sleep-proxy-and-beacon-hosts. - Linux.
sudo apt install avahi-utils. Saturn requires Avahi ≥ 0.9-rc3; older builds are exposed to CVE-2025-68276 / 68468 / 68471. Ubuntu 24.04 LTS is patched. - Windows. Install Bonjour Print Services. If
saturnis not onPATH, usepython -m saturn.
Docs · Contributing · License
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file saturn_ai-1.1.0.tar.gz.
File metadata
- Download URL: saturn_ai-1.1.0.tar.gz
- Upload date:
- Size: 253.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ac09f3a0b32b8774b3687f4b1b74e8e439f8c98f5092b7be4ed11ed471613f05
|
|
| MD5 |
2298c1a0fdc5f207624aa53d446d8988
|
|
| BLAKE2b-256 |
c9a9a2a2f2cf09dd8c7bdc4ca91e762118828537bc75bdc3aa564bc243638a17
|
Provenance
The following attestation bundles were made for saturn_ai-1.1.0.tar.gz:
Publisher:
pypi.yml on jperrello/Saturn
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
saturn_ai-1.1.0.tar.gz -
Subject digest:
ac09f3a0b32b8774b3687f4b1b74e8e439f8c98f5092b7be4ed11ed471613f05 - Sigstore transparency entry: 1586464041
- Sigstore integration time:
-
Permalink:
jperrello/Saturn@4fc93149a7c2da84274e8d3937439963f9248efa -
Branch / Tag:
refs/tags/pypi-v1.1.0 - Owner: https://github.com/jperrello
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
pypi.yml@4fc93149a7c2da84274e8d3937439963f9248efa -
Trigger Event:
push
-
Statement type:
File details
Details for the file saturn_ai-1.1.0-py3-none-any.whl.
File metadata
- Download URL: saturn_ai-1.1.0-py3-none-any.whl
- Upload date:
- Size: 306.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
20b822b03719a9165c216b3871aefee2506bdf9c2ee5ff6466d973221b36ca1a
|
|
| MD5 |
ba962cca48eb26eb03a49e639c20d6d3
|
|
| BLAKE2b-256 |
008976999c85c6ba7d377ac4e51ac1e22aed6ea5ac307bf125af2a114cc125a0
|
Provenance
The following attestation bundles were made for saturn_ai-1.1.0-py3-none-any.whl:
Publisher:
pypi.yml on jperrello/Saturn
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
saturn_ai-1.1.0-py3-none-any.whl -
Subject digest:
20b822b03719a9165c216b3871aefee2506bdf9c2ee5ff6466d973221b36ca1a - Sigstore transparency entry: 1586464046
- Sigstore integration time:
-
Permalink:
jperrello/Saturn@4fc93149a7c2da84274e8d3937439963f9248efa -
Branch / Tag:
refs/tags/pypi-v1.1.0 - Owner: https://github.com/jperrello
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
pypi.yml@4fc93149a7c2da84274e8d3937439963f9248efa -
Trigger Event:
push
-
Statement type: