Skip to content
Metamynd
Developers · Evidence

Signed policy bundles & evidence proofs

Two separate guarantees: a policy bundle lets you verify the RULES an agent is bound to without trusting whoever handed you a copy of them, and an evidence proof lets you verify that a DECISION was actually made without trusting MetaMynd's own record of it.

01

Signed policy bundles

  • GET /policy/bundle/:did — the agent's evaluable policy (its Standards and SOPs, compiled), signed by the issuer
  • GET /magp/policy/pubkey — the verification key
  • A guard MUST verify the signature before evaluating, and MUST refuse an unsigned or invalid bundle for a value-bearing action — POLICY_BUNDLE_UNSIGNED, POLICY_BUNDLE_SIGNATURE_INVALID
  • Bundles carry a maxStaleness; a value-bearing action fails closed on a stale one too — POLICY_BUNDLE_STALE
  • policyPublicKey pins the key at the CALLER, not just the bundle fetch — a scaffolded gateway that sets it can no longer be handed a valid-looking bundle signed by the wrong key at all, closing a man-in-the-middle swap rather than merely detecting one after the fact
02

Evidence and anchoring

Every decision produces an evidence record. Records are batched, hashed into a Merkle tree, and a single root is anchored — so anchoring cost doesn't scale with decision volume. GET /magp/evidence/:eventId/proof returns the leaf, the path, and the anchored root: enough to check inclusion completely offline, without asking MetaMynd anything. That's the actual property being claimed: a regulator or an auditor recomputes the proof themselves rather than trusting a copy of the record. The guard's own proof(eventId) does exactly that recomputation client-side, and reports failed and pending as different outcomes — a decision made seconds ago is normally pending (anchoring is asynchronous), never silently read as failed.

03

What's in the leaf, and what isn't

The leaf composition is part of the protocol — adding a field changes every digest and invalidates every previously anchored proof, so it's treated as a breaking change. What's deliberately excluded: context field VALUES. A decision record keeps the names of the context fields a rule evaluated (so an auditor can tell "the spend-cap clause never saw an amount" from "it saw one and passed it"), never their values — those stay the tenant's.

Example

See it in code

verify-a-proof.ts
// decision.eventId comes back on every verdict (allow, block or escalate alike).
const result = await guard.proof(decision.eventId);

// The SDK fetched the leaf + sibling chain + anchored root, then recomputed the
// root ITSELF and compared — `verified` is this code's own conclusion, not a
// claim it took on trust.
switch (result.status) {
  case "verified":     /* provably in the anchored batch */ break;
  case "pending":      /* anchoring is async — check again shortly, not an error */ break;
  case "failed":       /* the proof does NOT reconstruct the root — take this seriously */ break;
  case "unreachable":  /* could not ask the gate — nothing implied either way */ break;
}

Prepare your organisation for the Agentic Economy