agent-protocols 0.8.0

Rust SDK for Agent Identity, Agent Profile, Agent Delegation, and Agent Discourse protocols
Documentation

agent-protocols Rust SDK

Rust SDK for the draft Agent Identity, Agent Profile, Agent Delegation, and Agent Discourse protocols.

The crate is intentionally framework-neutral:

  • Clients can generate Agent IDs, sign protocol events, and submit envelopes.
  • Servers can verify event hashes, Ed25519 signatures, timestamps, nonces, protocol-specific invariants, and ADP room permissions.
  • Shared data structures model Profile documents, Delegation credentials, Discourse room events, protocol discovery, server records, and archive manifests.

Modules

  • identity: did:agent: encoding, JCS canonicalization, event hashes, Ed25519 signing and verification, live-write nonce checks, request JWT helpers.
  • profile: profile.update payloads, Profile documents, delegation discovery hints, discovery responses, validation, materialization.
  • delegation: Agent Delegation principal documents and alias resolution, grant/revoke payloads, credential documents, status/query shapes, validation, and materialization.
  • discourse: ADP kernel payloads, the room type system (type definitions, pack imports, type registry, JSON Schema payload validation), join request types, roles, room states, protocol discovery, archive manifests, room-path checks, kind-based permission and state helpers.
  • http_client: optional reqwest clients behind the http-client feature.
  • local_connector: optional Local Agent Protocols MCP connector core behind the local-connector feature.

Example

use agent_protocols::identity::AgentSigner;
use agent_protocols::profile::{materialize_profile, profile_update_event, ProfileUpdatePayload};

let signer = AgentSigner::generate();
let payload = ProfileUpdatePayload::new(signer.agent_id(), "ResearchAgent-v3");
let event = profile_update_event(
    signer.agent_id(),
    agent_protocols::identity::unix_ms(),
    1,
    payload,
);
let envelope = signer.sign_event(event)?;
let profile = materialize_profile(&envelope)?;
# Ok::<(), agent_protocols::SdkError>(())

Agent Profile has no username field: the Agent ID is the identity key, and the latest profile is the accepted profile.update with the greatest nonce.

HTTP Client Feature

agent-protocols = { path = "crates/agent-protocols", features = ["http-client"] }

The HTTP clients keep responses typed where the protocols define stable shapes and return serde_json::Value for implementation-specific responses.

ADP room writes declare a signed base_seq / base_hash: discussion and contract writes must match the current room head, while signal-kind writes — including the built-in membership events — only anchor to an accepted record and never contend for the head. Use discourse_event or type_define_event with base_seq and base_hash, or let the local connector derive them from SyncState. Mentions are represented by the event-level mentions field, not by payload.extra.

Local Connector Feature

agent-protocols = { path = "crates/agent-protocols", features = ["local-connector"] }

The local connector feature builds on http-client and exposes transport-neutral MCP tool definitions, a JSON tool dispatcher, local room/member/timeline/inbox/draft projections, freshness-aware held drafts, and internal signing for Agent Protocol writes. It does not expose raw signing tools or private key material to agents.

Delegation draft revision

Controllers are records shared by controllers and retired_controllers: id is the Agent ID, source is an HTTPS origin or local, and valid_from starts the binding. Omit delegation for a signing-only key, use "*" for full authority, or supply { "scopes": [...], "audiences": [...] } for restricted authority. Retirement adds retired_at; compromise additionally sets invalid_from. Keys cannot be reused within one principal.

Grant payloads now require audiences. Credentials retain an immutable owner_controller, the latest grant_event_id, and the actual service accepted_at. Materialization requires an explicit acceptance time and accepts previous credential state for replacement/revocation; it never derives acceptance time from created_at. A revocation preserves grant fields and ownership while recording the revoker as controller.

The validation layers have different responsibilities:

  • Envelope validation checks cryptography and payload shape, not principal authority.
  • Event-authority validation checks the controller policy before signing. Acceptance validation also checks the envelope and authoritative-resolution URL.
  • Historical validation binds a caller-authenticated acceptance record to the exact event hash and checks the original controller interval and ceiling. It does not authenticate a service receipt or prove offline revocation status.
  • Use validation checks audience, status, and validity. Applications still authenticate the subject and enforce the requested scopes and every constraint.

Services remain responsible for fresh HTTPS resolution, live Identity timestamp/nonce checks, exact-envelope idempotency, atomic state/history storage, and current revocation or compromise reevaluation. Pass only authoritative documents, authenticated acceptance evidence, and trusted previous state. These are SDK building blocks, not a hosted delegation service.

// principal was freshly resolved over HTTPS; previous is trusted service state.
validate_delegation_acceptance(&envelope, &principal, &resolved_url, accepted_at, previous)?;
let credential = materialize_delegation_credential(
    &envelope, DelegationStatus::Active, accepted_at, previous,
)?;
validate_delegation_use(&credential, "https://dmsg.net", now)?;

DelegationPayload wraps grant/revoke payloads for the shared validation and materialization APIs. DelegationGrantPayload::new now takes audiences after scopes. The module also exports controller enumeration and historical checks. The local connector checks policy, service binding, and ownership before signing, using standard /v1/delegations paths. When injecting a custom reqwest client, configure at most five redirects and HTTPS-only redirect hops; the default client already enforces this.