{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "title": "Pitchfork Configuration",
  "description": "Configuration schema for pitchfork.toml daemon supervisor configuration files.\n\nNote: When read from a file, daemon keys are short names (e.g., \"api\").\nAfter merging, keys become qualified DaemonIds (e.g., \"project/api\").",
  "type": "object",
  "properties": {
    "daemons": {
      "description": "Map of daemon IDs to their configurations",
      "type": "object",
      "additionalProperties": false,
      "patternProperties": {
        "^[A-Za-z0-9_.-]+(/[A-Za-z0-9_.-]+)?$": {
          "$ref": "#/$defs/PitchforkTomlDaemon"
        }
      }
    },
    "env": {
      "description": "Top-level environment variables applied to all daemons as defaults.\nPer-daemon `env` overrides these on key conflicts. Values support Tera\ntemplates (e.g. `{{ daemons.api.port }}`, `{{ settings.proxy.tld }}`).",
      "type": [
        "object",
        "null"
      ],
      "additionalProperties": {
        "type": "string"
      }
    },
    "groups": {
      "description": "Named groups of daemons for batch operations.",
      "type": "object",
      "additionalProperties": {
        "$ref": "#/$defs/GroupEntryRaw"
      }
    },
    "namespace": {
      "description": "Optional explicit namespace declared in this file.\n\nThis applies to per-file read/write flows. Merged configs may contain\ndaemons from multiple namespaces and leave this as `None`.",
      "type": [
        "string",
        "null"
      ]
    },
    "namespaces": {
      "description": "Namespace registry (merged from global config files).\nMaps namespace names to their project directory.",
      "type": "object",
      "additionalProperties": {
        "$ref": "#/$defs/NamespaceEntryRaw"
      }
    },
    "settings": {
      "description": "Settings configuration (merged from all config files).\n\n**Note:** This field exists for serialization round-trips and for\n`PitchforkToml::merge()` to collect per-file overrides.  It is **not**\nconsumed by the global `settings()` singleton, which is populated\nindependently by `Settings::load()` to avoid a circular dependency\nbetween `PitchforkToml` and `Settings`.  Do not rely on mutations to\nthis field being reflected in `settings()`.",
      "$ref": "#/$defs/SettingsPartial",
      "default": {}
    },
    "slugs": {
      "description": "Slug registry (merged from global config files).\nMaps slug names to their project directory and optional daemon name.\nOnly populated from global config files (`~/.config/pitchfork/config.toml`\nor `/etc/pitchfork/config.toml`).",
      "type": "object",
      "additionalProperties": {
        "$ref": "#/$defs/SlugEntryRaw"
      }
    }
  },
  "$defs": {
    "CpuLimit": {
      "description": "CPU usage limit as a percentage (e.g. 80 for 80% of one core, 200 for 2 cores)",
      "type": "number",
      "exclusiveMinimum": 0
    },
    "CronRetrigger": {
      "description": "Retrigger behavior for cron-scheduled daemons",
      "oneOf": [
        {
          "description": "Retrigger only if the previous run has finished (success or error)",
          "type": "string",
          "const": "finish"
        },
        {
          "description": "Always retrigger, stopping the previous run if still active",
          "type": "string",
          "const": "always"
        },
        {
          "description": "Retrigger only if the previous run succeeded",
          "type": "string",
          "const": "success"
        },
        {
          "description": "Retrigger only if the previous run failed",
          "type": "string",
          "const": "fail"
        }
      ]
    },
    "DaemonId": {
      "description": "Daemon name (e.g. 'api') or qualified ID ('namespace/name') for cross-namespace references",
      "type": "string",
      "not": {
        "pattern": "\\.\\.|--|(^|/)-|-($|/)|^\\.$|^\\./|/\\.$"
      },
      "pattern": "^[A-Za-z0-9_.-]+(/[A-Za-z0-9_.-]+)?$"
    },
    "GroupEntryRaw": {
      "description": "Raw group entry as read from TOML.\n```toml\n[groups.backend]\ndaemons = [\"api\", \"worker\"]\n```",
      "type": "object",
      "properties": {
        "daemons": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/DaemonId"
          }
        }
      },
      "required": [
        "daemons"
      ]
    },
    "MemoryLimit": {
      "description": "A byte size, as either a human-readable string (e.g. \"1.5 KiB\") or a number of bytes",
      "type": [
        "string",
        "integer"
      ]
    },
    "NamespaceEntryRaw": {
      "description": "Raw namespace entry as read from TOML.\n```toml\n[namespaces.myproject]\ndir = \"/home/user/projects/myproject\"\n```",
      "type": "object",
      "properties": {
        "dir": {
          "description": "Project directory containing the pitchfork.toml",
          "type": "string"
        }
      },
      "required": [
        "dir"
      ]
    },
    "OnOutputHook": {
      "description": "Output hook configuration.\n\nAccepts two forms:\n```toml\non_output = \"echo matched\"                              # shorthand (run only)\non_output = { run = \"echo matched\", filter = \"ready\" }  # full\n```\n\nPattern matching (`filter` / `regex`) is performed against ANSI-stripped\noutput and covers both stdout and stderr.",
      "type": "object",
      "properties": {
        "debounce": {
          "description": "Minimum time between successive firings (humantime, e.g. `\"500ms\"`).\nDefaults to `\"1000ms\"`.",
          "type": [
            "string",
            "null"
          ]
        },
        "filter": {
          "description": "Fire when a line of output contains this substring",
          "type": [
            "string",
            "null"
          ]
        },
        "regex": {
          "description": "Fire when a line of output matches this regular expression",
          "type": [
            "string",
            "null"
          ]
        },
        "run": {
          "description": "Command to run when the output condition is met",
          "type": "string"
        }
      },
      "required": [
        "run"
      ]
    },
    "PitchforkTomlAuto": {
      "description": "Auto start/stop configuration",
      "type": "string",
      "enum": [
        "start",
        "stop"
      ]
    },
    "PitchforkTomlCron": {
      "description": "Cron scheduling: a cron expression string, or { schedule, retrigger, immediate } object",
      "oneOf": [
        {
          "description": "Cron expression (e.g. '0 * * * *')",
          "type": "string"
        },
        {
          "type": "object",
          "properties": {
            "immediate": {
              "description": "Trigger immediately on first check (default: false)",
              "type": "boolean"
            },
            "retrigger": {
              "$ref": "#/$defs/CronRetrigger"
            },
            "schedule": {
              "description": "Cron expression",
              "type": "string"
            }
          },
          "required": [
            "schedule"
          ]
        }
      ]
    },
    "PitchforkTomlDaemon": {
      "description": "Configuration for a single daemon (internal representation with DaemonId)",
      "type": "object",
      "properties": {
        "archive_hook": {
          "description": "Archive hook command invoked before retention prunes this daemon's logs.\nOverrides the global `settings.logs.archive_hook.command` when set.",
          "type": [
            "string",
            "null"
          ]
        },
        "auto": {
          "description": "Automatic start/stop behavior based on shell hooks",
          "type": "array",
          "default": [],
          "items": {
            "$ref": "#/$defs/PitchforkTomlAuto"
          }
        },
        "boot_start": {
          "description": "Whether to start this daemon automatically on system boot",
          "type": [
            "boolean",
            "null"
          ]
        },
        "cpu_limit": {
          "description": "CPU usage limit as a percentage (e.g. 80 for 80%, 200 for 2 cores).\nThe supervisor periodically monitors CPU usage and kills the process if it exceeds the limit.",
          "anyOf": [
            {
              "$ref": "#/$defs/CpuLimit"
            },
            {
              "type": "null"
            }
          ]
        },
        "cron": {
          "description": "Cron scheduling configuration for periodic execution",
          "anyOf": [
            {
              "$ref": "#/$defs/PitchforkTomlCron"
            },
            {
              "type": "null"
            }
          ]
        },
        "depends": {
          "description": "List of daemon IDs that must be started before this one",
          "type": "array",
          "default": [],
          "items": {
            "$ref": "#/$defs/DaemonId"
          }
        },
        "dir": {
          "description": "Working directory for the daemon. Relative paths are resolved from the pitchfork.toml location.",
          "type": [
            "string",
            "null"
          ]
        },
        "env": {
          "description": "Environment variables to set for the daemon process",
          "type": [
            "object",
            "null"
          ],
          "additionalProperties": {
            "type": "string"
          }
        },
        "hooks": {
          "description": "Lifecycle hooks (on_ready, on_fail, on_retry)",
          "anyOf": [
            {
              "$ref": "#/$defs/PitchforkTomlHooks"
            },
            {
              "type": "null"
            }
          ]
        },
        "line_retention": {
          "description": "Maximum number of log entries to keep per daemon.\nOverrides the global `settings.logs.line_retention` when set.",
          "type": [
            "integer",
            "null"
          ],
          "format": "int64"
        },
        "logs": {
          "description": "Per-daemon log configuration sub-table.",
          "anyOf": [
            {
              "$ref": "#/$defs/PitchforkTomlDaemonLogs"
            },
            {
              "type": "null"
            }
          ]
        },
        "memory_limit": {
          "description": "Memory limit for the daemon process (e.g. \"50MB\", \"1GiB\").\nThe supervisor periodically monitors RSS and kills the process if it exceeds the limit.",
          "anyOf": [
            {
              "$ref": "#/$defs/MemoryLimit"
            },
            {
              "type": "null"
            }
          ]
        },
        "mise": {
          "description": "Wrap this daemon's command with `mise x --` for tool/env setup.\nOverrides the global `settings.general.mise` when set.",
          "type": [
            "boolean",
            "null"
          ]
        },
        "port": {
          "description": "Port configuration: expected ports and auto-bump settings",
          "anyOf": [
            {
              "$ref": "#/$defs/PortConfig"
            },
            {
              "type": "null"
            }
          ]
        },
        "pty": {
          "description": "Allocate a pseudo-terminal for the daemon process.",
          "type": [
            "boolean",
            "null"
          ]
        },
        "ready_cmd": {
          "description": "Shell command to poll for readiness (exit code 0 = ready)",
          "anyOf": [
            {
              "$ref": "#/$defs/ReadyCmd"
            },
            {
              "type": "null"
            }
          ]
        },
        "ready_delay": {
          "description": "Delay in seconds before considering the daemon ready",
          "type": [
            "integer",
            "null"
          ],
          "format": "uint64",
          "minimum": 0
        },
        "ready_http": {
          "description": "HTTP URL to poll for readiness. Accepts any 2xx response by default, or configured statuses.",
          "anyOf": [
            {
              "$ref": "#/$defs/ReadyHttp"
            },
            {
              "type": "null"
            }
          ]
        },
        "ready_output": {
          "description": "Regex pattern to match in ANSI-stripped stdout/stderr to determine readiness",
          "anyOf": [
            {
              "$ref": "#/$defs/ReadyOutput"
            },
            {
              "type": "null"
            }
          ]
        },
        "ready_port": {
          "description": "TCP port to check for readiness (connection success = ready).\nAccepts a port number, a Tera template string that renders to one, or an\nobject with an optional overall polling timeout.",
          "anyOf": [
            {
              "$ref": "#/$defs/ReadyPort"
            },
            {
              "type": "null"
            }
          ]
        },
        "retry": {
          "description": "Number of times to retry if the daemon fails.\nCan be a number (e.g., `3`) or `true` for infinite retries.",
          "$ref": "#/$defs/Retry",
          "default": 0
        },
        "run": {
          "description": "The command to run. Prepend with 'exec' to avoid shell process overhead.",
          "type": "string",
          "examples": [
            "exec node server.js"
          ]
        },
        "stop_signal": {
          "description": "Stop signal and optional per-daemon timeout. Accepts a signal name string\nor `{ signal = \"...\", timeout = \"...\" }` object.",
          "anyOf": [
            {
              "$ref": "#/$defs/StopConfig"
            },
            {
              "type": "null"
            }
          ]
        },
        "time_retention": {
          "description": "Maximum age of log entries to keep (e.g. \"7d\", \"30d\").\nOverrides the global `settings.logs.time_retention` when set.",
          "type": [
            "string",
            "null"
          ]
        },
        "user": {
          "description": "Unix user to run this daemon as. Overrides `settings.supervisor.user` when set.",
          "type": [
            "string",
            "null"
          ]
        },
        "watch": {
          "description": "File patterns to watch for changes",
          "type": "array",
          "default": [],
          "items": {
            "type": "string"
          }
        },
        "watch_mode": {
          "description": "File watching backend mode.\n\n- `native`: use platform-native notifications (default)\n- `poll`: use polling-based watcher\n- `auto`: prefer native, fall back to polling if native watch fails",
          "$ref": "#/$defs/WatchMode",
          "default": "native"
        }
      },
      "required": [
        "run"
      ]
    },
    "PitchforkTomlDaemonLogs": {
      "description": "Per-daemon log configuration sub-table `[daemons.<name>.logs]`.\n\nFields here override the top-level daemon fields (`time_retention`,\n`line_retention`, `archive_hook`) and the global `[settings.logs]` defaults.",
      "type": "object",
      "properties": {
        "archive_hook": {
          "description": "Archive hook command invoked before retention prunes this daemon's logs.",
          "type": [
            "string",
            "null"
          ]
        },
        "line_retention": {
          "description": "Maximum number of log entries to keep per daemon.",
          "type": [
            "integer",
            "null"
          ],
          "format": "int64"
        },
        "log_format": {
          "description": "Log line format: `json`, `logfmt`, or `text`.\nDefaults to `text` (no parsing).",
          "type": [
            "string",
            "null"
          ]
        },
        "time_retention": {
          "description": "Maximum age of log entries to keep (e.g. \"7d\", \"30d\").",
          "type": [
            "string",
            "null"
          ]
        }
      }
    },
    "PitchforkTomlHooks": {
      "description": "Lifecycle hooks for a daemon",
      "type": "object",
      "properties": {
        "on_exit": {
          "description": "Command to run on any daemon termination (clean exit, crash, or stop)",
          "type": [
            "string",
            "null"
          ]
        },
        "on_fail": {
          "description": "Command to run when the daemon fails and all retries are exhausted",
          "type": [
            "string",
            "null"
          ]
        },
        "on_output": {
          "description": "Hook triggered when the daemon produces matching output",
          "anyOf": [
            {
              "$ref": "#/$defs/OnOutputHook"
            },
            {
              "type": "null"
            }
          ]
        },
        "on_ready": {
          "description": "Command to run when the daemon becomes ready",
          "type": [
            "string",
            "null"
          ]
        },
        "on_retry": {
          "description": "Command to run before each retry attempt",
          "type": [
            "string",
            "null"
          ]
        },
        "on_stop": {
          "description": "Command to run when the daemon is explicitly stopped by pitchfork",
          "type": [
            "string",
            "null"
          ]
        }
      }
    },
    "PortBump": {
      "description": "Port bump: true = unlimited, false/0 = disabled, number = max attempts",
      "oneOf": [
        {
          "type": "boolean"
        },
        {
          "type": "integer",
          "minimum": 0
        }
      ]
    },
    "PortConfig": {
      "description": "Port config: a port number, array of ports, or { expect, bump } object",
      "oneOf": [
        {
          "type": "integer",
          "maximum": 65535,
          "minimum": 0
        },
        {
          "type": "array",
          "items": {
            "type": "integer",
            "maximum": 65535,
            "minimum": 0
          }
        },
        {
          "type": "object",
          "properties": {
            "bump": {
              "$ref": "#/$defs/PortBump"
            },
            "expect": {
              "type": "array",
              "items": {
                "type": "integer",
                "maximum": 65535,
                "minimum": 0
              }
            }
          }
        }
      ]
    },
    "ReadyCmd": {
      "description": "Command readiness check: a shell command string, or { run, timeout } object with an optional overall polling timeout",
      "oneOf": [
        {
          "description": "Shell command that returns exit code 0 when ready",
          "type": "string"
        },
        {
          "type": "object",
          "properties": {
            "run": {
              "description": "Shell command that returns exit code 0 when ready",
              "type": "string"
            },
            "timeout": {
              "description": "Overall readiness polling timeout (e.g. '30s', '5m')",
              "type": "string"
            }
          },
          "required": [
            "run"
          ]
        }
      ]
    },
    "ReadyHttp": {
      "description": "HTTP readiness check: a URL string accepting any 2xx response, or { url, status, timeout } object with exact accepted status codes and optional overall polling timeout",
      "oneOf": [
        {
          "description": "HTTP URL to poll for readiness; any 2xx response is ready",
          "type": "string"
        },
        {
          "type": "object",
          "properties": {
            "status": {
              "description": "Exact HTTP status codes that indicate readiness. Omit to accept any 2xx response.",
              "type": "array",
              "items": {
                "type": "integer",
                "maximum": 599,
                "minimum": 100
              }
            },
            "timeout": {
              "description": "Overall readiness polling timeout (e.g. '30s', '5m'). Distinct from per-request http_client_timeout.",
              "type": "string"
            },
            "url": {
              "description": "HTTP URL to poll for readiness",
              "type": "string"
            }
          },
          "required": [
            "url"
          ]
        }
      ]
    },
    "ReadyOutput": {
      "description": "Output readiness check: a regex pattern string, or { pattern, timeout } object with an optional overall polling timeout",
      "oneOf": [
        {
          "description": "Regex pattern matched against ANSI-stripped stdout/stderr lines",
          "type": "string"
        },
        {
          "type": "object",
          "properties": {
            "pattern": {
              "description": "Regex pattern matched against ANSI-stripped stdout/stderr lines",
              "type": "string"
            },
            "timeout": {
              "description": "Overall readiness polling timeout (e.g. '30s', '5m')",
              "type": "string"
            }
          },
          "required": [
            "pattern"
          ]
        }
      ]
    },
    "ReadyPort": {
      "description": "TCP readiness port: a port number, a template string rendering to one, or an object with an optional overall polling timeout",
      "oneOf": [
        {
          "description": "TCP port number to check for readiness",
          "type": "integer",
          "maximum": 65535,
          "minimum": 1
        },
        {
          "description": "Tera template that renders to a port number",
          "type": "string"
        },
        {
          "type": "object",
          "properties": {
            "port": {
              "description": "TCP port number to check for readiness",
              "type": "integer",
              "maximum": 65535,
              "minimum": 1
            },
            "template": {
              "description": "Tera template that renders to a port number",
              "type": "string"
            },
            "timeout": {
              "description": "Overall readiness polling timeout (e.g. '30s', '5m')",
              "type": "string"
            }
          },
          "oneOf": [
            {
              "required": [
                "port"
              ]
            },
            {
              "required": [
                "template"
              ]
            }
          ]
        }
      ]
    },
    "Retry": {
      "description": "Retry: true = indefinite, false/0 = none, number = count",
      "oneOf": [
        {
          "type": "boolean"
        },
        {
          "type": "integer",
          "minimum": 0
        }
      ]
    },
    "SettingsApiPartial": {
      "type": "object",
      "properties": {
        "auto_start": {
          "description": "Automatically start the standalone API server",
          "type": [
            "boolean",
            "null"
          ]
        },
        "bind_address": {
          "description": "IP address the API server binds to",
          "type": [
            "string",
            "null"
          ]
        },
        "bind_port": {
          "description": "Port the standalone API server listens on",
          "type": [
            "integer",
            "null"
          ],
          "format": "int64"
        },
        "port_attempts": {
          "description": "Number of consecutive ports to try if api.bind_port is in use",
          "type": [
            "integer",
            "null"
          ],
          "format": "int64"
        },
        "token": {
          "description": "Authentication token for API access when bound to non-loopback addresses",
          "type": [
            "string",
            "null"
          ]
        }
      }
    },
    "SettingsGeneralPartial": {
      "type": "object",
      "properties": {
        "autostop_delay": {
          "description": "Delay before auto-stopping daemons when leaving a directory",
          "type": [
            "string",
            "null"
          ]
        },
        "interval": {
          "description": "Supervisor background task refresh interval",
          "type": [
            "string",
            "null"
          ]
        },
        "log_file_level": {
          "description": "File log level (trace, debug, info, warn, error)",
          "type": [
            "string",
            "null"
          ]
        },
        "log_level": {
          "description": "Console log level (trace, debug, info, warn, error)",
          "type": [
            "string",
            "null"
          ]
        },
        "mise": {
          "description": "Wrap daemon commands with mise x -- globally",
          "type": [
            "boolean",
            "null"
          ]
        },
        "mise_bin": {
          "description": "Explicit path to the mise binary",
          "type": [
            "string",
            "null"
          ]
        },
        "shell": {
          "description": "Shell command used to execute daemon run scripts",
          "type": [
            "string",
            "null"
          ]
        },
        "startup_log_timestamps": {
          "description": "Show timestamps in startup log output",
          "type": [
            "boolean",
            "null"
          ]
        }
      }
    },
    "SettingsIpcPartial": {
      "type": "object",
      "properties": {
        "connect_attempts": {
          "description": "Number of connection retry attempts",
          "type": [
            "integer",
            "null"
          ],
          "format": "int64"
        },
        "connect_max_delay": {
          "description": "Maximum delay between connection retries",
          "type": [
            "string",
            "null"
          ]
        },
        "connect_min_delay": {
          "description": "Minimum delay between connection retries",
          "type": [
            "string",
            "null"
          ]
        },
        "rate_limit": {
          "description": "Maximum IPC requests per second per connection",
          "type": [
            "integer",
            "null"
          ],
          "format": "int64"
        },
        "rate_limit_window": {
          "description": "Rate limit sliding window duration",
          "type": [
            "string",
            "null"
          ]
        },
        "request_timeout": {
          "description": "Default timeout for IPC requests",
          "type": [
            "string",
            "null"
          ]
        }
      }
    },
    "SettingsLogsArchiveHookPartial": {
      "type": "object",
      "properties": {
        "batch_size": {
          "description": "Maximum log entries per archive hook invocation",
          "type": [
            "integer",
            "null"
          ],
          "format": "int64"
        },
        "command": {
          "description": "Command to run before retention deletes old log entries",
          "type": [
            "string",
            "null"
          ]
        }
      }
    },
    "SettingsLogsPartial": {
      "type": "object",
      "properties": {
        "archive_hook": {
          "$ref": "#/$defs/SettingsLogsArchiveHookPartial"
        },
        "line_retention": {
          "description": "Count-based log retention (e.g. 10000)",
          "type": [
            "integer",
            "null"
          ],
          "format": "int64"
        },
        "log_format": {
          "description": "Default log format for daemons (json | logfmt | text)",
          "type": [
            "string",
            "null"
          ]
        },
        "time_retention": {
          "description": "Time-based log retention duration (e.g. '7d', '30d')",
          "type": [
            "string",
            "null"
          ]
        },
        "timestamp": {
          "description": "Show timestamps in log output",
          "type": [
            "boolean",
            "null"
          ]
        },
        "timestamp_format": {
          "description": "strftime format for log timestamps in `pitchfork logs` output",
          "type": [
            "string",
            "null"
          ]
        }
      }
    },
    "SettingsPartial": {
      "type": "object",
      "properties": {
        "api": {
          "$ref": "#/$defs/SettingsApiPartial"
        },
        "general": {
          "$ref": "#/$defs/SettingsGeneralPartial"
        },
        "ipc": {
          "$ref": "#/$defs/SettingsIpcPartial"
        },
        "logs": {
          "$ref": "#/$defs/SettingsLogsPartial"
        },
        "proxy": {
          "$ref": "#/$defs/SettingsProxyPartial"
        },
        "supervisor": {
          "$ref": "#/$defs/SettingsSupervisorPartial"
        },
        "tui": {
          "$ref": "#/$defs/SettingsTuiPartial"
        },
        "web": {
          "$ref": "#/$defs/SettingsWebPartial"
        }
      }
    },
    "SettingsProxyPartial": {
      "type": "object",
      "properties": {
        "auto_start": {
          "description": "Automatically start daemons when accessed via proxy URL",
          "type": [
            "boolean",
            "null"
          ]
        },
        "auto_start_timeout": {
          "description": "Maximum time to wait for an auto-started daemon to become ready",
          "type": [
            "string",
            "null"
          ]
        },
        "auto_trust": {
          "description": "Automatically install the proxy TLS certificate into the system trust store",
          "type": [
            "boolean",
            "null"
          ]
        },
        "enable": {
          "description": "Enable the reverse proxy server for daemons",
          "type": [
            "boolean",
            "null"
          ]
        },
        "host": {
          "description": "Bind address for the reverse proxy server",
          "type": [
            "string",
            "null"
          ]
        },
        "https": {
          "description": "Enable HTTPS for the reverse proxy",
          "type": [
            "boolean",
            "null"
          ]
        },
        "lan": {
          "description": "Enable LAN mode for the reverse proxy",
          "type": [
            "boolean",
            "null"
          ]
        },
        "lan_ip": {
          "description": "Pin a specific LAN IP address instead of auto-detecting",
          "type": [
            "string",
            "null"
          ]
        },
        "port": {
          "description": "Port the reverse proxy server listens on",
          "type": [
            "integer",
            "null"
          ],
          "format": "int64"
        },
        "sync_hosts": {
          "description": "Automatically sync slug hostnames to /etc/hosts",
          "type": [
            "boolean",
            "null"
          ]
        },
        "tld": {
          "description": "Top-level domain used for proxy URLs",
          "type": [
            "string",
            "null"
          ]
        },
        "tls_cert": {
          "description": "Path to TLS certificate file (PEM format) for HTTPS proxy",
          "type": [
            "string",
            "null"
          ]
        },
        "tls_key": {
          "description": "Path to TLS private key file (PEM format) for HTTPS proxy",
          "type": [
            "string",
            "null"
          ]
        },
        "wildcard": {
          "description": "Enable wildcard subdomain matching for proxy routes",
          "type": [
            "boolean",
            "null"
          ]
        },
        "worktree": {
          "description": "Enable git worktree / jj workspace auto-discovery for slug routing",
          "type": [
            "boolean",
            "null"
          ]
        }
      }
    },
    "SettingsSupervisorPartial": {
      "type": "object",
      "properties": {
        "auto_start": {
          "description": "Automatically start the supervisor when a client command needs it",
          "type": [
            "boolean",
            "null"
          ]
        },
        "cleanup_orphans": {
          "description": "Reconcile orphaned daemon processes when supervisor starts",
          "type": [
            "boolean",
            "null"
          ]
        },
        "container": {
          "description": "Enable container/PID1 mode for running inside Docker containers",
          "type": [
            "boolean",
            "null"
          ]
        },
        "cpu_violation_threshold": {
          "description": "Consecutive CPU-over-limit samples before killing a daemon",
          "type": [
            "integer",
            "null"
          ],
          "format": "int64"
        },
        "cron_check_interval": {
          "description": "Interval for checking cron schedules",
          "type": [
            "string",
            "null"
          ]
        },
        "file_watch_debounce": {
          "description": "File watch debounce duration",
          "type": [
            "string",
            "null"
          ]
        },
        "http_client_timeout": {
          "description": "Timeout for HTTP ready checks",
          "type": [
            "string",
            "null"
          ]
        },
        "log_flush_interval": {
          "description": "Daemon log buffer flush interval",
          "type": [
            "string",
            "null"
          ]
        },
        "orphan_policy": {
          "description": "What to do with live orphaned daemons on supervisor startup: adopt or kill",
          "type": [
            "string",
            "null"
          ]
        },
        "port_bump_attempts": {
          "description": "Maximum port increment attempts when auto_bump_port is enabled",
          "type": [
            "integer",
            "null"
          ],
          "format": "int64"
        },
        "ready_check_interval": {
          "description": "Interval between ready checks (HTTP, TCP, command)",
          "type": [
            "string",
            "null"
          ]
        },
        "restart_delay": {
          "description": "Delay between stop and start during restart",
          "type": [
            "string",
            "null"
          ]
        },
        "stop_timeout": {
          "description": "Maximum time to wait for daemon to stop gracefully",
          "type": [
            "string",
            "null"
          ]
        },
        "user": {
          "description": "Default user to run daemon processes as",
          "type": [
            "string",
            "null"
          ]
        },
        "watch_interval": {
          "description": "File watcher config refresh interval",
          "type": [
            "string",
            "null"
          ]
        },
        "watch_poll_interval": {
          "description": "Polling watcher filesystem scan interval",
          "type": [
            "string",
            "null"
          ]
        }
      }
    },
    "SettingsTuiPartial": {
      "type": "object",
      "properties": {
        "message_duration": {
          "description": "Status message display duration",
          "type": [
            "string",
            "null"
          ]
        },
        "refresh_rate": {
          "description": "Daemon list refresh interval",
          "type": [
            "string",
            "null"
          ]
        },
        "stat_history": {
          "description": "Number of stat samples to keep for graphs",
          "type": [
            "integer",
            "null"
          ],
          "format": "int64"
        },
        "tick_rate": {
          "description": "Event loop tick rate",
          "type": [
            "string",
            "null"
          ]
        }
      }
    },
    "SettingsWebPartial": {
      "type": "object",
      "properties": {
        "auto_start": {
          "description": "Automatically start web UI when supervisor starts",
          "type": [
            "boolean",
            "null"
          ]
        },
        "base_path": {
          "description": "URL path prefix for the web UI (e.g. \"ps\" serves at /ps/)",
          "type": [
            "string",
            "null"
          ]
        },
        "bind_address": {
          "description": "Web server bind address",
          "type": [
            "string",
            "null"
          ]
        },
        "bind_port": {
          "description": "Default web server port",
          "type": [
            "integer",
            "null"
          ],
          "format": "int64"
        },
        "log_lines": {
          "description": "Initial number of log lines to display",
          "type": [
            "integer",
            "null"
          ],
          "format": "int64"
        },
        "port_attempts": {
          "description": "Number of ports to try if default is in use",
          "type": [
            "integer",
            "null"
          ],
          "format": "int64"
        },
        "sse_poll_interval": {
          "description": "Server-Sent Events poll interval for log streaming",
          "type": [
            "string",
            "null"
          ]
        }
      }
    },
    "SlugEntryRaw": {
      "description": "Raw slug entry as read from TOML (uses String for dir path).\nFormat in global config:\n```toml\n[slugs]\napi = { dir = \"/home/user/my-api\", daemon = \"server\" }\ndocs = { dir = \"/home/user/docs-site\" }  # daemon defaults to slug name\n```",
      "type": "object",
      "properties": {
        "daemon": {
          "description": "Daemon name within that project (defaults to slug name if omitted)",
          "type": [
            "string",
            "null"
          ]
        },
        "dir": {
          "description": "Project directory containing the pitchfork.toml",
          "type": [
            "string",
            "null"
          ]
        },
        "namespace": {
          "description": "Namespace reference (alternative to dir)",
          "type": [
            "string",
            "null"
          ]
        }
      }
    },
    "StopConfig": {
      "description": "Stop signal config: a signal name string, or { signal, timeout } object",
      "oneOf": [
        {
          "$ref": "#/$defs/StopSignal"
        },
        {
          "type": "object",
          "properties": {
            "signal": {
              "$ref": "#/$defs/StopSignal"
            },
            "timeout": {
              "description": "Graceful shutdown timeout (e.g. '500ms', '3s')",
              "type": "string"
            }
          },
          "required": [
            "signal"
          ]
        }
      ]
    },
    "StopSignal": {
      "description": "Unix signal for graceful shutdown (e.g. 'SIGTERM', 'SIGINT', 'SIGHUP')",
      "type": "string",
      "enum": [
        "SIGTERM",
        "SIGINT",
        "SIGQUIT",
        "SIGHUP",
        "SIGUSR1",
        "SIGUSR2"
      ]
    },
    "WatchMode": {
      "description": "File watch backend mode for daemon `watch` patterns.",
      "oneOf": [
        {
          "description": "Use platform-native watcher backend (inotify/FSEvents/ReadDirectoryChangesW).",
          "type": "string",
          "const": "native"
        },
        {
          "description": "Use polling backend; more compatible on networked filesystems.",
          "type": "string",
          "const": "poll"
        },
        {
          "description": "Prefer native backend, fall back to polling when native watch setup fails.",
          "type": "string",
          "const": "auto"
        }
      ]
    }
  }
}
