{
  "name": "forge-comm",
  "language": "rust",
  "version": "0.2.0",
  "description": "ANVIL Communication Contract: message transport, envelopes, and protocol negotiation for the Forge SDK",
  "manifest": "forge-rs/crates/forge-comm/Cargo.toml",
  "manifestSha256": "cd3ca5ccc282c08cf418fa0ff0b319790d84631b00c56a1467006a74d79bb3a6",
  "status": "source-reference",
  "registryPublicationVerified": false,
  "route": "/libraries/rust/forge-comm",
  "features": {},
  "files": [
    {
      "path": "forge-rs/crates/forge-comm/src/channel.rs",
      "sha256": "0ba0913096938d10023b133f64f8e101a199f6cce3facb7278f86ebd8e962c3b",
      "artifactSha256": "bd0114fe4f17fc55e5408a5186f09bfbe3e93c803880eb238c4a6476586afee5",
      "url": "/reference/source/forge-rs/crates/forge-comm/src/channel.rs.txt",
      "declarations": [
        {
          "name": "::ChannelTransport",
          "line": 68,
          "signature": "pub struct ChannelTransport {\n\n}",
          "documentation": "A bounded async channel transport for in-process agent communication.\n\nCreated in pairs via [`ChannelTransport::new`], each `ChannelTransport`\nholds a sender to the peer's receive queue and a receiver for its own\nincoming messages. This enables bidirectional communication between two\nagents within the same process.\n\n# Capacity\n\nThe channel is bounded with the capacity specified at creation time.\nIf the channel is full, `send` will wait asynchronously until space\nbecomes available (backpressure).\n\n# Lifecycle\n\nWhen one side of the pair is dropped, the other side will receive\n[`CommError::ChannelClosed`] on subsequent `send` or `receive` calls.\n\n# ANVIL Spec Reference\n\n- ANVIL Spec section 10.1 -- Communication Contract\n- ANVIL Spec section 10.3 -- Channel Lifecycle"
        },
        {
          "name": "::ChannelTransport::new",
          "line": 103,
          "signature": "pub fn new(capacity: usize) -> (Self, Self);",
          "documentation": "Creates a new pair of connected `ChannelTransport` instances.\n\nMessages sent on the first transport are received by the second,\nand vice versa. The `capacity` parameter controls the bounded channel\nbuffer size for each direction.\n\n# Arguments\n\n* `capacity` - The maximum number of messages that can be buffered\n  in each direction before backpressure is applied.\n\n# Returns\n\nA tuple `(transport_a, transport_b)` where messages sent by `a`\nare received by `b` and messages sent by `b` are received by `a`.\n\n# Examples\n\n```\nuse forge_comm::channel::ChannelTransport;\n\nlet (a, b) = ChannelTransport::new(32);\n// a.send() -> b.receive()\n// b.send() -> a.receive()\n```"
        }
      ]
    },
    {
      "path": "forge-rs/crates/forge-comm/src/error.rs",
      "sha256": "bac2ceeffbe163b0698d94fac0621288e25dfd402f5effeeaa2770167befd214",
      "artifactSha256": "13dd3563fe5ac6fd269266c9d129cb335556b47b20f9a766158ab2f2eca8d904",
      "url": "/reference/source/forge-rs/crates/forge-comm/src/error.rs.txt",
      "declarations": [
        {
          "name": "::CommError",
          "line": 34,
          "signature": "#[derive(Debug, Error)]\npub enum CommError {\n    /// Message serialization to JSON failed.\n    ///\n    /// This typically indicates that the message payload contains values that\n    /// cannot be represented in JSON (e.g., NaN floats, circular references).\n    ///\n    /// See ANVIL Spec section 10.2 -- Agent Message Envelope.\n    #[error(\"message serialization failed: {reason}\")]\n    SerializationFailed {\n        /// A human-readable explanation of the serialization failure.\n        reason: String,\n    },\n\n    /// Message deserialization from JSON failed.\n    ///\n    /// This indicates that the received bytes do not constitute a valid\n    /// `AgentMessage` envelope. Common causes include malformed JSON,\n    /// missing required fields, or incompatible schema versions.\n    ///\n    /// See ANVIL Spec section 10.2 -- Agent Message Envelope.\n    #[error(\"message deserialization failed: {reason}\")]\n    DeserializationFailed {\n        /// A human-readable explanation of the deserialization failure.\n        reason: String,\n    },\n\n    /// The underlying transport mechanism failed.\n    ///\n    /// This covers network errors, I/O failures, and other transport-layer\n    /// issues that prevent message delivery.\n    ///\n    /// See ANVIL Spec section 10.1 -- Communication Contract.\n    #[error(\"transport failed: {reason}\")]\n    TransportFailed {\n        /// A human-readable explanation of the transport failure.\n        reason: String,\n    },\n\n    /// The transport is not connected and cannot send or receive messages.\n    ///\n    /// This is returned by transports that require an active connection\n    /// (e.g., `NoopTransport::receive`).\n    ///\n    /// See ANVIL Spec section 10.1 -- Communication Contract.\n    #[error(\"transport is not connected\")]\n    NotConnected,\n\n    /// The communication channel has been closed.\n    ///\n    /// This is returned when the peer endpoint of a channel-based transport\n    /// has been dropped, making further communication impossible.\n    ///\n    /// See ANVIL Spec section 10.3 -- Channel Lifecycle.\n    #[error(\"communication channel is closed\")]\n    ChannelClosed,\n\n    /// The message signature is invalid or cannot be verified.\n    ///\n    /// This indicates that the Ed25519 signature on the message does not\n    /// match the claimed sender's public key, or the signature is malformed.\n    ///\n    /// See ANVIL Spec section 10.4 -- Message Integrity.\n    #[error(\"invalid signature from sender '{sender}'\")]\n    SignatureInvalid {\n        /// The OAS DID of the sender whose signature failed verification.\n        sender: String,\n    },\n\n    /// Protocol negotiation between two agents failed.\n    ///\n    /// The offered protocol versions did not match any version supported\n    /// by the receiving agent.\n    ///\n    /// See ANVIL Spec section 10.5 -- Protocol Negotiation.\n    #[error(\"protocol negotiation failed for '{offered}': {reason}\")]\n    ProtocolNegotiationFailed {\n        /// The protocol identifier that was offered.\n        offered: String,\n        /// A human-readable explanation of why negotiation failed.\n        reason: String,\n    },\n\n    /// The message exceeds the maximum allowed size.\n    ///\n    /// Transports may enforce size limits to prevent resource exhaustion.\n    /// The message must be split or the payload reduced.\n    ///\n    /// See ANVIL Spec section 10.2 -- Agent Message Envelope.\n    #[error(\"message size {size} bytes exceeds maximum {max_size} bytes\")]\n    MessageTooLarge {\n        /// The actual size of the message in bytes.\n        size: usize,\n        /// The maximum allowed size in bytes.\n        max_size: usize,\n    },\n\n    /// A transport operation timed out.\n    ///\n    /// The operation did not complete within the specified duration.\n    /// This may indicate network congestion, an unresponsive peer, or\n    /// a misconfigured timeout value.\n    ///\n    /// See ANVIL Spec section 10.1 -- Communication Contract.\n    #[error(\"transport operation timed out after {duration_ms}ms\")]\n    Timeout {\n        /// The timeout duration in milliseconds.\n        duration_ms: u64,\n    },\n\n    /// Replay protection rejected the received message.\n    ///\n    /// The envelope's nonce was already seen within the validity window, its\n    /// timestamp was outside the configured clock-skew tolerance, or the\n    /// envelope was a legacy wire format and legacy acceptance is disabled.\n    /// The wrapped [`forge_core::replay::ReplayError`] carries the specific\n    /// reason.\n    ///\n    /// See ANVIL Spec section 10.4 -- Message Integrity.\n    #[error(\"replay protection rejected message: {0}\")]\n    ReplayDetected(#[from] forge_core::replay::ReplayError),\n}",
          "documentation": "Error type for communication, transport, and protocol negotiation operations.\n\nEvery variant includes actionable context: what failed, why, and what the\ndeveloper should check. No generic \"something went wrong\" messages.\n\n# Examples\n\n```\nuse forge_comm::error::CommError;\n\nlet err = CommError::MessageTooLarge {\n    size: 2_000_000,\n    max_size: 1_048_576,\n};\nlet msg = err.to_string();\nassert!(msg.contains(\"2000000\"));\nassert!(msg.contains(\"1048576\"));\n```"
        },
        {
          "name": "::CommResult",
          "line": 157,
          "signature": "pub type CommResult<T> = Result<T, CommError>;",
          "documentation": "A specialized `Result` type for `forge-comm` operations."
        }
      ]
    },
    {
      "path": "forge-rs/crates/forge-comm/src/lib.rs",
      "sha256": "c91ef5bff40e1628f7cb3c603b05df2d16d7ea340511445f6ee365194529412e",
      "artifactSha256": "44a68f2aa2bd16e18179a6276b505a522eba7d497543ac756b006c3beab9d583",
      "url": "/reference/source/forge-rs/crates/forge-comm/src/lib.rs.txt",
      "declarations": [
        {
          "name": "channel",
          "line": 96,
          "signature": "#[cfg(not(target_arch = \"wasm32\"))]\npub mod channel;",
          "documentation": "# forge-comm\n\nANVIL Communication Contract: message transport, envelopes, and protocol\nnegotiation for the Forge SDK.\n\nThis crate provides the inter-agent communication infrastructure for\nANVIL-compliant agents. It defines the message envelope format, the\ntransport trait for message delivery, built-in transport implementations,\nand protocol version negotiation.\n\n# Components\n\n- **Message envelope** -- [`AgentMessage`](message::AgentMessage) is the\n  fundamental unit of inter-agent communication, carrying sender/recipient\n  OAS DIDs, protocol identification, a JSON payload, and an optional\n  Ed25519 signature.\n- **Transport trait** -- [`MessageTransport`](transport::MessageTransport)\n  defines how agents send and receive messages. Implementations are\n  pluggable: channels, network sockets, message brokers, etc.\n- **NoopTransport** -- [`NoopTransport`](noop::NoopTransport) is the\n  default transport for standalone agents. It silently drops sent messages\n  and returns `NotConnected` on receive.\n- **ChannelTransport** -- [`ChannelTransport`](channel::ChannelTransport)\n  provides paired, bidirectional in-process communication using bounded\n  async channels.\n- **Protocol negotiation** -- [`negotiate_protocol`](protocol::negotiate_protocol)\n  selects the highest mutually supported protocol version between two agents.\n- **Error types** -- [`CommError`](error::CommError) covers all failure modes\n  in the communication layer with actionable, context-rich messages.\n\n# ANVIL Spec References\n\n- ANVIL Spec section 10 -- Communication Contract\n- ANVIL Spec section 10.1 -- Transport Model\n- ANVIL Spec section 10.2 -- Agent Message Envelope\n- ANVIL Spec section 10.3 -- Channel Lifecycle\n- ANVIL Spec section 10.4 -- Message Integrity\n- ANVIL Spec section 10.5 -- Protocol Negotiation\n\n# Examples\n\n## Standalone agent (no communication)\n\n```\nuse forge_comm::noop::NoopTransport;\nuse forge_comm::transport::MessageTransport;\n\nlet transport = NoopTransport;\n// Standalone agents use NoopTransport as their default.\n// send() silently drops messages, receive() returns NotConnected.\n```\n\n## In-process agent pair\n\n```\nuse forge_comm::channel::ChannelTransport;\nuse forge_comm::transport::MessageTransport;\nuse forge_comm::message::AgentMessage;\n\n# async fn example() -> Result<(), Box<dyn std::error::Error>> {\nlet (alice, bob) = ChannelTransport::new(16);\n\nlet msg = AgentMessage::new(\n    \"did:oas:l1fe:agent:alice\",\n    \"did:oas:l1fe:agent:bob\",\n    \"anvil.task.v1\",\n    \"request\",\n    serde_json::json!({\"task\": \"summarize\"}),\n);\nalice.send(msg).await?;\n\nlet received = bob.receive().await?;\nassert_eq!(received.sender, \"did:oas:l1fe:agent:alice\");\n# Ok(())\n# }\n```\n\n## Protocol negotiation\n\n```\nuse forge_comm::protocol::{ProtocolOffer, negotiate_protocol};\n\nlet offer = ProtocolOffer {\n    protocol: \"anvil.task\".to_string(),\n    versions: vec![\"v1\".to_string(), \"v2\".to_string()],\n    extensions: vec![\"streaming\".to_string()],\n};\n\nlet accept = negotiate_protocol(&offer, &[\"v1\", \"v2\", \"v3\"]).unwrap();\nassert_eq!(accept.version, \"v2\");\n```"
        },
        {
          "name": "error",
          "line": 97,
          "signature": "pub mod error;",
          "documentation": ""
        },
        {
          "name": "message",
          "line": 98,
          "signature": "pub mod message;",
          "documentation": ""
        },
        {
          "name": "noop",
          "line": 99,
          "signature": "pub mod noop;",
          "documentation": ""
        },
        {
          "name": "protocol",
          "line": 100,
          "signature": "pub mod protocol;",
          "documentation": ""
        },
        {
          "name": "transport",
          "line": 101,
          "signature": "pub mod transport;",
          "documentation": ""
        },
        {
          "name": "prelude",
          "line": 104,
          "signature": "pub mod prelude;",
          "documentation": "Re-exports of the most commonly used types."
        },
        {
          "name": "pub use crate::channel::ChannelTransport;",
          "line": 106,
          "signature": "#[cfg(not(target_arch = \"wasm32\"))]\npub use crate::channel::ChannelTransport;",
          "documentation": ""
        },
        {
          "name": "pub use crate::error::{CommError, CommResult};",
          "line": 107,
          "signature": "pub use crate::error::{CommError, CommResult};",
          "documentation": ""
        },
        {
          "name": "pub use crate::message::AgentMessage;",
          "line": 108,
          "signature": "pub use crate::message::AgentMessage;",
          "documentation": ""
        },
        {
          "name": "pub use crate::noop::NoopTransport;",
          "line": 109,
          "signature": "pub use crate::noop::NoopTransport;",
          "documentation": ""
        },
        {
          "name": "pub use crate::protocol::{negotiate_protocol, ProtocolAccept, ProtocolOffer};",
          "line": 110,
          "signature": "pub use crate::protocol::{negotiate_protocol, ProtocolAccept, ProtocolOffer};",
          "documentation": ""
        },
        {
          "name": "pub use crate::transport::MessageTransport;",
          "line": 111,
          "signature": "pub use crate::transport::MessageTransport;",
          "documentation": ""
        }
      ]
    },
    {
      "path": "forge-rs/crates/forge-comm/src/message.rs",
      "sha256": "a42919cfd41b1182096aa4c9950d6190390224837d9bb2b7de0b5172d2eb3668",
      "artifactSha256": "3659bbd79182ce7def0fd03645622797530b1e4c5f6fde8ed344e3d799c4bbe4",
      "url": "/reference/source/forge-rs/crates/forge-comm/src/message.rs.txt",
      "declarations": [
        {
          "name": "::NONCE_LEN",
          "line": 49,
          "signature": "pub const NONCE_LEN: usize;",
          "documentation": "Length in bytes of the replay-protection nonce."
        },
        {
          "name": "::AgentMessage",
          "line": 93,
          "signature": "#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]\npub struct AgentMessage {\n/// Unique message identifier (UUID v4).\n\npub id: String,\n/// Correlation ID linking related messages in a conversation.\n\n#[serde(skip_serializing_if = \"Option::is_none\")]\npub correlation_id: Option<String>,\n/// Message ID this is a direct reply to.\n\n#[serde(skip_serializing_if = \"Option::is_none\")]\npub reply_to: Option<String>,\n/// Sender's OAS DID.\n\npub sender: String,\n/// Recipient's OAS DID.\n\npub recipient: String,\n/// Protocol identifier (dot-separated, e.g., `\"anvil.task.v1\"`).\n\npub protocol: String,\n/// Message type within the protocol.\n\npub message_type: String,\n/// JSON payload, opaque to the transport layer.\n\npub payload: serde_json::Value,\n/// Ed25519 signature of the message (hex-encoded).\n\n///\n\n/// Computed over [`AgentMessage::signing_bytes`], which includes the\n\n/// replay-protection `nonce` and `timestamp_ms` fields. Verification\n\n/// uses the sender's public key resolved from their OAS DID document.\n\n#[serde(skip_serializing_if = \"Option::is_none\")]\npub signature: Option<String>,\n/// ISO 8601 creation timestamp (human-readable).\n\n///\n\n/// For replay protection use [`timestamp_ms`](Self::timestamp_ms); this\n\n/// field is retained for logging and audit trails.\n\npub timestamp: String,\n/// Unix-epoch milliseconds at send time. Covered by the signature.\n\n///\n\n/// `None` only for envelopes deserialized from a pre-replay-protection\n\n/// wire format. Present on every message produced by [`AgentMessage::new`].\n\n#[serde(skip_serializing_if = \"Option::is_none\")]\npub timestamp_ms: Option<i64>,\n/// 16-byte random nonce, hex-encoded. Covered by the signature.\n\n///\n\n/// `None` only for envelopes deserialized from a pre-replay-protection\n\n/// wire format. Present on every message produced by [`AgentMessage::new`].\n\n#[serde(skip_serializing_if = \"Option::is_none\")]\npub nonce: Option<String>\n}",
          "documentation": "An agent message envelope per ANVIL Spec section 10.2.\n\nThe `AgentMessage` is the fundamental unit of inter-agent communication.\nIt wraps a JSON payload with routing metadata (sender/recipient DIDs),\nprotocol identification, correlation tracking, and an optional\ncryptographic signature for integrity verification.\n\n# Replay Protection\n\n`nonce` and `timestamp_ms` are populated automatically by\n[`AgentMessage::new`]. They are covered by the Ed25519 signature produced\nover [`AgentMessage::signing_bytes`], so an attacker cannot mutate them\nwithout invalidating the signature. Receivers must feed these fields to\na [`forge_core::replay::ReplayValidator`] after verifying the signature.\n\nMessages deserialized from a pre-replay-protection wire format will have\n`nonce` and `timestamp_ms` as `None`; such messages are rejected unless\nthe operator opts into legacy acceptance \u2014 see\n[`AgentMessage::validate_replay`].\n\n# Fields\n\n| Field | Purpose |\n|-------|---------|\n| `id` | Unique message identifier (UUID v4) |\n| `correlation_id` | Links related messages in a conversation |\n| `reply_to` | Message ID this is a direct reply to |\n| `sender` | Sender's OAS DID |\n| `recipient` | Recipient's OAS DID |\n| `protocol` | Protocol identifier (e.g., `\"anvil.task.v1\"`) |\n| `message_type` | Message type within the protocol (e.g., `\"request\"`) |\n| `payload` | Arbitrary JSON payload |\n| `signature` | Optional Ed25519 signature (hex-encoded) |\n| `timestamp` | ISO 8601 creation timestamp |\n| `timestamp_ms` | Unix-epoch milliseconds (replay protection) |\n| `nonce` | 16-byte random nonce, hex-encoded (replay protection) |\n\n# ANVIL Spec Reference\n\n- ANVIL Spec section 10.2 -- Agent Message Envelope\n- ANVIL Spec section 10.4 -- Message Integrity"
        },
        {
          "name": "::AgentMessage::new",
          "line": 167,
          "signature": "pub fn new(\n        sender: impl Into<String>,\n        recipient: impl Into<String>,\n        protocol: impl Into<String>,\n        message_type: impl Into<String>,\n        payload: serde_json::Value,\n    ) -> Self;",
          "documentation": "Creates a new `AgentMessage` with a generated UUID, current timestamp,\nand fresh replay-protection fields (random nonce + `timestamp_ms`).\n\nThe message is created without a signature, correlation ID, or reply-to\nreference. Sign it with the sender's Ed25519 key over the output of\n[`signing_bytes`](Self::signing_bytes), then set [`signature`](Self::signature)\nto the hex-encoded signature bytes.\n\n# Arguments\n\n* `sender` - The sender's OAS DID string.\n* `recipient` - The recipient's OAS DID string.\n* `protocol` - The protocol identifier (e.g., `\"anvil.task.v1\"`).\n* `message_type` - The message type within the protocol.\n* `payload` - The JSON payload body."
        },
        {
          "name": "::AgentMessage::kind",
          "line": 197,
          "signature": "pub fn kind(&self) -> &str;",
          "documentation": "Returns the message type (backward-compatible accessor)."
        },
        {
          "name": "::AgentMessage::is_signed",
          "line": 203,
          "signature": "pub fn is_signed(&self) -> bool;",
          "documentation": "Returns whether this message has an Ed25519 signature."
        },
        {
          "name": "::AgentMessage::has_replay_fields",
          "line": 212,
          "signature": "pub fn has_replay_fields(&self) -> bool;",
          "documentation": "Returns `true` iff both replay-protection fields are populated.\n\nAn envelope lacking either field must not be accepted for replay\nchecking; see [`validate_replay`](Self::validate_replay) for the\nreceiver-side legacy-compat behavior."
        },
        {
          "name": "::AgentMessage::nonce_bytes",
          "line": 217,
          "signature": "pub fn nonce_bytes(&self) -> Option<[u8; NONCE_LEN]>;",
          "documentation": "Returns the nonce as raw bytes, if present and well-formed."
        },
        {
          "name": "::AgentMessage::with_correlation_id",
          "line": 223,
          "signature": "pub fn with_correlation_id(mut self, id: String) -> Self;",
          "documentation": "Sets the correlation ID, consuming and returning `self`."
        },
        {
          "name": "::AgentMessage::with_reply_to",
          "line": 229,
          "signature": "pub fn with_reply_to(mut self, id: String) -> Self;",
          "documentation": "Sets the reply-to message ID, consuming and returning `self`."
        },
        {
          "name": "::AgentMessage::with_replay_fields",
          "line": 239,
          "signature": "pub fn with_replay_fields(mut self, timestamp_ms: i64, nonce: [u8; NONCE_LEN]) -> Self;",
          "documentation": "Overrides the replay-protection fields with caller-supplied values.\n\nIntended for conformance harnesses and test vectors only. Production\ncode should rely on [`AgentMessage::new`] to populate these fields\nautomatically."
        },
        {
          "name": "::AgentMessage::signing_bytes",
          "line": 262,
          "signature": "pub fn signing_bytes(&self) -> Vec<u8>;",
          "documentation": "Canonical byte representation of the envelope, used as the input to\nthe Ed25519 signature.\n\nThe signature must cover every field that affects trust, including\nthe replay-protection `nonce` and `timestamp_ms`. This function\nserializes the envelope via `serde_json` with the `signature` field\nstripped, guaranteeing that verification always recomputes over the\nsame bytes the sender signed.\n\n# Determinism\n\n`serde_json` preserves struct field order as declared in the Rust\nsource, giving us deterministic output without pulling in a full\nJCS implementation. Non-Rust SDKs must match this struct's field\norder when building the signing bytes; the conformance suite enforces\nthis."
        },
        {
          "name": "::AgentMessage::validate_replay",
          "line": 287,
          "signature": "pub fn validate_replay(\n        &self,\n        validator: &forge_core::replay::ReplayValidator,\n    ) -> Result<(), forge_core::replay::ReplayError>;",
          "documentation": "Runs replay-protection checks against `validator`.\n\nCall this on the receiver after the Ed25519 signature has been\nverified. The flow is:\n\n1. If both `timestamp_ms` and `nonce` are present, forward them to\n   [`forge_core::replay::ReplayValidator::validate`].\n2. Otherwise delegate to\n   [`forge_core::replay::ReplayValidator::accept_legacy`], which\n   honors [`ReplayConfig::accept_legacy`] and the\n   `FORGE_ACCEPT_LEGACY_MESSAGES` env flag.\n\n# Errors\n\nReturns the underlying [`forge_core::replay::ReplayError`] on any\nvalidation failure."
        }
      ]
    },
    {
      "path": "forge-rs/crates/forge-comm/src/noop.rs",
      "sha256": "c130a342ec0876c2763898d588e5a57a283808a80ddfc179caccaa51cb9bf7ac",
      "artifactSha256": "428c43b459513ebd2a130d63bb72b9364a56f17c9468bb465a02b7fa3ee9cd97",
      "url": "/reference/source/forge-rs/crates/forge-comm/src/noop.rs.txt",
      "declarations": [
        {
          "name": "::NoopTransport",
          "line": 74,
          "signature": "#[derive(Debug, Clone, Copy, Default)]\npub struct NoopTransport;",
          "documentation": "A no-op message transport that drops sent messages and never receives.\n\n`NoopTransport` is the default transport for standalone agents that do\nnot participate in inter-agent messaging. It satisfies the\n[`MessageTransport`] trait contract with minimal overhead:\n\n- [`send`](MessageTransport::send) silently succeeds, dropping the message.\n- [`receive`](MessageTransport::receive) immediately returns\n  [`CommError::NotConnected`].\n\n# ANVIL Spec Reference\n\nANVIL Spec section 10.1 -- Communication Contract\n\n# Examples\n\n```\nuse forge_comm::noop::NoopTransport;\nuse forge_comm::transport::MessageTransport;\nuse forge_comm::message::AgentMessage;\n\n# async fn example() -> Result<(), Box<dyn std::error::Error>> {\nlet transport = NoopTransport;\n\n// Send always succeeds (message is dropped)\nlet msg = AgentMessage::new(\n    \"did:oas:l1fe:agent:a\",\n    \"did:oas:l1fe:agent:b\",\n    \"anvil.task.v1\",\n    \"request\",\n    serde_json::json!({}),\n);\ntransport.send(msg).await?;\n\n// Receive always fails with NotConnected\nlet result = transport.receive().await;\nassert!(result.is_err());\n# Ok(())\n# }\n```"
        }
      ]
    },
    {
      "path": "forge-rs/crates/forge-comm/src/protocol.rs",
      "sha256": "f8f3752d04f7740c0270fe78631bbb18270e23bf4630bc2e08e6aa651f9680c4",
      "artifactSha256": "50e514e02820f0e0d6133f3104359a45e59ed6f2c74b4d3c93d5d4732addfbd4",
      "url": "/reference/source/forge-rs/crates/forge-comm/src/protocol.rs.txt",
      "declarations": [
        {
          "name": "::ProtocolOffer",
          "line": 56,
          "signature": "#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]\npub struct ProtocolOffer {\n/// The protocol identifier (e.g., `\"anvil.task\"`).\n\n///\n\n/// This identifies the protocol family without a version suffix.\n\npub protocol: String,\n/// The versions the offering agent supports, ordered by preference.\n\n///\n\n/// Version strings follow the pattern `\"v1\"`, `\"v2\"`, etc. The first\n\n/// version in the list is the most preferred by the offering agent.\n\npub versions: Vec<String>,\n/// Optional extensions the offering agent supports.\n\n///\n\n/// Extensions are additional capabilities within the protocol, such as\n\n/// `\"streaming\"`, `\"compression\"`, or `\"batching\"`. Both agents must\n\n/// agree on extensions for them to be active.\n\npub extensions: Vec<String>\n}",
          "documentation": "A protocol version offer sent during negotiation.\n\nThe offering agent lists all protocol versions it supports, ordered\nby preference (first is most preferred). Extensions are optional\ncapabilities the offering agent supports within the protocol.\n\n# ANVIL Spec Reference\n\nANVIL Spec section 10.5 -- Protocol Negotiation\n\n# Examples\n\n```\nuse forge_comm::protocol::ProtocolOffer;\n\nlet offer = ProtocolOffer {\n    protocol: \"anvil.task\".to_string(),\n    versions: vec![\"v2\".to_string(), \"v1\".to_string()],\n    extensions: vec![\"compression\".to_string(), \"batching\".to_string()],\n};\nassert_eq!(offer.protocol, \"anvil.task\");\nassert_eq!(offer.versions.len(), 2);\n```"
        },
        {
          "name": "::ProtocolAccept",
          "line": 99,
          "signature": "#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]\npub struct ProtocolAccept {\n/// The agreed-upon protocol identifier.\n\npub protocol: String,\n/// The agreed-upon version string.\n\npub version: String,\n/// The extensions active for this protocol session.\n\n///\n\n/// This is the full set of extensions from the offer, carried through\n\n/// to the acceptance. In a full implementation, this would be intersected\n\n/// with the accepting agent's supported extensions.\n\npub extensions: Vec<String>\n}",
          "documentation": "An accepted protocol version resulting from successful negotiation.\n\nContains the agreed-upon protocol, version, and the subset of extensions\nthat both agents support.\n\n# ANVIL Spec Reference\n\nANVIL Spec section 10.5 -- Protocol Negotiation\n\n# Examples\n\n```\nuse forge_comm::protocol::ProtocolAccept;\n\nlet accept = ProtocolAccept {\n    protocol: \"anvil.task\".to_string(),\n    version: \"v2\".to_string(),\n    extensions: vec![\"streaming\".to_string()],\n};\nassert_eq!(accept.protocol, \"anvil.task\");\nassert_eq!(accept.version, \"v2\");\n```"
        },
        {
          "name": "::negotiate_protocol",
          "line": 154,
          "signature": "pub fn negotiate_protocol(\n    offered: &ProtocolOffer,\n    supported_versions: &[&str],\n) -> Result<ProtocolAccept, CommError>;",
          "documentation": "Negotiate the best matching protocol version between offered and supported.\n\nExamines the offered versions and selects the highest one (by position\nin `supported_versions`) that appears in both the offer and the supported\nlist. \"Highest\" means the last matching entry in `supported_versions`,\nwhich should be ordered from oldest to newest.\n\nIf no version matches, returns [`CommError::ProtocolNegotiationFailed`].\n\n# Arguments\n\n* `offered` - The protocol offer from the remote agent.\n* `supported_versions` - The versions the local agent supports, ordered\n  from oldest to newest (e.g., `[\"v1\", \"v2\", \"v3\"]`).\n\n# Returns\n\nA [`ProtocolAccept`] with the negotiated version and the offered extensions,\nor a [`CommError::ProtocolNegotiationFailed`] if no version matches.\n\n# ANVIL Spec Reference\n\nANVIL Spec section 10.5 -- Protocol Negotiation\n\n# Examples\n\n```\nuse forge_comm::protocol::{ProtocolOffer, negotiate_protocol};\n\nlet offer = ProtocolOffer {\n    protocol: \"anvil.task\".to_string(),\n    versions: vec![\"v1\".to_string(), \"v2\".to_string()],\n    extensions: vec![],\n};\n\n// We support v2 and v3, so v2 is the match\nlet accept = negotiate_protocol(&offer, &[\"v2\", \"v3\"]).unwrap();\nassert_eq!(accept.version, \"v2\");\n```"
        }
      ]
    },
    {
      "path": "forge-rs/crates/forge-comm/src/transport.rs",
      "sha256": "308622255b99934d699e2a41452ca5ec329c82b11799e80d76b24e3dab3098bd",
      "artifactSha256": "a99793abd92acb0156fbc186976af53808289bff12a4fa183b5de2cc6faf0fc1",
      "url": "/reference/source/forge-rs/crates/forge-comm/src/transport.rs.txt",
      "declarations": [
        {
          "name": "::MessageTransport",
          "line": 59,
          "signature": "#[async_trait::async_trait]\npub trait MessageTransport: Send + Sync {\n    /// Send a message to the recipient identified in the message envelope.\n    ///\n    /// The transport delivers the message to the recipient's receive queue.\n    /// Delivery semantics (at-most-once, at-least-once, exactly-once) depend\n    /// on the specific transport implementation.\n    ///\n    /// # Arguments\n    ///\n    /// * `message` - The agent message envelope to send.\n    ///\n    /// # Errors\n    ///\n    /// Returns [`CommError::TransportFailed`] if the underlying mechanism fails,\n    /// [`CommError::ChannelClosed`] if the peer endpoint has been dropped, or\n    /// [`CommError::MessageTooLarge`] if the message exceeds transport limits.\n    async fn send(&self, message: AgentMessage) -> Result<(), CommError>;\n\n    /// Receive the next available message.\n    ///\n    /// This method waits asynchronously until a message arrives or an error\n    /// occurs. The specific blocking behavior depends on the transport\n    /// implementation: channel transports suspend the current task, while\n    /// network transports may perform I/O polling.\n    ///\n    /// # Errors\n    ///\n    /// Returns [`CommError::NotConnected`] if the transport is not active,\n    /// [`CommError::ChannelClosed`] if the peer endpoint has been dropped, or\n    /// [`CommError::TransportFailed`] for other transport-level failures.\n    async fn receive(&self) -> Result<AgentMessage, CommError>;\n\n    /// Receive the next available message and enforce replay protection.\n    ///\n    /// This is the preferred receive path for any caller that has already\n    /// verified the sender's Ed25519 signature (or is about to, in a\n    /// subsequent step). It delegates to [`receive`](Self::receive) to pull\n    /// the next envelope off the wire, then calls\n    /// [`AgentMessage::validate_replay`](crate::message::AgentMessage::validate_replay)\n    /// with the provided `validator`.\n    ///\n    /// The replay validator enforces two invariants (see\n    /// [`forge_core::replay::ReplayValidator`]):\n    ///\n    /// 1. The envelope's `timestamp_ms` must be within the validator's\n    ///    configured clock-skew window.\n    /// 2. The envelope's `nonce` must not have been seen before, within the\n    ///    validity window.\n    ///\n    /// Legacy envelopes (no `nonce`/`timestamp_ms`) are rejected unless the\n    /// validator has been configured with `accept_legacy = true` or the\n    /// `FORGE_ACCEPT_LEGACY_MESSAGES=true` env flag is honored by the\n    /// caller's [`forge_core::replay::ReplayConfig`].\n    ///\n    /// # Errors\n    ///\n    /// - Any error returned by [`receive`](Self::receive).\n    /// - [`CommError::ReplayDetected`] if replay protection rejects the\n    ///   message.\n    async fn receive_validated(\n        &self,\n        validator: &ReplayValidator,\n    ) -> Result<AgentMessage, CommError> ;\n}",
          "documentation": "The message transport contract for ANVIL-compliant agent communication.\n\nImplementations of this trait provide the mechanism by which agents\nexchange [`AgentMessage`] envelopes. The trait is intentionally minimal:\nsend a message, receive a message. Higher-level concerns (protocol\nnegotiation, message routing, retry logic) are handled by upper layers.\n\n# Thread Safety\n\nAll implementations must be `Send + Sync` to allow shared ownership\nacross async tasks.\n\n# ANVIL Spec Reference\n\nANVIL Spec section 10.1 -- Communication Contract\n\n# Examples\n\n```\nuse forge_comm::transport::MessageTransport;\nuse forge_comm::noop::NoopTransport;\n\nlet transport = NoopTransport;\n// NoopTransport is a valid MessageTransport (compile-time check)\nfn assert_transport(_: &impl MessageTransport) {}\nassert_transport(&transport);\n```"
        }
      ]
    }
  ]
}
