{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "title": "Polytoken app config",
  "description": "The Polytoken application configuration file.",
  "type": "object",
  "properties": {
    "version": {
      "description": "Config schema version. Polytoken writes `3`; older configs without this\nkey are upgraded when loaded.",
      "type": "integer",
      "format": "uint8",
      "minimum": 0,
      "maximum": 255,
      "default": 3
    },
    "config_command_substitution": {
      "description": "When on, Polytoken resolves `$(command)` and `${VAR:-command}`\nsubstitutions in config values by running each command with\n`/bin/sh -c` once when it loads config. Only your user/global config\ncan turn this on; values in a project config never run commands. Off by\ndefault.",
      "type": [
        "boolean",
        "null"
      ]
    },
    "defaults": {
      "$ref": "#/$defs/ModelClassDefaults"
    },
    "providers": {
      "description": "Providers Polytoken can use, keyed by a name that models reference.",
      "type": "object",
      "additionalProperties": {
        "$ref": "#/$defs/AuthoredProviderInstance"
      }
    },
    "models": {
      "description": "Defines the models Polytoken can select, keyed by name. Each entry\nis a partial override: when the name matches a catalog model,\nPolytoken applies only the fields you set and inherits the rest;\nwhen it does not match, Polytoken builds a new model and requires\nyou to name its provider. You can set any field, including the\ncontext window, reasoning controls, edit format, and tool batching.\nSet `enabled` to false to remove a model Polytoken would otherwise\noffer.\n\nEntries can also target models a provider discovers at runtime.\nWhen the name matches a discovered model, Polytoken applies the\nentry as an overlay over the provider-reported configuration. If\nthe provider has not reported the model yet, the overlay has no\neffect until the model becomes available. The provider-reported\ncapability list determines eligibility for default slots, so the\n`class` override is informational for discovered models.",
      "type": "object",
      "additionalProperties": {
        "$ref": "#/$defs/AuthoredModelOverride"
      }
    },
    "active_session": {
      "anyOf": [
        {
          "$ref": "#/$defs/SessionConfig"
        },
        {
          "type": "null"
        }
      ]
    },
    "agent_behavior": {
      "anyOf": [
        {
          "$ref": "#/$defs/AgentBehavior"
        },
        {
          "type": "null"
        }
      ]
    },
    "permissions": {
      "description": "Protects secrets the model might otherwise read or repeat.\n`permissions.secret_words` lists values Polytoken blocks from\nenvironment exposure and redacts from tool output, and\n`permissions.secret_files` marks files Polytoken asks before reading\nand redacts from search results.\n\nThis block is separate from the permissions rule file, which\ncontrols the per-tool allow, ask, and deny rules.",
      "anyOf": [
        {
          "$ref": "#/$defs/PermissionSettingsConfig"
        },
        {
          "type": "null"
        }
      ]
    },
    "notifications": {
      "anyOf": [
        {
          "$ref": "#/$defs/NotificationsConfig"
        },
        {
          "type": "null"
        }
      ]
    },
    "default_permission_matcher": {
      "description": "Selects the strategy Polytoken uses to decide whether a tool call is\nallowed when no other matcher applies. The strategies are standard\n(apply your allow, ask, and deny rules), bypass (allow every call\nwithout asking), bypass_plus (allow every call except those your deny\nrules block), and autonomous (let a classifier decide which calls\nare safe to run without prompting you). Omit the key to use the\nstandard strategy.",
      "anyOf": [
        {
          "$ref": "#/$defs/PermissionMatcherKind"
        },
        {
          "type": "null"
        }
      ]
    },
    "autonomous_permission_matcher": {
      "description": "Tunes the autonomous permission classifier, which decides whether a\ntool call is safe to run without asking you.\n`autonomous_permission_matcher.classifier_model` names the model\nthat judges each call, `classifier_rules` gives it free-form\nguidance, and `max_consecutive_denials` caps how many denials the\nclassifier can return in a row before Polytoken escalates to you.\nThis block takes effect only when the autonomous strategy is active.",
      "anyOf": [
        {
          "$ref": "#/$defs/AuthoredAutonomousPermissionMatcherConfig"
        },
        {
          "type": "null"
        }
      ]
    },
    "plugins": {
      "description": "Configuration values for extensions, keyed by extension name. Polytoken\npasses each value to the matching extension and does not interpret the\ncontents itself.",
      "type": "object",
      "additionalProperties": true
    },
    "mcp_servers": {
      "type": "object",
      "additionalProperties": {
        "$ref": "#/$defs/McpServerConfig"
      }
    },
    "daemon": {
      "anyOf": [
        {
          "$ref": "#/$defs/DaemonConfig"
        },
        {
          "type": "null"
        }
      ]
    },
    "integrations": {
      "anyOf": [
        {
          "$ref": "#/$defs/IntegrationsConfig"
        },
        {
          "type": "null"
        }
      ]
    },
    "facets": {
      "description": "Sets the source for a named facet, overriding auto-discovery. A facet is a pre-prompted mode such as\nplan or execute. Each entry's `source` is a shipped `polytoken://`\nreference or a project-relative file path that stays within the\nproject.\n\nExplicit sources take precedence over the built-in facets and over\nany facet files Polytoken discovers in its facet directories.",
      "type": "object",
      "additionalProperties": {
        "$ref": "#/$defs/PromptDefinitionConfig"
      }
    },
    "subagents": {
      "description": "Sets the source for a named subagent, overriding auto-discovery. A subagent is a delegate Polytoken spawns\nto run a bounded task in its own context. Each entry's `source` is a\nshipped `polytoken://` reference or a project-relative file path that\nstays within the project.\n\nExplicit sources override the built-in subagents and any files\nPolytoken discovers in `.polytoken/subagents/`.",
      "type": "object",
      "additionalProperties": {
        "$ref": "#/$defs/PromptDefinitionConfig"
      }
    },
    "tui": {
      "anyOf": [
        {
          "$ref": "#/$defs/TuiConfig"
        },
        {
          "type": "null"
        }
      ]
    },
    "data": {
      "description": "Crash-reporting and diagnostic data policy. This block is\nglobal-only: a project config may not set or erase any key inside\nit. The `data.automatic_crash_reporting` key controls whether\nPolytoken sends automatic crash reports.",
      "anyOf": [
        {
          "$ref": "#/$defs/DataConfig"
        },
        {
          "type": "null"
        }
      ]
    },
    "updates": {
      "description": "Self-updater check behavior and release channel. This block is\nglobal-only: a project config may not set or erase any key inside\nit. The `updates.automatic_check` key controls whether Polytoken\nchecks for available updates at launch. The `updates.channel` key\nselects which release channel to track.",
      "anyOf": [
        {
          "$ref": "#/$defs/UpdatesConfig"
        },
        {
          "type": "null"
        }
      ]
    },
    "telemetry": {
      "description": "OpenTelemetry trace export. This block is global-only: a project\nconfig may not set or erase any key inside it. When this block is\nabsent, trace export is disabled and Polytoken sends no OTLP requests.\nAll settings come exclusively from this block; ambient `OTEL_*`\nenvironment variables do not enable or configure export.",
      "anyOf": [
        {
          "$ref": "#/$defs/TelemetryConfig"
        },
        {
          "type": "null"
        }
      ]
    }
  },
  "$defs": {
    "ModelClassDefaults": {
      "description": "Default model per size class.",
      "type": "object",
      "properties": {
        "full": {
          "description": "Name of the primary model a session uses by default. May include an\neffort suffix, e.g. `\"gpt-5.6-luna(high)\"`, to set the default\nreasoning effort for this tier.",
          "type": [
            "string",
            "null"
          ]
        },
        "mini": {
          "description": "Name of the smaller model Polytoken uses to compact context and to run\nthe autonomous permission classifier. Falls back to `full` when unset.\nMay include an effort suffix.",
          "type": [
            "string",
            "null"
          ]
        },
        "nano": {
          "description": "Name of the smallest model class. When unset, `default_model:nano`\nfalls back to `mini`, then `full`. May include an effort suffix.\nThis is an independent tier with its own model and effort.",
          "type": [
            "string",
            "null"
          ]
        }
      }
    },
    "AuthoredProviderInstance": {
      "description": "One provider entry, named by its key in `providers`.",
      "type": "object",
      "properties": {
        "kind": {
          "description": "Provider source: a built-in catalog entry, or a custom backend that\nspeaks the Anthropic or OpenAI protocol.",
          "$ref": "#/$defs/AuthoredProviderKind"
        },
        "url": {
          "description": "Base URL Polytoken sends provider requests to. Polytoken appends the\nendpoint path for the provider's protocol, so enter the origin only\n(for example `https://api.anthropic.com`) for Anthropic Messages\nproviders, or the versioned base (for example\n`https://api.openai.com/v1`) for OpenAI Chat Completions providers.\nOpenAI Responses accepts both the origin and a trailing `/v1`\n(it is deduplicated automatically). For Azure OpenAI Responses,\nuse `https://<resource>.openai.azure.com/openai/v1` as the base,\n`azure_api_key` for auth, and the deployment name as the model name.\nThe same base URL is also used to list available models. Overrides the\ncatalog default for catalog providers, and is required for custom\nproviders.",
          "type": [
            "string",
            "null"
          ]
        },
        "auth": {
          "description": "How Polytoken authenticates requests to the provider: no auth, a fixed\nkey, or the OpenAI Codex device flow.",
          "anyOf": [
            {
              "$ref": "#/$defs/AuthoredProviderAuthConfig"
            },
            {
              "type": "null"
            }
          ]
        },
        "protocol": {
          "description": "API dialect the provider speaks (for example `anthropic_messages`,\n`openai_chat_completions`, or `openai_responses`).\n`custom_open_ai_compatible` providers default to\n`openai_chat_completions`; set `openai_responses` explicitly only when\nthe provider serves the OpenAI Responses API.\n`custom_open_ai_responses` providers default to `openai_responses`.",
          "anyOf": [
            {
              "$ref": "#/$defs/ProviderProtocol"
            },
            {
              "type": "null"
            }
          ]
        },
        "headers": {
          "description": "Extra HTTP headers Polytoken attaches to every request sent to this\nprovider. Use this to satisfy gateways or proxies that require custom\nheaders, such as an internal routing token or a gateway-specific auth\nheader. Header names must be valid HTTP header names. When a header\nname matches one Polytoken already sends per request, the per-request\nvalue takes precedence.",
          "type": "object",
          "additionalProperties": {
            "type": "string"
          }
        },
        "cache_control_strategy": {
          "description": "Controls how prompt caching is handled for Anthropic Messages API\nproviders. Use `provider_managed` when the provider caches\nautomatically server-side, or `anthropic_breakpoints` to emit\nexplicit cache_control breakpoints for endpoints that forward to\nreal Anthropic. Defaults based on the provider URL: first-party\nAnthropic uses `anthropic_breakpoints`, all others use\n`provider_managed`. Only meaningful for Anthropic Messages protocol\nproviders.",
          "anyOf": [
            {
              "$ref": "#/$defs/MessagesCacheControlStrategy"
            },
            {
              "type": "null"
            }
          ]
        }
      },
      "required": [
        "kind"
      ]
    },
    "AuthoredProviderKind": {
      "description": "Provider source: a built-in catalog entry or a custom backend.",
      "oneOf": [
        {
          "description": "A built-in catalog provider, resolved by name.",
          "type": "object",
          "properties": {
            "name": {
              "description": "Catalog entry to resolve, such as `anthropic`, `openai`, or\n`codex`.",
              "type": "string"
            },
            "type": {
              "type": "string",
              "const": "catalog"
            }
          },
          "required": [
            "type",
            "name"
          ]
        },
        {
          "description": "A custom backend that speaks the Anthropic Messages API dialect.",
          "type": "object",
          "properties": {
            "type": {
              "type": "string",
              "const": "custom_anthropic_compatible"
            }
          },
          "required": [
            "type"
          ]
        },
        {
          "description": "A custom backend that speaks an OpenAI-compatible dialect.",
          "type": "object",
          "properties": {
            "type": {
              "type": "string",
              "const": "custom_open_ai_compatible"
            }
          },
          "required": [
            "type"
          ]
        },
        {
          "description": "A custom backend that speaks the OpenAI Responses API dialect.",
          "type": "object",
          "properties": {
            "type": {
              "type": "string",
              "const": "custom_open_ai_responses"
            }
          },
          "required": [
            "type"
          ]
        }
      ]
    },
    "AuthoredProviderAuthConfig": {
      "description": "How Polytoken authenticates to a provider.",
      "oneOf": [
        {
          "description": "No HTTP auth header. Use for local servers that need no credentials.",
          "type": "object",
          "properties": {
            "type": {
              "type": "string",
              "const": "no_auth"
            }
          },
          "required": [
            "type"
          ]
        },
        {
          "type": "object",
          "properties": {
            "key": {
              "description": "Secret key value sent in the auth header, usually an environment\nreference such as `${OPENAI_API_KEY}`. Leading and trailing\nwhitespace and newlines are stripped when the key is loaded;\nevery other character is preserved, so keys that contain dots\n(for example a z.ai key shaped like `id.payload.sig`) are valid.",
              "type": "string"
            },
            "format": {
              "description": "Header scheme for the key (`bearer_token`, `anthropic_x_api_key`,\nor `azure_api_key`). Omit to use the provider's recommended format.",
              "anyOf": [
                {
                  "$ref": "#/$defs/AuthFormat"
                },
                {
                  "type": "null"
                }
              ]
            },
            "type": {
              "type": "string",
              "const": "static_key"
            }
          },
          "required": [
            "type",
            "key"
          ]
        },
        {
          "type": "object",
          "properties": {
            "profile": {
              "description": "Codex auth profile name that supplies tokens for the device OAuth\nflow.",
              "$ref": "#/$defs/CodexAuthProfile"
            },
            "type": {
              "type": "string",
              "const": "codex_device"
            }
          },
          "required": [
            "type",
            "profile"
          ]
        },
        {
          "type": "object",
          "properties": {
            "profile": {
              "description": "Kimi Code auth profile name that supplies tokens for the device\ncode OAuth login flow. Use the profile name you chose when running\n`polytoken login` to authenticate with Kimi Code.",
              "$ref": "#/$defs/KimiCodeAuthProfile"
            },
            "type": {
              "type": "string",
              "const": "kimi_code_device"
            }
          },
          "required": [
            "type",
            "profile"
          ]
        }
      ]
    },
    "AuthFormat": {
      "description": "Auth-header scheme a provider uses.",
      "oneOf": [
        {
          "description": "`Authorization: Bearer <key>` header, for OpenAI-compatible APIs.",
          "type": "string",
          "const": "bearer_token"
        },
        {
          "description": "`x-api-key: <key>` header, for Anthropic native APIs.",
          "type": "string",
          "const": "anthropic_x_api_key"
        },
        {
          "description": "`api-key: <key>` header, for Azure OpenAI.",
          "type": "string",
          "const": "azure_api_key"
        }
      ]
    },
    "CodexAuthProfile": {
      "description": "A Codex device-auth profile name.",
      "type": "string"
    },
    "KimiCodeAuthProfile": {
      "description": "A Kimi Code device-auth profile name.",
      "type": "string"
    },
    "ProviderProtocol": {
      "description": "API dialect a provider speaks.",
      "type": "string",
      "enum": [
        "anthropic_messages",
        "openai_responses",
        "openai_chat_completions",
        "deepinfra_chat_completions",
        "xiaomi_chat_completions",
        "google_ai_chat_completions",
        "zai_messages",
        "minimax_messages",
        "deepseek_messages",
        "kimi_code_messages",
        "umans_messages",
        "neuralwatt_chat_completions",
        "moonshot_chat_completions",
        "codex_responses",
        "test"
      ]
    },
    "MessagesCacheControlStrategy": {
      "description": "How prompt caching is handled for an Anthropic Messages API provider.\n\nUse `provider_managed` when the endpoint handles caching itself.\nUse `anthropic_breakpoints` for first-party Anthropic or a proxy\nthat forwards to real Anthropic and requires explicit cache_control\nbreakpoints.",
      "oneOf": [
        {
          "description": "The provider caches automatically server-side. No explicit\ncache_control breakpoints are emitted.",
          "type": "string",
          "const": "provider_managed"
        },
        {
          "description": "Emit explicit cache_control breakpoints. Correct for first-party\nAnthropic and custom proxies that forward to real Anthropic.",
          "type": "string",
          "const": "anthropic_breakpoints"
        }
      ]
    },
    "AuthoredModelOverride": {
      "description": "Partial model override. Polytoken keeps catalog values for any fields you\ndo not set.",
      "type": "object",
      "properties": {
        "enabled": {
          "description": "Set to false to remove a model Polytoken would otherwise offer; omit\nto leave the model available.",
          "type": [
            "boolean",
            "null"
          ]
        },
        "provider_name": {
          "description": "Model identifier Polytoken sends to the provider. It can differ from\nthe name you use in `models`.",
          "type": [
            "string",
            "null"
          ]
        },
        "variant": {
          "description": "Model family: `claude`, `openai`, `gemini`, or `other`. Polytoken uses\nit to pick provider-appropriate defaults.",
          "anyOf": [
            {
              "$ref": "#/$defs/ModelVariant"
            },
            {
              "type": "null"
            }
          ]
        },
        "class": {
          "description": "Size class a model belongs to (`full`, `mini`, or `nano`). Required for\ncustom models that do not match a catalog entry.",
          "anyOf": [
            {
              "$ref": "#/$defs/ModelClass"
            },
            {
              "type": "null"
            }
          ]
        },
        "max_tokens": {
          "description": "Absolute output token ceiling the provider catalog reports for this\nmodel. Polytoken uses it for validation only; the effective limit sent\nto the provider is `max_output_tokens_per_turn`.",
          "type": [
            "integer",
            "null"
          ],
          "format": "uint32",
          "minimum": 0
        },
        "max_output_tokens_per_turn": {
          "description": "Per-turn output token limit Polytoken sends to the provider. When\nomitted, Polytoken derives a default from the model's context window.\nMust not exceed the model's hard ceiling (`max_tokens`).",
          "type": [
            "integer",
            "null"
          ],
          "format": "uint32",
          "minimum": 0
        },
        "stop_sequences": {
          "description": "Stop strings Polytoken forwards to the provider so generation halts on\na match.",
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "provider": {
          "description": "Provider backend this model runs on, which must match a configured\nprovider; required for custom models.",
          "type": [
            "string",
            "null"
          ]
        },
        "reasoning": {
          "description": "Reasoning or thinking capability: whether reasoning is off,\neffort-steered, or thinking-steered.",
          "anyOf": [
            {
              "$ref": "#/$defs/ModelReasoningCapability"
            },
            {
              "type": "null"
            }
          ]
        },
        "edit_format": {
          "description": "File-edit format Polytoken exposes for the model (for example a\nhashline or patch format); omit to use the default.",
          "type": [
            "string",
            "null"
          ]
        },
        "context_window": {
          "description": "Context-window size in tokens, which Polytoken uses to decide when to\ncompact and to derive the per-model compaction threshold. Required for\nevery model; omitting it produces a validation error.",
          "type": [
            "integer",
            "null"
          ],
          "format": "uint32",
          "minimum": 0
        },
        "compaction_threshold": {
          "description": "Share of the context window at which compaction triggers for this model.\nWhen omitted, Polytoken computes it from the model's context window and\nthe per-tier compaction reserve, rounded down to two decimal places.\nWhen `max_output_tokens_per_turn` is also set, the reserve grows to\naccommodate it. Set to a value in (0.0, 1.0].",
          "type": [
            "number",
            "null"
          ],
          "format": "float"
        },
        "tool_loading": {
          "description": "How Polytoken exposes tools to the model: from the first turn, on\ndemand, or not at all.",
          "anyOf": [
            {
              "$ref": "#/$defs/ToolLoading"
            },
            {
              "type": "null"
            }
          ]
        },
        "supports_vision": {
          "description": "Whether the model accepts image inputs and can see image content in\ntool results. Defaults to false for custom models.",
          "type": [
            "boolean",
            "null"
          ]
        },
        "forced_tool_choice_supported": {
          "description": "Whether the model can handle forced tool_choice requests end-to-end.\nSet to `false` for models whose thinking mode creates gaps that break\nsubsequent turns after a forced tool call. When `false`, Polytoken uses\na reminder message instead of forcing a tool call. Defaults to `true`.",
          "type": [
            "boolean",
            "null"
          ]
        },
        "max_tool_batch_size": {
          "description": "Maximum number of counted, non-exclusive tool calls the model may issue\nin one assistant message. When omitted, the value derives from the\nmodel's `context_window`: `4` for an unknown or small window, increasing\nfor larger windows up to `8`.",
          "type": [
            "integer",
            "null"
          ],
          "format": "uint32",
          "minimum": 0
        },
        "request_option_defaults": {
          "description": "Request options Polytoken applies by default when it calls this model.\nOmit the key or leave it empty to use provider defaults.",
          "$ref": "#/$defs/RequestOptionAssignmentMap"
        },
        "inherits": {
          "description": "Names the model whose provider identity, class metadata, context window,\nand request defaults this model inherits. The child keeps any explicitly\nauthored request options and replaces matching parent keys.\nOmit the key to keep the model independent.",
          "anyOf": [
            {
              "$ref": "#/$defs/ModelInheritanceTargetV1"
            },
            {
              "type": "null"
            }
          ]
        }
      }
    },
    "ModelVariant": {
      "description": "Model family: `claude`, `openai`, `gemini`, or `other`.",
      "type": "string",
      "enum": [
        "claude",
        "openai",
        "gemini",
        "other"
      ]
    },
    "ModelClass": {
      "description": "Size class a model belongs to: `full`, `mini`, or `nano`.",
      "type": "string",
      "enum": [
        "full",
        "mini",
        "nano"
      ]
    },
    "ModelReasoningCapability": {
      "description": "How a model's reasoning or thinking can be controlled.",
      "oneOf": [
        {
          "type": "object",
          "properties": {
            "type": {
              "type": "string",
              "const": "no_reasoning"
            }
          },
          "required": [
            "type"
          ]
        },
        {
          "type": "object",
          "properties": {
            "effort_set": {
              "description": "Effort family the levels belong to (for example an OpenAI\nreasoning effort set).",
              "type": "string"
            },
            "can_disable": {
              "description": "Whether the model can turn reasoning off.",
              "type": "boolean"
            },
            "levels": {
              "description": "Discrete effort levels the model accepts, in provider order.",
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "default_level": {
              "description": "Default reasoning effort when you do not name one. Must be one of\n`levels` when present.",
              "type": [
                "string",
                "null"
              ]
            },
            "type": {
              "type": "string",
              "const": "effort"
            }
          },
          "required": [
            "type",
            "effort_set",
            "can_disable",
            "levels"
          ]
        },
        {
          "type": "object",
          "properties": {
            "can_disable": {
              "description": "Whether the model can turn thinking off.",
              "type": "boolean"
            },
            "type": {
              "type": "string",
              "const": "thinking"
            }
          },
          "required": [
            "type",
            "can_disable"
          ]
        }
      ]
    },
    "ToolLoading": {
      "description": "Controls when the model can see the available tools.",
      "oneOf": [
        {
          "description": "All tools for the active facet are visible from the first turn.",
          "type": "string",
          "const": "eager"
        },
        {
          "description": "The model starts without the full tool list and can request tools as\nneeded. Requires provider support.",
          "type": "string",
          "const": "native_deferred"
        },
        {
          "description": "The model cannot use tools.",
          "type": "string",
          "const": "no_tools"
        }
      ]
    },
    "RequestOptionAssignmentMap": {
      "description": "An ordered key/value assignment map.",
      "type": "object",
      "additionalProperties": {
        "$ref": "#/$defs/RequestOptionValue"
      }
    },
    "RequestOptionValue": {
      "description": "A boolean or an open request-option string value.",
      "anyOf": [
        {
          "type": "boolean"
        },
        {
          "type": "string",
          "maxLength": 512
        }
      ]
    },
    "BoundedRequestOptionString": {
      "description": "A UTF-8 string whose encoded length is at most 512 bytes.",
      "type": "string"
    },
    "ModelInheritanceTargetV1": {
      "description": "A named model that supplies inherited request and model defaults.\n\nModel keys may contain provider-qualified paths, dots, slashes, underscores,\nand hyphens. The exact key is preserved for lookup.",
      "type": "string"
    },
    "SessionConfig": {
      "description": "Sets the defaults Polytoken uses for new sessions.",
      "type": "object",
      "properties": {
        "default_facet": {
          "description": "Facet Polytoken starts in for a new interactive session, such as\nplan or execute. Falls back to execute when unset.",
          "type": [
            "string",
            "null"
          ]
        },
        "default_exec_facet": {
          "description": "Facet Polytoken starts in for a non-interactive `polytoken exec` run.\nFalls back to execute when unset.",
          "type": [
            "string",
            "null"
          ]
        }
      }
    },
    "AgentBehavior": {
      "description": "Shell behavior for tool calls.",
      "type": "object",
      "properties": {
        "shell": {
          "$ref": "#/$defs/ShellConfig"
        }
      },
      "required": [
        "shell"
      ]
    },
    "ShellConfig": {
      "type": "object",
      "properties": {
        "command": {
          "description": "Shell Polytoken uses to run shell tool calls.",
          "$ref": "#/$defs/ShellCommand"
        },
        "init_script": {
          "description": "Project-relative script Polytoken sources once before the first shell\ntool call, so its environment changes apply to later shell calls.",
          "type": [
            "string",
            "null"
          ]
        }
      },
      "required": [
        "command"
      ]
    },
    "ShellCommand": {
      "type": "string",
      "enum": [
        "bash",
        "powershell"
      ]
    },
    "PermissionSettingsConfig": {
      "description": "Secret-protection settings under the `permissions` block.",
      "type": "object",
      "properties": {
        "secret_words": {
          "description": "Values Polytoken blocks from environment exposure and redacts from\ntool output.",
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "secret_files": {
          "description": "Files Polytoken asks before reading and redacts from search results.",
          "type": "array",
          "items": {
            "type": "string"
          }
        }
      },
      "additionalProperties": false
    },
    "NotificationsConfig": {
      "description": "Notification settings.",
      "type": "object",
      "properties": {
        "trigger_turn": {
          "description": "Whether Polytoken starts a new turn when a notification arrives,\ninstead of waiting for your next prompt. Reserved; Polytoken does not\nact on this setting.",
          "type": "boolean",
          "default": false
        },
        "trigger_types": {
          "description": "Notification types that should start a turn when `trigger_turn` is on.\nReserved; Polytoken does not act on this setting.",
          "type": "array",
          "items": {
            "type": "string"
          },
          "default": []
        },
        "auto_drain_notifications": {
          "description": "Whether Polytoken folds each notification into the session history as\nit arrives, so the model sees it without a manual step. On by default.",
          "type": "boolean",
          "default": true
        }
      }
    },
    "PermissionMatcherKind": {
      "type": "string",
      "enum": [
        "standard",
        "bypass",
        "bypass_plus",
        "autonomous"
      ]
    },
    "AuthoredAutonomousPermissionMatcherConfig": {
      "type": "object",
      "properties": {
        "classifier_model": {
          "description": "Model that judges whether each tool call is safe to run without asking\nyou.",
          "type": [
            "string",
            "null"
          ]
        },
        "classifier_rules": {
          "description": "Free-form guidance the classifier applies when judging tool calls.",
          "type": [
            "string",
            "null"
          ]
        },
        "max_consecutive_denials": {
          "description": "Number of denials the classifier may return in a row before Polytoken\nescalates to you.",
          "type": "integer",
          "format": "uint32",
          "minimum": 0,
          "default": 3
        }
      }
    },
    "McpServerConfig": {
      "type": "object",
      "properties": {
        "block_list": {
          "description": "MCP tool names, in the `mcp__server__tool` form, that Polytoken hides\nfrom the model.",
          "type": "array",
          "items": {
            "type": "string"
          },
          "default": []
        },
        "default_timeout_seconds": {
          "description": "Maximum seconds a single tool call to this server may run before\nPolytoken cancels it. Omit for no server-level limit; Polytoken rejects\nzero.",
          "type": [
            "integer",
            "null"
          ],
          "format": "uint64",
          "minimum": 0
        },
        "auth_key_name": {
          "description": "Directory name under `auth/mcp/` where Polytoken stores this server's\nOAuth credentials. Omit to use the server name (the default). Two OAuth\nservers that should keep separate credentials can set distinct names\nhere, for example `atlassian-polytoken` and `atlassian-summoner`. The\nname may contain only ASCII letters, digits, underscores, and hyphens,\nand must not start with an underscore or contain two underscores in a row.",
          "type": [
            "string",
            "null"
          ]
        },
        "default_enabled": {
          "description": "Whether Polytoken attempts to connect to this server at startup. Set to\n`false` to keep the server available but disconnected until you enable\nit with `/mcp`. Defaults to `true`.",
          "type": "boolean"
        }
      },
      "oneOf": [
        {
          "description": "Runs the MCP server as a local stdio child process.",
          "type": "object",
          "properties": {
            "command": {
              "description": "Executable to launch as the local stdio MCP server.",
              "type": "string"
            },
            "args": {
              "description": "Command-line arguments passed to the stdio server command.",
              "type": "array",
              "items": {
                "type": "string"
              },
              "default": []
            },
            "env": {
              "description": "Environment variables set on the stdio child process. The child\nstarts with a cleared environment. These override any variables\ncopied by `pass_env`.",
              "type": "object",
              "additionalProperties": {
                "type": "string"
              },
              "default": {}
            },
            "pass_env": {
              "description": "Names of environment variables to copy from the Polytoken process\ninto the stdio child process. Omit to use a safe default set\n(`HOME`, `PATH`, `LANG`, `TMPDIR`). Set to an empty list to pass\nnothing. Set to a list of names to pass exactly those variables.\nVariables in `env` with the same name override values passed\nthrough here.",
              "type": [
                "array",
                "null"
              ],
              "items": {
                "type": "string"
              }
            },
            "log_stderr": {
              "description": "When on, logs the server's stderr to a per-server log file. On by\ndefault.",
              "type": "boolean",
              "default": true
            },
            "log_stdout": {
              "description": "When on, logs the server's stdout to a per-server log file. Off by\ndefault.",
              "type": "boolean",
              "default": false
            },
            "transport": {
              "type": "string",
              "const": "stdio"
            }
          },
          "required": [
            "transport",
            "command"
          ]
        },
        {
          "description": "Connects to a remote streamable-HTTP MCP server.",
          "type": "object",
          "properties": {
            "url": {
              "description": "Endpoint URL of the remote streamable-HTTP MCP server.",
              "type": "string"
            },
            "auth": {
              "description": "How Polytoken authenticates to the remote server: none, a fixed\nAuthorization header, or OAuth.",
              "$ref": "#/$defs/McpRemoteAuthConfig"
            },
            "headers": {
              "description": "Extra HTTP headers Polytoken sends with every request to the remote\nserver.",
              "type": "object",
              "additionalProperties": {
                "type": "string"
              },
              "default": {}
            },
            "reinit_on_expired_session": {
              "description": "When on, reinitializes the HTTP session automatically when the\nserver signals it has expired.",
              "type": "boolean",
              "default": false
            },
            "transport": {
              "type": "string",
              "const": "http"
            }
          },
          "required": [
            "transport",
            "url"
          ]
        }
      ]
    },
    "McpRemoteAuthConfig": {
      "oneOf": [
        {
          "description": "Sends no authentication with remote server requests. The default.",
          "type": "object",
          "properties": {
            "type": {
              "type": "string",
              "const": "none"
            }
          },
          "required": [
            "type"
          ]
        },
        {
          "description": "Sends a fixed Authorization header value with each request.",
          "type": "object",
          "properties": {
            "value": {
              "description": "Authorization header value to send, including any scheme prefix (for\nexample `Bearer ...`).",
              "type": "string"
            },
            "type": {
              "type": "string",
              "const": "authorization-header"
            }
          },
          "required": [
            "type",
            "value"
          ]
        },
        {
          "description": "Authenticates to the remote server via an OAuth client flow.",
          "type": "object",
          "properties": {
            "scopes": {
              "description": "OAuth scopes to request during authorization. Omit to let the\nserver choose the defaults.",
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "registration": {
              "description": "How Polytoken registers its OAuth client: `auto`,\n`client-metadata-url`, or `pre-registered`.",
              "$ref": "#/$defs/McpOAuthRegistrationConfig",
              "default": {
                "type": "auto"
              }
            },
            "redirect": {
              "description": "How Polytoken handles the OAuth redirect: `ephemeral-loopback` or\n`fixed`.",
              "$ref": "#/$defs/McpOAuthRedirectConfig",
              "default": {
                "type": "ephemeral-loopback"
              }
            },
            "type": {
              "type": "string",
              "const": "oauth"
            }
          },
          "required": [
            "type"
          ]
        }
      ]
    },
    "McpOAuthRegistrationConfig": {
      "oneOf": [
        {
          "description": "Lets the server drive dynamic client registration. The default.",
          "type": "object",
          "properties": {
            "type": {
              "type": "string",
              "const": "auto"
            }
          },
          "required": [
            "type"
          ]
        },
        {
          "description": "Publishes client metadata at a URL for the server to fetch during\ndynamic registration.",
          "type": "object",
          "properties": {
            "url": {
              "description": "HTTPS URL with a non-root path that serves the client metadata\ndocument.",
              "type": "string"
            },
            "type": {
              "type": "string",
              "const": "client-metadata-url"
            }
          },
          "required": [
            "type",
            "url"
          ]
        },
        {
          "description": "Uses a client ID (and optional secret) already issued by the server.",
          "type": "object",
          "properties": {
            "client_id": {
              "description": "OAuth client identifier issued by the server.",
              "type": "string"
            },
            "client_secret": {
              "description": "OAuth client secret paired with the client ID, when the server\nrequires one.",
              "type": [
                "string",
                "null"
              ]
            },
            "type": {
              "type": "string",
              "const": "pre-registered"
            }
          },
          "required": [
            "type",
            "client_id"
          ]
        }
      ]
    },
    "McpOAuthRedirectConfig": {
      "oneOf": [
        {
          "description": "Polytoken opens a temporary loopback redirect URI and captures the\ncallback for you. The default.",
          "type": "object",
          "properties": {
            "type": {
              "type": "string",
              "const": "ephemeral-loopback"
            }
          },
          "required": [
            "type"
          ]
        },
        {
          "description": "Uses a fixed redirect URI you provide.",
          "type": "object",
          "properties": {
            "uri": {
              "description": "Fixed redirect URI the authorization server returns to after\nconsent. Must be HTTPS or a loopback HTTP address.",
              "type": "string"
            },
            "type": {
              "type": "string",
              "const": "fixed"
            }
          },
          "required": [
            "type",
            "uri"
          ]
        }
      ]
    },
    "DaemonConfig": {
      "type": "object",
      "properties": {
        "log_level": {
          "description": "Verbosity of Polytoken's diagnostic logs.",
          "$ref": "#/$defs/DaemonLogLevel"
        },
        "logging": {
          "$ref": "#/$defs/DaemonLoggingConfig"
        },
        "web": {
          "anyOf": [
            {
              "$ref": "#/$defs/WebConfig"
            },
            {
              "type": "null"
            }
          ]
        },
        "tls": {
          "anyOf": [
            {
              "$ref": "#/$defs/TlsConfig"
            },
            {
              "type": "null"
            }
          ]
        },
        "system_reminders": {
          "$ref": "#/$defs/SystemRemindersConfig"
        },
        "max_tool_turns": {
          "description": "Maximum number of tool round-trips a single turn may run before\nPolytoken ends the turn. Omit to use the built-in default; Polytoken\ntreats zero as unset.",
          "type": [
            "integer",
            "null"
          ],
          "format": "uint32",
          "minimum": 0
        },
        "provider_stream_idle_timeout_secs": {
          "description": "Seconds to wait for the next chunk from a provider stream before\nPolytoken treats the stream as stalled. When the stall fires,\nPolytoken collates whatever partial content arrived so far, persists\nit, and retries the provider request with that content in context\nrather than hanging indefinitely. Omit to use the built-in default;\nPolytoken treats zero as unset.",
          "type": [
            "integer",
            "null"
          ],
          "format": "uint64",
          "minimum": 0
        },
        "provider_stream_max_lifetime_secs": {
          "description": "Maximum wall-clock duration for a single provider stream before\nPolytoken proactively truncates it. When the limit fires, Polytoken\npreserves all partial content and continues the turn with a\ncontinuation prompt, avoiding upstream connection drops on long-running\nresponses. Omit to use the built-in default. Set to zero to disable.",
          "type": [
            "integer",
            "null"
          ],
          "format": "uint64",
          "minimum": 0
        },
        "subagent_stall_threshold_secs": {
          "description": "Wall-clock seconds without subagent activity before Polytoken marks the\nsubagent stalled and forces its provider stream to reconnect. Omit to use\na value above the provider stream idle timeout so it only catches stalls\nthe idle timer misses (such as a laptop sleeping on macOS). Polytoken\ntreats zero as unset. Applied at daemon start; requires a restart to\nchange.",
          "type": [
            "integer",
            "null"
          ],
          "format": "uint64",
          "minimum": 0
        },
        "subagent_liveness_watchdog_interval_secs": {
          "description": "How often Polytoken scans running subagents for stalled streams. Omit to\nuse the built-in default. Polytoken treats zero as unset. Applied at\ndaemon start; requires a restart to change.",
          "type": [
            "integer",
            "null"
          ],
          "format": "uint64",
          "minimum": 0
        },
        "follow_symlinks_for_configs": {
          "description": "Whether Polytoken follows symlinks when loading configuration and context\nfiles such as AGENTS.md, skills, facets, subagents, project variables, and\n.agentblock files. On by default. When disabled, Polytoken skips symlinked\nfiles and shows a warning for each one. Applies to both the project\n`.polytoken/` directory and the global configuration directory.",
          "type": "boolean"
        },
        "retry": {
          "$ref": "#/$defs/RetryConfig"
        },
        "goal_driver": {
          "$ref": "#/$defs/GoalDriverConfig"
        },
        "compaction_max_retries": {
          "description": "Maximum number of retry attempts when a compaction pass fails due to\na provider error or empty summary. Each retry applies progressively\nmore aggressive history stripping, and EmptySummary retries append a\nstronger instruction to the compaction prompt. Set to zero to disable\nretries. Omit to use the built-in default.",
          "type": [
            "integer",
            "null"
          ],
          "format": "uint32",
          "minimum": 0
        },
        "file_catalog": {
          "$ref": "#/$defs/FileCatalogConfig"
        }
      }
    },
    "DaemonLogLevel": {
      "type": "string",
      "enum": [
        "error",
        "warn",
        "info",
        "debug",
        "trace"
      ]
    },
    "DaemonLoggingConfig": {
      "type": "object",
      "properties": {
        "provider_autopsy": {
          "description": "When on, saves a redacted report for each provider failure, without the\nrequest or response contents. Off by default.",
          "type": "boolean",
          "default": false
        }
      }
    },
    "WebConfig": {
      "type": "object",
      "properties": {
        "http_proxy": {
          "description": "Proxy URL for the plain-HTTP requests the built-in web tools make.",
          "type": [
            "string",
            "null"
          ]
        },
        "https_proxy": {
          "description": "Proxy URL for the HTTPS requests the built-in web tools make.",
          "type": [
            "string",
            "null"
          ]
        },
        "web_fetch_disallow_http": {
          "description": "When on, blocks `web_fetch` from following plain-HTTP URLs except for\nlocalhost and loopback addresses.",
          "type": "boolean",
          "default": false
        }
      }
    },
    "TlsConfig": {
      "description": "Custom trust store for Polytoken's outbound HTTPS traffic.",
      "type": "object",
      "properties": {
        "trust_store": {
          "description": "Path to a PEM file holding one or more CA certificates Polytoken should\ntrust in addition to the root certificates it trusts by default (its\nbuilt-in root bundle). The default roots always stay enabled; the CA\nhere is added on top.\n\nUse this to inspect Polytoken's own traffic with an HTTPS interception\nproxy such as mitmproxy, Charles, or Burp Suite: point this at the\nproxy's CA certificate so Polytoken accepts the proxy's\nman-in-the-middle certificate instead of failing verification.\n\nThe file is a PEM bundle: one or more base64-encoded CA certificates,\neach wrapped in `-----BEGIN CERTIFICATE-----` and\n`-----END CERTIFICATE-----` markers. A single CA (for example\nmitmproxy's `mitmproxy-ca-cert.pem`) or a concatenated bundle of several\nCAs both work.\n\nRelative paths resolve against the directory Polytoken was started in\n(the daemon working directory, normally the project root). Absolute paths\nare used as given. Omit this key to trust only the default roots, which\nis the default.\n\nApplies to daemon-owned outbound HTTPS only: model provider requests, the\nbuilt-in `web_fetch` and `web_search` tools, and the OpenAI Codex login\nrefresh client. It does not apply to standalone `polytoken auth` or\nconfigurator flows run from the terminal. A path that cannot be read or\nparsed is a hard error at startup and on reload, so a missing or invalid\nfile is never silently ignored.",
          "type": [
            "string",
            "null"
          ]
        }
      }
    },
    "SystemRemindersConfig": {
      "type": "object",
      "properties": {
        "disabled": {
          "description": "Built-in system reminders Polytoken should not add to a session.\nPolytoken flags unknown or malformed names as config errors.",
          "type": "array",
          "items": {
            "type": "string"
          }
        }
      }
    },
    "RetryConfig": {
      "description": "Retry configuration for transient provider errors.",
      "type": "object",
      "properties": {
        "max_retries": {
          "description": "Maximum number of retry attempts for transient provider errors with\ncomputed backoff or a provider-supplied retry-after hint. Set to 0 to\ndisable all provider retries. Provider rate limits without a retry-after\nhint use Polytoken's fixed six-step schedule for any positive value.",
          "type": "integer",
          "format": "uint32",
          "minimum": 0,
          "default": 3
        },
        "base_delay_ms": {
          "description": "Base delay in milliseconds for computed exponential backoff. Provider\nrate limits without a retry-after hint use a fixed 30s, 60s, 120s,\n240s, 480s, 960s schedule instead.",
          "type": "integer",
          "format": "uint64",
          "minimum": 0,
          "default": 1000
        },
        "max_computed_delay_ms": {
          "description": "Maximum computed delay in milliseconds (caps exponential backoff only,\nnot provider-hinted Retry-After values or the fixed no-hint rate-limit\nschedule).",
          "type": "integer",
          "format": "uint64",
          "minimum": 0,
          "default": 60000
        }
      }
    },
    "GoalDriverConfig": {
      "description": "Goal Driver automation defaults. Plan handoff activation is on by default,\nso approved handoffs automatically start goal mode. Model goal auto-accept\nis off by default, so the model must wait for operator approval of proposed\ngoals unless you enable it here.",
      "type": "object",
      "properties": {
        "plan_handoff_activate_goal": {
          "description": "When on, a plan handoff automatically activates goal mode. When off, a\nplan handoff does not activate goal mode unless you enable it here.",
          "type": "boolean",
          "default": false
        },
        "agent_goal_auto_accept": {
          "description": "When on, Polytoken accepts goals the model proposes without asking you\nto confirm each one. When off, goals the model proposes require your\napproval before they take effect.",
          "type": "boolean",
          "default": false
        },
        "max_continuations_per_goal": {
          "description": "Maximum automatic continuations Polytoken may run for one active goal\nbefore it stops scheduling follow-up turns for that goal. Set this to\n`0` to disable automatic goal continuation while keeping Goal Driver\nmetadata and tools available.",
          "type": "integer",
          "format": "uint",
          "minimum": 0,
          "default": 50
        }
      }
    },
    "FileCatalogConfig": {
      "description": "Settings for the `@`-file reference catalog walk.\n\nThe file-count and time budgets apply ONLY when Polytoken runs in a\ndirectory that is not inside a source-controlled repository (git,\nJujutsu, or Sapling). Inside a VCS-backed project the walk is uncapped\nfor completeness, relying on generated-tree pruning and server-side\nquery filtering instead.",
      "type": "object",
      "properties": {
        "max_files": {
          "description": "Maximum number of entries the recursive catalog walk collects before\nstopping. Applies only outside source-controlled repositories.",
          "type": "integer",
          "format": "uint",
          "minimum": 0,
          "default": 250000
        },
        "max_duration_ms": {
          "description": "Maximum wall-clock milliseconds the recursive catalog walk may spend\nbefore stopping. Applies only outside source-controlled repositories.",
          "type": "integer",
          "format": "uint64",
          "minimum": 0,
          "default": 15000
        },
        "exclude_generated": {
          "description": "When on (default), Polytoken prunes generated build-output trees\n(`node_modules`, `bazel-out`, `bazel-bin`, `bazel-testlogs`, and\nany `bazel-*` directory) from the recursive catalog in all modes,\nincluding show-ignored mode.",
          "type": "boolean"
        },
        "cache_ttl_secs": {
          "description": "How long (in seconds) the daemon serves a cached file catalog before\nrebuilding it. The cache is also invalidated when a file-mutating\ntool completes.",
          "type": "integer",
          "format": "uint64",
          "minimum": 0,
          "default": 30
        }
      }
    },
    "IntegrationsConfig": {
      "description": "Hosted web-search providers that back the `web_search` tool.",
      "type": "object",
      "properties": {
        "search": {
          "anyOf": [
            {
              "$ref": "#/$defs/SearchIntegrationConfig"
            },
            {
              "type": "null"
            }
          ]
        }
      }
    },
    "SearchIntegrationConfig": {
      "description": "How Polytoken chooses a search provider for each `web_search` call.",
      "type": "object",
      "properties": {
        "strategy": {
          "description": "How Polytoken picks one enabled search provider per `web_search` call:\n`round_robin` to rotate in order, or `random` to select one per call.",
          "$ref": "#/$defs/SearchStrategy"
        },
        "providers": {
          "$ref": "#/$defs/SearchProvidersConfig"
        }
      }
    },
    "SearchStrategy": {
      "type": "string",
      "enum": [
        "round_robin",
        "random"
      ]
    },
    "SearchProvidersConfig": {
      "description": "The hosted search providers: `brave`, `tavily`, `exa`, and `kagi`.",
      "type": "object",
      "properties": {
        "brave": {
          "anyOf": [
            {
              "$ref": "#/$defs/SearchApiKeyProviderConfig"
            },
            {
              "type": "null"
            }
          ]
        },
        "tavily": {
          "anyOf": [
            {
              "$ref": "#/$defs/SearchApiKeyProviderConfig"
            },
            {
              "type": "null"
            }
          ]
        },
        "exa": {
          "anyOf": [
            {
              "$ref": "#/$defs/SearchApiKeyProviderConfig"
            },
            {
              "type": "null"
            }
          ]
        },
        "kagi": {
          "anyOf": [
            {
              "$ref": "#/$defs/SearchApiKeyProviderConfig"
            },
            {
              "type": "null"
            }
          ]
        }
      }
    },
    "SearchApiKeyProviderConfig": {
      "description": "A search provider's enabled flag and API key.",
      "type": "object",
      "properties": {
        "enabled": {
          "description": "Whether this provider is eligible for `web_search` calls.",
          "type": "boolean",
          "default": false
        },
        "key": {
          "description": "API key for this provider, usually an environment reference such as\n`${SEARCH_API_KEY}`.",
          "type": "string"
        }
      },
      "required": [
        "key"
      ]
    },
    "PromptDefinitionConfig": {
      "description": "Source for a facet or subagent definition.",
      "type": "object",
      "properties": {
        "source": {
          "description": "Definition source for this facet or subagent: a shipped `polytoken://`\nreference, or a project-relative file path that stays within the\nproject.",
          "type": "string"
        }
      },
      "required": [
        "source"
      ]
    },
    "TuiConfig": {
      "description": "Terminal interface display settings.",
      "type": "object",
      "properties": {
        "theme": {
          "description": "Color palette: `auto` (detect from the terminal background), `light`,\nor `dark`.",
          "$ref": "#/$defs/TuiTheme",
          "default": "auto"
        },
        "theme-file": {
          "description": "Theme file to load for the TUI. When unset, Polytoken uses the built-in\ndefault theme. Set this to a full path: use `polytoken://themes/default.yaml`\nfor a built-in theme, or `$USER_DIRECTORY/themes/my-theme.yaml` for a\nuser theme. The `$USER_DIRECTORY` variable resolves to your Polytoken\nconfig directory and supports env-substitution syntax.",
          "type": [
            "string",
            "null"
          ]
        },
        "alt-screen": {
          "description": "Alternate-screen policy: `auto` (render inline under a terminal\nmultiplexer, alternate screen otherwise), `always`, or `never`.",
          "$ref": "#/$defs/TuiAltScreen",
          "default": "auto"
        },
        "confirm-quit": {
          "description": "Whether Polytoken asks before quitting. When unset, Polytoken follows\nthe per-machine preference, and asks if no preference is set.",
          "type": [
            "boolean",
            "null"
          ]
        },
        "density": {
          "description": "Card spacing: `standard` (the default) or `compact`.",
          "$ref": "#/$defs/TuiDensity",
          "default": "standard"
        },
        "show-all-thinking-blocks": {
          "description": "Whether completed model thinking cards stay visible in the transcript\nafter they finish.",
          "type": "boolean",
          "default": false
        },
        "show-system-reminders": {
          "description": "Whether the transcript shows system-reminder cards.",
          "type": "boolean",
          "default": false
        },
        "help": {
          "$ref": "#/$defs/TuiHelpConfig"
        },
        "sidebar": {
          "$ref": "#/$defs/TuiSidebarConfig"
        },
        "mouse": {
          "$ref": "#/$defs/TuiMouseConfig"
        },
        "keyboard": {
          "description": "Keyboard shortcut overrides for production conversation TUI action commands.",
          "$ref": "#/$defs/TuiKeyboardConfig"
        },
        "editor": {
          "$ref": "#/$defs/TuiEditorConfig"
        },
        "prompt": {
          "$ref": "#/$defs/TuiPromptConfig"
        },
        "navigation": {
          "$ref": "#/$defs/TuiNavigationConfig"
        },
        "paste": {
          "$ref": "#/$defs/TuiPasteConfig"
        },
        "history": {
          "$ref": "#/$defs/TuiHistoryConfig"
        },
        "copy": {
          "$ref": "#/$defs/TuiCopyConfig"
        },
        "animations": {
          "$ref": "#/$defs/TuiAnimationsConfig"
        },
        "terminal-bell": {
          "description": "Bell behavior for attention states: `off`, `audible`, or `auto` (the\ndefault, which notifies on attention).",
          "$ref": "#/$defs/TuiTerminalBell"
        },
        "slow-refresh": {
          "description": "When on, the TUI redraws streaming content at most every 5 seconds\ninstead of the default ~30 times per second. This reduces screen\nflashing on e-ink displays during active assistant turns. Typing,\nscrolling, and resizing stay immediate.",
          "type": "boolean"
        },
        "expand-file-edit-cards": {
          "description": "When on, file write and edit tool-call cards (file_write,\nfile_edit_search_replace, file_edit_hashline, patch_edit) start\nexpanded in the conversation transcript so you can see the full\ndiff or content without clicking. You can still collapse any card\nand it stays collapsed. On by default.",
          "type": "boolean"
        },
        "show-ignored-files-in-picker": {
          "description": "Whether the reference (`@`) file picker shows files matched by\n.gitignore, .claudeignore, or .polytokenignore when it opens. Off by\ndefault. You can toggle this at any time during a session with\nShift+Tab inside the `@` typeahead; this setting controls only the\nstarting state.",
          "type": "boolean"
        },
        "status-line": {
          "description": "Ordered list of modules shown in the status line. Set this in your user\nconfig; project config cannot change it.",
          "type": "array",
          "items": {
            "$ref": "#/$defs/TuiStatusLineItem"
          }
        }
      }
    },
    "TuiTheme": {
      "description": "Color theme: `auto`, `light`, or `dark`.",
      "type": "string",
      "enum": [
        "auto",
        "light",
        "dark"
      ]
    },
    "TuiAltScreen": {
      "description": "Alternate-screen policy: `auto`, `always`, or `never`.",
      "type": "string",
      "enum": [
        "auto",
        "always",
        "never"
      ]
    },
    "TuiDensity": {
      "description": "Terminal card spacing.",
      "type": "string",
      "enum": [
        "standard",
        "compact"
      ]
    },
    "TuiHelpConfig": {
      "description": "TUI help overlay configuration.",
      "type": "object",
      "properties": {
        "default-tier": {
          "description": "Starting scope of the help overlay when opened: `overview` (the\ndefault), `navigation`, or `advanced`.",
          "$ref": "#/$defs/TuiHelpTier",
          "default": "overview"
        }
      }
    },
    "TuiHelpTier": {
      "description": "Starting scope of the help overlay.",
      "type": "string",
      "enum": [
        "overview",
        "navigation",
        "advanced"
      ]
    },
    "TuiSidebarConfig": {
      "description": "Sidebar display settings.",
      "type": "object",
      "properties": {
        "side": {
          "description": "Which side the sidebar appears on: `left` or `right` (the default).",
          "$ref": "#/$defs/TuiSidebarSide",
          "default": "right"
        },
        "default-state": {
          "description": "Initial sidebar state: `open` (the default) or `collapsed`. Polytoken\nstill collapses it automatically on narrow terminals.",
          "$ref": "#/$defs/TuiSidebarDefaultState",
          "default": "open"
        },
        "collapse-threshold": {
          "description": "Viewport column width below which Polytoken switches to mini mode,\nretracting the sidebar into a floating overlay.",
          "type": "integer",
          "format": "uint16",
          "minimum": 0,
          "maximum": 65535,
          "default": 82
        },
        "width": {
          "description": "Column width of the sidebar. Polytoken keeps it between 30 and 60.",
          "type": "integer",
          "format": "uint16",
          "minimum": 0,
          "maximum": 65535,
          "default": 40
        }
      }
    },
    "TuiSidebarSide": {
      "description": "Which side of the terminal the sidebar appears on.",
      "type": "string",
      "enum": [
        "left",
        "right"
      ]
    },
    "TuiSidebarDefaultState": {
      "description": "Whether the sidebar starts open (the default) or collapsed.",
      "type": "string",
      "enum": [
        "open",
        "collapsed"
      ]
    },
    "TuiMouseConfig": {
      "description": "Mouse input settings.",
      "type": "object",
      "properties": {
        "enabled": {
          "description": "Whether mouse capture and mouse-driven interactions are on. On by\ndefault.",
          "type": "boolean",
          "default": true
        }
      }
    },
    "TuiKeyboardConfig": {
      "description": "Keyboard shortcut overrides for production conversation TUI action commands.",
      "type": "object",
      "properties": {
        "commands": {
          "description": "Key chord overrides keyed by command id. A value may be one chord string\nor a list of chord strings. Omit a command to use its built-in default,\nor set it to an empty list to disable that command. Duplicate chords are\nallowed; the active TUI context and command priority decide which action\nruns first.",
          "type": "object",
          "additionalProperties": {
            "$ref": "#/$defs/TuiCommandKeyBinding"
          }
        }
      }
    },
    "TuiCommandKeyBinding": {
      "description": "Key bindings for production conversation TUI action commands.",
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "TuiEditorConfig": {
      "description": "External editor settings.",
      "type": "object",
      "properties": {
        "command": {
          "description": "External editor command to launch. When unset, Polytoken picks an\neditor automatically.",
          "type": [
            "string",
            "null"
          ]
        }
      }
    },
    "TuiPromptConfig": {
      "description": "TUI prompt settings.",
      "type": "object"
    },
    "TuiNavigationConfig": {
      "description": "Keyboard navigation settings.",
      "type": "object"
    },
    "TuiPasteConfig": {
      "description": "TUI paste sidecar configuration.",
      "type": "object",
      "properties": {
        "collapse-threshold": {
          "description": "Paste size above which pasted content collapses into a sidecar preview\ninstead of rendering inline.",
          "type": "integer",
          "format": "uint32",
          "minimum": 0,
          "default": 10000
        }
      }
    },
    "TuiHistoryConfig": {
      "description": "Prompt history settings.",
      "type": "object",
      "properties": {
        "persist": {
          "description": "Whether Polytoken saves prompt history under the project `.polytoken`\ndirectory. On by default.",
          "type": "boolean",
          "default": true
        },
        "max-entries": {
          "description": "Maximum number of prompt history entries retained.",
          "type": "integer",
          "format": "uint32",
          "minimum": 0,
          "default": 1000
        }
      }
    },
    "TuiCopyConfig": {
      "description": "TUI clipboard-copy configuration.",
      "type": "object",
      "properties": {
        "size-cap": {
          "description": "Maximum byte size of a single clipboard copy.",
          "type": "integer",
          "format": "uint32",
          "minimum": 0,
          "default": 71680
        }
      }
    },
    "TuiAnimationsConfig": {
      "description": "Animation settings.",
      "type": "object",
      "properties": {
        "enabled": {
          "description": "Whether animations run at all. On by default.",
          "type": "boolean",
          "default": true
        },
        "terminal-title": {
          "description": "Whether the terminal title animates during an assistant turn. On by\ndefault.",
          "type": "boolean",
          "default": true
        }
      }
    },
    "TuiTerminalBell": {
      "description": "Bell behavior for attention states: `off`, `audible`, or `auto`.",
      "type": "string",
      "enum": [
        "off",
        "audible",
        "auto"
      ]
    },
    "TuiStatusLineItem": {
      "description": "One module in the status line.",
      "type": "object",
      "properties": {
        "kind": {
          "description": "Which module to render: `cwd`, `source-control`, `facet`, `model`,\n`permissions`, or `context-usage`.\n\nThe `source-control` module shows the current branch label. For Git\nrepositories, the label turns yellow when the working tree has\nuncommitted changes, and arrows indicate how many commits the local\nbranch is ahead (`↑`) or behind (`↓`) its tracked upstream branch.",
          "$ref": "#/$defs/TuiStatusLineKind"
        },
        "args": {
          "description": "Reserved per-module arguments for the status-line module.",
          "$ref": "#/$defs/TuiStatusLineArgs"
        }
      },
      "required": [
        "kind"
      ]
    },
    "TuiStatusLineKind": {
      "type": "string",
      "enum": [
        "cwd",
        "source-control",
        "facet",
        "model",
        "permissions",
        "context-usage"
      ]
    },
    "TuiStatusLineArgs": {
      "type": "object"
    },
    "DataConfig": {
      "description": "Controls diagnostic and crash-report data policy.\n\nThis block is global-only. A project config may not set or erase any key\ninside it.",
      "type": "object",
      "properties": {
        "automatic_crash_reporting": {
          "description": "Controls whether Polytoken sends automatic crash reports when the\nprocess exits unexpectedly. On by default once your user/global\nconfig loads successfully. Set to false to opt out. If your global\nconfig is missing, unreadable, or malformed, crash reporting stays\noff. Project configs may not set this key.",
          "type": [
            "boolean",
            "null"
          ]
        }
      }
    },
    "UpdatesConfig": {
      "description": "Controls the self-updater's check behavior and release channel.\n\nThis is the **authored** type used by `AuthoredConfig.updates`. Fields are\n`Option<T>` so that `None` means \"user did not author this key,\" distinct\nfrom an explicit `Some(true)` or `Some(Latest)`. The runtime `Config`\nresolves these to concrete values during expansion (see\n[`ResolvedUpdatesConfig`]). This block is global-only.",
      "type": "object",
      "properties": {
        "automatic_check": {
          "description": "Whether Polytoken checks for available updates at launch. On by\ndefault. Set to false to disable the automatic launch-time check;\n`polytoken update` still works manually regardless of this setting.\nProject configs may not set this key.",
          "type": [
            "boolean",
            "null"
          ]
        },
        "channel": {
          "description": "Which release channel to track for updates. Defaults to `latest`,\nwhich resolves the newest published release. Set to `stable` to skip\nunstable pre-releases. Project configs may not set this key.",
          "anyOf": [
            {
              "$ref": "#/$defs/UpdateChannel"
            },
            {
              "type": "null"
            }
          ]
        }
      }
    },
    "UpdateChannel": {
      "description": "The release channel Polytoken tracks for self-updates.\n\n`latest` resolves the newest published release, whether stable or\nunstable. `stable` resolves only stable releases, skipping unstable\npre-releases.",
      "oneOf": [
        {
          "description": "Track the newest published release, whether stable or unstable.",
          "type": "string",
          "const": "latest"
        },
        {
          "description": "Track only stable releases, skipping unstable pre-releases.",
          "type": "string",
          "const": "stable"
        }
      ]
    },
    "TelemetryConfig": {
      "description": "Controls OpenTelemetry trace export.\n\nThis block is global-only: a project config may not set or erase any key\ninside it. When this block is absent, trace export is disabled and Polytoken\nsends no OTLP requests.\n\nAll settings come exclusively from this block. Ambient `OTEL_*` environment\nvariables do not enable, configure, or override trace export.\n\nHeader keys and values are sensitive. Polytoken substitutes environment\nvariables (for example `${COLLECTOR_KEY}`) during config loading, but never\nwrites raw header values to diagnostics, logs, or span attributes.",
      "type": "object",
      "properties": {
        "protocol": {
          "description": "The transport protocol for trace data. Set to `http/protobuf` for\nOTLP/HTTP or `grpc` for OTLP/gRPC.",
          "$ref": "#/$defs/TelemetryProtocol"
        },
        "endpoint": {
          "description": "The collector endpoint. For `http/protobuf`, Polytoken expects a base\nURI such as `http://localhost:4318` and appends `/v1/traces`\nautomatically. For `grpc`, Polytoken expects a base URI such as\n`http://localhost:4317` and uses it as the gRPC authority. The endpoint\nmust not contain a path (other than a single trailing slash), query\nparameters, fragments, or userinfo.",
          "type": "string"
        },
        "headers": {
          "description": "Custom headers to send with each trace export request. Keys and values\nsupport environment-variable substitution (for example\n`key = \"${AUTH_TOKEN}\"`). Polytoken treats both keys and values as\nsecrets and never writes them to diagnostics, logs, or spans.",
          "type": "object",
          "additionalProperties": {
            "type": "string"
          }
        },
        "service_name": {
          "description": "The service name reported in trace resource attributes. Defaults to\n`polytoken` when not set. Polytoken distinguishes daemon and exec modes\nwith a separate attribute rather than changing the service name.",
          "type": [
            "string",
            "null"
          ]
        }
      },
      "required": [
        "protocol",
        "endpoint"
      ]
    },
    "TelemetryProtocol": {
      "description": "The transport protocol for sending trace data to a collector.\n\n`http/protobuf` sends OTLP trace data as HTTP POST requests with a\nProtocol Buffers body. `grpc` sends OTLP trace data over a tonic gRPC\nconnection. Choose `http/protobuf` when your collector accepts HTTP (the\ndefault collector port is 4318); choose `grpc` when your collector uses the\ngRPC protocol (the default collector port is 4317).",
      "oneOf": [
        {
          "description": "OTLP/HTTP with Protocol Buffers encoding. The endpoint you configure is\na base URI such as `http://localhost:4318`; Polytoken appends the\n`/v1/traces` signal path automatically.",
          "type": "string",
          "const": "http/protobuf"
        },
        {
          "description": "OTLP/gRPC using tonic. The endpoint you configure is a base URI such as\n`http://localhost:4317`. Polytoken uses it directly as the gRPC\nauthority without appending any path.",
          "type": "string",
          "const": "grpc"
        }
      ]
    }
  }
}
