{
 "openapi": "3.1.0",
 "info": {
  "title": "reverser.space account API",
  "version": "1.1.0",
  "description": "The signed-in API behind app.reverser.space: sessions, uploads, analysis, sharing, collaboration and agents. Authenticate with POST /api/auth/login and send the returned token as 'Authorization: Bearer <token>' on every other call.\n\nAddresses: parameters take 0x-prefixed hex strings like 0x401000. Responses return addresses as decimal byte offsets (Ghidra offsets); the one exception is /triage, which returns 0x-prefixed hex strings ready to pass back.\n\nErrors are always {\"error\": \"...\"}. A session idle long enough reopens from its saved Ghidra project on the first request, which can take a few seconds.\n\nRoles: each session grants you viewer, editor or creator; operations note the role they need. 401 no or bad token; 403 role too low; 404 also covers sessions you hold no grant on, which stay indistinguishable from ones that do not exist.\n\nA WebSocket at /api/s/{sid}/ws streams live session events; it is outside this spec, as is the owner-only /api/admin surface. The read-only share-link API is documented separately in /openapi.json."
 },
 "externalDocs": {
  "description": "Guide with worked examples",
  "url": "https://app.reverser.space/agent-api.html"
 },
 "servers": [
  {
   "url": "https://app.reverser.space"
  }
 ],
 "security": [
  {
   "bearerAuth": []
  }
 ],
 "paths": {
  "/api/auth/login": {
   "post": {
    "operationId": "login",
    "summary": "Sign in; the returned token authenticates every other call",
    "security": [],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/LoginRequest"
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "JSON result",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/LoginResponse"
        }
       }
      }
     },
     "401": {
      "description": "Bad username or password",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "default": {
      "$ref": "#/components/responses/error"
     }
    }
   }
  },
  "/api/auth/logout": {
   "post": {
    "operationId": "logout",
    "summary": "Revoke the current token",
    "responses": {
     "200": {
      "description": "JSON result",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Status"
        }
       }
      }
     },
     "default": {
      "$ref": "#/components/responses/error"
     },
     "401": {
      "$ref": "#/components/responses/unauthorized"
     }
    }
   }
  },
  "/api/auth/me": {
   "get": {
    "operationId": "me",
    "summary": "The signed-in account",
    "responses": {
     "200": {
      "description": "JSON result",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/PublicUser"
        }
       }
      }
     },
     "default": {
      "$ref": "#/components/responses/error"
     },
     "401": {
      "$ref": "#/components/responses/unauthorized"
     }
    }
   }
  },
  "/api/sessions": {
   "get": {
    "operationId": "sessions",
    "summary": "Sessions this account can see, with its role on each",
    "responses": {
     "200": {
      "description": "JSON result",
      "content": {
       "application/json": {
        "schema": {
         "type": "array",
         "items": {
          "$ref": "#/components/schemas/SessionInfo"
         }
        }
       }
      }
     },
     "default": {
      "$ref": "#/components/responses/error"
     },
     "401": {
      "$ref": "#/components/responses/unauthorized"
     }
    }
   }
  },
  "/api/capacity": {
   "get": {
    "operationId": "capacity",
    "summary": "How full the gateway is, and this account's own allowance",
    "responses": {
     "200": {
      "description": "JSON result",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/GatewayCapacity"
        }
       }
      }
     },
     "default": {
      "$ref": "#/components/responses/error"
     },
     "401": {
      "$ref": "#/components/responses/unauthorized"
     }
    }
   }
  },
  "/api/upload": {
   "post": {
    "operationId": "upload",
    "summary": "Upload a binary; creates a private session with this account as creator",
    "description": "Analysis does not start until POST /api/s/{sid}/analyze, so symbols can be attached first. Re-uploading identical bytes returns the existing session. An optional 'symbols' part stages a PDB alongside in one request.",
    "requestBody": {
     "required": true,
     "content": {
      "multipart/form-data": {
       "schema": {
        "type": "object",
        "properties": {
         "file": {
          "type": "string",
          "format": "binary"
         },
         "symbols": {
          "type": "string",
          "format": "binary",
          "description": "Optional PDB"
         }
        },
        "required": [
         "file"
        ]
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "JSON result",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/SessionInfo"
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/badRequest"
     },
     "409": {
      "description": "This account holds as many binaries as it may",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "413": {
      "description": "Larger than the gateway's per-file limit",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "default": {
      "$ref": "#/components/responses/error"
     },
     "401": {
      "$ref": "#/components/responses/unauthorized"
     }
    }
   }
  },
  "/api/agents": {
   "get": {
    "operationId": "agents",
    "summary": "Agents this gateway offers",
    "responses": {
     "200": {
      "description": "JSON result",
      "content": {
       "application/json": {
        "schema": {
         "type": "array",
         "items": {
          "$ref": "#/components/schemas/PublicAgent"
         }
        }
       }
      }
     },
     "default": {
      "$ref": "#/components/responses/error"
     },
     "401": {
      "$ref": "#/components/responses/unauthorized"
     }
    }
   }
  },
  "/api/agent-key": {
   "get": {
    "operationId": "getAgentKey",
    "summary": "Whether this account has stored agent API keys (never the keys themselves)",
    "responses": {
     "200": {
      "description": "JSON result",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/KeyStatus"
        }
       }
      }
     },
     "default": {
      "$ref": "#/components/responses/error"
     },
     "401": {
      "$ref": "#/components/responses/unauthorized"
     }
    }
   },
   "post": {
    "operationId": "setAgentKey",
    "summary": "Store a provider API key for this account's agent runs",
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/SetKeyRequest"
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "JSON result",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/KeyStatus"
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/badRequest"
     },
     "default": {
      "$ref": "#/components/responses/error"
     },
     "401": {
      "$ref": "#/components/responses/unauthorized"
     }
    }
   },
   "delete": {
    "operationId": "deleteAgentKey",
    "summary": "Forget this account's stored key",
    "parameters": [
     {
      "name": "provider",
      "in": "query",
      "description": "Which provider's key to forget",
      "schema": {
       "type": "string",
       "enum": [
        "gemini",
        "openai"
       ]
      }
     }
    ],
    "responses": {
     "200": {
      "description": "JSON result",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/KeyStatus"
        }
       }
      }
     },
     "default": {
      "$ref": "#/components/responses/error"
     },
     "401": {
      "$ref": "#/components/responses/unauthorized"
     }
    }
   }
  },
  "/api/autorun": {
   "get": {
    "operationId": "getAutorun",
    "summary": "This account's auto-run preference for new uploads",
    "responses": {
     "200": {
      "description": "JSON result",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/AutorunSetting"
        }
       }
      }
     },
     "default": {
      "$ref": "#/components/responses/error"
     },
     "401": {
      "$ref": "#/components/responses/unauthorized"
     }
    }
   },
   "post": {
    "operationId": "setAutorun",
    "summary": "Run an agent automatically on each of this account's uploads",
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/AutorunSetting"
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "JSON result",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/AutorunSetting"
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/badRequest"
     },
     "default": {
      "$ref": "#/components/responses/error"
     },
     "401": {
      "$ref": "#/components/responses/unauthorized"
     }
    }
   }
  },
  "/api/s/{sid}/ready": {
   "get": {
    "operationId": "openSession",
    "summary": "Start opening the session and report where it got to, without waiting",
    "description": "Kicks an idle session into reopening and returns at once; poll until status is 'ready'. 409 when the binary has not been analysed yet (call analyze) or the last open failed.",
    "parameters": [
     {
      "$ref": "#/components/parameters/sid"
     }
    ],
    "responses": {
     "200": {
      "description": "JSON result",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/SessionInfo"
        }
       }
      }
     },
     "404": {
      "$ref": "#/components/responses/notFound"
     },
     "409": {
      "description": "Not analysed yet, or the last open failed",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "default": {
      "$ref": "#/components/responses/error"
     },
     "401": {
      "$ref": "#/components/responses/unauthorized"
     }
    }
   }
  },
  "/api/s/{sid}/analyze": {
   "post": {
    "operationId": "analyze",
    "summary": "Start the one-time analysis of a pending binary (editor)",
    "description": "Idempotent: a session already analysing, ready or idle reports its state instead of erroring. Minutes of work for a large binary; poll GET /api/sessions for the analyzing to ready transition.",
    "parameters": [
     {
      "$ref": "#/components/parameters/sid"
     }
    ],
    "requestBody": {
     "required": false,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/AnalyzeRequest"
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "JSON result",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/SessionInfo"
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/badRequest"
     },
     "404": {
      "$ref": "#/components/responses/notFound"
     },
     "default": {
      "$ref": "#/components/responses/error"
     },
     "401": {
      "$ref": "#/components/responses/unauthorized"
     }
    }
   }
  },
  "/api/s/{sid}/symbols": {
   "post": {
    "operationId": "stageSymbols",
    "summary": "Attach a PDB to a not-yet-analysed session (editor)",
    "parameters": [
     {
      "$ref": "#/components/parameters/sid"
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "multipart/form-data": {
       "schema": {
        "type": "object",
        "properties": {
         "file": {
          "type": "string",
          "format": "binary"
         }
        },
        "required": [
         "file"
        ]
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "JSON result",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/StageSymbolsResult"
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/badRequest"
     },
     "404": {
      "$ref": "#/components/responses/notFound"
     },
     "default": {
      "$ref": "#/components/responses/error"
     },
     "401": {
      "$ref": "#/components/responses/unauthorized"
     }
    }
   },
   "delete": {
    "operationId": "unstageSymbols",
    "summary": "Take back a staged PDB before analysis bakes it in (editor)",
    "parameters": [
     {
      "$ref": "#/components/parameters/sid"
     }
    ],
    "responses": {
     "200": {
      "description": "JSON result",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Status"
        }
       }
      }
     },
     "404": {
      "$ref": "#/components/responses/notFound"
     },
     "409": {
      "description": "Already analysed; the symbols can't be detached",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "default": {
      "$ref": "#/components/responses/error"
     },
     "401": {
      "$ref": "#/components/responses/unauthorized"
     }
    }
   },
   "get": {
    "operationId": "symbols",
    "summary": "Every symbol with address, binding and type",
    "parameters": [
     {
      "$ref": "#/components/parameters/sid"
     }
    ],
    "responses": {
     "200": {
      "description": "JSON result",
      "content": {
       "application/json": {
        "schema": {
         "type": "array",
         "items": {
          "$ref": "#/components/schemas/Symbol"
         }
        }
       }
      }
     },
     "404": {
      "$ref": "#/components/responses/notFound"
     },
     "default": {
      "$ref": "#/components/responses/error"
     },
     "401": {
      "$ref": "#/components/responses/unauthorized"
     }
    }
   }
  },
  "/api/s/{sid}/download": {
   "get": {
    "operationId": "download",
    "summary": "The original uploaded binary",
    "parameters": [
     {
      "$ref": "#/components/parameters/sid"
     }
    ],
    "responses": {
     "200": {
      "description": "The binary itself",
      "content": {
       "application/octet-stream": {
        "schema": {
         "type": "string",
         "format": "binary"
        }
       }
      }
     },
     "403": {
      "description": "Downloads are disabled on this gateway",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "404": {
      "$ref": "#/components/responses/notFound"
     },
     "default": {
      "$ref": "#/components/responses/error"
     },
     "401": {
      "$ref": "#/components/responses/unauthorized"
     }
    }
   }
  },
  "/api/s/{sid}": {
   "delete": {
    "operationId": "deleteSession",
    "summary": "Delete the session, its uploads and its project (creator)",
    "parameters": [
     {
      "$ref": "#/components/parameters/sid"
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/DeleteSessionRequest"
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "JSON result",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Status"
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/badRequest"
     },
     "404": {
      "$ref": "#/components/responses/notFound"
     },
     "409": {
      "description": "Refused: someone is connected, or it is still analysing",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "default": {
      "$ref": "#/components/responses/error"
     },
     "401": {
      "$ref": "#/components/responses/unauthorized"
     }
    }
   }
  },
  "/api/s/{sid}/share": {
   "get": {
    "operationId": "getShare",
    "summary": "The session's share token, if any (editor)",
    "parameters": [
     {
      "$ref": "#/components/parameters/sid"
     }
    ],
    "responses": {
     "200": {
      "description": "JSON result",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/ShareResponse"
        }
       }
      }
     },
     "404": {
      "$ref": "#/components/responses/notFound"
     },
     "default": {
      "$ref": "#/components/responses/error"
     },
     "401": {
      "$ref": "#/components/responses/unauthorized"
     }
    }
   },
   "post": {
    "operationId": "createShare",
    "summary": "Mint a fresh read-only share token, replacing any existing one (editor)",
    "parameters": [
     {
      "$ref": "#/components/parameters/sid"
     }
    ],
    "responses": {
     "200": {
      "description": "JSON result",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/ShareResponse"
        }
       }
      }
     },
     "404": {
      "$ref": "#/components/responses/notFound"
     },
     "default": {
      "$ref": "#/components/responses/error"
     },
     "401": {
      "$ref": "#/components/responses/unauthorized"
     }
    }
   },
   "delete": {
    "operationId": "revokeShare",
    "summary": "Revoke the share token (editor)",
    "parameters": [
     {
      "$ref": "#/components/parameters/sid"
     }
    ],
    "responses": {
     "200": {
      "description": "JSON result",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Status"
        }
       }
      }
     },
     "404": {
      "$ref": "#/components/responses/notFound"
     },
     "default": {
      "$ref": "#/components/responses/error"
     },
     "401": {
      "$ref": "#/components/responses/unauthorized"
     }
    }
   }
  },
  "/api/s/{sid}/access": {
   "get": {
    "operationId": "listAccess",
    "summary": "Who holds a grant on this session",
    "parameters": [
     {
      "$ref": "#/components/parameters/sid"
     }
    ],
    "responses": {
     "200": {
      "description": "JSON result",
      "content": {
       "application/json": {
        "schema": {
         "type": "array",
         "items": {
          "$ref": "#/components/schemas/AccessEntry"
         }
        }
       }
      }
     },
     "404": {
      "$ref": "#/components/responses/notFound"
     },
     "default": {
      "$ref": "#/components/responses/error"
     },
     "401": {
      "$ref": "#/components/responses/unauthorized"
     }
    }
   },
   "post": {
    "operationId": "grantAccess",
    "summary": "Grant an account a role on this session (editor)",
    "parameters": [
     {
      "$ref": "#/components/parameters/sid"
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/GrantAccessRequest"
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "JSON result",
      "content": {
       "application/json": {
        "schema": {
         "type": "array",
         "items": {
          "$ref": "#/components/schemas/AccessEntry"
         }
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/badRequest"
     },
     "404": {
      "$ref": "#/components/responses/notFound"
     },
     "default": {
      "$ref": "#/components/responses/error"
     },
     "401": {
      "$ref": "#/components/responses/unauthorized"
     }
    }
   }
  },
  "/api/s/{sid}/access/{uid}": {
   "delete": {
    "operationId": "revokeAccess",
    "summary": "Revoke an account's grant (editor; a creator's grant is protected)",
    "parameters": [
     {
      "$ref": "#/components/parameters/sid"
     },
     {
      "name": "uid",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      },
      "description": "Account id from the access list"
     }
    ],
    "responses": {
     "200": {
      "description": "JSON result",
      "content": {
       "application/json": {
        "schema": {
         "type": "array",
         "items": {
          "$ref": "#/components/schemas/AccessEntry"
         }
        }
       }
      }
     },
     "403": {
      "description": "Editors cannot revoke a creator",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "404": {
      "$ref": "#/components/responses/notFound"
     },
     "default": {
      "$ref": "#/components/responses/error"
     },
     "401": {
      "$ref": "#/components/responses/unauthorized"
     }
    }
   }
  },
  "/api/s/{sid}/layout": {
   "get": {
    "operationId": "getLayout",
    "summary": "The creator's saved panel layout",
    "parameters": [
     {
      "$ref": "#/components/parameters/sid"
     }
    ],
    "responses": {
     "200": {
      "description": "JSON result",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Layout"
        }
       }
      }
     },
     "404": {
      "$ref": "#/components/responses/notFound"
     },
     "default": {
      "$ref": "#/components/responses/error"
     },
     "401": {
      "$ref": "#/components/responses/unauthorized"
     }
    }
   },
   "put": {
    "operationId": "setLayout",
    "summary": "Save the dock layout (creator)",
    "parameters": [
     {
      "$ref": "#/components/parameters/sid"
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/Layout"
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "JSON result",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Status"
        }
       }
      }
     },
     "404": {
      "$ref": "#/components/responses/notFound"
     },
     "default": {
      "$ref": "#/components/responses/error"
     },
     "401": {
      "$ref": "#/components/responses/unauthorized"
     }
    }
   }
  },
  "/api/s/{sid}/agents": {
   "get": {
    "operationId": "listAgentCreds",
    "summary": "Agents currently authorized on this session",
    "parameters": [
     {
      "$ref": "#/components/parameters/sid"
     }
    ],
    "responses": {
     "200": {
      "description": "JSON result",
      "content": {
       "application/json": {
        "schema": {
         "type": "array",
         "items": {
          "$ref": "#/components/schemas/AgentCred"
         }
        }
       }
      }
     },
     "404": {
      "$ref": "#/components/responses/notFound"
     },
     "default": {
      "$ref": "#/components/responses/error"
     },
     "401": {
      "$ref": "#/components/responses/unauthorized"
     }
    }
   },
   "post": {
    "operationId": "inviteAgent",
    "summary": "Invite an agent to work this session and start its run",
    "description": "The agent acts at the lower of its configured ceiling and your own role here; it can never outrank you.",
    "parameters": [
     {
      "$ref": "#/components/parameters/sid"
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/InviteAgentRequest"
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "JSON result",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/AgentCred"
        }
       }
      }
     },
     "400": {
      "description": "No funding key for the agent's provider",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "404": {
      "$ref": "#/components/responses/notFound"
     },
     "503": {
      "description": "All agent run slots are busy",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "default": {
      "$ref": "#/components/responses/error"
     },
     "401": {
      "$ref": "#/components/responses/unauthorized"
     }
    }
   }
  },
  "/api/s/{sid}/agents/{id}": {
   "delete": {
    "operationId": "revokeAgent",
    "summary": "Revoke an agent's authorization",
    "parameters": [
     {
      "$ref": "#/components/parameters/sid"
     },
     {
      "name": "id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      },
      "description": "Credential id from the agents list"
     }
    ],
    "responses": {
     "200": {
      "description": "JSON result",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Status"
        }
       }
      }
     },
     "404": {
      "$ref": "#/components/responses/notFound"
     },
     "default": {
      "$ref": "#/components/responses/error"
     },
     "401": {
      "$ref": "#/components/responses/unauthorized"
     }
    }
   }
  },
  "/api/s/{sid}/chat": {
   "get": {
    "operationId": "getChat",
    "summary": "The session's shared chat, humans and agents alike",
    "parameters": [
     {
      "$ref": "#/components/parameters/sid"
     }
    ],
    "responses": {
     "200": {
      "description": "JSON result",
      "content": {
       "application/json": {
        "schema": {
         "type": "array",
         "items": {
          "$ref": "#/components/schemas/ChatMessage"
         }
        }
       }
      }
     },
     "404": {
      "$ref": "#/components/responses/notFound"
     },
     "default": {
      "$ref": "#/components/responses/error"
     },
     "401": {
      "$ref": "#/components/responses/unauthorized"
     }
    }
   },
   "post": {
    "operationId": "sendChat",
    "summary": "Send a message to an agent; its reply lands in the chat",
    "description": "Starts an interactive run under your own authority; the agent can read the session, and write to it when your role allows. Watch the chat (or the WebSocket) for the reply.",
    "parameters": [
     {
      "$ref": "#/components/parameters/sid"
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/SendChatRequest"
       }
      }
     }
    },
    "responses": {
     "202": {
      "description": "The run was started; the reply arrives in the chat",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/StartedRun"
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/badRequest"
     },
     "404": {
      "$ref": "#/components/responses/notFound"
     },
     "503": {
      "description": "All agent run slots are busy",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "default": {
      "$ref": "#/components/responses/error"
     },
     "401": {
      "$ref": "#/components/responses/unauthorized"
     }
    }
   },
   "delete": {
    "operationId": "clearChat",
    "summary": "Wipe the shared chat history (editor)",
    "parameters": [
     {
      "$ref": "#/components/parameters/sid"
     }
    ],
    "responses": {
     "200": {
      "description": "JSON result",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Status"
        }
       }
      }
     },
     "404": {
      "$ref": "#/components/responses/notFound"
     },
     "default": {
      "$ref": "#/components/responses/error"
     },
     "401": {
      "$ref": "#/components/responses/unauthorized"
     }
    }
   }
  },
  "/api/s/{sid}/runs": {
   "get": {
    "operationId": "listRuns",
    "summary": "Agent runs in flight on this session",
    "parameters": [
     {
      "$ref": "#/components/parameters/sid"
     }
    ],
    "responses": {
     "200": {
      "description": "JSON result",
      "content": {
       "application/json": {
        "schema": {
         "type": "array",
         "items": {
          "$ref": "#/components/schemas/ActiveRun"
         }
        }
       }
      }
     },
     "404": {
      "$ref": "#/components/responses/notFound"
     },
     "default": {
      "$ref": "#/components/responses/error"
     },
     "401": {
      "$ref": "#/components/responses/unauthorized"
     }
    }
   }
  },
  "/api/s/{sid}/runs/{id}": {
   "delete": {
    "operationId": "stopRun",
    "summary": "Stop a run: your own, or anyone's as editor",
    "parameters": [
     {
      "$ref": "#/components/parameters/sid"
     },
     {
      "name": "id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      },
      "description": "Run id from the runs list"
     }
    ],
    "responses": {
     "200": {
      "description": "JSON result",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Status"
        }
       }
      }
     },
     "403": {
      "description": "Not your run, and you are not an editor",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "404": {
      "$ref": "#/components/responses/notFound"
     },
     "default": {
      "$ref": "#/components/responses/error"
     },
     "401": {
      "$ref": "#/components/responses/unauthorized"
     }
    }
   }
  },
  "/api/s/{sid}/agent-peers": {
   "get": {
    "operationId": "agentPeers",
    "summary": "Where each agent that has run here was last seen",
    "parameters": [
     {
      "$ref": "#/components/parameters/sid"
     }
    ],
    "responses": {
     "200": {
      "description": "JSON result",
      "content": {
       "application/json": {
        "schema": {
         "type": "array",
         "items": {
          "$ref": "#/components/schemas/AgentPeer"
         }
        }
       }
      }
     },
     "404": {
      "$ref": "#/components/responses/notFound"
     },
     "default": {
      "$ref": "#/components/responses/error"
     },
     "401": {
      "$ref": "#/components/responses/unauthorized"
     }
    }
   }
  },
  "/api/s/{sid}/info": {
   "get": {
    "operationId": "info",
    "summary": "File format, architecture, entry point and hardening flags",
    "parameters": [
     {
      "$ref": "#/components/parameters/sid"
     }
    ],
    "responses": {
     "200": {
      "description": "JSON result",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Info"
        }
       }
      }
     },
     "404": {
      "$ref": "#/components/responses/notFound"
     },
     "default": {
      "$ref": "#/components/responses/error"
     },
     "401": {
      "$ref": "#/components/responses/unauthorized"
     }
    }
   }
  },
  "/api/s/{sid}/overview": {
   "get": {
    "operationId": "overview",
    "summary": "Summary counts: functions, strings, symbols, imports, xrefs, calls",
    "parameters": [
     {
      "$ref": "#/components/parameters/sid"
     }
    ],
    "responses": {
     "200": {
      "description": "JSON result",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Overview"
        }
       }
      }
     },
     "404": {
      "$ref": "#/components/responses/notFound"
     },
     "default": {
      "$ref": "#/components/responses/error"
     },
     "401": {
      "$ref": "#/components/responses/unauthorized"
     }
    }
   }
  },
  "/api/s/{sid}/triage": {
   "get": {
    "operationId": "triage",
    "summary": "Functions ranked by how likely they are to repay reading first, with reasons",
    "parameters": [
     {
      "$ref": "#/components/parameters/sid"
     },
     {
      "name": "limit",
      "in": "query",
      "description": "How many ranked functions to return (default 100)",
      "schema": {
       "type": "integer",
       "minimum": 1,
       "maximum": 500,
       "default": 100
      }
     }
    ],
    "responses": {
     "200": {
      "description": "JSON result",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Triage"
        }
       }
      }
     },
     "404": {
      "$ref": "#/components/responses/notFound"
     },
     "default": {
      "$ref": "#/components/responses/error"
     },
     "401": {
      "$ref": "#/components/responses/unauthorized"
     }
    }
   }
  },
  "/api/s/{sid}/hashes": {
   "get": {
    "operationId": "hashes",
    "summary": "File hashes and whole-file entropy",
    "parameters": [
     {
      "$ref": "#/components/parameters/sid"
     }
    ],
    "responses": {
     "200": {
      "description": "JSON result",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Hashes"
        }
       }
      }
     },
     "404": {
      "$ref": "#/components/responses/notFound"
     },
     "default": {
      "$ref": "#/components/responses/error"
     },
     "401": {
      "$ref": "#/components/responses/unauthorized"
     }
    }
   }
  },
  "/api/s/{sid}/entropy": {
   "get": {
    "operationId": "entropy",
    "summary": "Shannon entropy per bucket across initialised memory, labelled by section",
    "description": "High and flat reads as compressed or encrypted; low and spiky as text or padding. Buckets never straddle sections, so the answer can hold a few more samples than asked for.",
    "parameters": [
     {
      "$ref": "#/components/parameters/sid"
     },
     {
      "name": "buckets",
      "in": "query",
      "description": "Target resolution (default 256)",
      "schema": {
       "type": "integer",
       "minimum": 16,
       "maximum": 2048,
       "default": 256
      }
     }
    ],
    "responses": {
     "200": {
      "description": "JSON result",
      "content": {
       "application/json": {
        "schema": {
         "type": "array",
         "items": {
          "$ref": "#/components/schemas/EntropyBucket"
         }
        }
       }
      }
     },
     "404": {
      "$ref": "#/components/responses/notFound"
     },
     "default": {
      "$ref": "#/components/responses/error"
     },
     "401": {
      "$ref": "#/components/responses/unauthorized"
     }
    }
   }
  },
  "/api/s/{sid}/sections": {
   "get": {
    "operationId": "sections",
    "summary": "Sections with addresses, sizes and permissions",
    "parameters": [
     {
      "$ref": "#/components/parameters/sid"
     }
    ],
    "responses": {
     "200": {
      "description": "JSON result",
      "content": {
       "application/json": {
        "schema": {
         "type": "array",
         "items": {
          "$ref": "#/components/schemas/Section"
         }
        }
       }
      }
     },
     "404": {
      "$ref": "#/components/responses/notFound"
     },
     "default": {
      "$ref": "#/components/responses/error"
     },
     "401": {
      "$ref": "#/components/responses/unauthorized"
     }
    }
   }
  },
  "/api/s/{sid}/certificates": {
   "get": {
    "operationId": "certificates",
    "summary": "Code-signing certificates where the format carries them",
    "parameters": [
     {
      "$ref": "#/components/parameters/sid"
     }
    ],
    "responses": {
     "200": {
      "description": "JSON result",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "additionalProperties": true
        }
       }
      }
     },
     "404": {
      "$ref": "#/components/responses/notFound"
     },
     "default": {
      "$ref": "#/components/responses/error"
     },
     "401": {
      "$ref": "#/components/responses/unauthorized"
     }
    }
   }
  },
  "/api/s/{sid}/versioninfo": {
   "get": {
    "operationId": "versioninfo",
    "summary": "Imported library version requirements",
    "parameters": [
     {
      "$ref": "#/components/parameters/sid"
     }
    ],
    "responses": {
     "200": {
      "description": "JSON result",
      "content": {
       "application/json": {
        "schema": {
         "description": "Format-specific; a list of libraries with their version tags on ELF",
         "type": [
          "array",
          "object"
         ],
         "items": {
          "type": "object",
          "additionalProperties": true
         },
         "additionalProperties": true
        }
       }
      }
     },
     "404": {
      "$ref": "#/components/responses/notFound"
     },
     "default": {
      "$ref": "#/components/responses/error"
     },
     "401": {
      "$ref": "#/components/responses/unauthorized"
     }
    }
   }
  },
  "/api/s/{sid}/libraries": {
   "get": {
    "operationId": "libraries",
    "summary": "Shared libraries the binary links against",
    "parameters": [
     {
      "$ref": "#/components/parameters/sid"
     }
    ],
    "responses": {
     "200": {
      "description": "JSON result",
      "content": {
       "application/json": {
        "schema": {
         "type": "array",
         "items": {
          "type": "string"
         }
        }
       }
      }
     },
     "404": {
      "$ref": "#/components/responses/notFound"
     },
     "default": {
      "$ref": "#/components/responses/error"
     },
     "401": {
      "$ref": "#/components/responses/unauthorized"
     }
    }
   }
  },
  "/api/s/{sid}/functions": {
   "get": {
    "operationId": "functions",
    "summary": "Every function with name, address, size and complexity",
    "parameters": [
     {
      "$ref": "#/components/parameters/sid"
     }
    ],
    "responses": {
     "200": {
      "description": "JSON result",
      "content": {
       "application/json": {
        "schema": {
         "type": "array",
         "items": {
          "$ref": "#/components/schemas/Function"
         }
        }
       }
      }
     },
     "404": {
      "$ref": "#/components/responses/notFound"
     },
     "default": {
      "$ref": "#/components/responses/error"
     },
     "401": {
      "$ref": "#/components/responses/unauthorized"
     }
    }
   }
  },
  "/api/s/{sid}/disasm": {
   "get": {
    "operationId": "disasm",
    "summary": "Disassembly of the function at an address",
    "parameters": [
     {
      "$ref": "#/components/parameters/sid"
     },
     {
      "$ref": "#/components/parameters/addr"
     }
    ],
    "responses": {
     "200": {
      "description": "JSON result",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Disasm"
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/badRequest"
     },
     "404": {
      "$ref": "#/components/responses/notFound"
     },
     "default": {
      "$ref": "#/components/responses/error"
     },
     "401": {
      "$ref": "#/components/responses/unauthorized"
     }
    }
   }
  },
  "/api/s/{sid}/decompile": {
   "get": {
    "operationId": "decompile",
    "summary": "Decompiled C for the function at an address",
    "parameters": [
     {
      "$ref": "#/components/parameters/sid"
     },
     {
      "$ref": "#/components/parameters/addr"
     }
    ],
    "responses": {
     "200": {
      "description": "JSON result",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Decompile"
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/badRequest"
     },
     "404": {
      "$ref": "#/components/responses/notFound"
     },
     "default": {
      "$ref": "#/components/responses/error"
     },
     "401": {
      "$ref": "#/components/responses/unauthorized"
     }
    }
   }
  },
  "/api/s/{sid}/vars": {
   "get": {
    "operationId": "vars",
    "summary": "The function's variables and arguments with types and storage",
    "parameters": [
     {
      "$ref": "#/components/parameters/sid"
     },
     {
      "$ref": "#/components/parameters/addr"
     }
    ],
    "responses": {
     "200": {
      "description": "JSON result",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Vars"
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/badRequest"
     },
     "404": {
      "$ref": "#/components/responses/notFound"
     },
     "default": {
      "$ref": "#/components/responses/error"
     },
     "401": {
      "$ref": "#/components/responses/unauthorized"
     }
    }
   }
  },
  "/api/s/{sid}/graph": {
   "get": {
    "operationId": "graph",
    "summary": "Basic-block control-flow graph of the function at an address",
    "parameters": [
     {
      "$ref": "#/components/parameters/sid"
     },
     {
      "$ref": "#/components/parameters/addr"
     }
    ],
    "responses": {
     "200": {
      "description": "JSON result",
      "content": {
       "application/json": {
        "schema": {
         "type": "array",
         "items": {
          "$ref": "#/components/schemas/Graph"
         }
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/badRequest"
     },
     "404": {
      "$ref": "#/components/responses/notFound"
     },
     "default": {
      "$ref": "#/components/responses/error"
     },
     "401": {
      "$ref": "#/components/responses/unauthorized"
     }
    }
   }
  },
  "/api/s/{sid}/xrefs": {
   "get": {
    "operationId": "xrefs",
    "summary": "Cross-references to an address: who reads, writes, calls or jumps here",
    "parameters": [
     {
      "$ref": "#/components/parameters/sid"
     },
     {
      "$ref": "#/components/parameters/addr"
     }
    ],
    "responses": {
     "200": {
      "description": "JSON result",
      "content": {
       "application/json": {
        "schema": {
         "type": "array",
         "items": {
          "$ref": "#/components/schemas/Xref"
         }
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/badRequest"
     },
     "404": {
      "$ref": "#/components/responses/notFound"
     },
     "default": {
      "$ref": "#/components/responses/error"
     },
     "401": {
      "$ref": "#/components/responses/unauthorized"
     }
    }
   }
  },
  "/api/s/{sid}/calltree": {
   "get": {
    "operationId": "calltree",
    "summary": "Callers and callees of the function at an address",
    "parameters": [
     {
      "$ref": "#/components/parameters/sid"
     },
     {
      "$ref": "#/components/parameters/addr"
     }
    ],
    "responses": {
     "200": {
      "description": "JSON result",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/CallTree"
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/badRequest"
     },
     "404": {
      "$ref": "#/components/responses/notFound"
     },
     "default": {
      "$ref": "#/components/responses/error"
     },
     "401": {
      "$ref": "#/components/responses/unauthorized"
     }
    }
   }
  },
  "/api/s/{sid}/callgraph": {
   "get": {
    "operationId": "callgraph",
    "summary": "The whole-program call graph: every function with its callees by name",
    "parameters": [
     {
      "$ref": "#/components/parameters/sid"
     }
    ],
    "responses": {
     "200": {
      "description": "JSON result",
      "content": {
       "application/json": {
        "schema": {
         "type": "array",
         "items": {
          "$ref": "#/components/schemas/CallGraphNode"
         }
        }
       }
      }
     },
     "404": {
      "$ref": "#/components/responses/notFound"
     },
     "default": {
      "$ref": "#/components/responses/error"
     }
    }
   }
  },
  "/api/s/{sid}/instruction": {
   "get": {
    "operationId": "instruction",
    "summary": "One instruction decoded: operands, control flow, p-code",
    "parameters": [
     {
      "$ref": "#/components/parameters/sid"
     },
     {
      "$ref": "#/components/parameters/addr"
     }
    ],
    "responses": {
     "200": {
      "description": "JSON result",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Instruction"
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/badRequest"
     },
     "404": {
      "$ref": "#/components/responses/notFound"
     },
     "default": {
      "$ref": "#/components/responses/error"
     },
     "401": {
      "$ref": "#/components/responses/unauthorized"
     }
    }
   }
  },
  "/api/s/{sid}/resolveaddr": {
   "get": {
    "operationId": "resolveaddr",
    "summary": "The function containing an address",
    "parameters": [
     {
      "$ref": "#/components/parameters/sid"
     },
     {
      "$ref": "#/components/parameters/addr"
     }
    ],
    "responses": {
     "200": {
      "description": "JSON result",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/ResolveAddr"
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/badRequest"
     },
     "404": {
      "$ref": "#/components/responses/notFound"
     },
     "default": {
      "$ref": "#/components/responses/error"
     },
     "401": {
      "$ref": "#/components/responses/unauthorized"
     }
    }
   }
  },
  "/api/s/{sid}/signature": {
   "get": {
    "operationId": "signature",
    "summary": "The function's C prototype and calling convention",
    "parameters": [
     {
      "$ref": "#/components/parameters/sid"
     },
     {
      "$ref": "#/components/parameters/addr"
     }
    ],
    "responses": {
     "200": {
      "description": "JSON result",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Signature"
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/badRequest"
     },
     "404": {
      "$ref": "#/components/responses/notFound"
     },
     "default": {
      "$ref": "#/components/responses/error"
     },
     "401": {
      "$ref": "#/components/responses/unauthorized"
     }
    }
   },
   "post": {
    "operationId": "setSignature",
    "summary": "Apply an edited C prototype to a function (editor)",
    "parameters": [
     {
      "$ref": "#/components/parameters/sid"
     }
    ],
    "responses": {
     "200": {
      "description": "JSON result",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "additionalProperties": true,
         "description": "The read-back state after the change; a 200 means the model really holds it"
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/badRequest"
     },
     "404": {
      "$ref": "#/components/responses/notFound"
     },
     "default": {
      "$ref": "#/components/responses/error"
     },
     "401": {
      "$ref": "#/components/responses/unauthorized"
     }
    },
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/SignatureRequest"
       }
      }
     }
    }
   }
  },
  "/api/s/{sid}/strings": {
   "get": {
    "operationId": "strings",
    "summary": "Strings with addresses and sections",
    "parameters": [
     {
      "$ref": "#/components/parameters/sid"
     },
     {
      "name": "scope",
      "in": "query",
      "description": "Pass 'all' to additionally sweep undefined memory for string-shaped runs; noisier, but finds strings compilers park in .text",
      "schema": {
       "type": "string",
       "enum": [
        "all"
       ]
      }
     }
    ],
    "responses": {
     "200": {
      "description": "JSON result",
      "content": {
       "application/json": {
        "schema": {
         "type": "array",
         "items": {
          "$ref": "#/components/schemas/StringItem"
         }
        }
       }
      }
     },
     "404": {
      "$ref": "#/components/responses/notFound"
     },
     "default": {
      "$ref": "#/components/responses/error"
     },
     "401": {
      "$ref": "#/components/responses/unauthorized"
     }
    }
   }
  },
  "/api/s/{sid}/hex": {
   "get": {
    "operationId": "hex",
    "summary": "Raw bytes at an address, as an array of byte values",
    "parameters": [
     {
      "$ref": "#/components/parameters/sid"
     },
     {
      "$ref": "#/components/parameters/addr"
     },
     {
      "name": "len",
      "in": "query",
      "description": "How many bytes (default 256)",
      "schema": {
       "type": "integer",
       "minimum": 1,
       "maximum": 4096,
       "default": 256
      }
     }
    ],
    "responses": {
     "200": {
      "description": "JSON result",
      "content": {
       "application/json": {
        "schema": {
         "type": "array",
         "items": {
          "type": "integer",
          "minimum": 0,
          "maximum": 255
         }
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/badRequest"
     },
     "404": {
      "$ref": "#/components/responses/notFound"
     },
     "default": {
      "$ref": "#/components/responses/error"
     },
     "401": {
      "$ref": "#/components/responses/unauthorized"
     }
    }
   }
  },
  "/api/s/{sid}/imports": {
   "get": {
    "operationId": "imports",
    "summary": "Imported functions with their thunk addresses",
    "parameters": [
     {
      "$ref": "#/components/parameters/sid"
     }
    ],
    "responses": {
     "200": {
      "description": "JSON result",
      "content": {
       "application/json": {
        "schema": {
         "type": "array",
         "items": {
          "$ref": "#/components/schemas/Import"
         }
        }
       }
      }
     },
     "404": {
      "$ref": "#/components/responses/notFound"
     },
     "default": {
      "$ref": "#/components/responses/error"
     },
     "401": {
      "$ref": "#/components/responses/unauthorized"
     }
    }
   }
  },
  "/api/s/{sid}/exports": {
   "get": {
    "operationId": "exports",
    "summary": "Exported symbols",
    "parameters": [
     {
      "$ref": "#/components/parameters/sid"
     }
    ],
    "responses": {
     "200": {
      "description": "JSON result",
      "content": {
       "application/json": {
        "schema": {
         "type": "array",
         "items": {
          "$ref": "#/components/schemas/Symbol"
         }
        }
       }
      }
     },
     "404": {
      "$ref": "#/components/responses/notFound"
     },
     "default": {
      "$ref": "#/components/responses/error"
     },
     "401": {
      "$ref": "#/components/responses/unauthorized"
     }
    }
   }
  },
  "/api/s/{sid}/types": {
   "get": {
    "operationId": "types",
    "summary": "Data types known to the program",
    "parameters": [
     {
      "$ref": "#/components/parameters/sid"
     }
    ],
    "responses": {
     "200": {
      "description": "JSON result",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Types"
        }
       }
      }
     },
     "404": {
      "$ref": "#/components/responses/notFound"
     },
     "default": {
      "$ref": "#/components/responses/error"
     },
     "401": {
      "$ref": "#/components/responses/unauthorized"
     }
    }
   }
  },
  "/api/s/{sid}/type": {
   "get": {
    "operationId": "type",
    "summary": "One type's definition: members for a composite, values for an enum",
    "parameters": [
     {
      "$ref": "#/components/parameters/sid"
     },
     {
      "name": "name",
      "in": "query",
      "required": true,
      "description": "Type name or category path, e.g. \"sockaddr_in\"",
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "description": "JSON result",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/TypeDetail"
        }
       }
      }
     },
     "404": {
      "$ref": "#/components/responses/notFound"
     },
     "default": {
      "$ref": "#/components/responses/error"
     },
     "401": {
      "$ref": "#/components/responses/unauthorized"
     }
    }
   }
  },
  "/api/s/{sid}/type/uses": {
   "get": {
    "operationId": "typeUses",
    "summary": "How many data, variables and types would revert to undefined if this type were deleted",
    "parameters": [
     {
      "$ref": "#/components/parameters/sid"
     },
     {
      "name": "name",
      "in": "query",
      "required": true,
      "description": "Type name or category path, e.g. \"sockaddr_in\"",
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "description": "JSON result",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/TypeUses"
        }
       }
      }
     },
     "404": {
      "$ref": "#/components/responses/notFound"
     },
     "default": {
      "$ref": "#/components/responses/error"
     },
     "401": {
      "$ref": "#/components/responses/unauthorized"
     }
    }
   }
  },
  "/api/s/{sid}/parsetypes": {
   "post": {
    "operationId": "parseTypes",
    "summary": "Define types from C declarations: structs, unions, enums, typedefs (editor)",
    "parameters": [
     {
      "$ref": "#/components/parameters/sid"
     }
    ],
    "responses": {
     "200": {
      "description": "JSON result",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "additionalProperties": true,
         "description": "The read-back state after the change; a 200 means the model really holds it"
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/badRequest"
     },
     "404": {
      "$ref": "#/components/responses/notFound"
     },
     "default": {
      "$ref": "#/components/responses/error"
     },
     "401": {
      "$ref": "#/components/responses/unauthorized"
     },
     "409": {
      "description": "A type of that name already exists; pass replace to overwrite",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    },
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/ParseTypesRequest"
       }
      }
     }
    }
   }
  },
  "/api/s/{sid}/deletetype": {
   "post": {
    "operationId": "deleteType",
    "summary": "Remove a type; every use of it reverts to undefined (editor)",
    "parameters": [
     {
      "$ref": "#/components/parameters/sid"
     }
    ],
    "responses": {
     "200": {
      "description": "JSON result",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "additionalProperties": true,
         "description": "The read-back state after the change; a 200 means the model really holds it"
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/badRequest"
     },
     "404": {
      "$ref": "#/components/responses/notFound"
     },
     "default": {
      "$ref": "#/components/responses/error"
     },
     "401": {
      "$ref": "#/components/responses/unauthorized"
     }
    },
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/DeleteTypeRequest"
       }
      }
     }
    }
   }
  },
  "/api/s/{sid}/search": {
   "get": {
    "operationId": "search",
    "summary": "Search strings, symbols and bytes across the program",
    "parameters": [
     {
      "$ref": "#/components/parameters/sid"
     },
     {
      "name": "query",
      "in": "query",
      "description": "What to search for. Literal text by default; hex bytes like 'deadbeef' with mode=hex; a Java regular expression with mode=regex",
      "schema": {
       "type": "string"
      },
      "required": true
     },
     {
      "name": "mode",
      "in": "query",
      "description": "How to interpret the query. Anything else falls back to a literal text search",
      "schema": {
       "type": "string",
       "enum": [
        "hex",
        "regex"
       ]
      }
     }
    ],
    "responses": {
     "200": {
      "description": "JSON result",
      "content": {
       "application/json": {
        "schema": {
         "type": "array",
         "items": {
          "$ref": "#/components/schemas/SearchHit"
         }
        }
       }
      }
     },
     "404": {
      "$ref": "#/components/responses/notFound"
     },
     "default": {
      "$ref": "#/components/responses/error"
     },
     "401": {
      "$ref": "#/components/responses/unauthorized"
     }
    }
   }
  },
  "/api/s/{sid}/comments": {
   "get": {
    "operationId": "comments",
    "summary": "Analyst comments with author and address",
    "parameters": [
     {
      "$ref": "#/components/parameters/sid"
     }
    ],
    "responses": {
     "200": {
      "description": "JSON result",
      "content": {
       "application/json": {
        "schema": {
         "type": "array",
         "items": {
          "$ref": "#/components/schemas/Comment"
         }
        }
       }
      }
     },
     "404": {
      "$ref": "#/components/responses/notFound"
     },
     "default": {
      "$ref": "#/components/responses/error"
     },
     "401": {
      "$ref": "#/components/responses/unauthorized"
     }
    }
   }
  },
  "/api/s/{sid}/labels": {
   "get": {
    "operationId": "labels",
    "summary": "User and analysis labels at an address",
    "parameters": [
     {
      "$ref": "#/components/parameters/sid"
     },
     {
      "$ref": "#/components/parameters/addr"
     }
    ],
    "responses": {
     "200": {
      "description": "JSON result",
      "content": {
       "application/json": {
        "schema": {
         "type": "array",
         "items": {
          "$ref": "#/components/schemas/Label"
         }
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/badRequest"
     },
     "404": {
      "$ref": "#/components/responses/notFound"
     },
     "default": {
      "$ref": "#/components/responses/error"
     },
     "401": {
      "$ref": "#/components/responses/unauthorized"
     }
    }
   }
  },
  "/api/s/{sid}/bookmarks": {
   "get": {
    "operationId": "bookmarks",
    "summary": "Bookmarked addresses with notes",
    "parameters": [
     {
      "$ref": "#/components/parameters/sid"
     }
    ],
    "responses": {
     "200": {
      "description": "JSON result",
      "content": {
       "application/json": {
        "schema": {
         "type": "array",
         "items": {
          "$ref": "#/components/schemas/Bookmark"
         }
        }
       }
      }
     },
     "404": {
      "$ref": "#/components/responses/notFound"
     },
     "default": {
      "$ref": "#/components/responses/error"
     },
     "401": {
      "$ref": "#/components/responses/unauthorized"
     }
    }
   }
  },
  "/api/s/{sid}/notes": {
   "get": {
    "operationId": "notes",
    "summary": "The analysts' shared write-up of this binary",
    "description": "Markdown, maintained by the people and agents working the session. Usually the best first read: it says what the binary is and where the interesting parts are.",
    "parameters": [
     {
      "$ref": "#/components/parameters/sid"
     }
    ],
    "responses": {
     "200": {
      "description": "JSON result",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Notes"
        }
       }
      }
     },
     "404": {
      "$ref": "#/components/responses/notFound"
     },
     "default": {
      "$ref": "#/components/responses/error"
     },
     "401": {
      "$ref": "#/components/responses/unauthorized"
     }
    }
   },
   "post": {
    "operationId": "setNotes",
    "summary": "Replace the shared session notes (editor)",
    "parameters": [
     {
      "$ref": "#/components/parameters/sid"
     }
    ],
    "responses": {
     "200": {
      "description": "JSON result",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "additionalProperties": true,
         "description": "The read-back state after the change; a 200 means the model really holds it"
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/badRequest"
     },
     "404": {
      "$ref": "#/components/responses/notFound"
     },
     "default": {
      "$ref": "#/components/responses/error"
     },
     "401": {
      "$ref": "#/components/responses/unauthorized"
     }
    },
    "description": "Read first and merge: this replaces the whole text, and others may have written since.",
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/SetNotesRequest"
       }
      }
     }
    }
   }
  },
  "/api/s/{sid}/findings": {
   "get": {
    "operationId": "listFindings",
    "summary": "The structured findings background agent runs recorded, oldest first, superseded ones marked",
    "parameters": [
     {
      "name": "sid",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      },
      "description": "The session id."
     }
    ],
    "responses": {
     "200": {
      "description": "JSON result",
      "content": {
       "application/json": {
        "schema": {
         "type": "array",
         "items": {
          "$ref": "#/components/schemas/Finding"
         }
        }
       }
      }
     },
     "default": {
      "$ref": "#/components/responses/error"
     }
    }
   }
  },
  "/api/s/{sid}/undostate": {
   "get": {
    "operationId": "undostate",
    "summary": "What undo would revert next, and the program's history stack",
    "responses": {
     "200": {
      "description": "JSON result",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "additionalProperties": false,
         "properties": {
          "canUndo": {
           "type": "boolean"
          },
          "canRedo": {
           "type": "boolean"
          },
          "undoName": {
           "type": "string",
           "description": "The next change undo would revert, named with who made it"
          },
          "redoName": {
           "type": "string"
          },
          "undoStack": {
           "type": "array",
           "items": {
            "type": "string"
           },
           "description": "Newest first"
          },
          "redoStack": {
           "type": "array",
           "items": {
            "type": "string"
           }
          }
         }
        }
       }
      }
     },
     "default": {
      "$ref": "#/components/responses/error"
     }
    },
    "parameters": [
     {
      "$ref": "#/components/parameters/sid"
     }
    ]
   }
  },
  "/api/s/{sid}/undo": {
   "post": {
    "operationId": "undo",
    "summary": "Revert the program's most recent change",
    "responses": {
     "200": {
      "description": "Applied",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "additionalProperties": false,
         "properties": {
          "reverted": {
           "type": "string",
           "description": "The transaction that was undone or redone"
          },
          "by": {
           "type": "string"
          }
         }
        }
       }
      }
     },
     "409": {
      "description": "Nothing to undo or redo",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "default": {
      "$ref": "#/components/responses/error"
     }
    },
    "parameters": [
     {
      "$ref": "#/components/parameters/sid"
     }
    ]
   }
  },
  "/api/s/{sid}/redo": {
   "post": {
    "operationId": "redo",
    "summary": "Reapply the change undo last reverted",
    "responses": {
     "200": {
      "description": "Applied",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "additionalProperties": false,
         "properties": {
          "reverted": {
           "type": "string",
           "description": "The transaction that was undone or redone"
          },
          "by": {
           "type": "string"
          }
         }
        }
       }
      }
     },
     "409": {
      "description": "Nothing to undo or redo",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "default": {
      "$ref": "#/components/responses/error"
     }
    },
    "parameters": [
     {
      "$ref": "#/components/parameters/sid"
     }
    ]
   }
  },
  "/api/s/{sid}/activity": {
   "get": {
    "operationId": "activity",
    "summary": "Recent session activity: renames, comments, notes edits",
    "parameters": [
     {
      "$ref": "#/components/parameters/sid"
     }
    ],
    "responses": {
     "200": {
      "description": "JSON result",
      "content": {
       "application/json": {
        "schema": {
         "type": "array",
         "items": {
          "$ref": "#/components/schemas/ActivityEvent"
         }
        }
       }
      }
     },
     "404": {
      "$ref": "#/components/responses/notFound"
     },
     "default": {
      "$ref": "#/components/responses/error"
     },
     "401": {
      "$ref": "#/components/responses/unauthorized"
     }
    }
   }
  },
  "/api/s/{sid}/rename": {
   "post": {
    "operationId": "rename",
    "summary": "Rename the function at an address (editor)",
    "parameters": [
     {
      "$ref": "#/components/parameters/sid"
     }
    ],
    "responses": {
     "200": {
      "description": "JSON result",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "additionalProperties": true,
         "description": "The read-back state after the change; a 200 means the model really holds it"
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/badRequest"
     },
     "404": {
      "$ref": "#/components/responses/notFound"
     },
     "default": {
      "$ref": "#/components/responses/error"
     },
     "401": {
      "$ref": "#/components/responses/unauthorized"
     }
    },
    "description": "The worker applies it in a transaction and reads it back before answering, so a 200 means the model really holds the new name.",
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/RenameRequest"
       }
      }
     }
    }
   }
  },
  "/api/s/{sid}/renamevar": {
   "post": {
    "operationId": "renameVar",
    "summary": "Rename a local or parameter (editor)",
    "parameters": [
     {
      "$ref": "#/components/parameters/sid"
     }
    ],
    "responses": {
     "200": {
      "description": "JSON result",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "additionalProperties": true,
         "description": "The read-back state after the change; a 200 means the model really holds it"
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/badRequest"
     },
     "404": {
      "$ref": "#/components/responses/notFound"
     },
     "default": {
      "$ref": "#/components/responses/error"
     },
     "401": {
      "$ref": "#/components/responses/unauthorized"
     }
    },
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/RenameVarRequest"
       }
      }
     }
    }
   }
  },
  "/api/s/{sid}/retypevar": {
   "post": {
    "operationId": "retypeVar",
    "summary": "Change a variable's type (editor)",
    "parameters": [
     {
      "$ref": "#/components/parameters/sid"
     }
    ],
    "responses": {
     "200": {
      "description": "JSON result",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "additionalProperties": true,
         "description": "The read-back state after the change; a 200 means the model really holds it"
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/badRequest"
     },
     "404": {
      "$ref": "#/components/responses/notFound"
     },
     "default": {
      "$ref": "#/components/responses/error"
     },
     "401": {
      "$ref": "#/components/responses/unauthorized"
     }
    },
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/RetypeVarRequest"
       }
      }
     }
    }
   }
  },
  "/api/s/{sid}/comment": {
   "post": {
    "operationId": "setComment",
    "summary": "Set the comment at an address (editor)",
    "parameters": [
     {
      "$ref": "#/components/parameters/sid"
     }
    ],
    "responses": {
     "200": {
      "description": "JSON result",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "additionalProperties": true,
         "description": "The read-back state after the change; a 200 means the model really holds it"
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/badRequest"
     },
     "404": {
      "$ref": "#/components/responses/notFound"
     },
     "default": {
      "$ref": "#/components/responses/error"
     },
     "401": {
      "$ref": "#/components/responses/unauthorized"
     }
    },
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/CommentRequest"
       }
      }
     }
    }
   },
   "delete": {
    "operationId": "deleteComment",
    "summary": "Delete the comment at an address (editor)",
    "parameters": [
     {
      "$ref": "#/components/parameters/sid"
     },
     {
      "$ref": "#/components/parameters/addr"
     }
    ],
    "responses": {
     "200": {
      "description": "JSON result",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "additionalProperties": true,
         "description": "The read-back state after the change; a 200 means the model really holds it"
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/badRequest"
     },
     "404": {
      "$ref": "#/components/responses/notFound"
     },
     "default": {
      "$ref": "#/components/responses/error"
     },
     "401": {
      "$ref": "#/components/responses/unauthorized"
     }
    }
   }
  },
  "/api/s/{sid}/label": {
   "post": {
    "operationId": "setLabel",
    "summary": "Name an address, or clear it with an empty name (editor)",
    "parameters": [
     {
      "$ref": "#/components/parameters/sid"
     }
    ],
    "responses": {
     "200": {
      "description": "JSON result",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "additionalProperties": true,
         "description": "The read-back state after the change; a 200 means the model really holds it"
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/badRequest"
     },
     "404": {
      "$ref": "#/components/responses/notFound"
     },
     "default": {
      "$ref": "#/components/responses/error"
     },
     "401": {
      "$ref": "#/components/responses/unauthorized"
     }
    },
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/LabelRequest"
       }
      }
     }
    }
   }
  },
  "/api/s/{sid}/data": {
   "post": {
    "operationId": "setData",
    "summary": "Define the bytes at an address as a type, or clear with an empty type (editor)",
    "parameters": [
     {
      "$ref": "#/components/parameters/sid"
     }
    ],
    "responses": {
     "200": {
      "description": "JSON result",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "additionalProperties": true,
         "description": "The read-back state after the change; a 200 means the model really holds it"
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/badRequest"
     },
     "404": {
      "$ref": "#/components/responses/notFound"
     },
     "default": {
      "$ref": "#/components/responses/error"
     },
     "401": {
      "$ref": "#/components/responses/unauthorized"
     }
    },
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/DataRequest"
       }
      }
     }
    }
   }
  },
  "/api/s/{sid}/bookmark": {
   "post": {
    "operationId": "setBookmark",
    "summary": "Bookmark an address, or remove it with an empty comment (editor)",
    "parameters": [
     {
      "$ref": "#/components/parameters/sid"
     }
    ],
    "responses": {
     "200": {
      "description": "JSON result",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "additionalProperties": true,
         "description": "The read-back state after the change; a 200 means the model really holds it"
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/badRequest"
     },
     "404": {
      "$ref": "#/components/responses/notFound"
     },
     "default": {
      "$ref": "#/components/responses/error"
     },
     "401": {
      "$ref": "#/components/responses/unauthorized"
     }
    },
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/BookmarkRequest"
       }
      }
     }
    }
   }
  },
  "/api/posts": {
   "get": {
    "operationId": "listPosts",
    "summary": "Every writeup this account has written",
    "responses": {
     "200": {
      "description": "JSON result",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Post"
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/unauthorized"
     },
     "404": {
      "$ref": "#/components/responses/notFound"
     },
     "default": {
      "$ref": "#/components/responses/error"
     }
    }
   }
  },
  "/api/posts/{id}": {
   "delete": {
    "operationId": "deletePost",
    "summary": "Unpublish a writeup and delete the snapshot serving it (author)",
    "parameters": [
     {
      "name": "id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      },
      "description": "The writeup's id."
     }
    ],
    "responses": {
     "200": {
      "description": "JSON result",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Post"
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/unauthorized"
     },
     "404": {
      "$ref": "#/components/responses/notFound"
     },
     "default": {
      "$ref": "#/components/responses/error"
     }
    }
   }
  },
  "/api/p/{author}/{slug}/fork": {
   "post": {
    "operationId": "forkPost",
    "summary": "Copy a published writeup's snapshot into your own account",
    "description": "Lands in your uploads, counts against your quota, and you hold creator on it -- so you can rename, comment and run agents where the writeup itself is frozen. Refused when the writeup publishes its analysis but not the sample, since a fork hands over the binary as surely as a download does.",
    "parameters": [
     {
      "name": "author",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      },
      "description": "The author's username, matched case-insensitively. Slugs are unique per author, so this segment is part of the post's name."
     },
     {
      "name": "slug",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      },
      "description": "The writeup's published slug."
     }
    ],
    "responses": {
     "200": {
      "description": "JSON result",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/ForkResponse"
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/unauthorized"
     },
     "403": {
      "description": "This writeup does not publish its sample."
     },
     "404": {
      "$ref": "#/components/responses/notFound"
     },
     "409": {
      "description": "You are at your binary limit."
     },
     "default": {
      "$ref": "#/components/responses/error"
     }
    }
   }
  },
  "/api/p/{author}/{slug}/download": {
   "get": {
    "operationId": "downloadPostSample",
    "summary": "Download a published writeup's sample",
    "description": "The one part of a writeup that needs an account: the prose, the analysis and the MCP tools are all public, and the sample is what a reader is asked to sign up for. Refused unless the author published the sample and the gateway releases samples through published writeups.",
    "parameters": [
     {
      "name": "author",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      },
      "description": "The author's username, matched case-insensitively. Slugs are unique per author, so this segment is part of the post's name."
     },
     {
      "name": "slug",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      },
      "description": "The writeup's published slug."
     }
    ],
    "responses": {
     "200": {
      "description": "The binary.",
      "content": {
       "application/octet-stream": {
        "schema": {
         "type": "string",
         "format": "binary"
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/unauthorized"
     },
     "403": {
      "description": "This writeup does not release its sample."
     },
     "404": {
      "$ref": "#/components/responses/notFound"
     },
     "default": {
      "$ref": "#/components/responses/error"
     }
    }
   }
  },
  "/api/s/{sid}/post": {
   "get": {
    "operationId": "getSessionPost",
    "summary": "This session's writeup, and what publishing its notes now would produce",
    "parameters": [
     {
      "$ref": "#/components/parameters/sid"
     }
    ],
    "responses": {
     "200": {
      "description": "JSON result",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/SessionPost"
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/unauthorized"
     },
     "404": {
      "$ref": "#/components/responses/notFound"
     },
     "default": {
      "$ref": "#/components/responses/error"
     }
    }
   },
   "post": {
    "operationId": "publishSessionPost",
    "summary": "Publish this session's notes as a writeup (creator)",
    "description": "The notes are the writeup: the prose, its title and the references that become links all come from them, so there is nothing to submit but the link and whether the sample travels. Publishing freezes a copy of the session; publishing again updates the page and keeps the link.",
    "parameters": [
     {
      "$ref": "#/components/parameters/sid"
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "slug": {
          "type": "string",
          "description": "Suggested from the notes' first heading. Fixed at the first publish; ignored afterwards."
         },
         "allowDownload": {
          "type": "boolean",
          "description": "Whether readers may take the sample and open their own copy."
         }
        }
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "JSON result",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Post"
        }
       }
      }
     },
     "400": {
      "description": "The notes are empty, or the link is malformed."
     },
     "401": {
      "$ref": "#/components/responses/unauthorized"
     },
     "403": {
      "description": "Publishing needs creator access to the session."
     },
     "404": {
      "$ref": "#/components/responses/notFound"
     },
     "409": {
      "description": "That link is taken, or you are at your writeup limit."
     },
     "default": {
      "$ref": "#/components/responses/error"
     }
    }
   }
  }
 },
 "components": {
  "securitySchemes": {
   "bearerAuth": {
    "type": "http",
    "scheme": "bearer",
    "description": "Token from POST /api/auth/login"
   }
  },
  "parameters": {
   "sid": {
    "name": "sid",
    "in": "path",
    "required": true,
    "description": "Session id, from GET /api/sessions or the upload response",
    "schema": {
     "type": "string"
    }
   },
   "addr": {
    "name": "addr",
    "in": "query",
    "required": true,
    "description": "Address as a 0x-prefixed hex string, e.g. 0x401000. Function endpoints accept any address inside the function.",
    "schema": {
     "type": "string",
     "pattern": "^(0x)?[0-9a-fA-F]+$"
    }
   }
  },
  "responses": {
   "badRequest": {
    "description": "Malformed parameter or body (bad address, out-of-range number)",
    "content": {
     "application/json": {
      "schema": {
       "$ref": "#/components/schemas/Error"
      }
     }
    }
   },
   "notFound": {
    "description": "Nothing there: unknown session or token, or nothing at that address",
    "content": {
     "application/json": {
      "schema": {
       "$ref": "#/components/schemas/Error"
      }
     }
    }
   },
   "error": {
    "description": "Any other failure, same {error} shape. 409: uploaded but not analysed yet. 503: the gateway is at capacity or the session's worker is unavailable; retry later.",
    "content": {
     "application/json": {
      "schema": {
       "$ref": "#/components/schemas/Error"
      }
     }
    }
   },
   "unauthorized": {
    "description": "No token, or a revoked one; sign in again",
    "content": {
     "application/json": {
      "schema": {
       "$ref": "#/components/schemas/Error"
      }
     }
    }
   }
  },
  "schemas": {
   "Error": {
    "type": "object",
    "properties": {
     "error": {
      "type": "string",
      "description": "What went wrong, as a sentence"
     }
    },
    "additionalProperties": false,
    "required": [
     "error"
    ]
   },
   "Info": {
    "type": "object",
    "properties": {
     "core": {
      "type": "object",
      "properties": {
       "file": {
        "type": "string",
        "description": "Display name"
       },
       "format": {
        "type": "string",
        "description": "Container format, e.g. ELF or PE"
       },
       "humansz": {
        "type": "string",
        "description": "Human-readable size"
       },
       "size": {
        "type": "integer",
        "description": "Size in bytes"
       }
      },
      "additionalProperties": true
     },
     "bin": {
      "type": "object",
      "properties": {
       "arch": {
        "type": "string"
       },
       "bits": {
        "type": "integer"
       },
       "endian": {
        "type": "string",
        "enum": [
         "little",
         "big"
        ]
       },
       "baddr": {
        "type": "integer",
        "description": "Image base address"
       },
       "bintype": {
        "type": "string"
       },
       "compiler": {
        "type": "string"
       },
       "language": {
        "type": "string",
        "description": "Ghidra language id, e.g. x86:LE:64:default"
       },
       "canary": {
        "type": "boolean"
       },
       "nx": {
        "type": "boolean"
       },
       "pic": {
        "type": "boolean"
       },
       "relocs": {
        "type": "boolean"
       },
       "relro": {
        "type": "string"
       },
       "static": {
        "type": "boolean"
       },
       "stripped": {
        "type": "boolean"
       }
      },
      "additionalProperties": true
     }
    },
    "additionalProperties": false,
    "required": [
     "core",
     "bin"
    ]
   },
   "Overview": {
    "type": "object",
    "properties": {
     "functions": {
      "type": "integer"
     },
     "xrefs": {
      "type": "integer"
     },
     "calls": {
      "type": "integer"
     },
     "strings": {
      "type": "integer"
     },
     "symbols": {
      "type": "integer"
     },
     "imports": {
      "type": "integer"
     }
    },
    "additionalProperties": false
   },
   "Triage": {
    "type": "object",
    "properties": {
     "items": {
      "type": "array",
      "items": {
       "type": "object",
       "properties": {
        "addr": {
         "type": "string",
         "description": "Function entry point as a 0x-prefixed hex string (unlike list endpoints, which return decimal offsets)"
        },
        "name": {
         "type": "string"
        },
        "size": {
         "type": "integer",
         "description": "Function size in bytes"
        },
        "score": {
         "type": "integer",
         "description": "Rank score; higher means more worth reading first"
        },
        "reasons": {
         "type": "array",
         "items": {
          "type": "string"
         },
         "description": "Why it ranked, e.g. 'exported entry point', 'complex'"
        }
       },
       "additionalProperties": false
      }
     },
     "ranked": {
      "type": "integer",
      "description": "How many functions scored above zero"
     },
     "total": {
      "type": "integer",
      "description": "How many functions exist"
     }
    },
    "additionalProperties": false,
    "required": [
     "items",
     "ranked",
     "total"
    ]
   },
   "Hashes": {
    "type": "object",
    "properties": {
     "md5": {
      "type": "string"
     },
     "sha1": {
      "type": "string"
     },
     "sha256": {
      "type": "string"
     },
     "crc32": {
      "type": "string"
     },
     "entropy": {
      "type": "string",
      "description": "Whole-file Shannon entropy, 0-8 bits per byte"
     }
    },
    "additionalProperties": false
   },
   "EntropyBucket": {
    "type": "object",
    "properties": {
     "addr": {
      "type": "integer",
      "description": "Address as a decimal byte offset in the program's address space. Render as hex for display; pass back to addr parameters as a 0x-prefixed hex string."
     },
     "size": {
      "type": "integer",
      "description": "Bytes sampled in this bucket"
     },
     "section": {
      "type": "string",
      "description": "Memory block the bucket lies in; buckets never straddle blocks"
     },
     "entropy": {
      "type": "number",
      "description": "Shannon entropy of the bucket, 0-8 bits per byte"
     }
    },
    "additionalProperties": false
   },
   "Section": {
    "type": "object",
    "properties": {
     "name": {
      "type": "string"
     },
     "size": {
      "type": "integer",
      "description": "File size"
     },
     "vsize": {
      "type": "integer",
      "description": "Size in memory"
     },
     "type": {
      "type": "string"
     },
     "perm": {
      "type": "string",
      "description": "Permissions as rwx string, e.g. 'r-x'"
     },
     "flags": {
      "type": "integer"
     },
     "vaddr": {
      "type": "integer",
      "description": "Address as a decimal byte offset in the program's address space. Render as hex for display; pass back to addr parameters as a 0x-prefixed hex string."
     },
     "paddr": {
      "type": "integer",
      "description": "File offset"
     },
     "loaded": {
      "type": "boolean"
     }
    },
    "additionalProperties": false
   },
   "Function": {
    "type": "object",
    "properties": {
     "addr": {
      "type": "integer",
      "description": "Address as a decimal byte offset in the program's address space. Render as hex for display; pass back to addr parameters as a 0x-prefixed hex string."
     },
     "name": {
      "type": "string"
     },
     "size": {
      "type": "integer",
      "description": "Bytes in the function body"
     },
     "end": {
      "type": "integer",
      "description": "Last address, decimal"
     },
     "nbbs": {
      "type": "integer",
      "description": "Basic block count"
     },
     "cc": {
      "type": "integer",
      "description": "Cyclomatic complexity"
     },
     "ninstrs": {
      "type": "integer",
      "description": "Instruction count"
     },
     "indegree": {
      "type": "integer",
      "description": "How many functions call this one"
     }
    },
    "additionalProperties": false
   },
   "Op": {
    "type": "object",
    "properties": {
     "addr": {
      "type": "integer",
      "description": "Address as a decimal byte offset in the program's address space. Render as hex for display; pass back to addr parameters as a 0x-prefixed hex string."
     },
     "bytes": {
      "type": "string",
      "description": "Instruction bytes as lowercase hex"
     },
     "disasm": {
      "type": "string"
     },
     "opcode": {
      "type": "string"
     }
    },
    "additionalProperties": false
   },
   "Disasm": {
    "type": "object",
    "properties": {
     "addr": {
      "type": "integer",
      "description": "Address as a decimal byte offset in the program's address space. Render as hex for display; pass back to addr parameters as a 0x-prefixed hex string."
     },
     "name": {
      "type": "string",
      "description": "Containing function"
     },
     "size": {
      "type": "integer"
     },
     "ops": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/Op"
      }
     }
    },
    "additionalProperties": false
   },
   "Decompile": {
    "type": "object",
    "properties": {
     "lines": {
      "type": "array",
      "items": {
       "type": "object",
       "properties": {
        "str": {
         "type": "string",
         "description": "One line of C"
        },
        "offset": {
         "type": "integer",
         "description": "Address the line maps to, decimal; absent on lines with no location"
        }
       },
       "additionalProperties": false,
       "required": [
        "str"
       ]
      }
     },
     "annotatedVars": {
      "type": "array",
      "items": {
       "type": "string"
      },
      "description": "Variable and symbol names appearing in the listing"
     }
    },
    "additionalProperties": false,
    "required": [
     "lines"
    ]
   },
   "Vars": {
    "type": "object",
    "properties": {
     "reg": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/Var"
      },
      "description": "Register-backed variables"
     },
     "sp": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/Var"
      },
      "description": "Stack variables"
     },
     "bp": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/Var"
      },
      "description": "Frame-base variables"
     }
    },
    "additionalProperties": false
   },
   "Var": {
    "type": "object",
    "properties": {
     "name": {
      "type": "string"
     },
     "type": {
      "type": "string"
     },
     "kind": {
      "type": "string",
      "enum": [
       "arg",
       "var"
      ]
     },
     "ref": {
      "type": "string",
      "description": "Storage location, e.g. 'RDI:8' or a stack offset"
     }
    },
    "additionalProperties": false
   },
   "Graph": {
    "type": "object",
    "properties": {
     "name": {
      "type": "string",
      "description": "Function name"
     },
     "addr": {
      "type": "integer",
      "description": "Address as a decimal byte offset in the program's address space. Render as hex for display; pass back to addr parameters as a 0x-prefixed hex string."
     },
     "blocks": {
      "type": "array",
      "items": {
       "type": "object",
       "properties": {
        "addr": {
         "type": "integer",
         "description": "Address as a decimal byte offset in the program's address space. Render as hex for display; pass back to addr parameters as a 0x-prefixed hex string."
        },
        "size": {
         "type": "integer",
         "description": "Addresses spanned"
        },
        "jump": {
         "type": "integer",
         "description": "Branch-taken successor, decimal; absent when none"
        },
        "fail": {
         "type": "integer",
         "description": "Fall-through successor, decimal; absent when none"
        },
        "ops": {
         "type": "array",
         "items": {
          "$ref": "#/components/schemas/Op"
         }
        }
       },
       "additionalProperties": false,
       "required": [
        "addr",
        "size",
        "ops"
       ]
      }
     }
    },
    "additionalProperties": false
   },
   "Xref": {
    "type": "object",
    "properties": {
     "from": {
      "type": "integer",
      "description": "Referencing address, decimal"
     },
     "type": {
      "type": "string",
      "description": "Reference type, e.g. CALL, READ, WRITE, JUMP"
     },
     "opcode": {
      "type": "string",
      "description": "Disassembly at the referencing address"
     },
     "fcn_name": {
      "type": "string",
      "description": "Function containing the reference, when any"
     },
     "realname": {
      "type": "string"
     }
    },
    "additionalProperties": false
   },
   "CallTree": {
    "type": "object",
    "properties": {
     "incoming": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/NamedAddr"
      },
      "description": "Functions that call this one"
     },
     "outgoing": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/NamedAddr"
      },
      "description": "Functions this one calls"
     }
    },
    "additionalProperties": false
   },
   "CallGraphNode": {
    "type": "object",
    "properties": {
     "addr": {
      "type": "integer",
      "description": "Entry point, decimal"
     },
     "name": {
      "type": "string"
     },
     "callees": {
      "type": "array",
      "items": {
       "type": "string"
      },
      "description": "Functions this one calls, by name; empty for leaves"
     }
    },
    "additionalProperties": false
   },
   "NamedAddr": {
    "type": "object",
    "properties": {
     "addr": {
      "type": "integer",
      "description": "Address as a decimal byte offset in the program's address space. Render as hex for display; pass back to addr parameters as a 0x-prefixed hex string."
     },
     "name": {
      "type": "string"
     }
    },
    "additionalProperties": false
   },
   "Instruction": {
    "type": "object",
    "properties": {
     "addr": {
      "type": "integer",
      "description": "Address as a decimal byte offset in the program's address space. Render as hex for display; pass back to addr parameters as a 0x-prefixed hex string."
     },
     "mnemonic": {
      "type": "string"
     },
     "text": {
      "type": "string"
     },
     "length": {
      "type": "integer"
     },
     "flow": {
      "type": "string",
      "description": "Control-flow class, e.g. FALL_THROUGH, UNCONDITIONAL_CALL"
     },
     "bytes": {
      "type": "string",
      "description": "Encoding as lowercase hex"
     },
     "operands": {
      "type": "array",
      "items": {
       "type": "object",
       "properties": {
        "text": {
         "type": "string"
        },
        "type": {
         "type": "string"
        },
        "refers": {
         "type": "integer",
         "description": "Address the operand refers to, decimal; absent when none"
        }
       },
       "additionalProperties": false,
       "required": [
        "text",
        "type"
       ]
      }
     },
     "pcode": {
      "type": "array",
      "items": {
       "type": "string"
      },
      "description": "The instruction's p-code ops, one string each"
     }
    },
    "additionalProperties": false
   },
   "ResolveAddr": {
    "type": "object",
    "properties": {
     "addr": {
      "type": "integer",
      "description": "Address as a decimal byte offset in the program's address space. Render as hex for display; pass back to addr parameters as a 0x-prefixed hex string."
     },
     "name": {
      "type": "string",
      "description": "Containing function"
     },
     "size": {
      "type": "integer"
     },
     "end": {
      "type": "integer"
     }
    },
    "additionalProperties": false
   },
   "Signature": {
    "type": "object",
    "properties": {
     "addr": {
      "type": "integer",
      "description": "Address as a decimal byte offset in the program's address space. Render as hex for display; pass back to addr parameters as a 0x-prefixed hex string."
     },
     "name": {
      "type": "string"
     },
     "signature": {
      "type": "string",
      "description": "Full C prototype"
     },
     "callingConvention": {
      "type": "string"
     },
     "callingConventions": {
      "type": "array",
      "items": {
       "type": "string"
      },
      "description": "Conventions this program accepts"
     }
    },
    "additionalProperties": false
   },
   "StringItem": {
    "type": "object",
    "properties": {
     "vaddr": {
      "type": "integer",
      "description": "Address as a decimal byte offset in the program's address space. Render as hex for display; pass back to addr parameters as a 0x-prefixed hex string."
     },
     "paddr": {
      "type": "integer",
      "description": "File offset"
     },
     "size": {
      "type": "integer",
      "description": "Bytes including terminator"
     },
     "length": {
      "type": "integer",
      "description": "Characters"
     },
     "section": {
      "type": "string"
     },
     "type": {
      "type": "string",
      "description": "E.g. TerminatedCString, unicode"
     },
     "string": {
      "type": "string",
      "description": "The text itself"
     }
    },
    "additionalProperties": false
   },
   "Symbol": {
    "type": "object",
    "properties": {
     "name": {
      "type": "string"
     },
     "flagname": {
      "type": "string"
     },
     "realname": {
      "type": "string"
     },
     "ordinal": {
      "type": "integer"
     },
     "bind": {
      "type": "string"
     },
     "type": {
      "type": "string"
     },
     "size": {
      "type": "integer"
     },
     "vaddr": {
      "type": "integer",
      "description": "Address as a decimal byte offset in the program's address space. Render as hex for display; pass back to addr parameters as a 0x-prefixed hex string."
     },
     "paddr": {
      "type": "integer"
     },
     "is_imported": {
      "type": "boolean"
     }
    },
    "additionalProperties": false
   },
   "Import": {
    "type": "object",
    "properties": {
     "ordinal": {
      "type": "integer"
     },
     "bind": {
      "type": "string"
     },
     "type": {
      "type": "string"
     },
     "name": {
      "type": "string"
     },
     "plt": {
      "type": "integer",
      "description": "Thunk address, decimal"
     }
    },
    "additionalProperties": false
   },
   "Types": {
    "type": "object",
    "properties": {
     "types": {
      "type": "array",
      "items": {
       "type": "object",
       "properties": {
        "type": {
         "type": "string",
         "description": "Type name"
        },
        "size": {
         "type": "integer",
         "description": "Bytes"
        },
        "format": {
         "type": "string",
         "description": "Category path in Ghidra's type manager"
        },
        "kind": {
         "type": "string",
         "description": "struct, union, enum, typedef, funcdef, pointer, array or builtin"
        }
       },
       "additionalProperties": false
      }
     }
    },
    "additionalProperties": false
   },
   "SearchHit": {
    "type": "object",
    "properties": {
     "addr": {
      "type": "integer",
      "description": "Address as a decimal byte offset in the program's address space. Render as hex for display; pass back to addr parameters as a 0x-prefixed hex string."
     },
     "type": {
      "type": "string",
      "description": "What matched: string, bytes, or similar"
     },
     "data": {
      "type": "string",
      "description": "The matching text or bytes"
     }
    },
    "additionalProperties": false
   },
   "Comment": {
    "type": "object",
    "properties": {
     "offset": {
      "type": "integer",
      "description": "Address, decimal"
     },
     "name": {
      "type": "string",
      "description": "The comment text"
     },
     "author": {
      "type": "string",
      "description": "Username that wrote it"
     },
     "at": {
      "type": "integer",
      "description": "Unix epoch milliseconds"
     }
    },
    "additionalProperties": false
   },
   "Label": {
    "type": "object",
    "properties": {
     "addr": {
      "type": "integer",
      "description": "Address as a decimal byte offset in the program's address space. Render as hex for display; pass back to addr parameters as a 0x-prefixed hex string."
     },
     "name": {
      "type": "string"
     },
     "user": {
      "type": "boolean",
      "description": "True when a person named it rather than analysis"
     }
    },
    "additionalProperties": false
   },
   "Bookmark": {
    "type": "object",
    "properties": {
     "addr": {
      "type": "integer",
      "description": "Address as a decimal byte offset in the program's address space. Render as hex for display; pass back to addr parameters as a 0x-prefixed hex string."
     },
     "category": {
      "type": "string"
     },
     "comment": {
      "type": "string"
     }
    },
    "additionalProperties": false
   },
   "ChatMessage": {
    "type": "object",
    "properties": {
     "id": {
      "type": "string"
     },
     "role": {
      "type": "string",
      "enum": [
       "user",
       "agent",
       "system"
      ]
     },
     "author": {
      "type": "string"
     },
     "text": {
      "type": "string",
      "description": "Markdown"
     },
     "at": {
      "type": "integer",
      "description": "Unix epoch milliseconds"
     }
    },
    "additionalProperties": false
   },
   "Notes": {
    "type": "object",
    "properties": {
     "text": {
      "type": "string",
      "description": "The shared session notes, markdown"
     }
    },
    "additionalProperties": false,
    "required": [
     "text"
    ]
   },
   "ActivityEvent": {
    "type": "object",
    "properties": {
     "type": {
      "type": "string",
      "description": "Event name, e.g. functionRenamed, commentsChanged, notesChanged"
     },
     "userId": {
      "type": "string",
      "description": "Who did it"
     },
     "addr": {
      "type": "string",
      "description": "Affected address when the event has one, 0x-prefixed hex"
     },
     "command": {
      "type": "string"
     },
     "timestamp": {
      "type": "integer",
      "description": "Unix epoch milliseconds"
     }
    },
    "additionalProperties": true
   },
   "Layout": {
    "description": "The creator's saved dock layout, or null when none was saved. An opaque frontend structure; not useful outside the workspace.",
    "type": [
     "object",
     "null"
    ],
    "additionalProperties": true
   },
   "PublicUser": {
    "type": "object",
    "properties": {
     "id": {
      "type": "string"
     },
     "username": {
      "type": "string"
     },
     "role": {
      "type": "string",
      "description": "Account role on the gateway"
     }
    },
    "additionalProperties": false,
    "required": [
     "id",
     "username",
     "role"
    ]
   },
   "LoginRequest": {
    "type": "object",
    "properties": {
     "username": {
      "type": "string"
     },
     "password": {
      "type": "string"
     }
    },
    "additionalProperties": false,
    "required": [
     "username",
     "password"
    ]
   },
   "LoginResponse": {
    "type": "object",
    "properties": {
     "token": {
      "type": "string",
      "description": "Bearer token for every authenticated call"
     },
     "user": {
      "$ref": "#/components/schemas/PublicUser"
     }
    },
    "additionalProperties": false,
    "required": [
     "token",
     "user"
    ]
   },
   "SessionInfo": {
    "type": "object",
    "properties": {
     "id": {
      "type": "string",
      "description": "Session id, the {sid} in every session route"
     },
     "name": {
      "type": "string",
      "description": "The binary's display name"
     },
     "status": {
      "type": "string",
      "enum": [
       "pending",
       "queued",
       "analyzing",
       "ready",
       "errored"
      ]
     },
     "error": {
      "type": "string",
      "description": "Why the session is errored, when it is"
     },
     "yourRole": {
      "type": "string",
      "enum": [
       "viewer",
       "editor",
       "creator"
      ],
      "description": "Session role"
     },
     "hasSymbols": {
      "type": "boolean",
      "description": "Whether debug symbols are loaded"
     },
     "defaultBackend": {
      "type": "string",
      "description": "Decompiler backend chosen at analysis time, when one was"
     },
     "resident": {
      "type": "boolean",
      "description": "Whether a worker is held right now; false means opening waits for a slot"
     },
     "queueReason": {
      "type": "string",
      "enum": [
       "analysis",
       "capacity"
      ],
      "description": "Which queue a queued session is in"
     },
     "openError": {
      "type": "string",
      "description": "Why the last open gave up, for a reason that will pass"
     }
    },
    "additionalProperties": false,
    "required": [
     "id",
     "name",
     "status"
    ]
   },
   "GatewayCapacity": {
    "type": "object",
    "properties": {
     "resident": {
      "type": "integer",
      "description": "Worker slots held"
     },
     "maxResident": {
      "type": "integer"
     },
     "analyzing": {
      "type": "integer"
     },
     "analysisSlots": {
      "type": "integer"
     },
     "yourResident": {
      "type": "integer",
      "description": "This account's own residents; 0 when the per-account limit is off"
     },
     "yourMax": {
      "type": "integer",
      "description": "This account's allowance; 0 when off"
     }
    },
    "additionalProperties": false
   },
   "Status": {
    "type": "object",
    "properties": {
     "status": {
      "type": "string"
     }
    },
    "additionalProperties": false,
    "required": [
     "status"
    ]
   },
   "ShareResponse": {
    "type": "object",
    "properties": {
     "token": {
      "type": "string",
      "description": "The share token; empty means not shared. The link is app.reverser.space/v/{token}"
     }
    },
    "additionalProperties": false,
    "required": [
     "token"
    ]
   },
   "AccessEntry": {
    "type": "object",
    "properties": {
     "userId": {
      "type": "string"
     },
     "username": {
      "type": "string"
     },
     "role": {
      "type": "string",
      "enum": [
       "viewer",
       "editor",
       "creator"
      ],
      "description": "Session role"
     }
    },
    "additionalProperties": false
   },
   "GrantAccessRequest": {
    "type": "object",
    "properties": {
     "username": {
      "type": "string",
      "description": "Account to grant"
     },
     "role": {
      "type": "string",
      "enum": [
       "viewer",
       "editor",
       "creator"
      ],
      "description": "Session role"
     }
    },
    "additionalProperties": false,
    "required": [
     "username",
     "role"
    ]
   },
   "StageSymbolsResult": {
    "type": "object",
    "properties": {
     "staged": {
      "type": "boolean"
     },
     "appliedOnAnalysis": {
      "type": "boolean",
      "description": "True when the session is still pending, so analysis will use the file; false means it was stored but the session was already analysed"
     }
    },
    "additionalProperties": false
   },
   "AnalyzeRequest": {
    "type": "object",
    "properties": {
     "backend": {
      "type": "string",
      "description": "Decompiler backend the workspace should open with; absent leaves the default"
     }
    },
    "additionalProperties": false
   },
   "DeleteSessionRequest": {
    "type": "object",
    "properties": {
     "confirm": {
      "type": "string",
      "description": "The binary's display name, typed back to confirm"
     }
    },
    "additionalProperties": false,
    "required": [
     "confirm"
    ]
   },
   "PublicAgent": {
    "type": "object",
    "properties": {
     "name": {
      "type": "string"
     },
     "provider": {
      "type": "string",
      "enum": [
       "gemini",
       "openai"
      ]
     },
     "model": {
      "type": "string"
     },
     "roleCeiling": {
      "type": "string",
      "enum": [
       "viewer",
       "editor",
       "creator"
      ],
      "description": "Session role"
     }
    },
    "additionalProperties": false
   },
   "InviteAgentRequest": {
    "type": "object",
    "properties": {
     "agent": {
      "type": "string",
      "description": "Agent name from GET /api/agents"
     },
     "task": {
      "type": "string",
      "description": "What to work on; optional"
     }
    },
    "additionalProperties": false,
    "required": [
     "agent"
    ]
   },
   "AgentCred": {
    "type": "object",
    "properties": {
     "id": {
      "type": "string"
     },
     "agent": {
      "type": "string"
     },
     "grantedBy": {
      "type": "string",
      "description": "Username"
     },
     "role": {
      "type": "string",
      "enum": [
       "viewer",
       "editor",
       "creator"
      ],
      "description": "Session role"
     },
     "expiresAt": {
      "type": "integer",
      "description": "Unix epoch milliseconds"
     }
    },
    "additionalProperties": false
   },
   "ActiveRun": {
    "type": "object",
    "properties": {
     "id": {
      "type": "string"
     },
     "sessionId": {
      "type": "string"
     },
     "agent": {
      "type": "string"
     },
     "startedBy": {
      "type": "string",
      "description": "Account id whose authority the run acts under"
     },
     "startedByName": {
      "type": "string",
      "description": "Username of startedBy"
     },
     "startedAt": {
      "type": "integer",
      "description": "Unix epoch milliseconds"
     }
    },
    "additionalProperties": false
   },
   "StartedRun": {
    "type": "object",
    "properties": {
     "status": {
      "type": "string",
      "enum": [
       "started"
      ]
     },
     "runId": {
      "type": "string"
     }
    },
    "additionalProperties": false,
    "required": [
     "status",
     "runId"
    ]
   },
   "SendChatRequest": {
    "type": "object",
    "properties": {
     "agent": {
      "type": "string",
      "description": "Which agent to address, from GET /api/agents"
     },
     "text": {
      "type": "string",
      "description": "The message; markdown"
     }
    },
    "additionalProperties": false,
    "required": [
     "agent",
     "text"
    ]
   },
   "AgentPeer": {
    "type": "object",
    "properties": {
     "kind": {
      "type": "string"
     },
     "userId": {
      "type": "string"
     },
     "name": {
      "type": "string",
      "description": "Agent name"
     },
     "addr": {
      "type": "integer",
      "description": "Where it was last seen, decimal"
     },
     "pane": {
      "type": "string",
      "description": "Which panel it was in"
     },
     "agent": {
      "type": "boolean"
     },
     "idle": {
      "type": "boolean"
     }
    },
    "additionalProperties": true
   },
   "KeyStatus": {
    "type": "object",
    "properties": {
     "enabled": {
      "type": "boolean",
      "description": "Whether this gateway can store keys at all (a KEK is configured)"
     },
     "providers": {
      "type": "array",
      "items": {
       "type": "object",
       "properties": {
        "provider": {
         "type": "string",
         "enum": [
          "gemini",
          "openai"
         ]
        },
        "hasKey": {
         "type": "boolean",
         "description": "Whether this account stored a key"
        },
        "pooled": {
         "type": "boolean",
         "description": "Whether runs are operator-funded when this account stores no key"
        }
       },
       "additionalProperties": false
      }
     }
    },
    "additionalProperties": false
   },
   "SetKeyRequest": {
    "type": "object",
    "properties": {
     "provider": {
      "type": "string",
      "enum": [
       "gemini",
       "openai"
      ]
     },
     "key": {
      "type": "string",
      "description": "The provider API key; stored encrypted, never read back"
     }
    },
    "additionalProperties": false,
    "required": [
     "provider",
     "key"
    ]
   },
   "AutorunSetting": {
    "type": "object",
    "properties": {
     "enabled": {
      "type": "boolean"
     },
     "agent": {
      "type": "string",
      "description": "Which agent runs on each of this account's uploads"
     },
     "role": {
      "type": "string",
      "enum": [
       "viewer",
       "editor",
       "creator"
      ],
      "description": "Session role"
     }
    },
    "additionalProperties": false
   },
   "RenameRequest": {
    "type": "object",
    "properties": {
     "addr": {
      "type": "string",
      "description": "0x-prefixed hex"
     },
     "name": {
      "type": "string",
      "description": "New function name"
     }
    },
    "additionalProperties": false,
    "required": [
     "addr",
     "name"
    ]
   },
   "RenameVarRequest": {
    "type": "object",
    "properties": {
     "addr": {
      "type": "string",
      "description": "0x-prefixed hex, inside the function"
     },
     "oldName": {
      "type": "string"
     },
     "newName": {
      "type": "string"
     }
    },
    "additionalProperties": false,
    "required": [
     "addr",
     "oldName",
     "newName"
    ]
   },
   "RetypeVarRequest": {
    "type": "object",
    "properties": {
     "addr": {
      "type": "string",
      "description": "0x-prefixed hex, inside the function"
     },
     "name": {
      "type": "string",
      "description": "Variable name"
     },
     "type": {
      "type": "string",
      "description": "C type, e.g. 'char *'"
     }
    },
    "additionalProperties": false,
    "required": [
     "addr",
     "name",
     "type"
    ]
   },
   "CommentRequest": {
    "type": "object",
    "properties": {
     "addr": {
      "type": "string",
      "description": "0x-prefixed hex"
     },
     "text": {
      "type": "string",
      "description": "Empty deletes nothing; use DELETE /comment for that"
     }
    },
    "additionalProperties": false,
    "required": [
     "addr",
     "text"
    ]
   },
   "LabelRequest": {
    "type": "object",
    "properties": {
     "addr": {
      "type": "string",
      "description": "0x-prefixed hex"
     },
     "name": {
      "type": "string",
      "description": "Empty clears the label"
     }
    },
    "additionalProperties": false,
    "required": [
     "addr",
     "name"
    ]
   },
   "DataRequest": {
    "type": "object",
    "properties": {
     "addr": {
      "type": "string",
      "description": "0x-prefixed hex"
     },
     "type": {
      "type": "string",
      "description": "Type to define the bytes as; empty clears the definition"
     }
    },
    "additionalProperties": false,
    "required": [
     "addr",
     "type"
    ]
   },
   "BookmarkRequest": {
    "type": "object",
    "properties": {
     "addr": {
      "type": "string",
      "description": "0x-prefixed hex"
     },
     "category": {
      "type": "string"
     },
     "comment": {
      "type": "string",
      "description": "Empty removes the bookmark"
     }
    },
    "additionalProperties": false,
    "required": [
     "addr",
     "comment"
    ]
   },
   "SignatureRequest": {
    "type": "object",
    "properties": {
     "addr": {
      "type": "string",
      "description": "0x-prefixed hex"
     },
     "signature": {
      "type": "string",
      "description": "Full C prototype"
     },
     "callingConvention": {
      "type": "string"
     }
    },
    "additionalProperties": false,
    "required": [
     "addr",
     "signature"
    ]
   },
   "SetNotesRequest": {
    "type": "object",
    "properties": {
     "text": {
      "type": "string",
      "description": "The whole notes text; this replaces, not appends"
     }
    },
    "additionalProperties": false,
    "required": [
     "text"
    ]
   },
   "Post": {
    "type": "object",
    "description": "A writeup bound to a frozen copy of a session. Drafts have no slug and no snapshot; both are settled at publish.",
    "properties": {
     "id": {
      "type": "string"
     },
     "slug": {
      "type": "string",
      "description": "Its published URL is /p/{slug}. Absent while it is a draft, immutable once set."
     },
     "authorId": {
      "type": "string"
     },
     "sourceSessionId": {
      "type": "string",
      "description": "The session it was written against."
     },
     "snapshotSessionId": {
      "type": "string",
      "description": "The frozen copy readers reach. It carries no grants, so every caller -- the author included -- reads it at viewer through the share token."
     },
     "title": {
      "type": "string"
     },
     "summary": {
      "type": "string"
     },
     "allowDownload": {
      "type": "boolean",
      "description": "Whether readers may pull the sample itself, as opposed to exploring the analysis."
     },
     "meta": {
      "type": "object",
      "description": "Sample frontmatter stamped at publish: sha256, size, format, arch, bits."
     },
     "createdAt": {
      "type": "integer",
      "format": "int64"
     },
     "updatedAt": {
      "type": "integer",
      "format": "int64"
     },
     "publishedAt": {
      "type": "integer",
      "format": "int64"
     }
    }
   },
   "PublicPost": {
    "type": "object",
    "description": "A published writeup as a reader loads it: rendered prose plus everything needed to reach the frozen session it argues about.",
    "properties": {
     "slug": {
      "type": "string"
     },
     "title": {
      "type": "string"
     },
     "summary": {
      "type": "string"
     },
     "html": {
      "type": "string",
      "description": "The prose, rendered at publish. References are anchors carrying revspace-addr: / revspace-fn: hrefs."
     },
     "token": {
      "type": "string",
      "description": "The share token for the frozen session: the reader's whole capability."
     },
     "mcpUrl": {
      "type": "string",
      "description": "The post's MCP endpoint, so a reader's own agent can read the sample."
     },
     "meta": {
      "type": "object"
     },
     "allowDownload": {
      "type": "boolean"
     },
     "publishedAt": {
      "type": "integer",
      "format": "int64"
     },
     "updatedAt": {
      "type": "integer",
      "format": "int64"
     }
    }
   },
   "ForkResponse": {
    "type": "object",
    "description": "The reader's own copy of a writeup's snapshot.",
    "properties": {
     "sessionId": {
      "type": "string",
      "description": "The new session, which the caller holds creator on."
     },
     "name": {
      "type": "string"
     },
     "existing": {
      "type": "boolean",
      "description": "True when the caller already held these bytes and was handed their own existing session instead of a fresh copy, so their work on it is not overwritten."
     }
    }
   },
   "SessionPost": {
    "type": "object",
    "description": "A session's writeup, if it has one, and what publishing its notes right now would produce.",
    "properties": {
     "post": {
      "$ref": "#/components/schemas/Post"
     },
     "title": {
      "type": "string",
      "description": "Read live off the notes: their first heading, or the binary's name."
     },
     "slug": {
      "type": "string",
      "description": "The published link, or a suggestion when there is not one yet."
     },
     "notes": {
      "type": "integer",
      "description": "Characters of notes, so a caller can tell there is nothing to publish."
     },
     "canPublish": {
      "type": "boolean",
      "description": "Whether the caller holds creator on the session."
     },
     "token": {
      "type": "string",
      "description": "The published snapshot's share token, once there is one."
     }
    }
   },
   "TypeDetail": {
    "type": "object",
    "properties": {
     "name": {
      "type": "string",
      "description": "Category path of the type"
     },
     "kind": {
      "type": "string",
      "description": "struct, union, enum, typedef, funcdef, pointer, array or builtin"
     },
     "size": {
      "type": "integer",
      "description": "Bytes"
     },
     "base": {
      "type": "string",
      "description": "Underlying type; typedefs only"
     },
     "members": {
      "type": "array",
      "description": "Fields for a struct or union, values for an enum",
      "items": {
       "type": "object",
       "properties": {
        "offset": {
         "type": "integer",
         "description": "Byte offset; composites only"
        },
        "name": {
         "type": "string",
         "description": "Field or constant name"
        },
        "type": {
         "type": "string",
         "description": "Field type; composites only"
        },
        "size": {
         "type": "integer",
         "description": "Field size; composites only"
        },
        "comment": {
         "type": "string",
         "description": "Field comment; composites only"
        },
        "value": {
         "type": "integer",
         "description": "Constant value; enums only"
        }
       }
      }
     }
    }
   },
   "ParseTypesRequest": {
    "type": "object",
    "properties": {
     "source": {
      "type": "string",
      "description": "C declarations: structs, unions, enums, typedefs"
     },
     "replace": {
      "type": "boolean",
      "description": "Overwrite types that already exist; without it a clash is a 409"
     }
    },
    "additionalProperties": false,
    "required": [
     "source"
    ]
   },
   "DeleteTypeRequest": {
    "type": "object",
    "properties": {
     "name": {
      "type": "string",
      "description": "Type to remove; its uses revert to undefined"
     }
    },
    "additionalProperties": false,
    "required": [
     "name"
    ]
   },
   "TypeUses": {
    "type": "object",
    "description": "What deleting this type would revert to undefined",
    "properties": {
     "name": {
      "type": "string",
      "description": "Category path of the type"
     },
     "data": {
      "type": "integer",
      "description": "Defined data using it"
     },
     "variables": {
      "type": "integer",
      "description": "Function variables typed as it"
     },
     "types": {
      "type": "integer",
      "description": "Other types built from it"
     },
     "total": {
      "type": "integer",
      "description": "Sum of the three"
     }
    }
   },
   "Finding": {
    "type": "object",
    "description": "One structured claim a background agent run recorded. Append-only: a corrected finding is superseded by a newer one, never edited.",
    "properties": {
     "id": {
      "type": "string"
     },
     "agent": {
      "type": "string"
     },
     "userId": {
      "type": "string"
     },
     "claim": {
      "type": "string"
     },
     "addr": {
      "type": "string"
     },
     "confidence": {
      "type": "string",
      "enum": [
       "low",
       "medium",
       "high"
      ]
     },
     "createdAt": {
      "type": "integer"
     },
     "supersedes": {
      "type": "string"
     },
     "supersededBy": {
      "type": "string"
     }
    },
    "required": [
     "id",
     "claim",
     "createdAt"
    ]
   }
  }
 }
}
