Developer guide

Write and validate an agent mandate

A mandate expresses a boundary only through valid enforcement fields; an invalid mandate makes every action check answer error.

Start from a template

This exact file sandbox entry comes from the templates embedded in public/try.1.js. Its first clause denies the sensitive prefixes, its second clause permits file reads and writes under one workspace prefix, and its default denies anything unmatched.

  {
    "name": "file-sandbox",
    "title": "File sandbox",
    "description": "Deny sensitive directories and permit reads and writes under one bounded directory.",
    "mandate": {
      "schema_version": "0.2-draft",
      "mandate_id": "template-file-sandbox",
      "purpose": "Confine file reads and writes to one working directory.",
      "default": "deny",
      "clauses": [
        { "id": "deny-sensitive", "effect": "deny", "match": { "kind": ["file"], "target_prefix": ["~/.ssh/", "/etc/"] } },
        { "id": "permit-workspace", "effect": "permit", "match": { "kind": ["file"], "verb": ["read", "write"], "target_prefix": ["/workspace/project/"] } }
      ]
    },
    "action": {
      "schema_version": "0.1-draft",
      "requested_by": { "agent": "template-agent" },
      "operation": { "kind": "file", "verb": "write", "target": "/workspace/project/report.txt" },
      "justification": "Write the report inside the bounded workspace."
    },
    "outcome": "permit"
  },

Change the mandate identifier for tracking and change the enforcement fields to match the authority you intend. Purpose, note, and justification are prose and never restrict an action. Only clause match fields, not_valid_after, requires_human, and default do. Put narrower denials before broader permits because the first matching clause decides. Do not put secrets, personal data, or confidential policies in the mandate.

Validate the mandate

The form uses this exact validation flow from public/try.1.js. It initializes MCP, calls validate_mandate, and accepts structured content or the text fallback.

export async function validateMandate(mandateText, fetchImpl = fetch) {
  const mandate = parseDocument(mandateText, "mandate");
  const initialized = await postJson(MCP_URL, {
    jsonrpc: "2.0",
    id: 1,
    method: "initialize",
    params: {
      protocolVersion: "2025-11-25",
      capabilities: {},
      clientInfo: { name: "hanria.ai-try-it", version: "1" }
    }
  }, fetchImpl);
  if (initialized.error) throw new Error(initialized.error.message || "initialize failed", { cause: "response" });
  const called = await postJson(MCP_URL, {
    jsonrpc: "2.0",
    id: 2,
    method: "tools/call",
    params: { name: "validate_mandate", arguments: { mandate } }
  }, fetchImpl);
  if (called.error) throw new Error(called.error.message || "validate_mandate failed", { cause: "response" });
  const structured = called.result?.structuredContent;
  if (structured && typeof structured === "object") return structured;
  const text = called.result?.content?.find((item) => item.type === "text")?.text;
  if (typeof text === "string") {
    try {
      return JSON.parse(text);
    } catch {
      throw new Error("invalid validate_mandate result", { cause: "response" });
    }
  }
  throw new Error("missing validate_mandate result", { cause: "response" });
}

Run it

  1. Open the form

    Go to the try-it form and select File sandbox.

  2. Edit the mandate

    Replace the example identifiers and boundaries with the structured limits you intend.

  3. Validate only

    Select Validate mandate only. A result with valid: true means the validator accepted the document. A result with valid: false names the validation problem. Fix it before using the mandate.

  4. Check an action

    Use the mandate with a representative action and inspect the outcome, governing clause, and signed receipt.

Handle every outcome

The action check returns permit, deny, or escalate with the governing clause and a signed receipt. The check is advisory, and your integration is what refuses the action. The hosted check evaluates the request in memory and keeps no request content.

An invalid mandate makes every action check return error, which your integration must treat as deny; it does not express a boundary. Validation does not convert the mandate into an enforcement boundary.

References

Try the check · Verify signed receipts · OpenAPI document · Agent-facing summary