Rust client for the AGNTCY Directory, feature-equivalent to
dir-sdk-javascript and dir-sdk-python.
- async (
tokio) gRPC client ontonic/prost, with protobuf‑JSONserdesupport on every message - every Directory service: store, routing, publication, search, sign/verify, sync, events, identity
- auth modes: insecure,
tls(mTLS files),x509/jwt(SPIFFE Workload API),oidc(bearer token + interactive PKCE login withdirctl-compatible token cache) - native signing (cosign keys or keyless Sigstore OIDC) and local verification, no
dirctlorcosignbinary required - no
protocneeded: stubs are generated at build time from the vendoredproto/tree with the pure-Rustprotox
[dependencies]
agntcy-dir = { git = "https://github.com/agntcy/dir-sdk-rust" }
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
serde_json = "1"use agntcy_dir::models::core_v1::Record;
use agntcy_dir::{Client, Config};
#[tokio::main]
async fn main() -> agntcy_dir::Result<()> {
let client = Client::new(Config::from_env()?).await?;
// Records are protobuf Structs; build them from JSON.
let record: Record = serde_json::from_str(r#"{"data": {"name": "my-agent", "version": "v1.0.0"}}"#)?;
let refs = client.push(vec![record]).await?;
let pulled = client.pull(refs.clone()).await?;
println!("{}", serde_json::to_string_pretty(&pulled[0])?);
client.delete(refs).await?;
Ok(())
}More in examples/.
Config::from_env() reads the same variables as the other SDKs:
| Variable | Default | |
|---|---|---|
DIRECTORY_CLIENT_SERVER_ADDRESS |
127.0.0.1:8888 |
host:port or URL |
DIRECTORY_CLIENT_AUTH_MODE |
"" |
"", x509, jwt, tls, oidc |
DIRECTORY_CLIENT_SPIFFE_SOCKET_PATH |
SPIRE agent socket (x509, jwt) |
|
DIRECTORY_CLIENT_JWT_AUDIENCE |
audience (jwt) |
|
DIRECTORY_CLIENT_TLS_CA_FILE / _TLS_CERT_FILE / _TLS_KEY_FILE |
tls mode; _CA_FILE is optional for oidc |
|
DIRECTORY_CLIENT_TLS_SERVER_NAME |
SNI / authority override | |
DIRECTORY_CLIENT_TLS_SKIP_VERIFY |
false |
OIDC discovery/token HTTP calls only |
DIRECTORY_CLIENT_AUTH_TOKEN |
pre-supplied OIDC access token | |
DIRECTORY_CLIENT_OIDC_ISSUER, _CLIENT_ID, _CLIENT_SECRET |
PKCE login | |
DIRECTORY_CLIENT_OIDC_REDIRECT_URI |
http://localhost:8484/callback |
|
DIRECTORY_CLIENT_OIDC_CALLBACK_PORT |
8484 |
|
DIRECTORY_CLIENT_OIDC_AUTH_TIMEOUT |
300 |
seconds |
DIRECTORY_CLIENT_OIDC_SCOPES |
openid,profile,email |
comma separated |
let client = Client::new(Config::from_env()?).await?; // AUTH_MODE=oidc
if !client.has_cached_oauth_token() {
client.authenticate_oauth_pkce().await?; // opens the browser, caches the token
}The cache lives at $XDG_CONFIG_HOME/dirctl/auth-token.json (default ~/.config/dirctl/), file-compatible with dirctl.
Client methods mirror the other SDKs in snake_case: push, push_referrer, pull, pull_referrer,
lookup, delete, delete_referrer, search_cids, search_records, list, search_routing,
publish, unpublish, create_publication, list_publication, get_publication, sign, verify,
create_sync, list_syncs, get_sync, delete_sync, listen, resolve, get_verification_info.
Streaming RPCs are collected into Vecs (except listen, which returns the tonic::Streaming).
Generated models live in agntcy_dir::models::{core_v1, routing_v1, ...}; raw gRPC clients are available
through client.store_service().client() etc.
task test # kind cluster + live Directory node (needs docker, go, helm deps via Taskfile)
cargo test # unit + offline tests only
DIRECTORY_CLIENT_SERVER_ADDRESS=localhost:8888 \
cargo test --test client -- --ignored # against a live Directory
DIRCTL_PATH=... COSIGN_PATH=... DIRECTORY_CLIENT_SERVER_ADDRESS=localhost:8888 \
cargo test --test dirctl_interop -- --ignored # SDK <-> dirctl signing interoperability (skips if unavailable)The API protos are not committed: task proto:export runs buf export of the pinned buf.build/agntcy/dir release tag (see BUF_TAG in the Taskfile) into proto/, which build.rs compiles. They are shipped inside the published crate, so crates.io users need neither buf nor a BSR token. Requires the buf CLI (logged in). To pick up API changes, bump BUF_TAG to the matching Directory release.
Apache-2.0