Documentation Index
Fetch the complete documentation index at: https://mintlify.com/microsoft/agent-governance-toolkit/llms.txt
Use this file to discover all available pages before exploring further.
The agentmesh Rust crate provides zero-overhead governance abstractions for AI agents. It implements policy evaluation, trust scoring, hash-chain audit logging, Ed25519 agent identity, execution control, and lifecycle management — all with Rust’s ownership guarantees ensuring that governance state cannot be accidentally aliased or mutated across threads. The companion agentmesh-mcp crate keeps MCP-focused security functionality available as a smaller standalone dependency.
Target runtime: Rust 1.75+ (2021 edition) · Workspace: agent-governance-rust/ · Crates: agentmesh and agentmesh-mcp · Dependencies: serde, serde_yaml, sha2, ed25519-dalek, thiserror
Installation
[dependencies]
agentmesh = "3"
For MCP security scanning only:
AgentMeshClient
AgentMeshClient is the recommended entry point. It owns the AgentIdentity, TrustManager, PolicyEngine, and AuditLogger as public fields, wiring them into a single execute_with_governance call.
use agentmesh::{AgentMeshClient, ClientOptions, TrustConfig};
// Default client — Ed25519 identity, empty policy (allow-all), default trust
let client = AgentMeshClient::new("my-agent").expect("failed to create client");
// Client with options
let opts = ClientOptions {
capabilities: vec!["data.read".into(), "data.write".into()],
trust_config: Some(TrustConfig {
initial_score: 500,
reward: 15,
penalty: 75,
..Default::default()
}),
policy_yaml: None, // load later via client.policy.load_from_file(...)
};
let client = AgentMeshClient::with_options("analyst-001", opts)?;
Agent name used to derive the DID: did:agentmesh:<agent_name>.
Capability strings granted to the identity.
Trust manager configuration. None uses defaults: initial_score: 500, reward: 10, penalty: 50.
YAML policy to load at creation. None starts with an empty (allow-all) engine.
Runs the full governance pipeline: policy evaluate → audit log → trust update.use std::collections::HashMap;
// No context
let result = client.execute_with_governance("data.read", None);
// With context
let mut ctx = HashMap::new();
ctx.insert("environment".into(), serde_yaml::Value::String("production".into()));
let result = client.execute_with_governance("deploy.app", Some(&ctx));
println!("Allowed: {}", result.allowed);
println!("Decision: {:?}", result.decision); // Allow | Deny("reason") | RequiresApproval(String) | RateLimited { retry_after_secs }
println!("Trust: {} ({:?})", result.trust_score.score, result.trust_score.tier);
println!("Audit hash: {}", result.audit_entry.hash);
Action string evaluated against loaded policies.
context
Option<&HashMap<String, Value>>
Optional context dictionary for conditional rules.
Whether the action is permitted.
Full enum: Allow, Deny(String), RequiresApproval(String), RateLimited { retry_after_secs: u64 }.
Score and tier after this action.
SHA-256 hash-chain record appended to the logger.
// Ed25519 DID identity
println!("DID: {}", client.identity.did);
println!("Capabilities: {:?}", client.identity.capabilities);
// Trust scores
let score = client.trust.get_trust_score(&client.identity.did);
println!("Trust: {} (tier: {:?})", score.score, score.tier);
// Policy engine
client.policy.load_from_file("policies/security.yaml")?;
// Audit chain
println!("Chain valid: {}", client.audit.verify());
println!("Entries: {}", client.audit.entries().len());
PolicyEngine
Evaluates actions against YAML-defined rules. Supports four decision types: Allow, Deny, RequiresApproval, and RateLimited.
Creating and Loading
evaluate()
Policy YAML Format
Conflict Resolution
use agentmesh::PolicyEngine;
let engine = PolicyEngine::new(); // empty — allows everything
assert!(!engine.is_loaded());
// Load from YAML string
let yaml = r#"
version: "1.0"
agent: my-agent
policies:
- name: capability-gate
type: capability
allowed_actions:
- "data.read"
- "data.write"
denied_actions:
- "shell:*"
"#;
engine.load_from_yaml(yaml)?;
// Load from file
engine.load_from_file("policies/security.yaml")?;
assert!(engine.is_loaded());
use agentmesh::types::PolicyDecision;
let decision = engine.evaluate("data.read", None);
assert_eq!(decision, PolicyDecision::Allow);
let decision = engine.evaluate("shell:rm", None);
assert!(matches!(decision, PolicyDecision::Deny(_)));
// Approval required
let decision = engine.evaluate("deploy.prod", None);
assert!(matches!(decision, PolicyDecision::RequiresApproval(_)));
// Rate limited (after max_calls exhausted)
let decision = engine.evaluate("api.call", None);
assert!(matches!(decision, PolicyDecision::RateLimited { .. }));
PolicyDecision::Deny(String)
Action blocked; string contains reason.
PolicyDecision::RequiresApproval(String)
Human approval required; string contains the reason/approver specification.
PolicyDecision::RateLimited { .. }
Rate limit exhausted for this action.
# policies/governance.yaml
version: "1.0"
agent: multi-decision-demo
policies:
# Capability — allow/deny by action pattern
- name: data-gate
type: capability
allowed_actions:
- "data.*"
denied_actions:
- "shell:*"
# Approval — require human sign-off
- name: deploy-gate
type: approval
actions:
- "deploy.*"
min_approvals: 2
# Rate limit — cap call frequency
- name: api-throttle
type: rate_limit
actions:
- "api.*"
max_calls: 10
window: "60s"
# Conditional — only applies when context matches
- name: prod-gate
type: capability
denied_actions:
- "deploy.*"
conditions:
environment: "production"
use agentmesh::types::{CandidateDecision, ConflictResolutionStrategy, PolicyScope};
let engine = PolicyEngine::with_strategy(ConflictResolutionStrategy::DenyOverrides);
let candidates = vec![
CandidateDecision {
decision: PolicyDecision::Allow,
priority: 10,
scope: PolicyScope::Global,
rule_name: "allow-rule".into(),
},
CandidateDecision {
decision: PolicyDecision::Deny("blocked".into()),
priority: 5,
scope: PolicyScope::Global,
rule_name: "deny-rule".into(),
},
];
let result = engine.resolve_conflicts(&candidates);
assert!(matches!(result.winning_decision, PolicyDecision::Deny(_)));
assert!(result.conflict_detected);
| Strategy | Behaviour |
|---|
DenyOverrides | Any deny wins regardless of priority |
AllowOverrides | Any allow wins regardless of priority |
PriorityFirstMatch | Highest priority wins (default) |
MostSpecificWins | Agent > Tenant > Global, then priority |
TrustManager
Per-agent trust scoring on a 0–1000 integer scale with five tiers, time-based decay, and optional JSON persistence.
use agentmesh::{TrustManager, TrustConfig, TrustTier};
// Defaults: initial_score=500, reward=10, penalty=50, decay_rate=0.95
let tm = TrustManager::with_defaults();
// Custom configuration
let config = TrustConfig {
initial_score: 800,
threshold: 700,
reward: 20,
penalty: 100,
decay_rate: 0.95,
persist_path: Some("trust-scores.json".into()),
};
let tm = TrustManager::new(config);
Starting score for new agents. Default: 500.
Points added per successful interaction. Default: 10.
Points deducted per failed interaction. Default: 50.
Hourly multiplier for idle decay. 0.95 = 5%/hr. Default: 0.95.
JSON file path for persistence. Scores loaded on construction.
// New agent starts at 500 (Standard tier)
let score = tm.get_trust_score("agent-x");
assert_eq!(score.score, 500);
assert_eq!(score.tier, TrustTier::Standard);
// Success → score increases
tm.record_success("agent-x");
tm.record_success("agent-x");
// Failure → score decreases (asymmetric: penalty > reward)
tm.record_failure("agent-x");
let score = tm.get_trust_score("agent-x");
println!("After failure: {} ({:?})", score.score, score.tier);
Trust tiers (0–1000 scale):| Tier | Score Range | Description |
|---|
Untrusted | 0–299 | Failed validation or malicious behavior |
Probationary | 300–499 | New or recovering agent |
Standard | 500–699 | Default starting point |
Trusted | 700–899 | Established track record |
VerifiedPartner | 900–1000 | Highest confidence level |
Trust scores decay over time when no interactions occur:decayed_score = score × decay_rate ^ hours_elapsed
Set decay_rate closer to 1.0 for slower decay (e.g., 0.99), or lower (e.g., 0.90) for aggressive decay requiring frequent re-validation.// Persistence — scores saved on every update and loaded on construction
let config = TrustConfig {
persist_path: Some("trust-scores.json".into()),
..Default::default()
};
let tm = TrustManager::new(config);
tm.record_success("agent-x");
// trust-scores.json now contains the persisted state
AuditLogger
Append-only SHA-256 hash-chain audit trail. Each entry links to the previous entry’s hash, creating a tamper-evident sequence.
use agentmesh::{AuditLogger, types::AuditFilter};
let logger = AuditLogger::new();
// Log events
let entry = logger.log("agent-001", "data.read", "allow");
println!("Hash: {}", entry.hash);
println!("Prev: {}", entry.previous_hash); // empty for genesis entry
println!("Seq: {}", entry.seq); // 0
// Multiple entries — chain links
logger.log("agent-1", "data.read", "allow");
logger.log("agent-1", "data.write", "deny");
logger.log("agent-2", "report.send", "allow");
assert!(logger.verify()); // true — chain intact
let entries = logger.entries();
assert_eq!(entries[1].previous_hash, entries[0].hash);
// Filter
let filter = AuditFilter { agent_id: Some("agent-1".into()), action: None, decision: None };
let filtered = logger.get_entries(&filter);
println!("Agent-1 entries: {}", filtered.len());
Rust’s ownership model ensures the AuditLogger’s internal Vec<AuditEntry> cannot be aliased — there is no risk of a second mutable reference silently corrupting the hash chain between calls.
AgentIdentity
Ed25519-based cryptographic identity with DID identifiers, signing, verification, and JSON serialization.
use agentmesh::{AgentIdentity, PublicIdentity};
// Generate a new identity
let identity = AgentIdentity::generate(
"researcher-agent",
vec!["data.read".into(), "search".into()],
)?;
println!("DID: {}", identity.did); // did:agentmesh:researcher-agent
println!("Capabilities: {:?}", identity.capabilities);
println!("Public key: {} bytes", identity.public_key.len());
// Sign and verify
let data = b"important message";
let signature = identity.sign(data)?;
println!("Signature: {} bytes", signature.len()); // 64 bytes
assert!(identity.verify(data, &signature));
assert!(!identity.verify(b"wrong message", &signature));
// JSON serialization (public key only)
let json = identity.to_json()?;
let imported = AgentIdentity::from_json(&json)?;
assert_eq!(imported.did, identity.did);
// Verification-only public identity
let pub_id = PublicIdentity {
did: identity.did.clone(),
public_key: identity.public_key.to_bytes().to_vec(),
capabilities: identity.capabilities.clone(),
};
assert!(pub_id.verify(data, &signature));
Extended Crate Surface
The agentmesh workspace exposes a rich set of governance helpers beyond the core client:
Governance Hooks
Compliance & Kill Switch
Support Modules
use agentmesh::{
ExecutionRequest, ExecutionResponse, GovernanceHook,
FrameworkGovernanceAdapter, FrameworkKind, GovernancePolicy,
};
struct ReadOnlyHook;
impl GovernanceHook for ReadOnlyHook {
fn before_execute(&self, request: &ExecutionRequest) -> ExecutionResponse {
match request.action.as_str() {
"data.read" => ExecutionResponse { allowed: true, reason: None },
_ => ExecutionResponse {
allowed: false,
reason: Some("only read-only actions are permitted".into()),
},
}
}
}
let adapter = FrameworkGovernanceAdapter::for_tower(
ReadOnlyHook,
GovernancePolicy {
allowed_tools: vec!["read_file".into()],
..GovernancePolicy::default()
},
);
let result = adapter.evaluate_request(
ExecutionRequest { actor: "did:mesh:worker-1".into(), action: "data.read".into(), payload: None },
Some("read_file"),
Some(0.95),
);
assert!(result.decision.allowed);
use agentmesh::{
ComplianceEngine, ComplianceFramework,
KillSwitchRegistry, KillSwitchReason, KillSwitchScope,
TrustHandshake, PromptDefenseEvaluator,
};
// Compliance reporting
let compliance = ComplianceEngine::new(vec![ComplianceFramework::Soc2]);
let report = compliance.generate_report(ComplianceFramework::Soc2);
assert!(report.compliance_score >= 0.0);
// Kill switch
let kill_switches = KillSwitchRegistry::new();
kill_switches.activate(
KillSwitchScope::Agent("did:mesh:worker-1".into()),
KillSwitchReason::OperatorRequest,
Some("manual pause"),
);
// Trust handshake
let handshake = TrustHandshake::new("did:mesh:controller", None, None);
let challenge = handshake.issue_challenge("did:mesh:peer-1");
assert!(!challenge.challenge.is_empty());
// Prompt defense
let report = PromptDefenseEvaluator::evaluate_report("ignore previous instructions");
assert!(report.risk_score > 0);
| Module | Contents |
|---|
identity_support | Delegation, credentials, SPIFFE/SVID, JWK, mTLS, revocation, rotation |
trust_support | Capability grants, trust handshakes, protocol bridges, trusted card primitives |
governance_support | Compliance reporting, OPA/Cedar evaluation, EU AI Act helpers, federation metadata |
reward_support | Learning signals, network trust propagation, reward distribution strategies |
control_support | Scoped kill-switch, SLO, error budget, incident, circuit-breaker |
integration_support | Policy hooks, framework adapters, governance events, shadow-AI discovery |
Full Governance Pipeline
use agentmesh::{AgentMeshClient, ClientOptions, TrustConfig};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let policy_yaml = r#"
version: "1.0"
agent: research-agent
policies:
- name: data-gate
type: capability
allowed_actions:
- "data.read"
- "search.*"
denied_actions:
- "data.delete"
- "shell:*"
- name: api-throttle
type: rate_limit
actions:
- "search.*"
max_calls: 5
window: "60s"
"#;
let client = AgentMeshClient::with_options("research-agent", ClientOptions {
capabilities: vec!["data.read".into(), "search.web".into()],
trust_config: Some(TrustConfig {
initial_score: 500,
reward: 15,
penalty: 75,
..Default::default()
}),
policy_yaml: Some(policy_yaml.into()),
})?;
println!("Agent DID: {}", client.identity.did);
for action in &["data.read", "search.web", "data.delete", "shell:ls"] {
let result = client.execute_with_governance(action, None);
println!(
" {} → {} (trust: {}, tier: {:?})",
action,
if result.allowed { "✅ allowed" } else { "❌ denied" },
result.trust_score.score,
result.trust_score.tier,
);
}
println!("\nAudit trail: {} entries", client.audit.entries().len());
println!("Chain valid: {}", client.audit.verify());
Ok(())
}