MAP Docs
SDKs

Rust

The reference SDK. macs-sdk, marc-sdk, mata-sdk, plugin-sdk. Async/await, tokio-native.

The Rust SDKs are the reference clients for MAP. They live in /Volumes/L1feAI/l1feosx/map/sdks/rust/ and use the same engine/common types the engine itself uses — no translation layer.

Installation

The SDKs are published as part of the MAP workspace. Until they're on crates.io, depend by git ref:

[dependencies]
macs-sdk   = { git = "https://github.com/l1fe-ai/map", package = "macs-sdk" }
marc-sdk   = { git = "https://github.com/l1fe-ai/map", package = "marc-sdk" }
mata-sdk   = { git = "https://github.com/l1fe-ai/map", package = "mata-sdk" }
plugin-sdk = { git = "https://github.com/l1fe-ai/map", package = "plugin-sdk" }
tokio      = { version = "1", features = ["macros", "rt-multi-thread"] }
serde_json = "1"

MacsClient

For authentication, capability derivation, and identity verification.

use macs_sdk::{MacsClient, AuthNegotiationPayload, AuthProfile, ChallengeKind};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = MacsClient::from_env()?;

    let negotiation = client.auth_negotiation(AuthNegotiationPayload {
        profile: AuthProfile::DidAuth,
        challenge_kind: ChallengeKind::Nonce,
    }).await?;

    let challenge = client.generate_challenge(&negotiation.session_id).await?;
    let signed = sign_challenge_with_my_key(&challenge.nonce)?;
    let verified = client.verify_response(&challenge.session_id, &signed).await?;

    println!("verified envelope: {:#?}", verified);
    Ok(())
}

MarcClient

For reasoning tasks and model publishing.

use marc_sdk::{MarcClient, ReasoningTaskPayload, Budget};
use serde_json::json;

let client = MarcClient::from_env()?;
let resp = client.reasoning_task(ReasoningTaskPayload {
    intent: "Is the proposed treaty enforceable under the active charter?".into(),
    premises: vec![
        "mars://treaty/0x91a".into(),
        "mars://policy/0x12c".into(),
    ],
    world_model_snapshot: Some("mind://snapshot/0x4f81b3a".into()),
    budget: Budget { tokens: 32_000, deadline_ms: 12_000 },
    return_fields: vec!["derivation".into(), "citations".into(), "confidence".into()],
}).await?;

println!("verdict: {}",         resp.verdict);
println!("derivation: {:?}",    resp.derivation_ref);
println!("citations: {:?}",     resp.citations);
println!("confidence band: {:?}", resp.confidence);

MataClient

For trust scores and reputation updates.

use mata_sdk::{MataClient, PoolPayload};

let client = MataClient::from_env()?;
let pooled = client.pool(PoolPayload {
    target_claim: "did:oas:l1fe:agent:0xa3f...".into(),
    sources: vec!["maven://0x12...".into(), "maven://0xb4...".into()],
}).await?;
println!("composite credence: {}", pooled.credence);

plugin-sdk

For developers building Tier-2 WASI plugins. Provides:

  • PluginManifest builder with type-checked operations
  • wit-bindgen-derived bindings to the engine ABI
  • A protocol_module! macro that generates the boilerplate ProtocolModule impl from a plain function table
use plugin_sdk::{protocol_module, InvokeContext, Response, ProtocolError};
use serde_json::Value;

protocol_module! {
    name = "MYPROTOCOL";
    version = "v0.1.0";
    operations {
        async fn hello(payload: Value, ctx: &InvokeContext) -> Result<Response, ProtocolError> {
            let id = ctx.identity().ok_or_else(|| ProtocolError::PolicyDenied { reason: "unresolved".into() })?;
            Ok(Response { data: serde_json::json!({ "greeting": format!("hello, {}", id.did) }), metadata: None })
        }
    }
}

Build for WASI:

cargo build --release --target wasm32-wasip2
# Bundle with plugin.toml manifest

Authentication

Every SDK constructor uses from_env() which reads in order:

  1. Explicit constructor args
  2. Env vars: MAP_API_KEY, MAP_AGENT_DID, MAP_API_URL
  3. CLI config at ~/.map/config.json

To pass explicitly:

let client = MacsClient::new(macs_sdk::Config {
    api_url: "https://api.multiagentic.dev".parse()?,
    api_key: std::env::var("MAP_API_KEY")?,
    agent_did: "did:oas:l1fe:agent:0xa3f...".into(),
    tenant_id: "org_acme".into(),
});

Error model

Every SDK shares the MapError enum:

#[derive(thiserror::Error, Debug)]
pub enum MapError {
    #[error("rate limited; retry after {0:?}")]
    RateLimited(std::time::Duration),

    #[error("capability denied: {protocol}.{operation}")]
    CapabilityDenied { protocol: String, operation: String },

    #[error("circuit open for {0}")]
    CircuitOpen(String),

    #[error("timeout")]
    Timeout,

    #[error("policy denied: {0}")]
    PolicyDenied(String),

    #[error("transport: {0}")]
    Transport(#[from] reqwest::Error),

    #[error("decode: {0}")]
    Decode(#[from] serde_json::Error),

    #[error("other: {0}")]
    Other(String),
}

Match on the variant for retry policy:

match client.dispatch(...).await {
    Err(MapError::RateLimited(retry)) => {
        tokio::time::sleep(retry).await;
        // retry once
    }
    Err(MapError::CapabilityDenied { protocol, operation }) => {
        anyhow::bail!("need capability map.{}.{}", protocol.to_lowercase(), operation);
    }
    Ok(resp) => { /* ... */ }
    Err(e) => { return Err(e.into()); }
}

Trace context

If your service is OTEL-instrumented, the SDK reads the active span automatically:

use opentelemetry::trace::TraceContextExt;
let span = opentelemetry::Context::current().span();
let resp = client.dispatch(...).with_span(&span).await?;

Otherwise, you can supply a trace context explicitly:

use map_common::TraceContext;
let resp = client.dispatch(...).with_trace(TraceContext::new("00-4f81b3a...-...-01")).await?;

Code-property guarantees

The SDKs share the engine's strict properties:

  • #![forbid(unsafe_code)]
  • #![deny(clippy::unwrap_used)]
  • Feature flags: native-adapter (default), wasm-adapter (WASIP2 target)

Working with the workspace. If you're contributing to the SDKs, run cargo test -p macs-sdk from the workspace root. Tests use MockTransport for offline development.

See also

On this page