{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://raw.githubusercontent.com/gavin-hu/my-pi-agent/main/assets/bytefly.schema.json",
  "title": "bytefly shared extension config",
  "description": "One document, one top-level section per extension (bytefly owns price, notify, doctor, and chrome). Resolution is low to high: built-in defaults, <agent-dir>/bytefly.json, then <cwd>/.pi/bytefly.json (project wins). Unknown keys are ignored.",
  "type": "object",
  "additionalProperties": false,
  "properties": {
    "$schema": {
      "type": "string",
      "description": "Editor-schema pointer; ignored by the loaders."
    },
    "version": {
      "type": "integer",
      "minimum": 1,
      "default": 1,
      "description": "Document schema version; absent means 1. The loader warns on a newer version."
    },
    "price": {
      "$ref": "#/$defs/price"
    },
    "notify": {
      "$ref": "#/$defs/notify"
    },
    "doctor": {
      "$ref": "#/$defs/doctor"
    },
    "chrome": {
      "$ref": "#/$defs/chrome"
    },
    "worktree": {
      "$ref": "#/$defs/worktree"
    },
    "rewind": {
      "$ref": "#/$defs/rewind"
    },
    "todo": {
      "$ref": "#/$defs/todo"
    },
    "goal": {
      "$ref": "#/$defs/goal"
    },
    "job": {
      "$ref": "#/$defs/job"
    },
    "watch": {
      "$ref": "#/$defs/watch"
    },
    "web-access": {
      "$ref": "#/$defs/webAccess"
    },
    "file-browse": {
      "$ref": "#/$defs/fileBrowse"
    },
    "document": {
      "$ref": "#/$defs/document"
    },
    "memory": {
      "$ref": "#/$defs/memory"
    },
    "wechat": {
      "$ref": "#/$defs/wechat"
    }
  },
  "$defs": {
    "stringArray": {
      "type": "array",
      "items": {
        "type": "string"
      },
      "description": "Strings are trimmed; empty entries are dropped."
    },
    "chrome": {
      "type": "object",
      "description": "bytefly's transcript chrome presentation.",
      "additionalProperties": false,
      "properties": {
        "rail": {
          "type": "string",
          "maxLength": 1,
          "default": "╎",
          "description": "The transcript rail glyph, exactly one visible column. A wide, emoji, multi-character, empty, or control value falls back to ╎. The rail leads a tool result and a notice row; it is also drawn on the call frame for the two file-mutating tools (`edit`, `write`), whose call body carries the result. There is no status fill."
        }
      }
    },
    "price": {
      "type": "object",
      "description": "bytefly's price calculation (the footer's cost bar).",
      "additionalProperties": false,
      "properties": {
        "currency": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "symbol": {
              "type": "string",
              "maxLength": 4,
              "default": "¥"
            },
            "decimals": {
              "type": "integer",
              "minimum": 0,
              "maximum": 4,
              "default": 2
            }
          }
        },
        "fallbackToRecordedCost": {
          "type": "boolean",
          "default": true
        },
        "rates": {
          "type": "object",
          "description": "Per-million-token prices keyed by provider/model; merges key by key across the global and project documents, and a key present in both is replaced.",
          "additionalProperties": {
            "$ref": "#/$defs/modelRates"
          }
        },
        "peak": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "timezone": {
              "type": "string",
              "default": "Asia/Shanghai"
            },
            "windows": {
              "type": "array",
              "maxItems": 16,
              "items": {
                "$ref": "#/$defs/peakWindow"
              }
            }
          }
        }
      }
    },
    "modelRates": {
      "type": "object",
      "minProperties": 1,
      "additionalProperties": false,
      "properties": {
        "input": {
          "type": "number",
          "minimum": 0,
          "maximum": 1000000,
          "default": 0
        },
        "output": {
          "type": "number",
          "minimum": 0,
          "maximum": 1000000,
          "default": 0
        },
        "cacheRead": {
          "type": "number",
          "minimum": 0,
          "maximum": 1000000,
          "default": 0
        },
        "cacheWrite": {
          "type": "number",
          "minimum": 0,
          "maximum": 1000000,
          "default": 0
        },
        "offPeakMultiplier": {
          "type": "number",
          "minimum": 0,
          "maximum": 1,
          "default": 1
        }
      }
    },
    "peakWindow": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "days": {
          "type": "array",
          "minItems": 1,
          "uniqueItems": true,
          "items": {
            "type": "integer",
            "minimum": 1,
            "maximum": 7
          },
          "description": "ISO weekdays, 1 = Monday. Omitted means every day."
        },
        "from": {
          "type": "string",
          "pattern": "^([01]?\\d|2[0-3]):[0-5]\\d$",
          "description": "Inclusive HH:MM, in the peak timezone."
        },
        "to": {
          "type": "string",
          "pattern": "^([01]?\\d|2[0-3]):[0-5]\\d$",
          "description": "Exclusive HH:MM; a value <= from wraps past midnight."
        }
      },
      "required": ["from", "to"]
    },
    "notify": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "enabled": {
          "type": "boolean",
          "default": false
        },
        "turnFinished": {
          "type": "boolean",
          "default": true
        },
        "needsInput": {
          "type": "boolean",
          "default": true
        },
        "jobFinished": {
          "type": "boolean",
          "default": true
        },
        "method": {
          "type": "string",
          "enum": ["auto", "osascript", "notify-send", "toast", "osc777", "osc99"],
          "default": "auto"
        },
        "title": {
          "type": "string",
          "maxLength": 40,
          "default": "Pi"
        }
      }
    },
    "doctor": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "proactive": {
          "type": "boolean",
          "default": true
        },
        "timeoutMs": {
          "type": "integer",
          "minimum": 100,
          "maximum": 30000,
          "default": 2000
        },
        "skip": {
          "$ref": "#/$defs/stringArray",
          "default": []
        }
      }
    },
    "worktree": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "dir": {
          "type": "string",
          "default": ".pi/worktrees"
        },
        "baseRef": {
          "type": "string",
          "enum": ["fresh", "head"],
          "default": "fresh"
        },
        "branchPrefix": {
          "type": "string",
          "default": "worktree-"
        },
        "fetchRemote": {
          "type": "boolean",
          "default": true
        },
        "fetchTimeoutMs": {
          "type": "integer",
          "minimum": 0,
          "maximum": 600000,
          "default": 5000
        },
        "onExit": {
          "type": "string",
          "enum": ["ask", "keep", "remove"],
          "default": "ask"
        },
        "pruneAfterDays": {
          "type": "integer",
          "minimum": 0,
          "maximum": 3650,
          "default": 7
        },
        "include": {
          "$ref": "#/$defs/stringArray",
          "default": []
        },
        "skipOverrides": {
          "$ref": "#/$defs/stringArray",
          "default": []
        },
        "guard": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "blockFileEscapes": {
              "type": "boolean",
              "default": true
            },
            "blockReadEscapes": {
              "type": "boolean",
              "default": false
            },
            "blockGitRedirects": {
              "type": "boolean",
              "default": true
            },
            "blockSymlinkEscapes": {
              "type": "boolean",
              "default": true
            },
            "blockUnparsableCommands": {
              "type": "boolean",
              "default": false
            }
          }
        }
      }
    },
    "rewind": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "autoSnapshots": {
          "type": "boolean",
          "default": true
        },
        "max": {
          "type": "integer",
          "minimum": 0,
          "maximum": 1000,
          "default": 20
        },
        "includeUntracked": {
          "type": "boolean",
          "default": true
        },
        "safetySnapshot": {
          "type": "boolean",
          "default": true
        },
        "autoPrune": {
          "type": "boolean",
          "default": true
        },
        "showStatus": {
          "type": "boolean",
          "default": true
        },
        "watch": {
          "$ref": "#/$defs/stringArray",
          "default": []
        },
        "ignore": {
          "$ref": "#/$defs/stringArray",
          "default": []
        },
        "refNamespace": {
          "type": "string",
          "default": "refs/pi/rewind"
        }
      }
    },
    "todo": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "hideWhenComplete": {
          "type": "boolean",
          "default": true
        }
      }
    },
    "goal": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "achieved": {
          "type": "string",
          "enum": ["show", "hide"],
          "default": "hide"
        }
      }
    },
    "job": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "enabled": {
          "type": "boolean",
          "default": true
        },
        "showStatus": {
          "type": "boolean",
          "default": true
        },
        "wakeOnFinish": {
          "type": "boolean",
          "default": false
        },
        "detachedByDefault": {
          "type": "boolean",
          "default": false
        },
        "maxJobs": {
          "type": "integer",
          "minimum": 1,
          "maximum": 500,
          "default": 20
        },
        "maxLogLines": {
          "type": "integer",
          "minimum": 1,
          "maximum": 5000,
          "default": 100
        },
        "killGraceMs": {
          "type": "integer",
          "minimum": 0,
          "maximum": 60000,
          "default": 5000
        },
        "repaintMs": {
          "type": "integer",
          "minimum": 100,
          "maximum": 10000,
          "default": 1000
        },
        "sessionTtlMs": {
          "type": "integer",
          "minimum": 5000,
          "maximum": 600000,
          "default": 60000
        },
        "registryDir": {
          "type": "string",
          "description": "Registry directory override; empty means the default under the agent dir."
        }
      }
    },
    "watch": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "enabled": {
          "type": "boolean",
          "default": true
        },
        "showStatus": {
          "type": "boolean",
          "default": true
        },
        "wakeOnMatch": {
          "type": "boolean",
          "default": false
        },
        "maxWatchers": {
          "type": "integer",
          "minimum": 1,
          "maximum": 200,
          "default": 20
        },
        "maxMatches": {
          "type": "integer",
          "minimum": 1,
          "maximum": 5000,
          "default": 200
        },
        "maxLogLines": {
          "type": "integer",
          "minimum": 1,
          "maximum": 5000,
          "default": 500
        },
        "matchLines": {
          "type": "integer",
          "minimum": 1,
          "maximum": 2000,
          "default": 50
        },
        "pollMs": {
          "type": "integer",
          "minimum": 100,
          "maximum": 60000,
          "default": 500
        }
      }
    },
    "webAccess": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "search": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "provider": {
              "type": "string",
              "enum": ["auto", "duckduckgo", "searxng", "brave"],
              "default": "auto"
            },
            "endpoint": {
              "type": "string",
              "description": "SearXNG base URL; empty means unset."
            },
            "language": {
              "type": "string",
              "default": "auto"
            },
            "safeSearch": {
              "type": "integer",
              "minimum": 0,
              "maximum": 2,
              "default": 0
            },
            "categories": {
              "type": "string",
              "default": "general"
            },
            "apiKeyEnv": {
              "type": "string",
              "default": ""
            },
            "apiKey": {
              "type": "string",
              "default": ""
            },
            "maxResults": {
              "type": "integer",
              "minimum": 1,
              "maximum": 20,
              "default": 8
            },
            "timeoutMs": {
              "type": "integer",
              "minimum": 1000,
              "maximum": 120000,
              "default": 15000
            },
            "maxBytes": {
              "type": "integer",
              "minimum": 1024,
              "maximum": 50000000,
              "default": 5000000
            },
            "minIntervalMs": {
              "type": "integer",
              "minimum": 0,
              "maximum": 60000,
              "default": 500
            },
            "maxOutputChars": {
              "type": "integer",
              "minimum": 1000,
              "maximum": 100000,
              "default": 12000
            },
            "userAgent": {
              "type": "string"
            }
          }
        },
        "fetch": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "timeoutMs": {
              "type": "integer",
              "minimum": 1000,
              "maximum": 120000,
              "default": 20000
            },
            "maxBytes": {
              "type": "integer",
              "minimum": 1024,
              "maximum": 50000000,
              "default": 5000000
            },
            "maxOutputChars": {
              "type": "integer",
              "minimum": 500,
              "maximum": 100000,
              "default": 20000
            },
            "userAgent": {
              "type": "string"
            },
            "acceptLanguage": {
              "type": "string"
            },
            "allowPrivateHosts": {
              "type": "boolean",
              "default": false
            },
            "maxRedirects": {
              "type": "integer",
              "minimum": 0,
              "maximum": 10,
              "default": 5
            },
            "maxBodyChars": {
              "type": "integer",
              "minimum": 1000,
              "maximum": 1000000,
              "default": 100000
            },
            "pdfEnabled": {
              "type": "boolean",
              "default": true
            },
            "cacheEnabled": {
              "type": "boolean",
              "default": true
            },
            "cacheTtlMs": {
              "type": "integer",
              "minimum": 0,
              "maximum": 3600000,
              "default": 300000
            },
            "cacheMaxEntries": {
              "type": "integer",
              "minimum": 1,
              "maximum": 50,
              "default": 8
            },
            "cacheMaxBytes": {
              "type": "integer",
              "minimum": 1024,
              "maximum": 50000000,
              "default": 8000000
            }
          }
        }
      }
    },
    "fileBrowse": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "port": {
          "type": "integer",
          "minimum": 0,
          "maximum": 65535,
          "default": 0
        },
        "autoOpen": {
          "type": "boolean",
          "default": true
        },
        "maxFileBytes": {
          "type": "integer",
          "minimum": 0,
          "maximum": 1073741824,
          "default": 1048576
        },
        "maxThumbBytes": {
          "type": "integer",
          "minimum": 0,
          "maximum": 1073741824,
          "default": 5242880
        },
        "maxTextLines": {
          "type": "integer",
          "minimum": 1,
          "maximum": 1000000,
          "default": 5000
        },
        "maxDirEntries": {
          "type": "integer",
          "minimum": 1,
          "maximum": 1000000,
          "default": 2000
        },
        "thumbnails": {
          "type": "boolean",
          "default": true
        },
        "markdown": {
          "type": "boolean",
          "default": true
        },
        "maxIndexEntries": {
          "type": "integer",
          "minimum": 1,
          "maximum": 1000000,
          "default": 20000
        }
      }
    },
    "document": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "maxFileBytes": {
          "type": "integer",
          "minimum": 1024,
          "maximum": 536870912,
          "default": 20971520
        },
        "maxChars": {
          "type": "integer",
          "minimum": 200,
          "maximum": 100000,
          "default": 40000
        },
        "formats": {
          "type": "object",
          "description": "Per-format on/off, merged over each format's default. Known ids: pdf, docx, doc, odt, rtf, xlsx.",
          "additionalProperties": {
            "type": "boolean"
          }
        }
      }
    },
    "memory": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "inject": {
          "type": "boolean",
          "default": true
        },
        "maxInjectBytes": {
          "type": "integer",
          "minimum": 512,
          "maximum": 32768,
          "default": 8192
        }
      }
    },
    "wechat": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "allowedPeers": {
          "$ref": "#/$defs/stringArray",
          "default": []
        },
        "maxReplyChars": {
          "type": "integer",
          "minimum": 1,
          "maximum": 20000,
          "default": 4000
        },
        "botAgent": {
          "type": "string",
          "maxLength": 256,
          "default": "pi-wechat"
        },
        "channelVersion": {
          "type": "string",
          "default": "0.1.0"
        },
        "cdnBaseUrl": {
          "type": "string",
          "default": "https://novac2c.cdn.weixin.qq.com/c2c"
        },
        "maxMediaBytes": {
          "type": "integer",
          "minimum": 1024,
          "maximum": 104857600,
          "default": 20971520
        },
        "typingIndicator": {
          "type": "boolean",
          "default": true
        },
        "remotePrompts": {
          "type": "boolean",
          "default": true
        }
      }
    }
  }
}
