{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "urn:field-pack:schema:pack:1",
  "title": "Field pack (schema v1)",
  "description": "One versioned, tested unit of task knowledge. The canonical source is a Markdown file with YAML front matter; build.py validates the front matter against this schema (after adding computed fields) and renders HTML, compact Markdown, JSON, feed entries and llms.txt lines from it.",
  "type": "object",
  "additionalProperties": false,
  "required": [
    "schema_version",
    "identity",
    "fit",
    "evidence",
    "procedure",
    "verification",
    "rights",
    "formats"
  ],
  "$defs": {
    "isoDate": {
      "type": "string",
      "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
    },
    "looseDate": {
      "type": "string",
      "pattern": "^\\d{4}-\\d{2}(-\\d{2})?$",
      "description": "YYYY-MM-DD, or YYYY-MM when only the month is known."
    },
    "nonEmpty": {
      "type": "string",
      "minLength": 1
    },
    "strList": {
      "type": "array",
      "items": {
        "type": "string",
        "minLength": 1
      }
    }
  },
  "properties": {
    "schema_version": {
      "const": 1
    },
    "identity": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "id",
        "title",
        "summary",
        "desk",
        "editor",
        "version",
        "status",
        "updated",
        "changelog"
      ],
      "properties": {
        "id": {
          "type": "string",
          "pattern": "^(bo|ab|rd)-\\d{3}-[a-z0-9-]+$",
          "description": "Stable ID. Never reused, never renamed. Desk prefix: bo = Bot Operations, ab = Agent Builder, rd = Research Desk."
        },
        "title": {
          "$ref": "#/$defs/nonEmpty"
        },
        "summary": {
          "type": "string",
          "minLength": 20,
          "maxLength": 400,
          "description": "One- or two-sentence answer an agent can use before reading anything else."
        },
        "desk": {
          "enum": [
            "bot-operations",
            "agent-builder",
            "research-desk"
          ]
        },
        "editor": {
          "$ref": "#/$defs/nonEmpty"
        },
        "second_reviewer": {
          "type": [
            "string",
            "null"
          ],
          "description": "Week-1 gate: every pack needs a second review before it can leave private-review."
        },
        "version": {
          "type": "string",
          "pattern": "^\\d+\\.\\d+\\.\\d+$"
        },
        "status": {
          "enum": [
            "draft",
            "private-review",
            "published",
            "retracted"
          ]
        },
        "published": {
          "oneOf": [
            {
              "$ref": "#/$defs/isoDate"
            },
            {
              "type": "null"
            }
          ]
        },
        "updated": {
          "$ref": "#/$defs/isoDate"
        },
        "canonical_url": {
          "type": "string",
          "description": "Filled by build.py from site.json base_url + /packs/<id>/. Do not hand-edit."
        },
        "changelog": {
          "type": "array",
          "minItems": 1,
          "items": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "version",
              "date",
              "note"
            ],
            "properties": {
              "version": {
                "type": "string"
              },
              "date": {
                "$ref": "#/$defs/isoDate"
              },
              "note": {
                "$ref": "#/$defs/nonEmpty"
              }
            }
          }
        }
      }
    },
    "fit": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "goal",
        "audience",
        "environment",
        "prerequisites",
        "permissions_required",
        "exclusions",
        "expected_output"
      ],
      "properties": {
        "goal": {
          "$ref": "#/$defs/nonEmpty"
        },
        "audience": {
          "$ref": "#/$defs/strList"
        },
        "environment": {
          "$ref": "#/$defs/strList"
        },
        "versions": {
          "$ref": "#/$defs/strList"
        },
        "prerequisites": {
          "$ref": "#/$defs/strList"
        },
        "permissions_required": {
          "$ref": "#/$defs/strList"
        },
        "exclusions": {
          "$ref": "#/$defs/strList",
          "description": "When NOT to use this pack."
        },
        "expected_output": {
          "$ref": "#/$defs/nonEmpty"
        }
      }
    },
    "evidence": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "sources",
        "observations",
        "test_environment",
        "uncertainty"
      ],
      "properties": {
        "sources": {
          "type": "array",
          "minItems": 1,
          "items": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "id",
              "title",
              "url",
              "publisher",
              "kind",
              "fetched",
              "supports"
            ],
            "properties": {
              "id": {
                "type": "string",
                "pattern": "^S\\d+$"
              },
              "title": {
                "$ref": "#/$defs/nonEmpty"
              },
              "url": {
                "type": "string",
                "pattern": "^https://"
              },
              "publisher": {
                "$ref": "#/$defs/nonEmpty"
              },
              "kind": {
                "enum": [
                  "primary",
                  "secondary",
                  "community"
                ]
              },
              "fetched": {
                "$ref": "#/$defs/isoDate"
              },
              "source_dated": {
                "type": "string",
                "description": "The date the source itself shows (e.g. 'Last validated Jan 5, 2026'), copied verbatim."
              },
              "supports": {
                "$ref": "#/$defs/nonEmpty",
                "description": "Which claim in this pack the source backs."
              }
            }
          }
        },
        "observations": {
          "type": "array",
          "items": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "date",
              "observed"
            ],
            "properties": {
              "date": {
                "$ref": "#/$defs/looseDate"
              },
              "setting": {
                "type": "string"
              },
              "observed": {
                "$ref": "#/$defs/nonEmpty"
              }
            }
          }
        },
        "test_environment": {
          "$ref": "#/$defs/nonEmpty"
        },
        "measured_outcomes": {
          "$ref": "#/$defs/strList"
        },
        "uncertainty": {
          "$ref": "#/$defs/strList"
        },
        "counterexamples": {
          "$ref": "#/$defs/strList"
        }
      }
    },
    "procedure": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "summary",
        "default_mode",
        "steps"
      ],
      "properties": {
        "summary": {
          "$ref": "#/$defs/nonEmpty"
        },
        "default_mode": {
          "enum": [
            "read-only",
            "dry-run"
          ],
          "description": "Packs never default to writing."
        },
        "external_content_notice": {
          "type": "string"
        },
        "steps": {
          "type": "array",
          "minItems": 1,
          "items": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "n",
              "title",
              "effect",
              "action",
              "expect"
            ],
            "properties": {
              "n": {
                "type": "integer",
                "minimum": 1
              },
              "title": {
                "$ref": "#/$defs/nonEmpty"
              },
              "effect": {
                "enum": [
                  "read",
                  "probe",
                  "write",
                  "irreversible"
                ],
                "description": "read = no side effects; probe = sends traffic or runs a no-op but changes no state; write = reversible state change; irreversible = cannot be undone."
              },
              "action": {
                "$ref": "#/$defs/nonEmpty"
              },
              "command": {
                "type": "string"
              },
              "expect": {
                "$ref": "#/$defs/nonEmpty"
              },
              "gate": {
                "type": "string",
                "description": "Who must approve before this step runs. Required for write and irreversible steps."
              },
              "untested": {
                "type": "boolean"
              }
            },
            "allOf": [
              {
                "if": {
                  "properties": {
                    "effect": {
                      "enum": [
                        "write",
                        "irreversible"
                      ]
                    }
                  }
                },
                "then": {
                  "required": [
                    "gate"
                  ]
                }
              }
            ]
          }
        }
      }
    },
    "verification": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "success_check",
        "failure_signatures",
        "rollback",
        "last_tested",
        "coverage",
        "tested_scope",
        "review_by",
        "retraction"
      ],
      "properties": {
        "success_check": {
          "$ref": "#/$defs/nonEmpty"
        },
        "failure_signatures": {
          "type": "array",
          "minItems": 2,
          "items": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "signature",
              "meaning",
              "next"
            ],
            "properties": {
              "signature": {
                "$ref": "#/$defs/nonEmpty"
              },
              "meaning": {
                "$ref": "#/$defs/nonEmpty"
              },
              "next": {
                "$ref": "#/$defs/nonEmpty"
              }
            }
          }
        },
        "rollback": {
          "$ref": "#/$defs/nonEmpty"
        },
        "last_tested": {
          "oneOf": [
            {
              "$ref": "#/$defs/isoDate"
            },
            {
              "const": "not yet tested"
            }
          ]
        },
        "coverage": {
          "enum": [
            "none",
            "tools-only",
            "partial",
            "full"
          ],
          "description": "How much of the procedure the last test exercised: none; tools-only (helper scripts on fixtures); partial (some real steps); full (the success check passed end to end in a real environment)."
        },
        "tested_scope": {
          "$ref": "#/$defs/nonEmpty",
          "description": "Exactly what the last test covered and what it did not."
        },
        "review_by": {
          "$ref": "#/$defs/isoDate"
        },
        "retraction": {
          "type": "object",
          "additionalProperties": false,
          "required": [
            "retracted"
          ],
          "properties": {
            "retracted": {
              "type": "boolean"
            },
            "reason": {
              "type": "string"
            },
            "date": {
              "$ref": "#/$defs/isoDate"
            }
          }
        }
      }
    },
    "rights": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "license",
        "provenance",
        "permissions_policy",
        "telemetry"
      ],
      "properties": {
        "license": {
          "$ref": "#/$defs/nonEmpty"
        },
        "provenance": {
          "$ref": "#/$defs/nonEmpty"
        },
        "dependency_licenses": {
          "$ref": "#/$defs/strList"
        },
        "permissions_policy": {
          "$ref": "#/$defs/nonEmpty"
        },
        "telemetry": {
          "$ref": "#/$defs/nonEmpty"
        },
        "integrity": {
          "type": "object",
          "additionalProperties": false,
          "required": [
            "content_digest",
            "digest_scope"
          ],
          "description": "Filled by build.py. A digest identifies content; it does not prove who wrote it.",
          "properties": {
            "content_digest": {
              "type": "string",
              "pattern": "^sha256:[0-9a-f]{64}$"
            },
            "digest_scope": {
              "type": "string"
            },
            "signed_manifest": {
              "type": [
                "string",
                "null"
              ]
            }
          }
        }
      }
    },
    "formats": {
      "type": "array",
      "minItems": 3,
      "uniqueItems": true,
      "items": {
        "enum": [
          "html",
          "markdown",
          "json",
          "skill"
        ]
      },
      "contains": {
        "const": "json"
      }
    },
    "assets": {
      "$ref": "#/$defs/strList",
      "description": "Repo-relative helper files (scripts, templates) shipped with the pack."
    },
    "related": {
      "$ref": "#/$defs/strList",
      "description": "Other pack IDs."
    }
  }
}
