{
  "$schema": "https://games.jeffdraws.net/schemas/games-agent-manifest-v1.schema.json",
  "contractVersion": "1.0.0",
  "name": "Jeff Plays agent contract",
  "purpose": "A personal game-progress magazine curated from Jeff's playthrough updates.",
  "canonicalOrigin": "https://games.jeffdraws.net",
  "humanGuide": "https://games.jeffdraws.net/agent-guide/",
  "state": {
    "schemaVersion": "1.0.0",
    "schema": "https://games.jeffdraws.net/schemas/game-progress-state-v1.schema.json",
    "readEndpoint": "https://games.jeffdraws.net/api/state",
    "writeEndpoint": "https://games.jeffdraws.net/api/state",
    "canonicalStore": "Cloudflare D1",
    "staticEmergencyFallback": "https://games.jeffdraws.net/data/progress.json",
    "maxBytes": 262144
  },
  "writeProtocol": {
    "method": "PUT",
    "authentication": "Bearer token supplied out of band; never discoverable from this site",
    "credentialLifecycle": {
      "cloudflareSecretName": "AGENT_WRITE_TOKEN",
      "retrievable": false,
      "replacementOnly": true,
      "authorizedEditorBootstrap": [
        "Generate a new high-entropy token locally without printing it.",
        "Retain it only in the editor's approved secret store.",
        "Set or rotate the production AGENT_WRITE_TOKEN through Cloudflare's secret mechanism.",
        "Redeploy the Pages project if Cloudflare requires the new secret to become active.",
        "Use the same locally held value as the API bearer token and verify by conditional read-write-readback."
      ],
      "withoutCloudflareAuthorization": "Request Cloudflare project access or an authorization handoff; do not request the production secret value.",
      "never": [
        "Ask the user to paste an existing production token into ordinary chat.",
        "Place a production token in logs, command output, source control, site forms, or public artifacts.",
        "Serve a secret-entry or secret-recovery interface from games.jeffdraws.net."
      ]
    },
    "precondition": "Send the exact ETag from the latest GET in If-Match",
    "conflictBehavior": "Stop on 409 or 412, refetch, reconcile, and retry intentionally",
    "verification": "Read back with cache bypass and confirm the new revision plus unchanged protected fields"
  },
  "routineUpdateFields": [
    "activeRunId",
    "runs[].status",
    "runs[].position",
    "runs[].progress",
    "runs[].milestones[].state",
    "runs[].milestones[].note",
    "runs[].latest",
    "runs[].nextCue",
    "runs[].fieldNotes",
    "runs[].sessions"
  ],
  "protectedFields": [
    "schemaVersion",
    "revision",
    "updatedAt",
    "runs[].id",
    "runs[].title",
    "runs[].platform",
    "runs[].dek",
    "runs[].artwork",
    "runs[].accent",
    "runs[].milestones[].id",
    "runs[].milestones[].label"
  ],
  "rules": {
    "publicQuestions": ["what game", "where Jeff is", "rough progress", "latest meaningful moment", "what comes next"],
    "progress": "Always publish basis and confidence; never infer story progress from achievements, mastery, or playtime without labeling it.",
    "milestones": "Use 3–5 curated guideposts with cleared/current/upcoming states and exactly one current state for an active run.",
    "detail": "Put granular routes, inventory, combat, objectives, and full sessions behind progressive disclosure.",
    "boundary": "Update content; do not redesign the site."
  },
  "compatibility": {
    "versioning": "semver",
    "unsupportedMajor": "stop_without_writing",
    "unknownFields": "preserve"
  },
  "indexing": {"humanGuide": "noindex,nofollow,noarchive", "manifest": "public machine discovery"}
}
