Seneschal › Gopher over HTTPS
A tiny, open convention for machine-readable service discovery: serve a 1991-vintage Gopher menu over plain HTTPS at /.well-known/agent.gopher. An AI agent learns what you offer — and drills into only the branch it needs — in a few hundred bytes instead of parsing a multi-kilobyte HTML page or JSON index.
It is a cheap table of contents an agent reads before it connects — a typed, navigable cousin of llms.txt. Not a replacement for MCP: MCP (JSON-RPC, full input schemas) is how you call a tool; this is how an agent finds it.
Seneschal runs it live, including a terse mirror of the official MCP registry.
View the live menu » As HTML As JSONTokens are money and latency. A discovery format should be terse and let an agent fetch only the branch it cares about. Gopher's menu line does both. Measured on Seneschal's real directory:
<type><label>TAB<selector> — no braces, no angle brackets, no repeated keys. The compact menu is ~20% smaller than classic Gopher, ~29% smaller than equivalent JSON, ~32% smaller than minimal HTML.$schema, versions and _meta timestamps an agent browsing "what exists and where" doesn't need.GET returning Content-Type: application/gopher. No new port, no gopher:// client, no dependency. TLS already supplies host + port, so those redundant fields are dropped."Tokens" are estimated as bytes / 4 — a stable proxy for the ordering, not an exact tokeniser count. The win is in discovery; tool results should stay JSON, where you want the schema and types.
This is exactly what GET https://seneschal.space/.well-known/agent.gopher returns today:
iAgent/MCP services — terse index for machines (Gopher-over-HTTPS).
iLines are <type><label>TAB<selector>. Type 1 = drill in, 0 = read, h = URL.
i
1Seneschal — Monero/Zcash payment webhooks + Ethereum data /.well-known/agent/seneschal
1FlashBank — non-custodial flash loans + P2P term loans /.well-known/agent/flashbank
1winbit32 — agent-facing private payments (FROST co-sign) /.well-known/agent/winbit32
1secresea — privacy NFT marketplace (Zcash shielded) /.well-known/agent/secresea
1MCP registry — live mirror of the official registry /.well-known/agent/registry
i
0about — what this directory is and why /.well-known/agent/about
0agents — how to consume it over HTTPS /.well-known/agent/agents
.
A leading 1 means "submenu — GET this selector to drill in". The menu ends with a line containing only a dot. Add ?format=json or ?format=html to any node for the same content in another shape.
GET the selector path over HTTPS. The root is always /.well-known/agent.gopher.<type><label>TAB<selector>: the first character is the type, then the display label, a single TAB, then the selector.| Type | Meaning | What an agent does |
|---|---|---|
1 | submenu (directory) | GET the selector to drill in |
0 | text leaf | GET the selector and read it |
h | external link | selector is URL:https://… — follow it |
i | info | presentational only — ignore for navigation |
7 | search | append a query to the selector |
3 | error | — |
A line that is only . ends the menu (RFC 1436). One-liner to see the whole tree:
curl -s https://seneschal.space/.well-known/agent.gopher
curl -s https://seneschal.space/.well-known/agent/registry # drill into the MCP registry mirror
Already connected over MCP? Seneschal also exposes this exact directory as an MCP tool — seneschal_agent_directory on mcp.seneschal.space (args: section, format, cursor). Same tree, including the registry mirror, without leaving the session — so the discovery layer lives inside MCP as well as over plain HTTPS.
The whole convention is: serve a Gopher menu over HTTPS at /.well-known/agent.gopher with Content-Type: application/gopher; charset=utf-8. Use absolute selectors (e.g. /.well-known/agent/catalogue) so a client can drill down by re-requesting them. That's it — there is no registry to join and no library you must use.
Simplest path: drop a file in your web root and set the content type. This is how the satellite sites in this ecosystem publish theirs.
The file (fields separated by a literal TAB; ends with a lone .):
iMy services — terse index for machines.
1Catalogue /.well-known/agent/catalogue
0about — what this is /.well-known/agent/about
hMCP server URL:https://mcp.example.com/
.
location = /.well-known/agent.gopher {
default_type application/gopher;
charset utf-8;
add_header X-Content-Type-Options nosniff;
}
On an SPA, make sure the real file is matched before your try_files fallback to index.html, or you'll serve HTML with a 200 instead of the menu. Check with curl -I that the Content-Type is application/gopher, not text/html.
For a dynamic directory (or to avoid hand-typing tabs), use the open-source gophermap primitive from payments-gateway (MIT). It builds, parses and sanitises menus so the type codes live in one place.
import {
info, menu, textItem, link, buildMenu
} from "payments-gateway/gophermap";
// Compact mode is the default (host+port dropped).
const body = buildMenu([
info("My services — terse index for machines."),
menu("Catalogue", "/.well-known/agent/catalogue"),
textItem("about", "/.well-known/agent/about"),
link("MCP server", "https://mcp.example.com/")
]);
// Serve it (Fastify shown; any framework works):
app.get("/.well-known/agent.gopher", (req, reply) =>
reply
.header("content-type", "application/gopher; charset=utf-8")
.header("cache-control", "public, max-age=600")
.send(body));
Behind a reverse proxy, hand the well-known paths to your app:
# Caddy
handle /.well-known/agent.gopher {
reverse_proxy 127.0.0.1:8810
}
handle /.well-known/agent/* {
reverse_proxy 127.0.0.1:8810
}
i lines describing the format, so a human (or a confused agent) who lands on it understands what it is.0about text leaf and a 0agents "how to consume" leaf at the bottom.max-age=600); this is a directory, not live data.h URL: lines or 1 submenus so agents can hop the graph.Seneschal's /.well-known/agent/registry branch is a live, cached (10 min) terse lens over the official MCP registry — public, API-first, Apache-2.0. Each remote server becomes a connectable h URL: line. We deliberately mirror only the official, open registry, not commercial directories with unclear terms. If you run a registry of your own, the same transform makes it agent-cheap to browse.
gopher:// is not worth it — it needs new clients and a new port for nothing TLS doesn't already give you. Borrow the menu format, serve it over HTTPS.llms.txt worked because everyone agreed on the path; /.well-known/agent.gopher is the proposal here.