Last month I was debugging a multi-agent system I'd built on acton-reactive when a deployment migration broke everything. I'd moved an approval agent from one cloud provider to another—different endpoint URL, different API gateway. Workflows that referenced the old URL started failing. Cached references in other agents? Stale. Audit logs? Now ambiguous about which agent they referred to.
The agent hadn't changed. Its capabilities hadn't changed. Its identity—for all practical purposes—hadn't changed. But because I'd used its URL as its identifier, a topology change became an identity crisis.
I've seen this pattern repeatedly. Agent identity gets tangled with agent location, and every migration, every scaling event, every infrastructure change threatens to break the system.
The Mistake We Keep Making
Think about how you identify agents in your current system. If you're using LangChain, it's probably a Python module path. MCP servers? Transport endpoints. A2A protocol? Agent Card URLs. Every major framework makes the same choice: the identifier contains location information.
This works fine until it doesn't. Move an agent, break its identity. Scale to multiple instances, now you have an identity crisis. Scale to hundreds or thousands of instances, now you have an identity catastrophe. Federate across organizations, and you need a registry that knows about everyone—which defeats the purpose of federation.
Saltzer wrote about this in 1982. Names should identify things. Addresses should locate things. Routes should describe how to reach things. When you conflate them, you get brittleness. The internet learned this lesson and built DNS. Agent systems haven't caught up.
What Would DNS for Agents Look Like?
I started sketching what a proper separation would require.
First, the identifier needs to say who without saying where. An agent's name should survive any number of migrations. If I move my approval agent from AWS to GCP to a local machine, it should still be the same agent with the same identity.
Second, the identifier should support capability queries. I don't always know which specific agent I need. Sometimes I just need "something that can approve invoices" or "anything that handles shipping quotes." Current systems force you to know the exact agent you want before you can find it.
Third, capability claims need verification. When an agent says "I can approve transactions up to $10,000," I want cryptographic proof, not just its word.
The Design
I ended up with a URI scheme:
agent://acme.com/workflow/approval/invoice/agent_01h455vb4pex5vsknk084sn02q
Three parts, each doing one job.
acme.com is the trust root—the organization vouching for this agent. Like a passport authority. Acme issues the credentials; anyone can verify them by fetching Acme's public keys.
/workflow/approval/invoice is the capability path—what the agent does, not where it lives. This enables queries: "find me anything under /workflow/approval" returns all approval-related agents.
agent_01h455vb4pex5vsknk084sn02q is a TypeID—globally unique, sortable by creation time, no coordination needed to generate.
None of these contain network addresses. The agent's current endpoints live in a distributed hash table (DHT)—a decentralized key-value store spread across many nodes, like BitTorrent uses for peer discovery. When the agent migrates, it updates its DHT record. The URI stays stable.
Discovery Without a Registry
The capability path enables something I'd wanted for a long time: finding agents by what they do rather than who they are.
The DHT key derivation includes the trust root, so acme.com/workflow/approval and globex.com/workflow/approval produce different keys. You can't accidentally discover agents from organizations you didn't query. Trust boundaries stay explicit.
Prefix queries work naturally. Query for /workflow/approval and you get agents at that path plus all children—invoice approval, expense approval, whatever exists underneath. Ask for a general capability, discover specific implementations.
Lookup is fast—logarithmic in the number of nodes—and requires no central registry. Resolution cost stays constant regardless of how many times an agent has migrated. The identity is stable; only the routing information changes.
Verified Capabilities
Self-declared capabilities don't scale. If any agent can claim any capability, you need to verify every claim through interaction. That's expensive and error-prone.
I used PASETO tokens for attestation—think JWT but with secure defaults baked in. A trust root issues a signed token binding an agent to specific capability paths. The token includes what paths the agent may claim, who issued it, and when it expires.
Verification is straightforward: fetch the trust root's public key (cached after first fetch), check the signature, confirm the claimed capability falls under the attested paths. No real-time contact with the trust root needed.
The verification cost is negligible—about 50 microseconds per signature check. Even verifying 100 agents from a prefix query takes single-digit milliseconds.
Where This Doesn't Help
Not every system needs this.
If your agents never migrate and you control all discovery, the overhead isn't worth it. Running trust root infrastructure is comparable to running a certificate authority—meaningful operational cost for meaningful benefit, but not free.
If your agents are ephemeral—spun up and torn down rapidly—stable identity for individual instances provides limited value. Though you might still want a stable identity for the gateway or load balancer in front of them.
If you don't need capability-based discovery, the capability path adds complexity without payoff. Some systems just need "call this specific agent"—they already know what they want.
The Broader Pattern
The underlying issue isn't specific to agents. Anywhere identity gets coupled to location—service endpoints, configuration references, resource handles—you get the same brittleness. Change the topology, break the references.
Saltzer's insight from 1982 still applies: separate names from addresses, let resolution handle the mapping, and the names survive infrastructure changes. DNS did this for the internet. Agent systems need the same separation.
The Rust implementation and ABNF grammar are at github.com/Govcraft/agent-uri-rs.
I've written up the formal details in a paper on arXiv. Feedback welcome—particularly on DHT participation incentives and capability mapping across organizations, which remain underspecified.

Comments
Nothing yet. Say the first thing.
Sign in to join the conversation.