{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "title": "Permissions file config",
  "description": "Rules loaded from version 2 `permissions.{yml,yaml}` files.\nA Polytoken permissions file: tool rules and filesystem rules, each grouped\ninto `allow`, `ask`, `ask-unless-allowed`, and `deny` buckets.",
  "type": "object",
  "properties": {
    "version": {
      "description": "Schema version. Always `2`.",
      "const": 2,
      "default": 2
    },
    "allow": {
      "description": "Run matching tool calls without asking.",
      "type": "array",
      "items": {
        "$ref": "#/$defs/PermissionRule"
      }
    },
    "ask": {
      "description": "Ask before running matching tool calls.",
      "type": "array",
      "items": {
        "$ref": "#/$defs/PermissionRule"
      }
    },
    "ask-unless-allowed": {
      "description": "Ask before running matching tool calls, unless an `allow` rule already\ncovers them.",
      "type": "array",
      "items": {
        "$ref": "#/$defs/PermissionRule"
      }
    },
    "deny": {
      "description": "Refuse matching tool calls.",
      "type": "array",
      "items": {
        "$ref": "#/$defs/PermissionRule"
      }
    },
    "filesystem": {
      "description": "Filesystem path-capability rules, using the same buckets.",
      "$ref": "#/$defs/FilesystemRuleBuckets"
    }
  },
  "additionalProperties": false,
  "required": [
    "version"
  ],
  "$defs": {
    "PermissionRule": {
      "description": "A single permission-file rule.",
      "type": "object",
      "properties": {
        "tool": {
          "description": "Tool name, glob, or `mcp__<server>` shorthand that matches every tool\nfrom that MCP server.",
          "type": "string"
        },
        "args": {
          "description": "Arguments that narrow the match. The keys present determine which\ncategory of argument narrowing applies: `path` for file tools, `url`\nfor web tools, `executable`/`subcommand`/`command_tokens`/`flags_present`\nfor shell tools, `pattern`/`include` for search tools, and `model` for\nmodel-scoped rules. Omit `args` for a name-only rule.",
          "anyOf": [
            {
              "$ref": "#/$defs/PermissionArgs"
            },
            {
              "type": "null"
            }
          ]
        },
        "message": {
          "description": "Optional reminder text shown to the model after a tool call matched by\nthis rule completes. Polytoken injects the text as a system reminder\nafter the full tool batch finishes, so it never interrupts tool results.\nUse this to give the model context about why a rule exists or what to do\nnext when the rule fires. The message only fires when a rule with this\nverdict is the resolved verdict: an allow rule on an allowed call, or a\ndeny rule on a denied call. If multiple rules with messages match the\nsame call, each one whose verdict matches the resolved outcome fires its\nmessage. Ask rules never produce a reminder. Bypass mode skips all\nmessages.",
          "type": [
            "string",
            "null"
          ]
        }
      },
      "additionalProperties": false,
      "required": [
        "tool"
      ]
    },
    "PermissionArgs": {
      "anyOf": [
        {
          "allOf": [
            {
              "$ref": "#/$defs/ShellPermissionArgs"
            }
          ],
          "minProperties": 1
        },
        {
          "allOf": [
            {
              "$ref": "#/$defs/SearchPermissionArgs"
            }
          ],
          "minProperties": 1
        },
        {
          "$ref": "#/$defs/PathPermissionArgs"
        },
        {
          "$ref": "#/$defs/UrlPermissionArgs"
        },
        {
          "$ref": "#/$defs/ModelPermissionArgs"
        }
      ]
    },
    "ShellPermissionArgs": {
      "description": "Shell command args for `shell_exec` and `shell_monitor`.",
      "type": "object",
      "properties": {
        "executable": {
          "description": "The executable name to match (e.g., `git`, `ls`).",
          "anyOf": [
            {
              "$ref": "#/$defs/PermissionValueMatcher"
            },
            {
              "type": "null"
            }
          ]
        },
        "command": {
          "description": "A full command string to match.",
          "anyOf": [
            {
              "$ref": "#/$defs/PermissionValueMatcher"
            },
            {
              "type": "null"
            }
          ]
        },
        "subcommand": {
          "description": "Ordered subcommand tokens after the executable.",
          "anyOf": [
            {
              "$ref": "#/$defs/SubcommandMatcher"
            },
            {
              "type": "null"
            }
          ]
        },
        "command_tokens": {
          "description": "Command tokens (`[executable, subcommand...]`) up to the first flag or\npath boundary. A trailing `\"*\"` in the YAML enables prefix matching.",
          "anyOf": [
            {
              "$ref": "#/$defs/CommandTokensMatcher"
            },
            {
              "type": "null"
            }
          ]
        },
        "flags_present": {
          "description": "Flag constraints. An array or single string requires those flags to be\npresent. An object with an `excludes` key requires those flags to be\nabsent.",
          "anyOf": [
            {
              "$ref": "#/$defs/FlagsPresentMatcher"
            },
            {
              "type": "null"
            }
          ]
        }
      },
      "additionalProperties": false
    },
    "PermissionValueMatcher": {
      "oneOf": [
        {
          "type": "string"
        },
        {
          "type": "object",
          "properties": {
            "exact": {
              "type": "string"
            }
          },
          "required": [
            "exact"
          ],
          "additionalProperties": false
        },
        {
          "type": "object",
          "properties": {
            "glob": {
              "type": "string"
            }
          },
          "required": [
            "glob"
          ],
          "additionalProperties": false
        }
      ]
    },
    "SubcommandMatcher": {
      "oneOf": [
        {
          "$ref": "#/$defs/PermissionValueMatcher"
        },
        {
          "type": "array",
          "minItems": 1,
          "items": {
            "$ref": "#/$defs/PermissionValueMatcher"
          }
        }
      ]
    },
    "CommandTokensMatcher": {
      "description": "An array of command token matchers. A trailing \"*\" enables prefix matching, allowing any additional tokens after the listed prefix.",
      "type": "array",
      "minItems": 1,
      "items": {
        "$ref": "#/$defs/PermissionValueMatcher"
      }
    },
    "FlagsPresentMatcher": {
      "oneOf": [
        {
          "type": "array",
          "minItems": 1,
          "items": {
            "$ref": "#/$defs/PermissionValueMatcher"
          }
        },
        {
          "$ref": "#/$defs/PermissionValueMatcher"
        },
        {
          "type": "object",
          "properties": {
            "contains": {
              "type": "array",
              "minItems": 1,
              "items": {
                "$ref": "#/$defs/PermissionValueMatcher"
              }
            }
          },
          "required": [
            "contains"
          ],
          "additionalProperties": false
        },
        {
          "type": "object",
          "properties": {
            "excludes": {
              "type": "array",
              "minItems": 1,
              "items": {
                "$ref": "#/$defs/PermissionValueMatcher"
              }
            }
          },
          "required": [
            "excludes"
          ],
          "additionalProperties": false
        }
      ]
    },
    "SearchPermissionArgs": {
      "description": "Search tool args with pattern, include, and/or path narrowing.",
      "type": "object",
      "properties": {
        "pattern": {
          "description": "Search pattern to match.",
          "anyOf": [
            {
              "$ref": "#/$defs/PermissionValueMatcher"
            },
            {
              "type": "null"
            }
          ]
        },
        "include": {
          "description": "File include filter to match.",
          "anyOf": [
            {
              "$ref": "#/$defs/PermissionValueMatcher"
            },
            {
              "type": "null"
            }
          ]
        },
        "path": {
          "description": "Path scope for the search.",
          "anyOf": [
            {
              "$ref": "#/$defs/PermissionValueMatcher"
            },
            {
              "type": "null"
            }
          ]
        }
      },
      "additionalProperties": false
    },
    "PathPermissionArgs": {
      "description": "Path-scoped args for file tools (`file_read`, `file_write`, etc.).",
      "type": "object",
      "properties": {
        "path": {
          "description": "Filesystem path to match. Bare strings with glob metacharacters are\ntreated as globs.",
          "$ref": "#/$defs/PermissionValueMatcher"
        }
      },
      "additionalProperties": false,
      "required": [
        "path"
      ]
    },
    "UrlPermissionArgs": {
      "description": "URL-scoped args for web tools (`web_fetch`).",
      "type": "object",
      "properties": {
        "url": {
          "description": "URL to match. Bare strings with glob metacharacters are treated as\nglobs.",
          "$ref": "#/$defs/PermissionValueMatcher"
        }
      },
      "additionalProperties": false,
      "required": [
        "url"
      ]
    },
    "ModelPermissionArgs": {
      "description": "Model-scoped args (e.g., for `subagent` model overrides).",
      "type": "object",
      "properties": {
        "model": {
          "description": "Model name to match.",
          "$ref": "#/$defs/PermissionValueMatcher"
        }
      },
      "additionalProperties": false,
      "required": [
        "model"
      ]
    },
    "FilesystemRuleBuckets": {
      "type": "object",
      "properties": {
        "allow": {
          "description": "Grant the listed path capabilities without asking.",
          "type": "array",
          "items": {
            "$ref": "#/$defs/FilesystemRule"
          }
        },
        "ask": {
          "description": "Ask before granting the listed path capabilities.",
          "type": "array",
          "items": {
            "$ref": "#/$defs/FilesystemRule"
          }
        },
        "ask-unless-allowed": {
          "description": "Ask before granting the listed path capabilities, unless an `allow` rule\nalready covers them.",
          "type": "array",
          "items": {
            "$ref": "#/$defs/FilesystemRule"
          }
        },
        "deny": {
          "description": "Refuse the listed path capabilities.",
          "type": "array",
          "items": {
            "$ref": "#/$defs/FilesystemRule"
          }
        }
      },
      "additionalProperties": false
    },
    "FilesystemRule": {
      "type": "object",
      "properties": {
        "access": {
          "description": "Path capabilities the rule grants: `read`, `write`, and `chdir`.",
          "type": "array",
          "minItems": 1,
          "uniqueItems": true,
          "items": {
            "$ref": "#/$defs/FilesystemCapability"
          }
        },
        "path": {
          "description": "Path the rule applies to. The suffix `{,/**}` means the path and\nanything under it.",
          "type": "string"
        }
      },
      "additionalProperties": false,
      "required": [
        "access",
        "path"
      ]
    },
    "FilesystemCapability": {
      "oneOf": [
        {
          "description": "Read file contents or inspect directory contents.",
          "type": "string",
          "const": "read"
        },
        {
          "description": "Create or overwrite files, and the write side of edits, deletes, or\nmoves. Does not grant read.",
          "type": "string",
          "const": "write"
        },
        {
          "description": "Change a shell command's working directory to the path.",
          "type": "string",
          "const": "chdir"
        }
      ]
    }
  }
}
