{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://hanria.ai/skill/schema/mandate.schema.json",
  "title": "HANRIA mandate",
  "description": "An operator-authored statement of what an agent may do. Written by a person, read by an agent, evaluated locally. A mandate is advisory: it describes intended authority and supports a local check, but it does not enforce anything. Enforcement requires a component that exclusively holds the credentials and can refuse.",
  "type": "object",
  "required": [
    "schema_version",
    "mandate_id",
    "purpose",
    "default",
    "clauses"
  ],
  "additionalProperties": false,
  "properties": {
    "schema_version": {
      "const": "0.2-draft",
      "description": "Draft. The shape may change while the runtime is unreleased."
    },
    "mandate_id": {
      "type": "string",
      "minLength": 1,
      "description": "Stable identifier for this mandate. Appears in every decision record made against it."
    },
    "issued_by": {
      "type": "string",
      "description": "Who wrote this mandate. Free text; not authenticated by anything in this skill."
    },
    "purpose": {
      "type": "string",
      "minLength": 1,
      "description": "What the agent is authorized to accomplish, in the operator's own words. Not evaluated mechanically; it is the human-readable statement against which a reviewer judges whether the clauses actually express the intent."
    },
    "not_valid_after": {
      "type": "string",
      "format": "date-time",
      "description": "RFC 3339 timestamp. After this instant every action is denied. Absent means no expiry, which is discouraged: an unbounded mandate is the condition that lets delegated authority outlive the task it was granted for."
    },
    "default": {
      "enum": [
        "deny",
        "escalate"
      ],
      "description": "What happens when no clause matches. 'permit' is deliberately not an option: a mandate that permits by default cannot express a limit."
    },
    "requires_human": {
      "type": "array",
      "description": "Operation kinds that always require a person, even where a clause permits them. These escalate rather than permit.",
      "items": {
        "enum": [
          "file",
          "process",
          "package",
          "network",
          "device",
          "credential_use",
          "transaction",
          "administrative"
        ]
      },
      "minItems": 0
    },
    "clauses": {
      "type": "array",
      "minItems": 1,
      "description": "Evaluated in order. The first matching clause decides. A request matching no clause takes the mandate default.",
      "items": {
        "type": "object",
        "required": [
          "id",
          "effect",
          "match"
        ],
        "additionalProperties": false,
        "properties": {
          "id": {
            "type": "string",
            "minLength": 1,
            "description": "Identifier for this clause. Returned with every decision so a reviewer can see which sentence of the mandate was relied on."
          },
          "effect": {
            "enum": [
              "permit",
              "deny",
              "escalate"
            ],
            "description": "What this clause does when it matches."
          },
          "note": {
            "type": "string",
            "description": "Why this clause exists. Carried into the decision record verbatim."
          },
          "match": {
            "type": "object",
            "required": [
              "kind"
            ],
            "additionalProperties": false,
            "description": "All present conditions must hold for the clause to match.",
            "properties": {
              "kind": {
                "type": "array",
                "minItems": 1,
                "description": "Operation kinds this clause covers.",
                "items": {
                  "enum": [
                    "file",
                    "process",
                    "package",
                    "network",
                    "device",
                    "credential_use",
                    "transaction",
                    "administrative"
                  ]
                }
              },
              "verb": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "description": "Permitted verbs, matched case-insensitively and exactly. Absent means any verb.",
                "minItems": 1
              },
              "target_prefix": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "description": "The operation target must begin with one of these strings. Absent means any target. Prefix matching is deliberately literal: it does not resolve symlinks, normalize paths, or understand hostnames, so a target is compared as written.",
                "minItems": 1
              },
              "counterparty": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "description": "Permitted counterparties, matched exactly. Absent means any counterparty.",
                "minItems": 1
              },
              "max_amount": {
                "type": "object",
                "required": [
                  "value",
                  "currency"
                ],
                "additionalProperties": false,
                "description": "Ceiling for an operation carrying an amount. A request above it does not match this clause.",
                "properties": {
                  "value": {
                    "type": "string",
                    "description": "Decimal as a string, to avoid float error."
                  },
                  "currency": {
                    "type": "string"
                  }
                }
              }
            }
          }
        }
      }
    }
  },
  "$comment": "A mandate names what may be done, not the means of doing it, and must never contain a credential, secret, key or token. The checker refuses a mandate carrying recognizable credential material rather than evaluating it, because anything in a clause note is copied into the decision record. That detection is a heuristic and cannot be complete."
}
