Build governance-aware AI agents in Go. The agentmesh module provides
Ed25519 cryptographic identity, trust scoring, declarative policy evaluation,
and hash-chain audit logging — all in a single go get.
Target runtime: Go 1.21+ Module:
github.com/microsoft/agent-governance-toolkit/sdks/goPackage:agentmesh
| Section | Topic |
|---|---|
| Quick Start | Evaluate a policy in 5 lines of Go |
| AgentMeshClient | Unified governance pipeline — identity + trust + policy + audit |
| PolicyEngine | Declarative rules, YAML policies, rate limiting, approval |
| TrustManager | Trust scoring with decay, tiers, and file persistence |
| AuditLogger | Hash-chain audit logging and verification |
| AgentIdentity | Ed25519 key pairs, DIDs, signing, JSON serialisation |
| Loading Policies from YAML | File-based policy configuration |
| Full Governance Pipeline | End-to-end example |
| Cross-Reference | Equivalent Python and TypeScript tutorials |
| Next Steps | Where to go from here |
- Go 1.21+
- Familiarity with Go modules (
go.mod) - Recommended: read Tutorial 01 — Policy Engine for governance concepts
go get github.com/microsoft/agent-governance-toolkit/sdks/goThe module has a single external dependency — gopkg.in/yaml.v3 for YAML
policy parsing.
# Verify the install
go list -m github.com/microsoft/agent-governance-toolkit/sdks/goFive lines to create a governed agent:
package main
import (
"fmt"
agentmesh "github.com/microsoft/agent-governance-toolkit/sdks/go"
)
func main() {
client, err := agentmesh.NewClient("my-agent")
if err != nil {
panic(err)
}
result, _ := client.ExecuteWithGovernance("data.read", nil)
fmt.Println("Allowed:", result.Allowed) // true
fmt.Println("Decision:", result.Decision) // allow
}When no policy rules are provided, the default decision is deny — secure by default.
Or configure at creation with functional options:
client, err := agentmesh.NewClient("my-agent",
agentmesh.WithCapabilities([]string{"data.read", "data.write"}),
agentmesh.WithPolicyRules([]agentmesh.PolicyRule{
{Action: "data.read", Effect: agentmesh.Allow},
{Action: "data.write", Effect: agentmesh.Allow},
{Action: "*", Effect: agentmesh.Deny},
}),
)AgentMeshClient is the recommended entry point. It wires together identity,
trust, policy, and audit into a single governance-aware pipeline.
// Default client — generates identity, no policy rules (deny-all)
client, err := agentmesh.NewClient("analyst-001")
// Client with functional options
client, err := agentmesh.NewClient("analyst-001",
agentmesh.WithCapabilities([]string{"data.read", "search"}),
agentmesh.WithTrustConfig(agentmesh.TrustConfig{
InitialScore: 0.8,
DecayRate: 0.01,
RewardFactor: 1.0,
PenaltyFactor: 1.5,
TierThresholds: agentmesh.TierThresholds{High: 0.8, Medium: 0.5},
}),
agentmesh.WithPolicyRules([]agentmesh.PolicyRule{
{Action: "data.read", Effect: agentmesh.Allow},
{Action: "*", Effect: agentmesh.Deny},
}),
)| Option | Description |
|---|---|
WithCapabilities([]string) |
Set capabilities on the generated identity |
WithTrustConfig(TrustConfig) |
Override default trust configuration |
WithPolicyRules([]PolicyRule) |
Set initial policy rules |
// Identity
fmt.Println("DID:", client.Identity.DID)
fmt.Println("Capabilities:", client.Identity.Capabilities)
// Trust
score := client.Trust.GetTrustScore(client.Identity.DID)
fmt.Println("Trust:", score.Overall, "Tier:", score.Tier)
// Audit
fmt.Println("Chain valid:", client.Audit.Verify())ExecuteWithGovernance runs the full pipeline: evaluate → log → trust update.
result, err := client.ExecuteWithGovernance("data.read", nil)
fmt.Println("Allowed:", result.Allowed)
fmt.Println("Decision:", result.Decision)
fmt.Println("Trust:", result.TrustScore.Overall)
fmt.Println("Audit hash:", result.AuditEntry.Hash)When the decision is Allow, trust increases. When it's Deny, trust
decreases. The audit entry is always appended to the chain.
The PolicyEngine evaluates actions against a set of rules. Rules are evaluated
in order; first match wins. The default decision when no rule matches is
Deny.
rules := []agentmesh.PolicyRule{
{Action: "data.read", Effect: agentmesh.Allow},
{Action: "data.write", Effect: agentmesh.Allow},
{Action: "deploy.*", Effect: agentmesh.Review},
{Action: "shell.*", Effect: agentmesh.Deny},
{Action: "*", Effect: agentmesh.Deny}, // catch-all
}
engine := agentmesh.NewPolicyEngine(rules)
fmt.Println(engine.Evaluate("data.read", nil)) // allow
fmt.Println(engine.Evaluate("shell.exec", nil)) // deny
fmt.Println(engine.Evaluate("deploy.prod", nil)) // review
fmt.Println(engine.Evaluate("unknown", nil)) // deny (catch-all)| Decision | Constant | Description |
|---|---|---|
| Allow | agentmesh.Allow |
Action is permitted |
| Deny | agentmesh.Deny |
Action is blocked |
| Review | agentmesh.Review |
Action requires human review |
| Rate Limit | agentmesh.RateLimit |
Action is rate-limited |
| Requires Approval | agentmesh.RequiresApproval |
Action needs explicit approval |
The engine supports glob-style action matching:
| Pattern | Matches | Does Not Match |
|---|---|---|
* |
Everything | — |
data.* |
data.read, data.write |
shell.exec |
shell.* |
shell.exec, shell.ls |
data.read |
data.read |
data.read (exact) |
data.write |
Rules can include conditions matched against a context map:
rules := []agentmesh.PolicyRule{
{
Action: "deploy.*",
Effect: agentmesh.Deny,
Conditions: map[string]interface{}{"environment": "production"},
},
{
Action: "deploy.*",
Effect: agentmesh.Allow,
},
}
engine := agentmesh.NewPolicyEngine(rules)
// Production deploys are denied
prodCtx := map[string]interface{}{"environment": "production"}
fmt.Println(engine.Evaluate("deploy.app", prodCtx)) // deny
// Staging deploys are allowed (conditions don't match first rule)
stagingCtx := map[string]interface{}{"environment": "staging"}
fmt.Println(engine.Evaluate("deploy.app", stagingCtx)) // allowThe engine supports $and, $or, $not, and comparison operators ($gt,
$gte, $lt, $lte, $ne, $in) in conditions.
Rules with MaxCalls and Window enable per-action rate limiting:
rules := []agentmesh.PolicyRule{
{
Action: "api.call",
Effect: agentmesh.Allow,
MaxCalls: 5,
Window: "1m", // 5 calls per minute
},
}
engine := agentmesh.NewPolicyEngine(rules)
for i := 0; i < 5; i++ {
fmt.Println(engine.Evaluate("api.call", nil)) // allow
}
fmt.Println(engine.Evaluate("api.call", nil)) // rate_limitrules := []agentmesh.PolicyRule{
{
Action: "deploy.production",
Effect: agentmesh.Allow,
MinApprovals: 2,
Approvers: []string{"lead", "sre"},
},
}
engine := agentmesh.NewPolicyEngine(rules)
fmt.Println(engine.Evaluate("deploy.production", nil)) // requires_approvalStore policies in version-controlled YAML files:
# policies/governance.yaml
rules:
- action: "data.read"
effect: allow
- action: "data.write"
effect: allow
conditions:
role: admin
- action: "shell.*"
effect: deny
- action: "deploy.*"
effect: review
- action: "*"
effect: denyengine := agentmesh.NewPolicyEngine(nil)
err := engine.LoadFromYAML("policies/governance.yaml")
if err != nil {
log.Fatalf("failed to load policy: %v", err)
}
fmt.Println(engine.Evaluate("data.read", nil)) // allowRules loaded from YAML are appended to any existing rules.
The TrustManager tracks per-agent trust scores on a 0.0–1.0 scale with
configurable tiers, decay, and file persistence.
| Tier | Score Range | Description |
|---|---|---|
low |
0.0–0.49 | Untrusted or new agent |
medium |
0.5–0.79 | Provisional trust |
high |
0.8–1.0 | Fully trusted |
tm := agentmesh.NewTrustManager(agentmesh.DefaultTrustConfig())
// New agent starts at 0.5 (medium tier)
score := tm.GetTrustScore("agent-x")
fmt.Println(score.Overall) // 0.5
fmt.Println(score.Tier) // medium
// Record successes — trust increases
tm.RecordSuccess("agent-x", 0.05)
tm.RecordSuccess("agent-x", 0.05)
score = tm.GetTrustScore("agent-x")
fmt.Println(score.Overall) // ~0.59
// Record failure — trust decreases (asymmetric: penalty factor = 1.5×)
tm.RecordFailure("agent-x", 0.1)
score = tm.GetTrustScore("agent-x")
fmt.Println(score.Overall, score.Tier)cfg := agentmesh.TrustConfig{
InitialScore: 0.8,
DecayRate: 0.02,
RewardFactor: 1.0,
PenaltyFactor: 2.0,
TierThresholds: agentmesh.TierThresholds{
High: 0.8,
Medium: 0.5,
},
MinInteractions: 5,
}
tm := agentmesh.NewTrustManager(cfg)
score := tm.GetTrustScore("high-trust-agent")
fmt.Println(score.Overall) // 0.8
fmt.Println(score.Tier) // highVerify a peer agent's identity and trust score in one call:
peer, _ := agentmesh.GenerateIdentity("peer-agent", nil)
result, err := tm.VerifyPeer("peer-agent", peer)
fmt.Println("Verified:", result.Verified)
fmt.Println("Score:", result.Score.Overall)Enable persistence to survive process restarts:
cfg := agentmesh.TrustConfig{
PersistPath: "trust-state.json",
// ... other config ...
}
tm := agentmesh.NewTrustManager(cfg)
// Scores are automatically saved after each update
tm.RecordSuccess("agent-x", 0.05)
// trust-state.json now contains the serialised score state
// On next startup, scores are loaded from disk automatically
tm2 := agentmesh.NewTrustManager(cfg)
score := tm2.GetTrustScore("agent-x")
fmt.Println(score.Overall) // restored scoreThe AuditLogger provides an append-only, hash-chain-linked audit trail. Each
entry's SHA-256 hash incorporates the previous entry's hash, creating a
tamper-evident chain.
logger := agentmesh.NewAuditLogger()
entry := logger.Log("agent-001", "data.read", agentmesh.Allow)
fmt.Println("Hash:", entry.Hash)
fmt.Println("Prev:", entry.PreviousHash) // empty for genesis entrylogger := agentmesh.NewAuditLogger()
logger.Log("agent-1", "data.read", agentmesh.Allow)
logger.Log("agent-1", "data.write", agentmesh.Deny)
logger.Log("agent-2", "report.send", agentmesh.Allow)
// Verify the entire chain
fmt.Println(logger.Verify()) // trueHow the chain works:
Entry 0 Entry 1 Entry 2
┌──────────┐ ┌──────────┐ ┌──────────┐
│ hash: A │──────▶│ prev: A │──────▶│ prev: B │
│ prev: "" │ │ hash: B │ │ hash: C │
└──────────┘ └──────────┘ └──────────┘
hash = SHA-256(timestamp | agentID | action | decision | previousHash)
Set MaxEntries to limit memory usage in long-running services:
logger := agentmesh.NewAuditLogger()
logger.MaxEntries = 1000 // keep last 1000 entries
// Old entries are evicted when the limit is exceeded
for i := 0; i < 1500; i++ {
logger.Log("agent", fmt.Sprintf("action-%d", i), agentmesh.Allow)
}
// Chain still verifies (eviction is chain-aware)
fmt.Println(logger.Verify()) // truefilter := agentmesh.AuditFilter{
AgentID: "agent-1",
}
entries := logger.GetEntries(filter)
fmt.Println("Agent-1 entries:", len(entries))
// Filter by decision
deny := agentmesh.Deny
filter = agentmesh.AuditFilter{
Decision: &deny,
}
denied := logger.GetEntries(filter)
fmt.Println("Denied entries:", len(denied))jsonStr, err := logger.ExportJSON()
if err != nil {
log.Fatal(err)
}
fmt.Println(jsonStr)The AgentIdentity provides Ed25519-based cryptographic identity with DID
identifiers and data signing.
identity, err := agentmesh.GenerateIdentity(
"researcher-agent",
[]string{"data.read", "search"},
)
if err != nil {
log.Fatal(err)
}
fmt.Println("DID:", identity.DID) // did:agentmesh:researcher-agent
fmt.Println("Capabilities:", identity.Capabilities)
fmt.Println("Public key:", len(identity.PublicKey), "bytes") // 32 bytesdata := []byte("important message")
// Sign
signature, err := identity.Sign(data)
if err != nil {
log.Fatal(err)
}
fmt.Println("Signature:", len(signature), "bytes") // 64 bytes
// Verify
fmt.Println("Valid:", identity.Verify(data, signature)) // true
// Tampered data fails
fmt.Println("Tampered:", identity.Verify([]byte("wrong"), signature)) // falseExport the public portion of an identity for sharing:
jsonBytes, err := identity.ToJSON()
if err != nil {
log.Fatal(err)
}
fmt.Println(string(jsonBytes))
// {"did":"did:agentmesh:researcher-agent","public_key":"...","capabilities":["data.read","search"]}
// Reconstruct from JSON (public key only)
imported, err := agentmesh.FromJSON(jsonBytes)
fmt.Println("Imported DID:", imported.DID)
fmt.Println("Can verify:", imported.Verify(data, signature)) // trueEnd-to-end example combining all subsystems:
package main
import (
"fmt"
"log"
agentmesh "github.com/microsoft/agent-governance-toolkit/sdks/go"
)
func main() {
// 1. Create a governed client
client, err := agentmesh.NewClient("research-agent",
agentmesh.WithCapabilities([]string{"data.read", "search.web"}),
agentmesh.WithTrustConfig(agentmesh.TrustConfig{
InitialScore: 0.5,
DecayRate: 0.01,
RewardFactor: 1.0,
PenaltyFactor: 1.5,
TierThresholds: agentmesh.TierThresholds{High: 0.8, Medium: 0.5},
}),
agentmesh.WithPolicyRules([]agentmesh.PolicyRule{
{Action: "data.read", Effect: agentmesh.Allow},
{Action: "search.*", Effect: agentmesh.Allow},
{Action: "data.write", Effect: agentmesh.Review},
{Action: "*", Effect: agentmesh.Deny},
}),
)
if err != nil {
log.Fatal(err)
}
fmt.Println("Agent DID:", client.Identity.DID)
// 2. Execute governed actions
actions := []string{"data.read", "search.web", "data.write", "shell.exec"}
for _, action := range actions {
result, _ := client.ExecuteWithGovernance(action, nil)
status := "✅ allowed"
if !result.Allowed {
status = "❌ denied"
}
fmt.Printf(" %s → %s (trust: %.2f, tier: %s)\n",
action, status, result.TrustScore.Overall, result.TrustScore.Tier)
}
// 3. Verify audit chain
fmt.Println("\nAudit chain valid:", client.Audit.Verify())
// 4. Export audit trail
jsonStr, _ := client.Audit.ExportJSON()
fmt.Println("Audit JSON:", jsonStr[:80], "...")
}Expected output:
Agent DID: did:agentmesh:research-agent
data.read → ✅ allowed (trust: 0.54, tier: medium)
search.web → ✅ allowed (trust: 0.59, tier: medium)
data.write → ❌ denied (trust: 0.44, tier: low)
shell.exec → ❌ denied (trust: 0.28, tier: low)
Audit chain valid: true
Audit JSON: [{"timestamp":"2025-07-15T10:30:00Z","agent_id":"did:agentmesh:resear ...
| Go SDK Feature | Python Equivalent | Tutorial |
|---|---|---|
PolicyEngine |
agent_os.policy |
Tutorial 01 — Policy Engine |
TrustManager |
agent_os.trust |
Tutorial 02 — Trust & Identity |
AuditLogger |
agent_os.audit |
Tutorial 04 — Audit & Compliance |
AgentIdentity |
agent_os.identity |
Tutorial 02 — Trust & Identity |
AgentMeshClient |
AgentMeshClient |
Tutorial 20 — TypeScript SDK |
Note: The Go SDK uses a 0.0–1.0 trust scale with three tiers, while the Rust SDK uses 0–1000 with five tiers. Both use the same governance concepts and YAML policy format.
| Component | Location |
|---|---|
| Client + options | packages/agent-mesh/sdks/go/client.go |
| Type definitions | packages/agent-mesh/sdks/go/types.go |
PolicyEngine |
packages/agent-mesh/sdks/go/policy.go |
TrustManager |
packages/agent-mesh/sdks/go/trust.go |
AuditLogger |
packages/agent-mesh/sdks/go/audit.go |
AgentIdentity |
packages/agent-mesh/sdks/go/identity.go |
| Conflict resolution | packages/agent-mesh/sdks/go/conflict.go |
| Metrics | packages/agent-mesh/sdks/go/metrics.go |
| Tests | packages/agent-mesh/sdks/go/*_test.go |
- Run the tests to see the SDK in action:
cd packages/agent-mesh/sdks/go go test ./...
- Load YAML policies from the repository's
policies/directory - Enable trust persistence with
PersistPathto retain scores across restarts - Verify audit chains in your CI/CD pipeline — call
Verify()as a post-deployment check - Explore the Rust SDK tutorial (Tutorial 21) for the Rust equivalent
- Read the Python tutorials (01–04) for detailed governance concepts