{
  "sandbox": true,
  "summary": "A sandbox agent token is a REAL token with REAL scopes on the SAME endpoints (MCP /api/mcp, A2A /api/a2a, REST) — the only difference is post-auth mutation routing: WRITE verbs scope-check normally but return a simulated receipt instead of mutating production state. READS always serve real data.",
  "how_to": "Mint a sandbox token via the normal device-code signup: POST /api/agent/signup/start with { scopes: [...], client_name, sandbox: true }. The minted token carries sandbox:true, and every WRITE it fires returns { ok:true, sandbox:true, simulated:true, would_have:{...} } instead of touching production state.",
  "endpoints": {
    "mcp": "https://www.immersivecommons.com/api/mcp",
    "a2a": "https://www.immersivecommons.com/api/a2a",
    "signup_start": "https://www.immersivecommons.com/api/agent/signup/start"
  },
  "fail_closed": {
    "note": "Not every write is sandbox-simulatable. A write with no provable token scope (role-gated-only checks, the x402 donation rail, or a tool not yet in the scope catalog) DENIES in sandbox rather than guessing — it never falls through to a real mutation. One documented exception stays real even in sandbox: the bug-report feedback channel must always reach a human.",
    "always_denies_in_sandbox": [
      "floorcast_run_ai_curation",
      "floorcast_set_ai_policy",
      "floorcast_set_feature_availability",
      "floorcast_set_feature_enabled",
      "ic_donate",
      "ic_files_update",
      "ic_folder_update",
      "ic_get_my_workshop_key",
      "ic_get_my_zai_key",
      "ic_rooms_create",
      "ic_rooms_join",
      "ic_rooms_send"
    ],
    "always_real_even_in_sandbox": [
      "ic_feedback_submit"
    ]
  },
  "docs": {
    "sandbox_page": "https://www.immersivecommons.com/sandbox",
    "sandbox_md": "https://www.immersivecommons.com/sandbox.md",
    "auth_md": "https://www.immersivecommons.com/auth.md",
    "developers_md": "https://www.immersivecommons.com/developers.md"
  }
}