{
  "schema": "noclip.geospatial-agent-contract/2.2",
  "title": "NOCLIP Geospatial + Live Scene Agent Contract",
  "ownerOnboarding": "https://noclip.org/?panel=agents",
  "baseUrl": "https://api.noclip.org",
  "modelInvocation": {
    "scope": "agent:invoke",
    "automaticAgentKeyIncludesScope": false,
    "enqueue": "POST /agent/chat/jobs",
    "poll": "GET /agent/chat/jobs/{jobId}",
    "ownership": "Authenticated account/API-key jobs are private to the account and originating API key; guest jobs and polls are bound to their privacy-preserving client identity.",
    "defaultModel": "local/omnius-robit-qwen38-27b-obliterated-e03-27b:latest",
    "models": [
      { "id": "local/omnius-robit-qwen38-27b-obliterated-e03-27b:latest", "provider": "local", "eligibility": "guest, account, or delegated API key" },
      { "id": "openai/gpt-5.4-mini", "provider": "openai", "eligibility": "JWT-backed account with its encrypted OpenAI credential" },
      { "id": "anthropic/claude-sonnet-5", "provider": "anthropic", "eligibility": "JWT-backed account with its encrypted Anthropic credential" }
    ],
    "providerPolicy": "Send only an exact model ID. Provider endpoints and credentials are backend-owned. A selected provider failure never falls back to another provider or public registry.",
    "concurrency": "Direct, queued, chat.begin WebSocket and legacy session SSE share one running cascade and at most 24 outstanding jobs per backend process across accounts; histories and results remain owner-isolated.",
    "labelNews": { "endpoint": "POST /agent/chat", "features": ["label_intel_modal", "regional_news_modal"], "policy": "public-only", "relevancePolicy": "poi-news-relevance.v2", "context": "Exact named entity or region, mapped city/address/website, scope, limit 1-6; business default scope news", "disclosure": "Public search/Reader/inference receives the selected target. No local model or compute-job lease; ordinary chat provider selection does not apply and account BYOK is never consumed.", "acceptance": "Fetched publisher body must match subject/branch; explicit public selection needs checked subject quote. News requires publication within 30 days. No unchecked fallback cards or old policy caches.", "status": ["summarized", "no-verified-matches", "verification-unavailable"], "cancellable": true, "commands": [] },
    "context": "Active renderer state, fresh watched GPS, selected mapped building records and bounded visible peer summaries; no account/session/device identifiers.",
    "completion": "A queued job ID is not success. Require status completed and inspect responseStatus and response.model."
  },
  "authentication": {
    "scheme": "bearer",
    "header": "Authorization: Bearer <NOCLIP_API_KEY>",
    "provisionedScope": ["data:read", "scene:observe", "scene:control"],
    "secretHandling": [
      "Obtain the one-time-reveal key from the account owner's Account > Agents page.",
      "Keep the key in private agent credential storage.",
      "Never put the key in a URL, query string, log, source file, public prompt, or user-visible response.",
      "Treat 401 or 403 as terminal and ask the owner to review or rotate the credential."
    ]
  },
  "discovery": [
    { "url": "https://api.noclip.org/v1/data/catalog", "mediaType": "application/json", "purpose": "Products, sources, provenance caveats, endpoint templates, and public governance metadata" },
    { "url": "https://api.noclip.org/docs/openapi", "mediaType": "text/yaml", "purpose": "Governed OpenAPI contract" },
    { "url": "https://noclip.org/llms.txt", "mediaType": "text/plain", "purpose": "Concise agent entry point" }
  ],
  "operatingRules": [
    "Discover before querying and remain within operations authorized for data:read, scene:observe, and scene:control.",
    "Prefer bounded bbox, radius, time-window, and result-limit queries; paginate and cache where supported.",
    "Preserve source/provider attribution, event time, retrieval time, confidence, precision, geometry, and product caveats.",
    "Never fabricate coordinates for non-geospatial records or present modeled/statistical products as observed incidents.",
    "On 429, stop and honor Retry-After and RateLimit reset headers without parallel retries.",
    "Report an exact missing endpoint or scope to the owner instead of attempting privilege escalation."
  ],
  "liveScene": {
    "leaseSeconds": 600,
    "stateSchema": "noclip.agent-interface-state/1.1",
    "ownership": "Each observation is bound to the authenticated account, originating API key, and selected online device.",
    "steps": [
      { "method": "GET", "path": "/agent/interface/sessions", "purpose": "List online account-owned Earth scene devices with bounded deviceClass, deviceName, displayType, and tags for explicit owner-requested selection" },
      { "method": "POST", "path": "/agent/interface/observations", "body": { "deviceId": "<DEVICE_ID>", "includeDetails": true, "includeImage": false } },
      { "method": "GET", "path": "/agent/interface/observations/<OBSERVATION_ID>", "purpose": "Read camera pose, authoritative viewshed, feed controls, optional scene image, and command results" },
      { "method": "POST", "path": "/agent/interface/observations/<OBSERVATION_ID>/commands", "body": { "command": { "intent": "set_feed_visibility", "slots": { "category": "trafficCameras", "enabled": true } } } },
      { "method": "DELETE", "path": "/agent/interface/observations/<OBSERVATION_ID>", "purpose": "Stop immediately when the task ends" }
    ],
    "deviceSelection": "When the owner identifies desktop, phone, VR, a device name, or a tag, select the matching session metadata. Never replace that instruction with most-recent activity.",
    "cameraState": {
      "logicalTarget": "state.surfaceLatLon may update when a surface transition starts.",
      "renderedPosition": "state.renderedSurfaceLatLon is the physical rendered-camera Earth-fixed subpoint.",
      "transition": "state.cameraTransition reports active camera travel and bounded progress.",
      "arrival": "For fly_to, poll until command.status is complete, command.result.toolResult.arrived is true, and renderedSurfaceLatLon matches the requested destination. Admission or a logical target update is not arrival."
    },
    "allowedControlIntents": ["set_location", "set_altitude", "set_camera_mode", "set_overlay_center", "set_overlay_visibility", "set_feed_visibility", "select_entity", "fly_to", "navigate_to", "step_camera"],
    "iterativeNavigation": {
      "intent": "step_camera",
      "surfaceOnly": true,
      "capabilityPath": "state.agentInterface.capabilities.controlIntents",
      "capabilityRule": "Require step_camera in the connected client's advertised control intents. If absent, ask the owner to reload that Earth client and do not probe the intent.",
      "loop": "Record sequence/image timestamp, submit exactly one bounded step, wait for completion, wait for newer rendered state/frame, inspect, then decide the next step.",
      "slots": {
        "forwardMeters": { "minimum": -10, "maximum": 10, "mapping": "W is positive; S is negative" },
        "rightMeters": { "minimum": -10, "maximum": 10, "mapping": "D is positive; A is negative" },
        "upMeters": { "minimum": -5, "maximum": 5 },
        "yawDegrees": { "minimum": -45, "maximum": 45 },
        "pitchDegrees": { "minimum": -30, "maximum": 30 }
      },
      "constraints": [
        "Combined horizontal displacement cannot exceed 10 metres.",
        "At least one delta must be non-zero.",
        "Raw keys, input durations, retained controls, unknown fields, and parallel step commands are rejected.",
        "Use command.result.toolResult for actual movement and rendered pose; a zero appliedHorizontalMeters result means translation was blocked."
      ]
    },
    "vision": {
      "authoritative": "state.agentInterface.viewshed contains post-culling renderer-backed scene visibility and state.agentInterface.feedControls contains feed enablement/status.",
      "image": "includeImage is opt-in; frames are capped at 320x180 and no more than once per five seconds."
    }
  },
  "rateAuthority": {
    "rule": "effective capacity is the minimum applicable limit",
    "dimensions": ["api-key policy", "holdings-derived account tier", "client/edge", "operation", "provider", "concurrency", "global safety"],
    "liveSignals": ["Retry-After", "RateLimit-Limit", "RateLimit-Remaining", "RateLimit-Reset"]
  },
  "starterRequests": [
    { "method": "GET", "path": "/v1/data/catalog" },
    { "method": "GET", "path": "/v1/regional-brief?lat=49.2827&lon=-123.1207&newsLimit=5" },
    { "method": "GET", "path": "/geocoding/search?q=Vancouver&limit=5" }
  ],
  "excludedFromAutomaticProvisioning": [
    { "scope": "agent:invoke", "reason": "Model invocation is not required for the bounded live-scene bridge." },
    { "scope": "scan:write", "reason": "Field-scan mutation is not required for read-only exploration." }
  ]
}
