agent-uri
Parser and validator for the agent:// URI scheme, providing topology-independent identity for agents in multi-agent systems.
Overview
Multi-agent systems need a standard way to identify agents that works regardless of where they're deployed. agent-uri solves this by encoding identity, authority, and capabilities into a single URI.
Each URI contains a trust root (who issued it), a capability path (what it can do), and an agent ID using TypeID format (who it is, when it was created). The typestate builder catches construction errors at compile time, and all components validate against the specification on parse.
URI Format
agent://example.com/assistant/chat/llm_chat_01h455vb4pex5vsknk084sn02q?version=1.0#task
└─ trust root ─┘└─ capability path ─┘└───────── agent id ────────┘└─ query ─┘└frag┘
| Component | Description |
|---|---|
| Trust Root | Domain or IP identifying the issuing authority |
| Capability Path | Hierarchical path describing agent capabilities |
| Agent ID | TypeID with semantic prefix + UUIDv7 suffix |
| Query | Optional metadata (version, ttl, attestation) |
| Fragment | Optional semantic annotation |
Installation
[]
= "0.6"
For JSON serialization support:
[]
= { = "0.6", = ["serde"] }
Quick Start
use *;
// Parse an existing URI
let uri = parse.unwrap;
// Access components
println!; // anthropic.com
println!; // assistant/chat
println!; // llm_chat_01h455vb4pex5vsknk084sn02q
println!; // llm_chat
Building URIs
The typestate builder enforces correct construction order at compile time:
use *;
let uri = new
.try_trust_root?
.try_capability_path?
.agent_id // generates fresh UUIDv7
.try_query?
.try_fragment?
.build?;
println!;
// agent://openai.com/tool/code/code_assist_01jj0t8yv4ex3vsknk084sn92a?version=2.0#streaming
The builder requires trust root, capability path, and agent ID in order. Query and fragment are optional at any stage.
Working with Components
Trust Root
let root = parse?;
assert_eq!;
assert_eq!;
// Modify port
let without_port = root.without_port;
A trust root is ASCII. A non-ASCII name is rejected rather than converted, so
münchen.de is an error and not a synonym for xn--mnchen-3ya.de; converting
an internationalized name to A-label form is the job of whatever accepts it
from a person. An xn-- label is then treated as an opaque DNS label — not
decoded, not checked as Punycode — so nothing here detects a homograph or a
name that was converted wrongly upstream. See the TrustRoot docs and
§8.11 of the specification.
Capability Path
let path = parse?;
assert_eq!;
assert!;
// Navigate hierarchy
for segment in path.iter
Agent ID
Agent IDs use TypeID format: a semantic prefix plus a base32-encoded UUIDv7.
// Create new ID (generates UUIDv7 automatically)
let id = new;
println!; // llm_chat_01h455vb4pex5vsknk084sn02q
// Parse existing
let parsed = parse?;
println!; // task_runner
println!; // extracts the UUIDv7
new follows mti, which this crate mints TypeIDs with: it sanitizes a prefix
the grammar refuses rather than failing, so AgentId::new("LLM Chat!") yields
the prefix llmchat and AgentId::new("123") falls back to agent. That is
what you want for a prefix you wrote and not for one that arrived from a peer,
a config file, or a URI, because the ID you get back names a class nobody
asked for. For those, AgentId::try_new reports the prefix instead of
rewriting it.
Query and Fragment
let uri = parse?;
// Access query parameters
if let Some = uri.query.version
// Access fragment
if let Some = uri.fragment
// Create modified URI
let updated = uri.with_query;
Features
| Feature | Description |
|---|---|
default |
Core parsing and validation |
serde |
Serialize/deserialize all types |
License
MIT OR Apache-2.0