{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://mergeharbor.com/schema/config.json",
  "title": "MergeHarbor configuration",
  "description": "Schema for .mergeharbor.yml and .mergeharbor/config.yml. See https://mergeharbor.com/docs/config/.",
  "type": "object",
  "additionalProperties": false,
  "properties": {
    "version": {
      "const": 1
    },
    "tier": {
      "enum": ["standard", "deep", "max"],
      "description": "Review tier. A pull request uses the highest tier any changed directory asks for."
    },
    "review": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "tier_rules": {
          "type": "array",
          "maxItems": 50,
          "description": "Rules that set the review tier when all their conditions hold, for example label security → max. They add to the organization's and repository's rules; the highest matching tier wins, and a rule set to auto lets MergeHarbor choose. Root configuration only.",
          "items": {
            "type": "object",
            "additionalProperties": false,
            "required": ["conditions", "tier"],
            "properties": {
              "name": { "type": "string", "maxLength": 100 },
              "conditions": {
                "type": "array",
                "minItems": 1,
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": ["field", "op", "values"],
                  "properties": {
                    "field": { "enum": ["author", "label", "base_branch", "head_branch", "path", "title", "files_changed", "lines_changed"] },
                    "op": { "enum": ["include", "exclude", "gt", "lt"] },
                    "values": { "type": "array", "items": { "type": "string" } }
                  }
                }
              },
              "tier": { "enum": ["standard", "deep", "max", "auto"] }
            }
          }
        },
        "reactions": {
          "type": "object",
          "additionalProperties": false,
          "description": "Emoji reactions on the pull request while MergeHarbor works: eyes when a review starts, thumbs up when it is posted, confused when it fails. Root configuration only.",
          "properties": { "enabled": { "type": "boolean" } }
        },
        "trigger": {
          "enum": ["all", "pushes", "opened", "never"],
          "description": "When reviews run automatically. Root configuration only."
        },
        "review_drafts": {
          "type": "boolean",
          "description": "Review draft pull requests. Root configuration only."
        },
        "filters": {
          "type": "array",
          "description": "Review only pull requests matching at least one rule. Root configuration only.",
          "items": {
            "type": "object",
            "additionalProperties": false,
            "required": ["conditions"],
            "properties": {
              "conditions": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": ["field", "op", "values"],
                  "properties": {
                    "field": {
                      "enum": ["author", "label", "base_branch", "head_branch", "path", "title", "files_changed", "lines_changed"]
                    },
                    "op": {
                      "enum": ["include", "exclude", "gt", "lt"],
                      "description": "include / exclude for text fields; gt / lt (greater or less than) for files_changed and lines_changed."
                    },
                    "values": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "depth": {
          "enum": ["quick", "standard", "deep", "max"],
          "description": "How much the reviewer investigates. Per directory: a pull request uses the deepest value any changed directory asks for. \"max\" is a shorthand for tier: max."
        },
        "strictness": {
          "enum": ["low", "medium", "high"],
          "description": "Shorthand for instructions.strictness."
        },
        "summary": {
          "type": "object",
          "additionalProperties": false,
          "description": "Root configuration only.",
          "properties": {
            "update_description": {
              "type": "boolean"
            },
            "include_summary": {
              "type": "boolean"
            },
            "include_confidence": {
              "type": "boolean"
            },
            "include_findings": {
              "type": "boolean"
            },
            "include_sequence_diagram": {
              "type": "boolean"
            },
            "collapsible": {
              "type": "boolean"
            }
          }
        },
        "instructions": {
          "description": "Custom review instructions (text), or an object with custom and strictness. In a nested directory they apply only to files under it.",
          "oneOf": [
            {
              "type": "string",
              "maxLength": 8000
            },
            {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "custom": {
                  "type": "string",
                  "maxLength": 8000
                },
                "strictness": {
                  "enum": ["low", "medium", "high"]
                }
              }
            }
          ]
        },
        "comments": {
          "type": "object",
          "additionalProperties": false,
          "description": "Root configuration only.",
          "properties": {
            "header": {
              "type": "string",
              "maxLength": 500
            },
            "include_fix_prompt": {
              "type": "boolean"
            }
          }
        },
        "fix": {
          "type": "object",
          "description": "Coding-agent hand-off: one-click buttons on comments, a line for every open finding in the summary, and closing findings that a push fixes.",
          "additionalProperties": false,
          "properties": {
            "links": {
              "enum": ["badges", "text", "off"],
              "description": "Buttons as small images, plain links (for mirrors that block images), or none."
            },
            "fix_all": { "type": "boolean", "description": "Add a line to the summary that sends every open finding to an agent." },
            "default_agent": { "enum": ["claude_code", "cursor", "codex", "copilot", "windsurf", "devin", "conductor"] },
            "auto_resolve": { "type": "boolean", "description": "Mark findings resolved when a push fixes them." },
            "resolve_threads": {
              "type": "boolean",
              "description": "Also resolve the conversation on the code host, or reply with the fixing commit."
            }
          }
        },
        "coding_agents": {
          "type": "array",
          "description": "Root configuration only.",
          "items": {
            "enum": ["claude_code", "cursor", "codex", "copilot", "windsurf", "devin", "conductor"]
          }
        },
        "merge_gate": {
          "type": "object",
          "additionalProperties": false,
          "description": "Merge gate: whether a pull request is safe to merge, reported as the \"MergeHarbor / merge gate\" check. Root configuration only.",
          "properties": {
            "enabled": { "type": "boolean" },
            "mode": {
              "enum": ["enforce", "advisory"],
              "description": "enforce: a blocked pull request fails the check. advisory: the check reports the verdict but never fails."
            },
            "preset": { "enum": ["relaxed", "standard", "strict", "regulated"], "description": "Starting point for the policy." },
            "rules": {
              "type": "object",
              "additionalProperties": false,
              "description": "Changes to the preset's checks. Anything left out keeps the preset's value. Actions are block, warn or off.",
              "properties": {
                "min_confidence": {
                  "type": "integer",
                  "minimum": 0,
                  "maximum": 5,
                  "description": "Lowest review confidence (1-5) that passes; 0 turns the check off."
                },
                "block_severity": {
                  "enum": ["critical", "major", "minor", "none"],
                  "description": "Open findings at or above this severity block the merge."
                },
                "warn_severity": {
                  "enum": ["critical", "major", "minor", "none"],
                  "description": "Open findings at or above this severity add a warning."
                },
                "proven_findings": {
                  "enum": ["block", "warn", "off"],
                  "description": "What an open finding proven by a failing generated test does."
                },
                "proof_run": {
                  "enum": ["block", "warn", "off"],
                  "description": "What a commit without a completed proof run does (when proof runs are on)."
                },
                "requirements": {
                  "enum": ["block", "warn", "off"],
                  "description": "What an acceptance criterion of a linked issue that is not met does."
                },
                "min_coverage": {
                  "type": "integer",
                  "minimum": 0,
                  "maximum": 100,
                  "description": "Changed-line test coverage (percent) below which the coverage action applies."
                },
                "coverage": { "enum": ["block", "warn", "off"], "description": "What changed-line coverage below min_coverage does." },
                "test_gaps": { "enum": ["block", "warn", "off"], "description": "What changed code without tests does." },
                "max_risk": { "enum": ["low", "medium", "high", "critical"], "description": "Highest change risk that passes." },
                "risk": { "enum": ["block", "warn", "off"], "description": "What change risk above max_risk does." },
                "required_approvals": {
                  "type": "integer",
                  "minimum": 0,
                  "maximum": 10,
                  "description": "Approvals the pull request needs on the code host."
                },
                "policy": { "enum": ["block", "warn", "off"], "description": "What team-rule violations and configuration errors do." }
              }
            },
            "branches": {
              "type": "array",
              "maxItems": 20,
              "description": "Policies for pull requests into matching target branches; the first matching pattern wins. Replaces the inherited list.",
              "items": {
                "type": "object",
                "additionalProperties": false,
                "required": ["pattern"],
                "properties": {
                  "pattern": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200,
                    "description": "Target branch name or glob, for example main or release/*."
                  },
                  "preset": {
                    "enum": ["relaxed", "standard", "strict", "regulated"],
                    "description": "Preset for these branches (left out: the default policy)."
                  },
                  "rules": {
                    "type": "object",
                    "additionalProperties": false,
                    "description": "Changes to the preset's checks. Anything left out keeps the preset's value. Actions are block, warn or off.",
                    "properties": {
                      "min_confidence": {
                        "type": "integer",
                        "minimum": 0,
                        "maximum": 5,
                        "description": "Lowest review confidence (1-5) that passes; 0 turns the check off."
                      },
                      "block_severity": {
                        "enum": ["critical", "major", "minor", "none"],
                        "description": "Open findings at or above this severity block the merge."
                      },
                      "warn_severity": {
                        "enum": ["critical", "major", "minor", "none"],
                        "description": "Open findings at or above this severity add a warning."
                      },
                      "proven_findings": {
                        "enum": ["block", "warn", "off"],
                        "description": "What an open finding proven by a failing generated test does."
                      },
                      "proof_run": {
                        "enum": ["block", "warn", "off"],
                        "description": "What a commit without a completed proof run does (when proof runs are on)."
                      },
                      "requirements": {
                        "enum": ["block", "warn", "off"],
                        "description": "What an acceptance criterion of a linked issue that is not met does."
                      },
                      "min_coverage": {
                        "type": "integer",
                        "minimum": 0,
                        "maximum": 100,
                        "description": "Changed-line test coverage (percent) below which the coverage action applies."
                      },
                      "coverage": { "enum": ["block", "warn", "off"], "description": "What changed-line coverage below min_coverage does." },
                      "test_gaps": { "enum": ["block", "warn", "off"], "description": "What changed code without tests does." },
                      "max_risk": { "enum": ["low", "medium", "high", "critical"], "description": "Highest change risk that passes." },
                      "risk": { "enum": ["block", "warn", "off"], "description": "What change risk above max_risk does." },
                      "required_approvals": {
                        "type": "integer",
                        "minimum": 0,
                        "maximum": 10,
                        "description": "Approvals the pull request needs on the code host."
                      },
                      "policy": { "enum": ["block", "warn", "off"], "description": "What team-rule violations and configuration errors do." }
                    }
                  }
                }
              }
            },
            "overrides": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "allowed": {
                  "type": "boolean",
                  "description": "Let people with the override permission override a block for one commit, with a reason."
                }
              }
            }
          }
        },
        "status_check": {
          "type": "object",
          "additionalProperties": false,
          "description": "Root configuration only.",
          "properties": {
            "enabled": {
              "type": "boolean"
            },
            "min_confidence_to_pass": {
              "type": "integer",
              "minimum": 0,
              "maximum": 5
            },
            "fail_on_severity": {
              "enum": ["critical", "major", null]
            },
            "post_error_comments": {
              "type": "boolean"
            }
          }
        },
        "auto_approve": {
          "type": "object",
          "additionalProperties": false,
          "description": "Root configuration only.",
          "properties": {
            "enabled": {
              "type": "boolean"
            }
          }
        },
        "ignore_paths": {
          "type": "array",
          "items": {
            "type": "string",
            "minLength": 1
          },
          "description": "Globs the review leaves out. In a nested directory the patterns are relative to it and add to the inherited ones."
        },
        "min_severity": {
          "enum": ["critical", "major", "minor", "nit"],
          "description": "Lowest severity posted. Per directory: the closest configuration to each file wins."
        },
        "max_comments": {
          "type": "integer",
          "minimum": 0,
          "maximum": 100,
          "description": "Root configuration only."
        },
        "categories": {
          "type": "array",
          "items": {
            "enum": [
              "correctness",
              "security",
              "concurrency",
              "performance",
              "error_handling",
              "api_contract",
              "data_integrity",
              "maintainability",
              "testing",
              "style"
            ]
          },
          "description": "Finding categories to report. Per directory: the closest configuration to each file wins."
        },
        "verify_findings": {
          "type": "boolean",
          "description": "Root configuration only."
        },
        "early_findings": {
          "type": "boolean",
          "description": "Post critical and major high-confidence findings as soon as they are found, before the full review. Root configuration only."
        },
        "quality": {
          "type": "object",
          "additionalProperties": false,
          "description": "Review-quality stages. Root configuration only.",
          "properties": {
            "hunk_triage": { "type": "boolean", "description": "Rank the diff's hunks by risk so the reviewer starts with the riskiest." },
            "impact_analysis": {
              "type": "boolean",
              "description": "Trace callers, implementations and config readers of the changed code; adds a blast-radius line."
            },
            "hybrid_retrieval": {
              "type": "boolean",
              "description": "Give the reviewer related code from text search, semantic search and the code graph."
            },
            "dedup": { "type": "boolean", "description": "Merge repeated findings and skip ones already raised on earlier commits." },
            "calibration": { "type": "boolean", "description": "Recompute confidence from the verifier's evidence and team feedback." },
            "precision_target": { "type": "number", "minimum": 0, "maximum": 0.95, "description": "With calibration: 0 (off) or 0.5-0.95." },
            "learned_suppression": {
              "type": "boolean",
              "description": "Hold back lower-priority categories the team keeps passing on (never security or correctness)."
            }
          }
        },
        "checks": {
          "type": "object",
          "additionalProperties": false,
          "description": "Deterministic checks. In a nested directory only disable applies.",
          "properties": {
            "enabled": {
              "type": "boolean"
            },
            "disable": {
              "type": "array",
              "items": {
                "enum": [
                  "*",
                  "secret.hardcoded",
                  "secret.private-key",
                  "secret.npm-token",
                  "secret.credential-file",
                  "sql.string-built",
                  "xss.html-sink",
                  "code.eval",
                  "shell.injection",
                  "tls.verify-disabled",
                  "svg.active-content",
                  "merge.conflict-marker",
                  "debug.breakpoint",
                  "go.unchecked-decode",
                  "debug.console-log",
                  "file.large",
                  "binary.source-file",
                  "binary.in-source",
                  "data.possible-dump",
                  "deserialize.unsafe",
                  "loop.off-by-one",
                  "async.not-awaited",
                  "java.string-identity",
                  "crypto.weak-hash",
                  "crypto.weak-random",
                  "error.swallowed",
                  "resource.not-closed",
                  "py.mutable-default",
                  "apex.soql-injection",
                  "sql.dynamic-concat",
                  "jcl.hardcoded-password",
                  "terraform.hardcoded-secret",
                  "docker.unpinned-base",
                  "docker.root-user",
                  "migration.index-blocking",
                  "migration.not-null-no-default",
                  "migration.column-type-change",
                  "migration.set-not-null",
                  "migration.constraint-validated",
                  "migration.drop-column",
                  "migration.drop-table",
                  "migration.rename",
                  "migration.backfill-in-transaction",
                  "migration.data-wipe",
                  "migration.irreversible",
                  "migration.edited",
                  "contract.openapi",
                  "contract.protobuf",
                  "contract.graphql"
                ]
              }
            },
            "enable": {
              "type": "array",
              "items": {
                "enum": [
                  "*",
                  "secret.hardcoded",
                  "secret.private-key",
                  "secret.npm-token",
                  "secret.credential-file",
                  "sql.string-built",
                  "xss.html-sink",
                  "code.eval",
                  "shell.injection",
                  "tls.verify-disabled",
                  "svg.active-content",
                  "merge.conflict-marker",
                  "debug.breakpoint",
                  "go.unchecked-decode",
                  "debug.console-log",
                  "file.large",
                  "binary.source-file",
                  "binary.in-source",
                  "data.possible-dump",
                  "deserialize.unsafe",
                  "loop.off-by-one",
                  "async.not-awaited",
                  "java.string-identity",
                  "crypto.weak-hash",
                  "crypto.weak-random",
                  "error.swallowed",
                  "resource.not-closed",
                  "py.mutable-default",
                  "apex.soql-injection",
                  "sql.dynamic-concat",
                  "jcl.hardcoded-password",
                  "terraform.hardcoded-secret",
                  "docker.unpinned-base",
                  "docker.root-user",
                  "migration.index-blocking",
                  "migration.not-null-no-default",
                  "migration.column-type-change",
                  "migration.set-not-null",
                  "migration.constraint-validated",
                  "migration.drop-column",
                  "migration.drop-table",
                  "migration.rename",
                  "migration.backfill-in-transaction",
                  "migration.data-wipe",
                  "migration.irreversible",
                  "migration.edited",
                  "contract.openapi",
                  "contract.protobuf",
                  "contract.graphql"
                ]
              }
            },
            "large_file_kb": {
              "type": "integer",
              "minimum": 0,
              "maximum": 1048576
            }
          }
        },
        "docstrings": {
          "type": "object",
          "additionalProperties": false,
          "description": "Generate docstrings: doc comments for the functions, methods, classes and exported symbols a pull request adds or changes without one (requested from the console or with `@mergeharbor docstrings`).",
          "properties": {
            "enabled": { "type": "boolean", "description": "Allow generating docstrings for this repository's pull requests (metered in credits)." },
            "delivery": { "enum": ["pull_request", "commit"], "description": "pull_request opens a follow-up pull request against the branch; commit pushes a commit to the branch (console requests only)." },
            "exclude": { "type": "array", "maxItems": 100, "items": { "type": "string" }, "description": "Path globs never documented." },
            "max_symbols": { "type": "integer", "minimum": 1, "maximum": 200, "description": "Symbols documented per request." }
          }
        },
        "test_gaps": {
          "type": "object",
          "additionalProperties": false,
          "description": "Test-gap detection: changed functions with logic that no test exercises, from CI coverage reports or a static estimate.",
          "properties": {
            "enabled": { "type": "boolean", "description": "Report changed functions that no test exercises." },
            "severity": { "enum": ["major", "minor", "nit"], "description": "Severity of test-gap findings." },
            "min_function_lines": { "type": "integer", "minimum": 1, "maximum": 500, "description": "Shorter functions are never reported." },
            "max_findings": {
              "type": "integer",
              "minimum": 0,
              "maximum": 20,
              "description": "Test-gap comments per review (0 = none; the console still shows the signals)."
            },
            "coverage_target": {
              "type": "integer",
              "minimum": 0,
              "maximum": 100,
              "description": "Share of changed lines tests should cover, in percent (0 = no target)."
            }
          }
        },
        "tier": {
          "enum": ["standard", "deep", "max"],
          "description": "Review tier. A pull request uses the highest tier any changed directory asks for."
        }
      }
    },
    "rules": {
      "type": "array",
      "maxItems": 100,
      "items": {
        "oneOf": [
          {
            "type": "string",
            "minLength": 1,
            "maxLength": 2000
          },
          {
            "type": "object",
            "additionalProperties": false,
            "required": ["rule"],
            "properties": {
              "rule": {
                "type": "string",
                "minLength": 1,
                "maxLength": 2000
              },
              "paths": {
                "type": "array",
                "items": {
                  "type": "string",
                  "minLength": 1
                },
                "description": "Globs relative to this directory; empty = the whole directory."
              },
              "scope": {
                "type": "array",
                "items": {
                  "type": "string",
                  "minLength": 1
                },
                "description": "Alias of paths."
              },
              "severity": {
                "enum": ["critical", "major", "minor", "nit"]
              },
              "id": {
                "type": "string",
                "pattern": "^[A-Za-z0-9._-]{1,64}$",
                "description": "Names the rule so a deeper folder can turn it off with disable_rules."
              }
            }
          }
        ]
      },
      "description": "Natural-language rules for files under this directory (same as rules.md)."
    },
    "context": {
      "description": "Files, notes and repositories the reviewer always receives as context. Paths are relative to this folder; a leading / means the repository root.",
      "oneOf": [
        {
          "type": "array",
          "maxItems": 20,
          "items": {
            "oneOf": [
              {
                "type": "string",
                "minLength": 1
              },
              {
                "type": "object",
                "additionalProperties": false,
                "required": ["path"],
                "properties": {
                  "path": {
                    "type": "string",
                    "minLength": 1
                  },
                  "reason": {
                    "type": "string"
                  },
                  "description": {
                    "type": "string"
                  },
                  "paths": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "minLength": 1
                    },
                    "description": "Only when the pull request changes matching files (relative to this folder)."
                  },
                  "scope": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "minLength": 1
                    },
                    "description": "Alias of paths."
                  }
                }
              }
            ]
          }
        },
        {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "version": {
              "const": 1
            },
            "files": {
              "type": "array",
              "maxItems": 20,
              "items": {
                "oneOf": [
                  {
                    "type": "string",
                    "minLength": 1
                  },
                  {
                    "type": "object",
                    "additionalProperties": false,
                    "required": ["path"],
                    "properties": {
                      "path": {
                        "type": "string",
                        "minLength": 1
                      },
                      "reason": {
                        "type": "string"
                      },
                      "description": {
                        "type": "string"
                      },
                      "paths": {
                        "type": "array",
                        "items": {
                          "type": "string",
                          "minLength": 1
                        },
                        "description": "Only when the pull request changes matching files (relative to this folder)."
                      },
                      "scope": {
                        "type": "array",
                        "items": {
                          "type": "string",
                          "minLength": 1
                        },
                        "description": "Alias of paths."
                      }
                    }
                  }
                ]
              }
            },
            "notes": {
              "type": "array",
              "items": {
                "oneOf": [
                  {
                    "type": "string",
                    "minLength": 1
                  },
                  {
                    "type": "object",
                    "additionalProperties": false,
                    "properties": {
                      "note": {
                        "type": "string"
                      },
                      "text": {
                        "type": "string"
                      },
                      "content": {
                        "type": "string"
                      },
                      "paths": {
                        "type": "array",
                        "items": {
                          "type": "string",
                          "minLength": 1
                        }
                      },
                      "scope": {
                        "type": "array",
                        "items": {
                          "type": "string",
                          "minLength": 1
                        }
                      }
                    }
                  }
                ]
              },
              "description": "Background the reviewer should know (not rules to enforce)."
            },
            "repos": {
              "type": "array",
              "maxItems": 20,
              "items": {
                "type": "string",
                "pattern": "^[A-Za-z0-9._-]+(/[A-Za-z0-9._-]+)+$"
              },
              "description": "Other repositories (owner/name) the reviewer may read as context."
            }
          }
        }
      ]
    },
    "tier_rules": {
      "type": "array",
      "maxItems": 50,
      "description": "Rules that set the review tier when all their conditions hold, for example label security → max. They add to the organization's and repository's rules; the highest matching tier wins, and a rule set to auto lets MergeHarbor choose. Root configuration only.",
      "items": {
        "type": "object",
        "additionalProperties": false,
        "required": ["conditions", "tier"],
        "properties": {
          "name": { "type": "string", "maxLength": 100 },
          "conditions": {
            "type": "array",
            "minItems": 1,
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": ["field", "op", "values"],
              "properties": {
                "field": { "enum": ["author", "label", "base_branch", "head_branch", "path", "title", "files_changed", "lines_changed"] },
                "op": { "enum": ["include", "exclude", "gt", "lt"] },
                "values": { "type": "array", "items": { "type": "string" } }
              }
            }
          },
          "tier": { "enum": ["standard", "deep", "max", "auto"] }
        }
      }
    },
    "reactions": {
      "type": "object",
      "additionalProperties": false,
      "description": "Emoji reactions on the pull request while MergeHarbor works: eyes when a review starts, thumbs up when it is posted, confused when it fails. Root configuration only.",
      "properties": { "enabled": { "type": "boolean" } }
    },
    "trigger": {
      "enum": ["all", "pushes", "opened", "never"],
      "description": "When reviews run automatically. Root configuration only."
    },
    "review_drafts": {
      "type": "boolean",
      "description": "Review draft pull requests. Root configuration only."
    },
    "filters": {
      "type": "array",
      "description": "Review only pull requests matching at least one rule. Root configuration only.",
      "items": {
        "type": "object",
        "additionalProperties": false,
        "required": ["conditions"],
        "properties": {
          "conditions": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": ["field", "op", "values"],
              "properties": {
                "field": {
                  "enum": ["author", "label", "base_branch", "head_branch", "path", "title", "files_changed", "lines_changed"]
                },
                "op": {
                  "enum": ["include", "exclude", "gt", "lt"],
                  "description": "include / exclude for text fields; gt / lt (greater or less than) for files_changed and lines_changed."
                },
                "values": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                }
              }
            }
          }
        }
      }
    },
    "depth": {
      "enum": ["quick", "standard", "deep", "max"],
      "description": "How much the reviewer investigates. Per directory: a pull request uses the deepest value any changed directory asks for. \"max\" is a shorthand for tier: max."
    },
    "strictness": {
      "enum": ["low", "medium", "high"],
      "description": "Shorthand for instructions.strictness."
    },
    "summary": {
      "type": "object",
      "additionalProperties": false,
      "description": "Root configuration only.",
      "properties": {
        "update_description": {
          "type": "boolean"
        },
        "include_summary": {
          "type": "boolean"
        },
        "include_confidence": {
          "type": "boolean"
        },
        "include_findings": {
          "type": "boolean"
        },
        "include_sequence_diagram": {
          "type": "boolean"
        },
        "collapsible": {
          "type": "boolean"
        }
      }
    },
    "instructions": {
      "description": "Custom review instructions (text), or an object with custom and strictness. In a nested directory they apply only to files under it.",
      "oneOf": [
        {
          "type": "string",
          "maxLength": 8000
        },
        {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "custom": {
              "type": "string",
              "maxLength": 8000
            },
            "strictness": {
              "enum": ["low", "medium", "high"]
            }
          }
        }
      ]
    },
    "comments": {
      "type": "object",
      "additionalProperties": false,
      "description": "Root configuration only.",
      "properties": {
        "header": {
          "type": "string",
          "maxLength": 500
        },
        "include_fix_prompt": {
          "type": "boolean"
        }
      }
    },
    "fix": {
      "type": "object",
      "description": "Coding-agent hand-off: one-click buttons on comments, a line for every open finding in the summary, and closing findings that a push fixes.",
      "additionalProperties": false,
      "properties": {
        "links": {
          "enum": ["badges", "text", "off"],
          "description": "Buttons as small images, plain links (for mirrors that block images), or none."
        },
        "fix_all": { "type": "boolean", "description": "Add a line to the summary that sends every open finding to an agent." },
        "default_agent": { "enum": ["claude_code", "cursor", "codex", "copilot", "windsurf", "devin", "conductor"] },
        "auto_resolve": { "type": "boolean", "description": "Mark findings resolved when a push fixes them." },
        "resolve_threads": { "type": "boolean", "description": "Also resolve the conversation on the code host, or reply with the fixing commit." }
      }
    },
    "coding_agents": {
      "type": "array",
      "description": "Root configuration only.",
      "items": {
        "enum": ["claude_code", "cursor", "codex", "copilot", "windsurf", "devin", "conductor"]
      }
    },
    "merge_gate": {
      "type": "object",
      "additionalProperties": false,
      "description": "Merge gate: whether a pull request is safe to merge, reported as the \"MergeHarbor / merge gate\" check. Root configuration only.",
      "properties": {
        "enabled": { "type": "boolean" },
        "mode": {
          "enum": ["enforce", "advisory"],
          "description": "enforce: a blocked pull request fails the check. advisory: the check reports the verdict but never fails."
        },
        "preset": { "enum": ["relaxed", "standard", "strict", "regulated"], "description": "Starting point for the policy." },
        "rules": {
          "type": "object",
          "additionalProperties": false,
          "description": "Changes to the preset's checks. Anything left out keeps the preset's value. Actions are block, warn or off.",
          "properties": {
            "min_confidence": {
              "type": "integer",
              "minimum": 0,
              "maximum": 5,
              "description": "Lowest review confidence (1-5) that passes; 0 turns the check off."
            },
            "block_severity": {
              "enum": ["critical", "major", "minor", "none"],
              "description": "Open findings at or above this severity block the merge."
            },
            "warn_severity": {
              "enum": ["critical", "major", "minor", "none"],
              "description": "Open findings at or above this severity add a warning."
            },
            "proven_findings": { "enum": ["block", "warn", "off"], "description": "What an open finding proven by a failing generated test does." },
            "proof_run": {
              "enum": ["block", "warn", "off"],
              "description": "What a commit without a completed proof run does (when proof runs are on)."
            },
            "requirements": {
              "enum": ["block", "warn", "off"],
              "description": "What an acceptance criterion of a linked issue that is not met does."
            },
            "min_coverage": {
              "type": "integer",
              "minimum": 0,
              "maximum": 100,
              "description": "Changed-line test coverage (percent) below which the coverage action applies."
            },
            "coverage": { "enum": ["block", "warn", "off"], "description": "What changed-line coverage below min_coverage does." },
            "test_gaps": { "enum": ["block", "warn", "off"], "description": "What changed code without tests does." },
            "max_risk": { "enum": ["low", "medium", "high", "critical"], "description": "Highest change risk that passes." },
            "risk": { "enum": ["block", "warn", "off"], "description": "What change risk above max_risk does." },
            "required_approvals": {
              "type": "integer",
              "minimum": 0,
              "maximum": 10,
              "description": "Approvals the pull request needs on the code host."
            },
            "policy": { "enum": ["block", "warn", "off"], "description": "What team-rule violations and configuration errors do." }
          }
        },
        "branches": {
          "type": "array",
          "maxItems": 20,
          "description": "Policies for pull requests into matching target branches; the first matching pattern wins. Replaces the inherited list.",
          "items": {
            "type": "object",
            "additionalProperties": false,
            "required": ["pattern"],
            "properties": {
              "pattern": {
                "type": "string",
                "minLength": 1,
                "maxLength": 200,
                "description": "Target branch name or glob, for example main or release/*."
              },
              "preset": {
                "enum": ["relaxed", "standard", "strict", "regulated"],
                "description": "Preset for these branches (left out: the default policy)."
              },
              "rules": {
                "type": "object",
                "additionalProperties": false,
                "description": "Changes to the preset's checks. Anything left out keeps the preset's value. Actions are block, warn or off.",
                "properties": {
                  "min_confidence": {
                    "type": "integer",
                    "minimum": 0,
                    "maximum": 5,
                    "description": "Lowest review confidence (1-5) that passes; 0 turns the check off."
                  },
                  "block_severity": {
                    "enum": ["critical", "major", "minor", "none"],
                    "description": "Open findings at or above this severity block the merge."
                  },
                  "warn_severity": {
                    "enum": ["critical", "major", "minor", "none"],
                    "description": "Open findings at or above this severity add a warning."
                  },
                  "proven_findings": {
                    "enum": ["block", "warn", "off"],
                    "description": "What an open finding proven by a failing generated test does."
                  },
                  "proof_run": {
                    "enum": ["block", "warn", "off"],
                    "description": "What a commit without a completed proof run does (when proof runs are on)."
                  },
                  "requirements": {
                    "enum": ["block", "warn", "off"],
                    "description": "What an acceptance criterion of a linked issue that is not met does."
                  },
                  "min_coverage": {
                    "type": "integer",
                    "minimum": 0,
                    "maximum": 100,
                    "description": "Changed-line test coverage (percent) below which the coverage action applies."
                  },
                  "coverage": { "enum": ["block", "warn", "off"], "description": "What changed-line coverage below min_coverage does." },
                  "test_gaps": { "enum": ["block", "warn", "off"], "description": "What changed code without tests does." },
                  "max_risk": { "enum": ["low", "medium", "high", "critical"], "description": "Highest change risk that passes." },
                  "risk": { "enum": ["block", "warn", "off"], "description": "What change risk above max_risk does." },
                  "required_approvals": {
                    "type": "integer",
                    "minimum": 0,
                    "maximum": 10,
                    "description": "Approvals the pull request needs on the code host."
                  },
                  "policy": { "enum": ["block", "warn", "off"], "description": "What team-rule violations and configuration errors do." }
                }
              }
            }
          }
        },
        "overrides": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "allowed": { "type": "boolean", "description": "Let people with the override permission override a block for one commit, with a reason." }
          }
        }
      }
    },
    "status_check": {
      "type": "object",
      "additionalProperties": false,
      "description": "Root configuration only.",
      "properties": {
        "enabled": {
          "type": "boolean"
        },
        "min_confidence_to_pass": {
          "type": "integer",
          "minimum": 0,
          "maximum": 5
        },
        "fail_on_severity": {
          "enum": ["critical", "major", null]
        },
        "post_error_comments": {
          "type": "boolean"
        }
      }
    },
    "auto_approve": {
      "type": "object",
      "additionalProperties": false,
      "description": "Root configuration only.",
      "properties": {
        "enabled": {
          "type": "boolean"
        }
      }
    },
    "ignore_paths": {
      "type": "array",
      "items": {
        "type": "string",
        "minLength": 1
      },
      "description": "Globs the review leaves out. In a nested directory the patterns are relative to it and add to the inherited ones."
    },
    "min_severity": {
      "enum": ["critical", "major", "minor", "nit"],
      "description": "Lowest severity posted. Per directory: the closest configuration to each file wins."
    },
    "max_comments": {
      "type": "integer",
      "minimum": 0,
      "maximum": 100,
      "description": "Root configuration only."
    },
    "categories": {
      "type": "array",
      "items": {
        "enum": [
          "correctness",
          "security",
          "concurrency",
          "performance",
          "error_handling",
          "api_contract",
          "data_integrity",
          "maintainability",
          "testing",
          "style"
        ]
      },
      "description": "Finding categories to report. Per directory: the closest configuration to each file wins."
    },
    "verify_findings": {
      "type": "boolean",
      "description": "Root configuration only."
    },
    "early_findings": {
      "type": "boolean",
      "description": "Post critical and major high-confidence findings as soon as they are found, before the full review. Root configuration only."
    },
    "quality": {
      "type": "object",
      "additionalProperties": false,
      "description": "Review-quality stages. Root configuration only.",
      "properties": {
        "hunk_triage": { "type": "boolean", "description": "Rank the diff's hunks by risk so the reviewer starts with the riskiest." },
        "impact_analysis": {
          "type": "boolean",
          "description": "Trace callers, implementations and config readers of the changed code; adds a blast-radius line."
        },
        "hybrid_retrieval": {
          "type": "boolean",
          "description": "Give the reviewer related code from text search, semantic search and the code graph."
        },
        "dedup": { "type": "boolean", "description": "Merge repeated findings and skip ones already raised on earlier commits." },
        "calibration": { "type": "boolean", "description": "Recompute confidence from the verifier's evidence and team feedback." },
        "precision_target": { "type": "number", "minimum": 0, "maximum": 0.95, "description": "With calibration: 0 (off) or 0.5-0.95." },
        "learned_suppression": {
          "type": "boolean",
          "description": "Hold back lower-priority categories the team keeps passing on (never security or correctness)."
        }
      }
    },
    "checks": {
      "type": "object",
      "additionalProperties": false,
      "description": "Deterministic checks. In a nested directory only disable applies.",
      "properties": {
        "enabled": {
          "type": "boolean"
        },
        "disable": {
          "type": "array",
          "items": {
            "enum": [
              "*",
              "secret.hardcoded",
              "secret.private-key",
              "secret.npm-token",
              "secret.credential-file",
              "sql.string-built",
              "xss.html-sink",
              "code.eval",
              "shell.injection",
              "tls.verify-disabled",
              "svg.active-content",
              "merge.conflict-marker",
              "debug.breakpoint",
              "go.unchecked-decode",
              "debug.console-log",
              "file.large",
              "binary.source-file",
              "binary.in-source",
              "data.possible-dump",
              "deserialize.unsafe",
              "loop.off-by-one",
              "async.not-awaited",
              "java.string-identity",
              "crypto.weak-hash",
              "crypto.weak-random",
              "error.swallowed",
              "resource.not-closed",
              "py.mutable-default",
              "apex.soql-injection",
              "sql.dynamic-concat",
              "jcl.hardcoded-password",
              "terraform.hardcoded-secret",
              "docker.unpinned-base",
              "docker.root-user",
              "migration.index-blocking",
              "migration.not-null-no-default",
              "migration.column-type-change",
              "migration.set-not-null",
              "migration.constraint-validated",
              "migration.drop-column",
              "migration.drop-table",
              "migration.rename",
              "migration.backfill-in-transaction",
              "migration.data-wipe",
              "migration.irreversible",
              "migration.edited",
              "contract.openapi",
              "contract.protobuf",
              "contract.graphql"
            ]
          }
        },
        "enable": {
          "type": "array",
          "items": {
            "enum": [
              "*",
              "secret.hardcoded",
              "secret.private-key",
              "secret.npm-token",
              "secret.credential-file",
              "sql.string-built",
              "xss.html-sink",
              "code.eval",
              "shell.injection",
              "tls.verify-disabled",
              "svg.active-content",
              "merge.conflict-marker",
              "debug.breakpoint",
              "go.unchecked-decode",
              "debug.console-log",
              "file.large",
              "binary.source-file",
              "binary.in-source",
              "data.possible-dump",
              "deserialize.unsafe",
              "loop.off-by-one",
              "async.not-awaited",
              "java.string-identity",
              "crypto.weak-hash",
              "crypto.weak-random",
              "error.swallowed",
              "resource.not-closed",
              "py.mutable-default",
              "apex.soql-injection",
              "sql.dynamic-concat",
              "jcl.hardcoded-password",
              "terraform.hardcoded-secret",
              "docker.unpinned-base",
              "docker.root-user",
              "migration.index-blocking",
              "migration.not-null-no-default",
              "migration.column-type-change",
              "migration.set-not-null",
              "migration.constraint-validated",
              "migration.drop-column",
              "migration.drop-table",
              "migration.rename",
              "migration.backfill-in-transaction",
              "migration.data-wipe",
              "migration.irreversible",
              "migration.edited",
              "contract.openapi",
              "contract.protobuf",
              "contract.graphql"
            ]
          }
        },
        "large_file_kb": {
          "type": "integer",
          "minimum": 0,
          "maximum": 1048576
        }
      }
    },
    "docstrings": {
      "type": "object",
      "additionalProperties": false,
      "description": "Generate docstrings: doc comments for the functions, methods, classes and exported symbols a pull request adds or changes without one (requested from the console or with `@mergeharbor docstrings`).",
      "properties": {
        "enabled": { "type": "boolean", "description": "Allow generating docstrings for this repository's pull requests (metered in credits)." },
        "delivery": { "enum": ["pull_request", "commit"], "description": "pull_request opens a follow-up pull request against the branch; commit pushes a commit to the branch (console requests only)." },
        "exclude": { "type": "array", "maxItems": 100, "items": { "type": "string" }, "description": "Path globs never documented." },
        "max_symbols": { "type": "integer", "minimum": 1, "maximum": 200, "description": "Symbols documented per request." }
      }
    },
    "test_gaps": {
      "type": "object",
      "additionalProperties": false,
      "description": "Test-gap detection: changed functions with logic that no test exercises, from CI coverage reports or a static estimate.",
      "properties": {
        "enabled": { "type": "boolean", "description": "Report changed functions that no test exercises." },
        "severity": { "enum": ["major", "minor", "nit"], "description": "Severity of test-gap findings." },
        "min_function_lines": { "type": "integer", "minimum": 1, "maximum": 500, "description": "Shorter functions are never reported." },
        "max_findings": {
          "type": "integer",
          "minimum": 0,
          "maximum": 20,
          "description": "Test-gap comments per review (0 = none; the console still shows the signals)."
        },
        "coverage_target": {
          "type": "integer",
          "minimum": 0,
          "maximum": 100,
          "description": "Share of changed lines tests should cover, in percent (0 = no target)."
        }
      }
    },
    "disable_rules": {
      "type": "array",
      "items": {
        "type": "string"
      },
      "description": "Rule ids inherited from folders above that do not apply here."
    },
    "security": {
      "type": "object",
      "description": "Vulnerability inventory scope (root configuration only). Test fixtures, examples and docs are skipped by default; vendored copies are read. See https://mergeharbor.com/docs/vulnerability-management/.",
      "additionalProperties": false,
      "properties": {
        "paths": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "include": { "type": "array", "maxItems": 100, "items": { "type": "string" }, "description": "Globs from the repository root read even where the defaults skip (they win over exclude)." },
            "exclude": { "type": "array", "maxItems": 100, "items": { "type": "string" }, "description": "Globs from the repository root never read." },
            "scan_examples_and_tests": { "type": "boolean", "description": "Read test fixtures, examples and documentation like the project's own code." }
          }
        }
      }
    },
    "compliance": {
      "type": "object",
      "description": "Compliance policies for this repository (root configuration only). They add to the organization's policies and cannot disable them. See https://mergeharbor.com/docs/compliance/.",
      "additionalProperties": false,
      "properties": {
        "version": { "const": 1 },
        "policies": {
          "type": "array",
          "maxItems": 200,
          "items": {
            "type": "object",
            "additionalProperties": false,
            "required": ["id", "require"],
            "properties": {
              "id": { "type": "string", "pattern": "^[a-z0-9][a-z0-9._-]{0,63}$" },
              "name": { "type": "string", "maxLength": 120 },
              "description": { "type": "string", "maxLength": 2000 },
              "severity": { "enum": ["blocking", "advisory"] },
              "applies_to": {
                "type": "object",
                "additionalProperties": false,
                "properties": {
                  "branches": {
                    "type": "array",
                    "items": { "type": "string" },
                    "description": "Target branch globs; $default is the repository's default branch."
                  },
                  "paths": { "type": "array", "items": { "type": "string" } },
                  "repos": { "type": "array", "items": { "type": "string" } },
                  "labels": { "type": "array", "items": { "type": "string" } }
                }
              },
              "require": {
                "type": "array",
                "minItems": 1,
                "maxItems": 20,
                "items": {
                  "oneOf": [
                    {
                      "enum": [
                        "approvals",
                        "no_open_findings",
                        "review_completed",
                        "no_secrets",
                        "migration_rollback",
                        "proof_run",
                        "requirements_met",
                        "merge_gate"
                      ]
                    },
                    {
                      "type": "object",
                      "minProperties": 1,
                      "maxProperties": 1,
                      "properties": {
                        "approvals": {
                          "type": ["object", "null"],
                          "additionalProperties": false,
                          "properties": {
                            "min": { "type": "integer", "minimum": 1, "maximum": 10 },
                            "exclude_author": { "type": "boolean" },
                            "on_final_commit": { "type": "boolean" },
                            "from_teams": { "type": "array", "items": { "type": "string" } }
                          }
                        },
                        "no_open_findings": {
                          "type": ["object", "null"],
                          "additionalProperties": false,
                          "properties": {
                            "min_severity": { "enum": ["critical", "major", "minor", "nit"] },
                            "categories": { "type": "array", "items": { "type": "string" } },
                            "dismissals_need_reason": { "type": "boolean" }
                          }
                        },
                        "review_completed": {
                          "type": ["object", "null"],
                          "additionalProperties": false,
                          "properties": { "on_final_commit": { "type": "boolean" }, "min_tier": { "enum": ["standard", "deep", "max"] } }
                        },
                        "category_reviewed": {
                          "type": "object",
                          "additionalProperties": false,
                          "required": ["category"],
                          "properties": { "category": { "type": "string" }, "min_severity": { "enum": ["critical", "major", "minor", "nit"] } }
                        },
                        "no_secrets": { "type": ["object", "null"], "additionalProperties": false },
                        "migration_rollback": {
                          "type": ["object", "null"],
                          "additionalProperties": false,
                          "properties": {
                            "paths": { "type": "array", "items": { "type": "string" } },
                            "rollback": { "type": "array", "items": { "type": "string" } },
                            "or_label": { "type": "string" },
                            "or_section": { "type": "string" }
                          }
                        },
                        "proof_run": {
                          "type": ["object", "null"],
                          "additionalProperties": false,
                          "properties": {
                            "outcomes": { "type": "array", "items": { "enum": ["passed", "bugs_found", "inconclusive", "no_tests"] } },
                            "on_final_commit": { "type": "boolean" }
                          }
                        },
                        "requirements_met": {
                          "type": ["object", "null"],
                          "additionalProperties": false,
                          "properties": { "allow_unclear": { "type": "boolean" }, "require_linked": { "type": "boolean" } }
                        },
                        "labels": {
                          "type": "object",
                          "additionalProperties": false,
                          "required": ["any_of"],
                          "properties": { "any_of": { "type": "array", "items": { "type": "string" } } }
                        },
                        "merge_gate": { "type": ["object", "null"], "additionalProperties": false }
                      },
                      "additionalProperties": false
                    }
                  ]
                }
              },
              "frameworks": {
                "type": "object",
                "description": "Framework requirement references, e.g. {soc2: [CC8.1], pci_dss: [6.5.1]}.",
                "additionalProperties": { "type": "array", "items": { "type": "string" } }
              }
            }
          }
        }
      }
    }
  }
}
