{
  "type": "object",
  "properties": {
    "$schema": {
      "type": "string",
      "description": "JSON Schema URL used by editors for validation and autocomplete."
    },
    "enabled": {
      "type": "boolean",
      "description": "Enable or disable the entire pi-tools-suite extension."
    },
    "disabledModules": {
      "type": "array",
      "items": {
        "type": "string"
      },
      "description": "List of disabled module names (e.g. ['lsp', 'prompt-commands'])."
    },
    "enabledModules": {
      "type": "array",
      "items": {
        "type": "string"
      },
      "description": "List of module names to explicitly enable, including modules that are disabled by default."
    },
    "modules": {
      "type": "object",
      "patternProperties": {
        "^.*$": {
          "type": "boolean"
        }
      },
      "description": "Per-module enable/disable map. credential-firewall is disabled by default and can be enabled here."
    },
    "todoThinking": {
      "type": "boolean",
      "description": "Enable per-todo thinking levels and automatic thinking switch/restore when tasks become in-progress/completed."
    },
    "todoThinkingOverrides": {
      "type": "object",
      "patternProperties": {
        "^.*$": {
          "anyOf": [
            {
              "type": "string",
              "const": "off"
            },
            {
              "type": "string",
              "const": "minimal"
            },
            {
              "type": "string",
              "const": "low"
            },
            {
              "type": "string",
              "const": "medium"
            },
            {
              "type": "string",
              "const": "high"
            },
            {
              "type": "string",
              "const": "xhigh"
            },
            {
              "type": "string",
              "const": "max"
            },
            {
              "type": "null"
            }
          ]
        }
      },
      "description": "Force per-todo thinking for matching provider/model or bare-model keys. Keys support * and ? wildcards; null removes an inherited override."
    },
    "lookupModel": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "description": "Vision-capable provider/model used by GLM's lookup tool; unset or null disables lookup."
    },
    "lookupFallbackModels": {
      "type": "array",
      "items": {
        "type": "string"
      },
      "description": "Ordered lookup model fallbacks tried after lookupModel."
    },
    "terminalBell": {
      "type": "object",
      "properties": {
        "sound": {
          "type": "boolean",
          "description": "Play terminal bell sound on completion/error."
        }
      },
      "description": "Terminal bell configuration."
    },
    "telegramConnector": {
      "type": "object",
      "properties": {
        "enabled": {
          "type": "boolean",
          "description": "Enable the Telegram task connector. Defaults to enabled when botToken and chatId are present."
        },
        "botToken": {
          "type": "string",
          "description": "Telegram Bot API token from @BotFather."
        },
        "chatId": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "integer"
            }
          ],
          "description": "Private Telegram chat id allowed to control Pix."
        }
      },
      "description": "Receive completion/question notifications and send follow-up or new-session tasks from Telegram."
    },
    "commentChecker": {
      "type": "object",
      "properties": {
        "enabled": {
          "type": "boolean",
          "description": "Enable or disable comment-checker without disabling the whole module."
        },
        "strictness": {
          "anyOf": [
            {
              "type": "string",
              "const": "conservative"
            },
            {
              "type": "string",
              "const": "balanced"
            },
            {
              "type": "string",
              "const": "aggressive"
            }
          ],
          "description": "Comment classification strictness. Defaults to balanced."
        }
      },
      "description": "Settings for the comment-checker module."
    },
    "dcp": {
      "type": "object",
      "properties": {
        "enabled": {
          "type": "boolean",
          "description": "Enable DCP (Dynamic Context Pruning)."
        },
        "debug": {
          "type": "boolean",
          "description": "Enable DCP debug logging."
        },
        "debugLog": {
          "type": "object",
          "properties": {
            "maxBytes": {
              "type": "number",
              "description": "Maximum size in bytes of the active debug log before it is rotated. Default 5242880 (5 MB).",
              "minimum": 1024
            },
            "maxBackups": {
              "type": "number",
              "description": "Number of rotated backups to keep (.1 .. .N). Default 3, minimum 1.",
              "minimum": 1
            }
          },
          "description": "Debug log rotation. The JSONL log is written to ~/.pi/agent/dcp-debug.jsonl."
        },
        "manualMode": {
          "type": "object",
          "properties": {
            "enabled": {
              "type": "boolean",
              "description": "Enable manual DCP mode."
            },
            "automaticStrategies": {
              "not": {},
              "description": "Removed legacy key. Manual mode now has only the explicit enabled flag."
            }
          },
          "description": "Manual mode configuration."
        },
        "compress": {
          "type": "object",
          "properties": {
            "maxContextPercent": {
              "anyOf": [
                {
                  "type": "number"
                },
                {
                  "type": "string"
                }
              ],
              "description": "Maximum context percent (0–1 or '80%') before compression triggers."
            },
            "minContextPercent": {
              "anyOf": [
                {
                  "type": "number"
                },
                {
                  "type": "string"
                }
              ],
              "description": "Target context percent after compression."
            },
            "modelMaxContextPercent": {
              "type": "object",
              "patternProperties": {
                "^.*$": {
                  "anyOf": [
                    {
                      "type": "number"
                    },
                    {
                      "type": "string"
                    }
                  ]
                }
              },
              "description": "Per-model max context overrides using the same fraction/token/percent formats."
            },
            "modelMinContextPercent": {
              "type": "object",
              "patternProperties": {
                "^.*$": {
                  "anyOf": [
                    {
                      "type": "number"
                    },
                    {
                      "type": "string"
                    }
                  ]
                }
              },
              "description": "Per-model min context overrides using the same fraction/token/percent formats."
            },
            "maxContextLimit": {
              "anyOf": [
                {
                  "type": "number"
                },
                {
                  "type": "string"
                }
              ],
              "description": "Absolute max context tokens or '200k'."
            },
            "minContextLimit": {
              "anyOf": [
                {
                  "type": "number"
                },
                {
                  "type": "string"
                }
              ],
              "description": "Absolute min context tokens."
            },
            "modelMaxContextLimits": {
              "type": "object",
              "patternProperties": {
                "^.*$": {
                  "anyOf": [
                    {
                      "type": "number"
                    },
                    {
                      "type": "string"
                    }
                  ]
                }
              },
              "description": "Per-model max context limit overrides."
            },
            "modelMinContextLimits": {
              "type": "object",
              "patternProperties": {
                "^.*$": {
                  "anyOf": [
                    {
                      "type": "number"
                    },
                    {
                      "type": "string"
                    }
                  ]
                }
              },
              "description": "Per-model min context limit overrides."
            },
            "summaryBuffer": {
              "type": "boolean",
              "description": "Buffer summary output."
            },
            "nudgeFrequency": {
              "type": "number",
              "description": "Inject nudge every N context events.",
              "minimum": 1
            },
            "iterationNudgeThreshold": {
              "type": "number",
              "description": "Nudge after N tool calls since last user message.",
              "minimum": 1
            },
            "nudgeForce": {
              "anyOf": [
                {
                  "type": "string",
                  "const": "strong"
                },
                {
                  "type": "string",
                  "const": "soft"
                }
              ],
              "description": "Nudge intensity."
            },
            "protectedTools": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "description": "Tool outputs protected from pruning."
            },
            "protectTags": {
              "type": "boolean",
              "description": "Protect XML-like tags from pruning."
            },
            "protectUserMessages": {
              "type": "boolean",
              "description": "Protect user messages from pruning."
            },
            "autoCandidates": {
              "type": "object",
              "properties": {
                "enabled": {
                  "type": "boolean",
                  "description": "Enable auto candidate selection for compression."
                },
                "minContextPercent": {
                  "type": "number",
                  "description": "Minimum context usage to trigger auto-candidates.",
                  "minimum": 0,
                  "maximum": 1
                },
                "keepRecentTurns": {
                  "type": "number",
                  "description": "Number of recent turns to keep.",
                  "minimum": 0
                },
                "minMessages": {
                  "type": "number",
                  "description": "Minimum messages before auto-candidate selection.",
                  "minimum": 0
                },
                "minTokens": {
                  "type": "number",
                  "description": "Minimum tokens for auto-candidate selection.",
                  "minimum": 0
                }
              },
              "description": "Auto-candidate selection for compression."
            },
            "messageMode": {
              "type": "object",
              "properties": {
                "enabled": {
                  "type": "boolean",
                  "description": "Enable message-mode compression suggestions."
                },
                "minContextPercent": {
                  "type": "number",
                  "description": "Minimum context usage to trigger message mode.",
                  "minimum": 0,
                  "maximum": 1
                },
                "keepRecentTurns": {
                  "type": "number",
                  "description": "Recent turns to keep.",
                  "minimum": 0
                },
                "mediumTokens": {
                  "type": "number",
                  "description": "Token threshold for medium-quality summary.",
                  "minimum": 0
                },
                "highTokens": {
                  "type": "number",
                  "description": "Token threshold for high-quality summary.",
                  "minimum": 0
                },
                "maxSuggestions": {
                  "type": "number",
                  "description": "Maximum compression suggestions.",
                  "minimum": 0
                }
              },
              "description": "Message-mode compression configuration."
            },
            "autoCompress": {
              "type": "object",
              "properties": {
                "enabled": {
                  "type": "boolean",
                  "description": "Allow autonomous compression after pressure/opportunity gates. Explicit compress calls can still use summarizerModel when summary is omitted."
                },
                "patience": {
                  "type": "number",
                  "description": "Completed actionable opportunities allowed before automatic compression.",
                  "minimum": 0
                },
                "summarizerModel": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  },
                  "description": "Ordered model refs used by auto-compress and explicit compress when summary is omitted; empty uses the deterministic extractive summary."
                },
                "summarizerFallbackModels": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  },
                  "description": "Ordered fallback model refs tried after summarizerModel."
                },
                "timeoutMs": {
                  "type": "number",
                  "description": "Per-summarizer deadline in milliseconds for automatic and explicit generated summaries.",
                  "minimum": 1
                }
              },
              "description": "Bounded automatic compression fallback."
            }
          },
          "description": "Compression trigger and behavior configuration."
        },
        "strategies": {
          "type": "object",
          "properties": {
            "emergencyCurrentTurnPruning": {
              "type": "object",
              "properties": {
                "enabled": {
                  "type": "boolean",
                  "description": "Enable bounded same-turn emergency planning and last-resort output pruning."
                },
                "hardContextPercent": {
                  "type": "number",
                  "description": "Context fraction that activates hard emergency pressure.",
                  "minimum": 0,
                  "maximum": 1
                },
                "targetContextPercent": {
                  "type": "number",
                  "description": "Context fraction the emergency path attempts to recover toward.",
                  "minimum": 0,
                  "maximum": 1
                },
                "patience": {
                  "type": "number",
                  "description": "Completed emergency opportunities allowed before last-resort pruning.",
                  "minimum": 0
                },
                "keepRecentToolPairs": {
                  "type": "number",
                  "description": "Newest complete tool-call/result pairs never selected by emergency cleanup.",
                  "minimum": 0
                },
                "minOutputTokens": {
                  "type": "number",
                  "description": "Minimum tool-result size eligible for emergency pruning.",
                  "minimum": 0
                },
                "maxSuggestions": {
                  "type": "number",
                  "description": "Maximum emergency message candidates shown in a reminder.",
                  "minimum": 0
                },
                "protectedTools": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  },
                  "description": "Additional tools protected from emergency pruning and manual sweep."
                }
              },
              "description": "Single bounded emergency cleanup strategy."
            },
            "deduplication": {
              "not": {},
              "description": "Removed legacy key; no automatic replacement policy maps to it."
            },
            "purgeErrors": {
              "not": {},
              "description": "Removed legacy key; no automatic replacement policy maps to it."
            },
            "autoToolPruning": {
              "not": {},
              "description": "Removed legacy key. Use explicit /dcp sweep or DCP compression/emergency policies instead."
            }
          },
          "description": "Bounded DCP emergency strategy."
        },
        "protectedFilePatterns": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "description": "File path glob patterns whose content is protected from pruning."
        },
        "modelOverrides": {
          "type": "object",
          "patternProperties": {
            "^.*$": {
              "type": "object",
              "properties": {
                "enabled": {
                  "type": "boolean"
                },
                "debug": {
                  "type": "boolean"
                },
                "debugLog": {
                  "type": "object",
                  "properties": {
                    "maxBytes": {
                      "type": "number",
                      "minimum": 1024
                    },
                    "maxBackups": {
                      "type": "number",
                      "minimum": 1
                    }
                  }
                },
                "manualMode": {
                  "type": "object",
                  "properties": {
                    "enabled": {
                      "type": "boolean",
                      "description": "Enable manual DCP mode."
                    },
                    "automaticStrategies": {
                      "not": {},
                      "description": "Removed legacy key. Manual mode now has only the explicit enabled flag."
                    }
                  },
                  "description": "Manual mode configuration."
                },
                "compress": {
                  "type": "object",
                  "properties": {
                    "maxContextPercent": {
                      "anyOf": [
                        {
                          "type": "number"
                        },
                        {
                          "type": "string"
                        }
                      ],
                      "description": "Maximum context percent (0–1 or '80%') before compression triggers."
                    },
                    "minContextPercent": {
                      "anyOf": [
                        {
                          "type": "number"
                        },
                        {
                          "type": "string"
                        }
                      ],
                      "description": "Target context percent after compression."
                    },
                    "modelMaxContextPercent": {
                      "type": "object",
                      "patternProperties": {
                        "^.*$": {
                          "anyOf": [
                            {
                              "type": "number"
                            },
                            {
                              "type": "string"
                            }
                          ]
                        }
                      },
                      "description": "Per-model max context overrides using the same fraction/token/percent formats."
                    },
                    "modelMinContextPercent": {
                      "type": "object",
                      "patternProperties": {
                        "^.*$": {
                          "anyOf": [
                            {
                              "type": "number"
                            },
                            {
                              "type": "string"
                            }
                          ]
                        }
                      },
                      "description": "Per-model min context overrides using the same fraction/token/percent formats."
                    },
                    "maxContextLimit": {
                      "anyOf": [
                        {
                          "type": "number"
                        },
                        {
                          "type": "string"
                        }
                      ],
                      "description": "Absolute max context tokens or '200k'."
                    },
                    "minContextLimit": {
                      "anyOf": [
                        {
                          "type": "number"
                        },
                        {
                          "type": "string"
                        }
                      ],
                      "description": "Absolute min context tokens."
                    },
                    "modelMaxContextLimits": {
                      "type": "object",
                      "patternProperties": {
                        "^.*$": {
                          "anyOf": [
                            {
                              "type": "number"
                            },
                            {
                              "type": "string"
                            }
                          ]
                        }
                      },
                      "description": "Per-model max context limit overrides."
                    },
                    "modelMinContextLimits": {
                      "type": "object",
                      "patternProperties": {
                        "^.*$": {
                          "anyOf": [
                            {
                              "type": "number"
                            },
                            {
                              "type": "string"
                            }
                          ]
                        }
                      },
                      "description": "Per-model min context limit overrides."
                    },
                    "summaryBuffer": {
                      "type": "boolean",
                      "description": "Buffer summary output."
                    },
                    "nudgeFrequency": {
                      "type": "number",
                      "description": "Inject nudge every N context events.",
                      "minimum": 1
                    },
                    "iterationNudgeThreshold": {
                      "type": "number",
                      "description": "Nudge after N tool calls since last user message.",
                      "minimum": 1
                    },
                    "nudgeForce": {
                      "anyOf": [
                        {
                          "type": "string",
                          "const": "strong"
                        },
                        {
                          "type": "string",
                          "const": "soft"
                        }
                      ],
                      "description": "Nudge intensity."
                    },
                    "protectedTools": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      },
                      "description": "Tool outputs protected from pruning."
                    },
                    "protectTags": {
                      "type": "boolean",
                      "description": "Protect XML-like tags from pruning."
                    },
                    "protectUserMessages": {
                      "type": "boolean",
                      "description": "Protect user messages from pruning."
                    },
                    "autoCandidates": {
                      "type": "object",
                      "properties": {
                        "enabled": {
                          "type": "boolean",
                          "description": "Enable auto candidate selection for compression."
                        },
                        "minContextPercent": {
                          "type": "number",
                          "description": "Minimum context usage to trigger auto-candidates.",
                          "minimum": 0,
                          "maximum": 1
                        },
                        "keepRecentTurns": {
                          "type": "number",
                          "description": "Number of recent turns to keep.",
                          "minimum": 0
                        },
                        "minMessages": {
                          "type": "number",
                          "description": "Minimum messages before auto-candidate selection.",
                          "minimum": 0
                        },
                        "minTokens": {
                          "type": "number",
                          "description": "Minimum tokens for auto-candidate selection.",
                          "minimum": 0
                        }
                      },
                      "description": "Auto-candidate selection for compression."
                    },
                    "messageMode": {
                      "type": "object",
                      "properties": {
                        "enabled": {
                          "type": "boolean",
                          "description": "Enable message-mode compression suggestions."
                        },
                        "minContextPercent": {
                          "type": "number",
                          "description": "Minimum context usage to trigger message mode.",
                          "minimum": 0,
                          "maximum": 1
                        },
                        "keepRecentTurns": {
                          "type": "number",
                          "description": "Recent turns to keep.",
                          "minimum": 0
                        },
                        "mediumTokens": {
                          "type": "number",
                          "description": "Token threshold for medium-quality summary.",
                          "minimum": 0
                        },
                        "highTokens": {
                          "type": "number",
                          "description": "Token threshold for high-quality summary.",
                          "minimum": 0
                        },
                        "maxSuggestions": {
                          "type": "number",
                          "description": "Maximum compression suggestions.",
                          "minimum": 0
                        }
                      },
                      "description": "Message-mode compression configuration."
                    },
                    "autoCompress": {
                      "type": "object",
                      "properties": {
                        "enabled": {
                          "type": "boolean",
                          "description": "Allow autonomous compression after pressure/opportunity gates. Explicit compress calls can still use summarizerModel when summary is omitted."
                        },
                        "patience": {
                          "type": "number",
                          "description": "Completed actionable opportunities allowed before automatic compression.",
                          "minimum": 0
                        },
                        "summarizerModel": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          },
                          "description": "Ordered model refs used by auto-compress and explicit compress when summary is omitted; empty uses the deterministic extractive summary."
                        },
                        "summarizerFallbackModels": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          },
                          "description": "Ordered fallback model refs tried after summarizerModel."
                        },
                        "timeoutMs": {
                          "type": "number",
                          "description": "Per-summarizer deadline in milliseconds for automatic and explicit generated summaries.",
                          "minimum": 1
                        }
                      },
                      "description": "Bounded automatic compression fallback."
                    }
                  },
                  "description": "Compression trigger and behavior configuration."
                },
                "strategies": {
                  "type": "object",
                  "properties": {
                    "emergencyCurrentTurnPruning": {
                      "type": "object",
                      "properties": {
                        "enabled": {
                          "type": "boolean",
                          "description": "Enable bounded same-turn emergency planning and last-resort output pruning."
                        },
                        "hardContextPercent": {
                          "type": "number",
                          "description": "Context fraction that activates hard emergency pressure.",
                          "minimum": 0,
                          "maximum": 1
                        },
                        "targetContextPercent": {
                          "type": "number",
                          "description": "Context fraction the emergency path attempts to recover toward.",
                          "minimum": 0,
                          "maximum": 1
                        },
                        "patience": {
                          "type": "number",
                          "description": "Completed emergency opportunities allowed before last-resort pruning.",
                          "minimum": 0
                        },
                        "keepRecentToolPairs": {
                          "type": "number",
                          "description": "Newest complete tool-call/result pairs never selected by emergency cleanup.",
                          "minimum": 0
                        },
                        "minOutputTokens": {
                          "type": "number",
                          "description": "Minimum tool-result size eligible for emergency pruning.",
                          "minimum": 0
                        },
                        "maxSuggestions": {
                          "type": "number",
                          "description": "Maximum emergency message candidates shown in a reminder.",
                          "minimum": 0
                        },
                        "protectedTools": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          },
                          "description": "Additional tools protected from emergency pruning and manual sweep."
                        }
                      },
                      "description": "Single bounded emergency cleanup strategy."
                    },
                    "deduplication": {
                      "not": {},
                      "description": "Removed legacy key; no automatic replacement policy maps to it."
                    },
                    "purgeErrors": {
                      "not": {},
                      "description": "Removed legacy key; no automatic replacement policy maps to it."
                    },
                    "autoToolPruning": {
                      "not": {},
                      "description": "Removed legacy key. Use explicit /dcp sweep or DCP compression/emergency policies instead."
                    }
                  },
                  "description": "Bounded DCP emergency strategy."
                },
                "protectedFilePatterns": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                },
                "pruneNotification": {
                  "not": {},
                  "description": "Removed legacy key; pruning notifications are no longer configurable."
                }
              },
              "description": "Partial DCP override applied to a matching provider/model or bare-model key. Keys support * and ? wildcards."
            }
          },
          "description": "Per-model partial DCP overrides. Exact keys take precedence over matching wildcards."
        },
        "pruneNotification": {
          "not": {},
          "description": "Removed legacy key; pruning notifications are no longer configurable."
        }
      },
      "description": "DCP (Dynamic Context Pruning) configuration."
    },
    "toolRenderer": {
      "type": "object",
      "properties": {
        "default": {
          "type": "object",
          "properties": {
            "previewLines": {
              "type": "number",
              "minimum": 0,
              "description": "Lines to show in the tool preview."
            },
            "direction": {
              "anyOf": [
                {
                  "type": "string",
                  "const": "head"
                },
                {
                  "type": "string",
                  "const": "tail"
                }
              ],
              "description": "Preview direction."
            },
            "color": {
              "type": "string",
              "description": "Theme color name or hex color."
            },
            "defaultExpanded": {
              "type": "boolean",
              "description": "Expand tool output by default."
            },
            "compactHidden": {
              "type": "boolean",
              "description": "Compact hidden placeholder."
            },
            "hidden": {
              "type": "boolean",
              "description": "Hide tool output completely."
            }
          },
          "description": "Per-tool rendering rule."
        },
        "tools": {
          "type": "object",
          "patternProperties": {
            "^.*$": {
              "type": "object",
              "properties": {
                "previewLines": {
                  "type": "number",
                  "minimum": 0,
                  "description": "Lines to show in the tool preview."
                },
                "direction": {
                  "anyOf": [
                    {
                      "type": "string",
                      "const": "head"
                    },
                    {
                      "type": "string",
                      "const": "tail"
                    }
                  ],
                  "description": "Preview direction."
                },
                "color": {
                  "type": "string",
                  "description": "Theme color name or hex color."
                },
                "defaultExpanded": {
                  "type": "boolean",
                  "description": "Expand tool output by default."
                },
                "compactHidden": {
                  "type": "boolean",
                  "description": "Compact hidden placeholder."
                },
                "hidden": {
                  "type": "boolean",
                  "description": "Hide tool output completely."
                }
              },
              "description": "Per-tool rendering rule."
            }
          },
          "description": "Tool-specific rendering rules keyed by tool name or glob pattern, e.g. 'bash' or 'repo_*'."
        }
      },
      "description": "Per-tool rendering configuration."
    },
    "promptCommands": {
      "type": "object",
      "properties": {
        "commands": {
          "type": "object",
          "patternProperties": {
            "^.*$": {
              "type": "object",
              "required": [
                "prompt"
              ],
              "properties": {
                "description": {
                  "type": "string",
                  "description": "Short description shown in command menu."
                },
                "prompt": {
                  "type": "string",
                  "description": "The prompt text to send. Supports {cwd} template variable."
                }
              },
              "description": "A saved slash command."
            }
          },
          "description": "Command definitions keyed by slash command name."
        }
      },
      "description": "User-defined slash commands."
    },
    "secretFirewall": {
      "type": "object",
      "properties": {
        "sessionHygiene": {
          "type": "boolean",
          "description": "Redact detected secret material from tool results and completed messages before it remains in session history."
        },
        "notify": {
          "type": "boolean",
          "description": "Show a warning when one or more secrets are redacted. Secret values are never included in notifications."
        }
      },
      "description": "Settings for the opt-in credential-firewall module."
    },
    "contextGateway": {
      "type": "object",
      "properties": {
        "mode": {
          "anyOf": [
            {
              "type": "string",
              "const": "off"
            },
            {
              "type": "string",
              "const": "observe"
            },
            {
              "type": "string",
              "const": "enforce"
            }
          ],
          "description": "Context Gateway mode. observe is passive; enforce only compacts proven complete simple test/build output and otherwise passes results through."
        },
        "budgets": {
          "type": "object",
          "properties": {
            "maxInlineBytes": {
              "type": "integer",
              "minimum": 1,
              "maximum": 67108864,
              "description": "Maximum inline size for a proven compact representation. Default 8192."
            },
            "maxResultBytes": {
              "type": "integer",
              "minimum": 1,
              "maximum": 67108864,
              "description": "Budget for shell/other result classes. Selective enforce currently compacts only recognised complete simple test/build output. Default 8192."
            },
            "maxExactReadBytes": {
              "type": "integer",
              "minimum": 1,
              "maximum": 67108864,
              "description": "Read-class observation budget. Reads remain passthrough because snapshot-safe recovery is not available. Default 32768."
            },
            "maxSearchBytes": {
              "type": "integer",
              "minimum": 1,
              "maximum": 67108864,
              "description": "Repo-search/AST/structure observation budget. Gateway does not post-hoc truncate producer output. Default 8192."
            },
            "maxSearchMatches": {
              "type": "integer",
              "minimum": 1,
              "maximum": 1000,
              "description": "Reserved search-match policy budget. Default 12."
            }
          },
          "description": "Context Gateway class-specific observation and selective-enforcement budgets."
        }
      },
      "description": "Context Gateway configuration. Default mode is off."
    },
    "repoDiscovery": {
      "type": "object",
      "properties": {
        "profile": {
          "anyOf": [
            {
              "type": "string",
              "const": "baseline"
            },
            {
              "type": "string",
              "const": "native-compact"
            }
          ],
          "description": "repo_* runtime profile. baseline preserves historical argv/defaults; native-compact enables bounded native flags, cursors, validation, and an explicit per-call full override."
        }
      },
      "description": "Repository discovery runtime policy. Default profile is baseline."
    },
    "resourceRegistry": {
      "type": "object",
      "properties": {
        "remote": {
          "type": "string",
          "description": "Git remote URL for the private registry. The repository contains reusable top-level skills/ and agents/ plus project-scoped state under projects/."
        },
        "branch": {
          "type": "string",
          "description": "Registry branch used for install/update/push/pull. Defaults to main."
        },
        "projectKey": {
          "type": "string",
          "description": "Optional explicit key for this project's projects/<key>/tasks.jsonc, plans/, and TODO.md state. Normally derived from the current Git origin."
        }
      },
      "description": "Private Git-backed registry for reusable skills/agents and project-scoped tasks/plans state."
    },
    "lsp": {
      "type": "object",
      "properties": {
        "servers": {
          "type": "array",
          "items": {
            "type": "object",
            "required": [
              "id",
              "bin"
            ],
            "properties": {
              "id": {
                "type": "string",
                "description": "Unique server identifier."
              },
              "enabled": {
                "type": "boolean",
                "description": "Enable/disable this server."
              },
              "include": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "description": "File glob patterns to include."
              },
              "exclude": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "description": "File glob patterns to exclude."
              },
              "rootMarkers": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "description": "Files that indicate a project root (e.g. ['package.json', '.git'])."
              },
              "maxFileSizeBytes": {
                "type": "number",
                "description": "Max file size to send to the server.",
                "minimum": 0
              },
              "bin": {
                "type": "string",
                "description": "Path to the language server binary."
              },
              "args": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "description": "Command-line arguments."
              },
              "cwd": {
                "type": "string",
                "description": "Working directory for the server process."
              },
              "env": {
                "type": "object",
                "patternProperties": {
                  "^.*$": {
                    "type": "string"
                  }
                },
                "description": "Environment variables."
              },
              "config": {
                "type": "string",
                "description": "Path to server configuration file."
              },
              "languageIdByExtension": {
                "type": "object",
                "patternProperties": {
                  "^.*$": {
                    "type": "string"
                  }
                },
                "description": "File extension → language ID mapping, e.g. {'.ts': 'typescript'}."
              },
              "startupTimeoutMs": {
                "type": "number",
                "description": "Server startup timeout in ms.",
                "minimum": 1000
              },
              "diagnosticsWaitMs": {
                "type": "number",
                "description": "Wait time for diagnostics after file change.",
                "minimum": 0
              },
              "pullDiagnostics": {
                "type": "boolean",
                "description": "When false, skip textDocument/diagnostic pull requests and rely on published diagnostics. Useful for servers where pull diagnostics is slow or incomplete."
              },
              "waitForPublishDiagnostics": {
                "type": "boolean",
                "description": "When false, do not wait for a fresh textDocument/publishDiagnostics notification after file change. diagnosticsWaitMs still bounds the wait when enabled."
              },
              "initializationOptions": {
                "description": "LSP initialization options passed to the server."
              },
              "settings": {
                "description": "LSP workspace/settings passed to the server."
              }
            },
            "description": "LSP server configuration."
          },
          "description": "LSP server definitions."
        }
      },
      "description": "Language Server Protocol configuration."
    },
    "asyncSubagents": {
      "not": {},
      "description": "Removed legacy key. Configure sub-agents in .pi/agents/*.md and model pools in .pi/agents/presets.jsonc."
    }
  },
  "$id": "https://unpkg.com/pi-ui-extend/schemas/pi-tools-suite.json",
  "$schema": "https://json-schema.org/draft-07/schema#",
  "title": "Pi Tools Suite Configuration",
  "description": "Configuration for the pi-tools-suite extension (~/.config/pi/pi-tools-suite.jsonc).",
  "additionalProperties": true
}
