{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://hushspec.org/schemas/hushspec-core.v1.schema.json",
  "title": "HushSpec Core v1",
  "description": "Schema for HushSpec Core 1.x documents, which also accepts the frozen 0.x lineage (core spec 2.2). Validates portable, engine-neutral AI agent security rules.",
  "type": "object",
  "required": [
    "hushspec"
  ],
  "additionalProperties": false,
  "properties": {
    "hushspec": {
      "type": "string",
      "pattern": "^(0|1)\\.\\d+\\.\\d+$",
      "description": "HushSpec document format version, MAJOR.MINOR.PATCH. The 0.x and 1.x lineages are accepted; an engine supporting minor X.Y accepts every X.Y.Z (core spec 2.2)."
    },
    "name": {
      "type": "string",
      "minLength": 1,
      "description": "Policy name. When present it must not be empty: bundle subjects and receipt policy summaries carry it (core spec 2)."
    },
    "description": {
      "type": "string"
    },
    "extends": {
      "type": "string",
      "description": "Reference to a base policy. Resolution is engine-specific."
    },
    "merge_strategy": {
      "type": "string",
      "enum": [
        "replace",
        "merge",
        "deep_merge"
      ],
      "default": "deep_merge",
      "description": "Strategy for merging with the base policy."
    },
    "rules": {
      "$ref": "#/$defs/Rules"
    },
    "extensions": {
      "$ref": "#/$defs/Extensions"
    },
    "metadata": {
      "$ref": "#/$defs/GovernanceMetadata"
    }
  },
  "$defs": {
    "Rules": {
      "type": "object",
      "additionalProperties": false,
      "description": "Security rule declarations.",
      "properties": {
        "forbidden_paths": {
          "$ref": "#/$defs/ForbiddenPaths"
        },
        "path_allowlist": {
          "$ref": "#/$defs/PathAllowlist"
        },
        "egress": {
          "$ref": "#/$defs/Egress"
        },
        "secret_patterns": {
          "$ref": "#/$defs/SecretPatterns"
        },
        "patch_integrity": {
          "$ref": "#/$defs/PatchIntegrity"
        },
        "shell_commands": {
          "$ref": "#/$defs/ShellCommands"
        },
        "tool_access": {
          "$ref": "#/$defs/ToolAccess"
        },
        "computer_use": {
          "$ref": "#/$defs/ComputerUse"
        },
        "remote_desktop_channels": {
          "$ref": "#/$defs/RemoteDesktopChannels"
        },
        "input_injection": {
          "$ref": "#/$defs/InputInjection"
        },
        "browser_automation": {
          "$ref": "#/$defs/BrowserAutomation"
        },
        "code_execution": {
          "$ref": "#/$defs/CodeExecution"
        }
      }
    },
    "ForbiddenPaths": {
      "type": "object",
      "additionalProperties": false,
      "description": "Block access to sensitive filesystem paths.",
      "properties": {
        "when": {
          "$ref": "#/$defs/Condition",
          "description": "Condition gating whether this block is active (core spec 3.13)."
        },
        "enabled": {
          "type": "boolean",
          "default": true,
          "description": "Whether this rule is active."
        },
        "patterns": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "default": [],
          "description": "Glob patterns matching forbidden paths."
        },
        "exceptions": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "default": [],
          "description": "Glob patterns that override pattern matches."
        }
      }
    },
    "PathAllowlist": {
      "type": "object",
      "additionalProperties": false,
      "description": "Allowlist-based path access control.",
      "properties": {
        "when": {
          "$ref": "#/$defs/Condition",
          "description": "Condition gating whether this block is active (core spec 3.13)."
        },
        "enabled": {
          "type": "boolean",
          "default": false,
          "description": "Whether this rule is active."
        },
        "read": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "default": [],
          "description": "Glob patterns allowed for read access."
        },
        "write": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "default": [],
          "description": "Glob patterns allowed for write access."
        },
        "patch": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "default": [],
          "description": "Glob patterns allowed for patch operations. If empty, falls back to write."
        }
      }
    },
    "Egress": {
      "type": "object",
      "additionalProperties": false,
      "description": "Network egress control by domain.",
      "properties": {
        "when": {
          "$ref": "#/$defs/Condition",
          "description": "Condition gating whether this block is active (core spec 3.13)."
        },
        "enabled": {
          "type": "boolean",
          "default": true,
          "description": "Whether this rule is active."
        },
        "allow": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "default": [],
          "description": "Domain glob patterns to allow."
        },
        "block": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "default": [],
          "description": "Domain glob patterns to block. Block takes precedence over allow."
        },
        "default": {
          "type": "string",
          "enum": [
            "allow",
            "block"
          ],
          "default": "block",
          "description": "Default decision when no pattern matches."
        }
      }
    },
    "SecretPattern": {
      "type": "object",
      "additionalProperties": false,
      "description": "A named regex pattern for secret detection.",
      "required": [
        "name",
        "pattern",
        "severity"
      ],
      "properties": {
        "name": {
          "type": "string",
          "description": "Unique identifier for this pattern."
        },
        "pattern": {
          "type": "string",
          "maxLength": 2048,
          "description": "Regular expression to match against content, in the HushSpec regex profile (core spec 3.14.3)."
        },
        "severity": {
          "type": "string",
          "enum": [
            "critical",
            "error",
            "warn"
          ],
          "description": "Severity level of a match."
        },
        "description": {
          "type": "string",
          "description": "Human-readable description of what this detects."
        }
      }
    },
    "SecretPatterns": {
      "type": "object",
      "additionalProperties": false,
      "description": "Detect secrets in content.",
      "properties": {
        "when": {
          "$ref": "#/$defs/Condition",
          "description": "Condition gating whether this block is active (core spec 3.13)."
        },
        "enabled": {
          "type": "boolean",
          "default": true,
          "description": "Whether this rule is active."
        },
        "patterns": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/SecretPattern"
          },
          "default": [],
          "description": "Named regex patterns for secret detection. Names must be unique."
        },
        "skip_paths": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "default": [],
          "description": "Glob patterns of paths to skip scanning."
        }
      }
    },
    "PatchIntegrity": {
      "type": "object",
      "additionalProperties": false,
      "description": "Validate patch/diff safety.",
      "properties": {
        "when": {
          "$ref": "#/$defs/Condition",
          "description": "Condition gating whether this block is active (core spec 3.13)."
        },
        "enabled": {
          "type": "boolean",
          "default": true,
          "description": "Whether this rule is active."
        },
        "max_additions": {
          "type": "integer",
          "minimum": 0,
          "default": 1000,
          "description": "Maximum number of added lines permitted.",
          "maximum": 9007199254740991
        },
        "max_deletions": {
          "type": "integer",
          "minimum": 0,
          "default": 500,
          "description": "Maximum number of deleted lines permitted.",
          "maximum": 9007199254740991
        },
        "forbidden_patterns": {
          "type": "array",
          "items": {
            "type": "string",
            "maxLength": 2048
          },
          "default": [],
          "description": "Regex patterns forbidden in patch content, in the HushSpec regex profile (core spec 3.14.3)."
        },
        "require_balance": {
          "type": "boolean",
          "default": false,
          "description": "Whether additions/deletions must be balanced."
        },
        "max_imbalance_ratio": {
          "type": "number",
          "exclusiveMinimum": 0,
          "default": 10,
          "description": "Maximum ratio of additions to deletions (or vice versa)."
        }
      }
    },
    "ShellCommands": {
      "type": "object",
      "additionalProperties": false,
      "description": "Block dangerous shell commands.",
      "properties": {
        "when": {
          "$ref": "#/$defs/Condition",
          "description": "Condition gating whether this block is active (core spec 3.13)."
        },
        "enabled": {
          "type": "boolean",
          "default": true,
          "description": "Whether this rule is active."
        },
        "forbidden_patterns": {
          "type": "array",
          "items": {
            "type": "string",
            "maxLength": 2048
          },
          "default": [],
          "description": "Regex patterns forbidden in shell commands, in the HushSpec regex profile (core spec 3.14.3)."
        }
      }
    },
    "ToolAccess": {
      "type": "object",
      "additionalProperties": false,
      "description": "Control tool/MCP invocations.",
      "properties": {
        "when": {
          "$ref": "#/$defs/Condition",
          "description": "Condition gating whether this block is active (core spec 3.13)."
        },
        "enabled": {
          "type": "boolean",
          "default": true,
          "description": "Whether this rule is active."
        },
        "allow": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "default": [],
          "description": "Tool name allowlist."
        },
        "block": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "default": [],
          "description": "Tool name blocklist. Block takes precedence."
        },
        "require_confirmation": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "default": [],
          "description": "Tools requiring user/operator approval."
        },
        "default": {
          "type": "string",
          "enum": [
            "allow",
            "block"
          ],
          "default": "allow",
          "description": "Default decision when no list matches."
        },
        "max_args_size": {
          "type": "integer",
          "minimum": 1,
          "description": "Maximum argument payload size in bytes.",
          "maximum": 9007199254740991
        }
      }
    },
    "ComputerUse": {
      "type": "object",
      "additionalProperties": false,
      "description": "Control computer use agent actions.",
      "properties": {
        "when": {
          "$ref": "#/$defs/Condition",
          "description": "Condition gating whether this block is active (core spec 3.13)."
        },
        "enabled": {
          "type": "boolean",
          "default": false,
          "description": "Whether this rule is active."
        },
        "mode": {
          "type": "string",
          "enum": [
            "observe",
            "guardrail",
            "fail_closed"
          ],
          "default": "guardrail",
          "description": "Enforcement mode."
        },
        "allowed_actions": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "default": [],
          "description": "Action identifiers permitted (e.g., 'remote.session.connect', 'input.inject')."
        }
      }
    },
    "RemoteDesktopChannels": {
      "type": "object",
      "additionalProperties": false,
      "description": "Control remote desktop side channels.",
      "properties": {
        "when": {
          "$ref": "#/$defs/Condition",
          "description": "Condition gating whether this block is active (core spec 3.13)."
        },
        "enabled": {
          "type": "boolean",
          "default": false,
          "description": "Whether this rule is active."
        },
        "clipboard": {
          "type": "boolean",
          "default": false,
          "description": "Allow clipboard sharing."
        },
        "file_transfer": {
          "type": "boolean",
          "default": false,
          "description": "Allow file transfer."
        },
        "audio": {
          "type": "boolean",
          "default": true,
          "description": "Allow audio redirection."
        },
        "drive_mapping": {
          "type": "boolean",
          "default": false,
          "description": "Allow drive/filesystem mapping."
        }
      }
    },
    "InputInjection": {
      "type": "object",
      "additionalProperties": false,
      "description": "Control input injection capabilities.",
      "properties": {
        "when": {
          "$ref": "#/$defs/Condition",
          "description": "Condition gating whether this block is active (core spec 3.13)."
        },
        "enabled": {
          "type": "boolean",
          "default": false,
          "description": "Whether this rule is active."
        },
        "allowed_types": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "default": [],
          "description": "Input type identifiers permitted (e.g., 'keyboard', 'mouse', 'touch')."
        },
        "require_postcondition_probe": {
          "type": "boolean",
          "default": false,
          "description": "Whether postcondition verification is required after input injection."
        }
      }
    },
    "BrowserAutomation": {
      "type": "object",
      "additionalProperties": false,
      "description": "Fine-grained controls for browser-automation tool calls: domain allowlist, verb allowlist, and credential detection in type actions.",
      "properties": {
        "when": {
          "$ref": "#/$defs/Condition",
          "description": "Condition gating whether this block is active (core spec 3.13)."
        },
        "enabled": {
          "type": "boolean",
          "default": false,
          "description": "Whether this rule is active."
        },
        "allowed_domains": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "default": [],
          "description": "Hosts the agent may navigate to. Supports exact match and *.suffix wildcards."
        },
        "blocked_domains": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "default": [],
          "description": "Hosts that are always denied (evaluated before the allowlist)."
        },
        "allowed_verbs": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "default": [],
          "description": "Verbs (actions) the agent may issue. Empty means any verb."
        },
        "credential_detection": {
          "type": "boolean",
          "default": true,
          "description": "Check type/input action values for credential-shaped secrets."
        },
        "extra_credential_patterns": {
          "type": "array",
          "items": {
            "type": "string",
            "maxLength": 2048
          },
          "default": [],
          "description": "Extra credential regex patterns layered on top of the built-in detectors, in the HushSpec regex profile (core spec 3.14.3)."
        }
      }
    },
    "CodeExecution": {
      "type": "object",
      "additionalProperties": false,
      "description": "Restrictions for sandboxed interpreter actions: language allowlist, dangerous module denylist, network gating, and execution-time bounds.",
      "properties": {
        "when": {
          "$ref": "#/$defs/Condition",
          "description": "Condition gating whether this block is active (core spec 3.13)."
        },
        "enabled": {
          "type": "boolean",
          "default": false,
          "description": "Whether this rule is active."
        },
        "language_allowlist": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "default": [],
          "description": "Allowed interpreter languages (e.g. python, javascript). Empty means any language."
        },
        "module_denylist": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "default": [],
          "description": "Module names whose imports or uses in the code body are denied (word-boundary literal matches)."
        },
        "network_access": {
          "type": "boolean",
          "default": false,
          "description": "Permit code-execution calls that request network access."
        },
        "max_execution_time_ms": {
          "type": "integer",
          "minimum": 0,
          "description": "Maximum execution time in milliseconds.",
          "maximum": 9007199254740991
        },
        "max_scan_bytes": {
          "type": "integer",
          "minimum": 1,
          "description": "Maximum bytes of code to scan for module detection.",
          "maximum": 9007199254740991
        }
      }
    },
    "Condition": {
      "type": "object",
      "additionalProperties": false,
      "description": "Conditional rule-block gate (core spec 3.13). Present fields are combined with AND. Parsers MUST also reject nesting deeper than 8 levels.",
      "properties": {
        "time_window": {
          "$ref": "#/$defs/TimeWindow"
        },
        "context": {
          "type": "object",
          "additionalProperties": true,
          "description": "Dot-delimited runtime-context paths matched against the given values. Comparison is type-sensitive and numbers compare exactly. A scalar matches an equal scalar, or membership in an array at that path; an array matches when it shares at least one element with the value at that path."
        },
        "all_of": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/Condition"
          },
          "description": "Every sub-condition must hold."
        },
        "any_of": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/Condition"
          },
          "description": "At least one sub-condition must hold; an empty array is treated as absent."
        },
        "not": {
          "$ref": "#/$defs/Condition",
          "description": "The sub-condition must not hold. Unevaluable when the sub-condition is unevaluable (the block stays active)."
        },
        "capability": {
          "type": "string",
          "pattern": "^[a-z][a-z0-9_]*(\\.[a-z][a-z0-9_]*)*$",
          "description": "The effective posture state must grant this capability. Unevaluable (the block stays active) when the policy has no posture extension."
        },
        "rate": {
          "$ref": "#/$defs/RateCondition"
        }
      }
    },
    "RateCondition": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "counter",
        "threshold",
        "comparison"
      ],
      "description": "Compares an engine-supplied counter (runtime context `counters`) with a threshold. Unevaluable (the block stays active) when the counter is absent; HushSpec never stores state.",
      "properties": {
        "counter": {
          "type": "string",
          "pattern": "^[a-z][a-z0-9_]*(\\.[a-z][a-z0-9_]*)*$",
          "description": "Counter name in the runtime context's `counters` map."
        },
        "threshold": {
          "type": "integer",
          "minimum": 0,
          "description": "Non-negative threshold.",
          "maximum": 9007199254740991
        },
        "comparison": {
          "type": "string",
          "enum": [
            "gte",
            "lt"
          ],
          "description": "`gte`: counter >= threshold; `lt`: counter < threshold."
        }
      }
    },
    "TimeWindow": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "start",
        "end"
      ],
      "description": "Daily time window; half-open [start, end), wrapping midnight when start > end.",
      "properties": {
        "start": {
          "type": "string",
          "pattern": "^([01][0-9]|2[0-3]):[0-5][0-9]$",
          "description": "Window start, HH:MM 24-hour."
        },
        "end": {
          "type": "string",
          "pattern": "^([01][0-9]|2[0-3]):[0-5][0-9]$",
          "description": "Window end, HH:MM 24-hour."
        },
        "timezone": {
          "type": "string",
          "default": "UTC",
          "description": "IANA time zone identifier or fixed offset (+HH:MM / -HH:MM)."
        },
        "days": {
          "type": "array",
          "items": {
            "type": "string",
            "pattern": "^([Mm][Oo][Nn]|[Tt][Uu][Ee]|[Ww][Ee][Dd]|[Tt][Hh][Uu]|[Ff][Rr][Ii]|[Ss][Aa][Tt]|[Ss][Uu][Nn])$"
          },
          "description": "Days on which the window applies (case-insensitive abbreviations); defaults to all days."
        }
      }
    },
    "Extensions": {
      "type": "object",
      "additionalProperties": false,
      "description": "Extension modules for optional capabilities beyond core rules.",
      "$comment": "Each extension key is validated by its companion schema, referenced by that schema's own $id. The three companion documents are embedded verbatim at the end of $defs, so every reference resolves with no network access and an unknown key inside an extension block is rejected here exactly as it is by the companion schema on its own. `unevaluatedProperties` keeps that closed even if a companion root ever stops setting `additionalProperties: false`.",
      "properties": {
        "posture": {
          "type": "object",
          "$ref": "https://hushspec.org/schemas/hushspec-posture.v1.schema.json",
          "unevaluatedProperties": false,
          "description": "Stateful capability and budget management, as defined by the posture companion schema."
        },
        "origins": {
          "type": "object",
          "$ref": "https://hushspec.org/schemas/hushspec-origins.v1.schema.json",
          "unevaluatedProperties": false,
          "description": "Origin-aware policy profiles, as defined by the origins companion schema."
        },
        "detection": {
          "type": "object",
          "$ref": "https://hushspec.org/schemas/hushspec-detection.v1.schema.json",
          "unevaluatedProperties": false,
          "description": "Detection engine thresholds and configuration, as defined by the detection companion schema."
        }
      }
    },
    "GovernanceMetadata": {
      "type": "object",
      "additionalProperties": false,
      "description": "Optional governance metadata for enterprise policy lifecycle management. Has no impact on evaluation.",
      "properties": {
        "author": {
          "type": "string",
          "description": "Identity of the policy author (e.g., email, team name)."
        },
        "approved_by": {
          "type": "string",
          "description": "Identity of the policy approver."
        },
        "approval_date": {
          "type": "string",
          "format": "date",
          "description": "ISO 8601 calendar date (YYYY-MM-DD) when the policy was approved."
        },
        "classification": {
          "type": "string",
          "enum": [
            "public",
            "internal",
            "confidential",
            "restricted"
          ],
          "description": "Data classification level of the policy."
        },
        "change_ticket": {
          "type": "string",
          "description": "Change management reference (e.g., JIRA ticket, ServiceNow ID)."
        },
        "lifecycle_state": {
          "type": "string",
          "enum": [
            "draft",
            "review",
            "approved",
            "deployed",
            "deprecated",
            "archived"
          ],
          "description": "Current lifecycle state of the policy."
        },
        "policy_version": {
          "type": "integer",
          "minimum": 1,
          "description": "Monotonically increasing policy version counter.",
          "maximum": 9007199254740991
        },
        "effective_date": {
          "type": "string",
          "format": "date",
          "description": "ISO 8601 calendar date (YYYY-MM-DD) when the policy becomes effective."
        },
        "expiry_date": {
          "type": "string",
          "format": "date",
          "description": "ISO 8601 calendar date (YYYY-MM-DD) when the policy expires."
        },
        "owner": {
          "type": "string",
          "description": "Identity accountable for the policy over its lifetime (e.g., a team or distribution list). Distinct from 'author', who wrote this revision."
        },
        "reviewers": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "description": "Identities who reviewed the policy. Advisory only; separation of duties is checked by tooling, never by an engine."
        },
        "next_review_date": {
          "type": "string",
          "format": "date",
          "description": "ISO 8601 calendar date (YYYY-MM-DD) by which the policy is due for its next review."
        },
        "changelog": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/ChangelogEntry"
          },
          "description": "Revision history, newest first. Declarative only: entries never influence evaluation."
        },
        "supersedes": {
          "type": "string",
          "description": "The 'policy_version' this document replaces. A document MUST NOT supersede its own version."
        },
        "controls": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/ControlMapping"
          },
          "description": "Compliance control mappings for this policy. Declarative only: mappings never influence evaluation."
        }
      }
    },
    "ControlMapping": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "framework",
        "control_id",
        "rule_paths"
      ],
      "description": "Maps one compliance control onto the parts of this document that implement it. Advisory metadata: it has no effect on evaluation.",
      "properties": {
        "framework": {
          "type": "string",
          "pattern": "^[a-z0-9][a-z0-9.-]*$",
          "description": "Framework identifier, e.g. 'hipaa-2013' or 'soc2-tsc-2017'. Registered ids and their control-id patterns are listed in spec/registries/frameworks.yaml; unregistered ids are valid but are flagged by linters."
        },
        "control_id": {
          "type": "string",
          "minLength": 1,
          "description": "Control identifier within the framework, e.g. '164.312(e)(1)' or 'CC6.1'. Each registered framework declares a control_id_pattern."
        },
        "rule_paths": {
          "type": "array",
          "minItems": 1,
          "items": {
            "type": "string",
            "minLength": 1
          },
          "description": "Dot paths into the resolved document that implement the control. Grammar: path = root *( \".\" segment ) [ selector ]; root = \"rules\" / \"extensions\"; segment = 1*( ALPHA / DIGIT / \"_\" ); selector = \"[\" 1*( %x20-5A / %x5C / %x5E-7E ) \"]\" (any character except '[' and ']'). A selector names a list entry by its 'name' or 'id' field. Examples: 'rules' (the whole rules object), 'rules.egress' (one rule block), 'rules.egress.allow' (one field), 'rules.secret_patterns.patterns[ssn]' (one named secret pattern), 'extensions.posture'."
        },
        "notes": {
          "type": "string",
          "description": "Free-text rationale explaining how the mapped paths satisfy the control."
        }
      }
    },
    "ChangelogEntry": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "version",
        "date",
        "summary"
      ],
      "description": "One revision of the policy. Advisory metadata: it has no effect on evaluation.",
      "properties": {
        "version": {
          "type": "string",
          "minLength": 1,
          "description": "The 'policy_version' this entry describes, as a string."
        },
        "date": {
          "type": "string",
          "format": "date",
          "description": "ISO 8601 calendar date (YYYY-MM-DD) the revision was made."
        },
        "summary": {
          "type": "string",
          "minLength": 1,
          "description": "What changed in this revision."
        },
        "author": {
          "type": "string",
          "description": "Identity that made the revision."
        }
      }
    },
    "PostureExtension": {
      "$schema": "https://json-schema.org/draft/2020-12/schema",
      "$id": "https://hushspec.org/schemas/hushspec-posture.v1.schema.json",
      "title": "HushSpec Posture Extension v1",
      "description": "Schema for the HushSpec Posture extension. Declares a state machine for capability and budget management.",
      "type": "object",
      "required": [
        "initial",
        "states",
        "transitions"
      ],
      "additionalProperties": false,
      "properties": {
        "initial": {
          "type": "string",
          "description": "Initial state name. Must reference a key in states."
        },
        "states": {
          "type": "object",
          "description": "Named states in the posture state machine.",
          "minProperties": 1,
          "additionalProperties": {
            "$ref": "#/$defs/PostureState"
          }
        },
        "transitions": {
          "type": "array",
          "description": "Transitions between states, triggered by events.",
          "items": {
            "$ref": "#/$defs/PostureTransition"
          }
        }
      },
      "$defs": {
        "PostureState": {
          "type": "object",
          "additionalProperties": false,
          "description": "A named state in the posture state machine.",
          "properties": {
            "description": {
              "type": "string"
            },
            "capabilities": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "description": "Capability identifiers available in this state. Standard values: file_access, file_write, egress, shell, tool_call, patch, custom."
            },
            "budgets": {
              "type": "object",
              "description": "Budget limits keyed by budget key. Standard keys: file_writes, egress_calls, shell_commands, tool_calls, patches, custom_calls.",
              "additionalProperties": {
                "type": "integer",
                "minimum": 0,
                "maximum": 9007199254740991
              }
            }
          }
        },
        "PostureTransition": {
          "type": "object",
          "required": [
            "from",
            "to",
            "on"
          ],
          "additionalProperties": false,
          "description": "A transition between posture states.",
          "properties": {
            "from": {
              "type": "string",
              "description": "Source state name, or \"*\" to match any state."
            },
            "to": {
              "type": "string",
              "not": {
                "const": "*"
              },
              "description": "Target state name. Must not be \"*\"."
            },
            "on": {
              "type": "string",
              "enum": [
                "user_approval",
                "user_denial",
                "critical_violation",
                "any_violation",
                "timeout",
                "budget_exhausted",
                "pattern_match"
              ],
              "description": "Trigger that causes this transition."
            },
            "after": {
              "type": "string",
              "pattern": "^\\d+[smhd]$",
              "description": "Duration string. Required when trigger is \"timeout\". Format: <number><unit> where unit is s, m, h, or d."
            }
          },
          "if": {
            "properties": {
              "on": {
                "const": "timeout"
              }
            },
            "required": [
              "on"
            ]
          },
          "then": {
            "required": [
              "from",
              "to",
              "on",
              "after"
            ]
          }
        }
      }
    },
    "OriginsExtension": {
      "$schema": "https://json-schema.org/draft/2020-12/schema",
      "$id": "https://hushspec.org/schemas/hushspec-origins.v1.schema.json",
      "title": "HushSpec Origins Extension v1",
      "description": "Schema for the HushSpec Origins extension. Declares origin-aware policy projection for multi-source agent workflows.",
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "default_behavior": {
          "type": "string",
          "enum": [
            "deny",
            "minimal_profile"
          ],
          "default": "deny",
          "description": "Behavior when no profile matches. \"deny\" blocks unmatched origins; \"minimal_profile\" proceeds under base policy."
        },
        "profiles": {
          "type": "array",
          "description": "Origin profiles, each with match criteria and policy overrides.",
          "items": {
            "$ref": "#/$defs/OriginProfile"
          }
        }
      },
      "$defs": {
        "OriginProfile": {
          "type": "object",
          "required": [
            "id"
          ],
          "additionalProperties": false,
          "description": "An origin profile that narrows the base policy for matching requests.",
          "properties": {
            "id": {
              "type": "string",
              "description": "Unique identifier for this profile."
            },
            "match": {
              "$ref": "#/$defs/OriginMatch"
            },
            "posture": {
              "type": "string",
              "description": "Initial posture state for this origin. Must reference a state in extensions.posture.states."
            },
            "tool_access": {
              "$ref": "#/$defs/ToolAccessRule"
            },
            "egress": {
              "$ref": "#/$defs/EgressRule"
            },
            "data": {
              "$ref": "#/$defs/DataPolicy"
            },
            "budgets": {
              "$ref": "#/$defs/OriginBudgets"
            },
            "bridge": {
              "$ref": "#/$defs/BridgePolicy"
            },
            "explanation": {
              "type": "string"
            }
          }
        },
        "OriginMatch": {
          "type": "object",
          "additionalProperties": false,
          "description": "Criteria for matching an incoming request to this profile.",
          "properties": {
            "provider": {
              "type": "string",
              "description": "Source provider. Standard values: slack, teams, github, jira, email, discord, webhook, custom."
            },
            "tenant_id": {
              "type": "string",
              "description": "Tenant or workspace identifier."
            },
            "space_id": {
              "type": "string",
              "description": "Channel, room, or repository identifier. Highest priority match field."
            },
            "space_type": {
              "type": "string",
              "enum": [
                "channel",
                "group",
                "dm",
                "thread",
                "issue",
                "ticket",
                "pull_request",
                "email_thread"
              ],
              "description": "Type of space the request originated from."
            },
            "visibility": {
              "type": "string",
              "enum": [
                "private",
                "internal",
                "public",
                "external_shared"
              ],
              "description": "Visibility level of the source space."
            },
            "external_participants": {
              "type": "boolean",
              "description": "Whether external participants are present in the source space."
            },
            "tags": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "description": "Tags that must ALL be present on the source (AND semantics)."
            },
            "sensitivity": {
              "type": "string",
              "description": "Sensitivity classification of the source context."
            },
            "actor_role": {
              "type": "string",
              "description": "Role of the requesting actor (e.g., admin, member, guest)."
            }
          }
        },
        "ToolAccessRule": {
          "type": "object",
          "additionalProperties": false,
          "description": "Tool access overrides for this origin. Composes with base rules.tool_access via intersection (allow) and union (block).",
          "properties": {
            "allow": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "description": "Tool name allowlist. Intersected with base allowlist."
            },
            "block": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "description": "Tool name blocklist. Unioned with base blocklist."
            },
            "require_confirmation": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "description": "Tools requiring user/operator approval. Unioned with base list."
            },
            "default": {
              "type": "string",
              "enum": [
                "allow",
                "block"
              ],
              "description": "Default decision. If either base or origin specifies \"block\", effective default is \"block\"."
            },
            "max_args_size": {
              "type": "integer",
              "minimum": 1,
              "description": "Maximum argument payload size in bytes. The smaller of base and origin applies.",
              "maximum": 9007199254740991
            }
          }
        },
        "EgressRule": {
          "type": "object",
          "additionalProperties": false,
          "description": "Egress overrides for this origin. Composes with base rules.egress via intersection (allow) and union (block).",
          "properties": {
            "allow": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "description": "Domain allowlist. Intersected with base allowlist."
            },
            "block": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "description": "Domain blocklist. Unioned with base blocklist."
            },
            "default": {
              "type": "string",
              "enum": [
                "allow",
                "block"
              ],
              "description": "Default decision. If either base or origin specifies \"block\", effective default is \"block\"."
            }
          }
        },
        "DataPolicy": {
          "type": "object",
          "additionalProperties": false,
          "description": "Data handling controls for this origin context.",
          "properties": {
            "allow_external_sharing": {
              "type": "boolean",
              "default": false,
              "description": "Whether content may be shared outside the origin context."
            },
            "redact_before_send": {
              "type": "boolean",
              "default": false,
              "description": "Whether sensitive content must be redacted before output."
            },
            "block_sensitive_outputs": {
              "type": "boolean",
              "default": false,
              "description": "Whether outputs containing sensitive patterns are blocked."
            }
          }
        },
        "OriginBudgets": {
          "type": "object",
          "additionalProperties": false,
          "description": "Budget overrides for this origin. The smaller of base and origin values applies.",
          "properties": {
            "tool_calls": {
              "type": "integer",
              "minimum": 0,
              "description": "Maximum number of tool/MCP invocations.",
              "maximum": 9007199254740991
            },
            "egress_calls": {
              "type": "integer",
              "minimum": 0,
              "description": "Maximum number of outbound network requests.",
              "maximum": 9007199254740991
            },
            "shell_commands": {
              "type": "integer",
              "minimum": 0,
              "description": "Maximum number of shell command executions.",
              "maximum": 9007199254740991
            }
          }
        },
        "BridgePolicy": {
          "type": "object",
          "additionalProperties": false,
          "description": "Controls for cross-origin data flow.",
          "properties": {
            "allow_cross_origin": {
              "type": "boolean",
              "default": false,
              "description": "Whether cross-origin data flow is permitted."
            },
            "allowed_targets": {
              "type": "array",
              "items": {
                "$ref": "#/$defs/BridgeTarget"
              },
              "description": "Specific destinations permitted for cross-origin data flow."
            },
            "require_approval": {
              "type": "boolean",
              "default": false,
              "description": "Whether cross-origin flows require user/operator approval."
            }
          }
        },
        "BridgeTarget": {
          "type": "object",
          "additionalProperties": false,
          "description": "A permitted destination for cross-origin data flow.",
          "properties": {
            "provider": {
              "type": "string",
              "description": "Target provider."
            },
            "space_type": {
              "type": "string",
              "enum": [
                "channel",
                "group",
                "dm",
                "thread",
                "issue",
                "ticket",
                "pull_request",
                "email_thread"
              ],
              "description": "Target space type."
            },
            "tags": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "description": "Required tags on the target (AND semantics)."
            },
            "visibility": {
              "type": "string",
              "enum": [
                "private",
                "internal",
                "public",
                "external_shared"
              ],
              "description": "Required visibility level of the target."
            }
          }
        }
      }
    },
    "DetectionExtension": {
      "$schema": "https://json-schema.org/draft/2020-12/schema",
      "$id": "https://hushspec.org/schemas/hushspec-detection.v1.schema.json",
      "title": "HushSpec Detection Extension v1",
      "description": "Schema for the HushSpec Detection extension. Declares thresholds and configuration for content analysis guards.",
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "prompt_injection": {
          "$ref": "#/$defs/PromptInjectionDetection"
        },
        "jailbreak": {
          "$ref": "#/$defs/JailbreakDetection"
        },
        "threat_intel": {
          "$ref": "#/$defs/ThreatIntelDetection"
        }
      },
      "$defs": {
        "Level": {
          "type": "string",
          "enum": [
            "safe",
            "suspicious",
            "high",
            "critical"
          ],
          "description": "Detection severity level, ordered: safe < suspicious < high < critical."
        },
        "PromptInjectionDetection": {
          "type": "object",
          "additionalProperties": false,
          "description": "Configuration for prompt injection detection.",
          "properties": {
            "enabled": {
              "type": "boolean",
              "default": true,
              "description": "Whether prompt injection detection is active."
            },
            "warn_at_or_above": {
              "$ref": "#/$defs/Level",
              "default": "suspicious",
              "description": "Minimum detection level that produces a warning."
            },
            "block_at_or_above": {
              "$ref": "#/$defs/Level",
              "default": "high",
              "description": "Minimum detection level that produces a denial."
            },
            "max_scan_bytes": {
              "type": "integer",
              "minimum": 1,
              "default": 200000,
              "description": "Maximum input size to scan, in bytes.",
              "maximum": 9007199254740991
            },
            "heuristics": {
              "$ref": "#/$defs/PromptInjectionHeuristics"
            }
          }
        },
        "PromptInjectionHeuristics": {
          "type": "object",
          "additionalProperties": false,
          "description": "Configuration of the normative heuristic_injection@1 detector (detection spec 3.5).",
          "properties": {
            "enabled": {
              "type": "boolean",
              "default": true,
              "description": "Whether the heuristic detector runs alongside the regex detector."
            },
            "min_score": {
              "type": "integer",
              "minimum": 0,
              "maximum": 100,
              "default": 0,
              "description": "Integer scores below this floor are reported as 0 (no signal)."
            }
          }
        },
        "JailbreakDetection": {
          "type": "object",
          "additionalProperties": false,
          "description": "Configuration for jailbreak detection.",
          "properties": {
            "enabled": {
              "type": "boolean",
              "default": true,
              "description": "Whether jailbreak detection is active."
            },
            "block_threshold": {
              "type": "integer",
              "minimum": 0,
              "maximum": 100,
              "default": 80,
              "description": "Risk score (0-100) at or above which input is denied."
            },
            "warn_threshold": {
              "type": "integer",
              "minimum": 0,
              "maximum": 100,
              "default": 50,
              "description": "Risk score (0-100) at or above which a warning is produced."
            },
            "max_input_bytes": {
              "type": "integer",
              "minimum": 1,
              "default": 200000,
              "description": "Maximum input size to scan, in bytes.",
              "maximum": 9007199254740991
            }
          }
        },
        "ThreatIntelDetection": {
          "type": "object",
          "additionalProperties": false,
          "description": "Configuration for threat intelligence screening.",
          "properties": {
            "enabled": {
              "type": "boolean",
              "default": false,
              "description": "Whether threat intelligence screening is active."
            },
            "pattern_db": {
              "type": "string",
              "description": "Path to pattern database file or \"builtin:<name>\" for engine-bundled databases."
            },
            "similarity_threshold": {
              "type": "number",
              "minimum": 0,
              "maximum": 1,
              "default": 0.7,
              "description": "Minimum similarity score (0.0-1.0) for a pattern match to be considered a finding."
            },
            "top_k": {
              "type": "integer",
              "minimum": 1,
              "default": 5,
              "description": "Number of top matches to include in evaluation evidence.",
              "maximum": 9007199254740991
            }
          }
        }
      }
    }
  }
}
