{
  "openapi": "3.0.0",
  "info": {
    "description": "API for manipulating filesystem, processes and network.",
    "title": "Sandbox API",
    "contact": {},
    "version": "0.0.1"
  },
  "paths": {
    "/archive/export": {
      "post": {
        "description": "Archives everything the sandbox changed on top of its base image and streams it, uncompressed, to a presigned S3 PUT URL. The memory of the sandbox is not archived.\nThe sandbox is quiesced first: the process list is saved (unless saveProcesses is false), every process is stopped, and the API then refuses the calls that would write to the filesystem. The freeze is not lifted afterwards, since an exported sandbox is meant to be restored elsewhere; call POST /archive/resume to lift it.\nA sandbox still frozen by an earlier export is exported as it is, with the process list that export saved.\nUse dryRun to get the archive's content and exact size without stopping anything and without uploading.\nSet async to start the export and answer immediately, which is what archiving a large filesystem needs: the export then reports itself through GET /archive/status.",
        "tags": [
          "archive"
        ],
        "summary": "Export the filesystem changes to a presigned URL",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ExportOptions"
              }
            }
          },
          "description": "Export options",
          "required": true
        },
        "responses": {
          "200": {
            "description": "Export result",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ExportResult"
                }
              }
            }
          },
          "202": {
            "description": "The export was started and runs in the background",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ExportProgress"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "409": {
            "description": "An export is already in progress, or the sandbox is frozen for a restore",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Export failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/archive/resume": {
      "post": {
        "description": "Makes the API serve every route again after an export. The processes stopped for the export are not relaunched: this exists so a failed or aborted export does not leave the sandbox unusable.",
        "tags": [
          "archive"
        ],
        "summary": "Lift the archive freeze",
        "responses": {
          "200": {
            "description": "Archive status",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/QuiesceStatus"
                }
              }
            }
          },
          "409": {
            "description": "An export or a restore is in progress",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "The root filesystem could not be made writable again",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/archive/status": {
      "get": {
        "description": "Reports whether the sandbox is frozen for an archive export, and which processes were stopped for it.",
        "tags": [
          "archive"
        ],
        "summary": "Get the archive status",
        "responses": {
          "200": {
            "description": "Archive status",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/QuiesceStatus"
                }
              }
            }
          }
        }
      }
    },
    "/codegen/fastapply/{path}": {
      "put": {
        "description": "Uses the configured LLM provider (Relace or Morph) to apply a code edit to the original content.\n\nTo use this endpoint as an agent tool, follow these guidelines:\n\nUse this tool to make an edit to an existing file. This will be read by a less intelligent model, which will quickly apply the edit. You should make it clear what the edit is, while also minimizing the unchanged code you write.\n\nWhen writing the edit, you should specify each edit in sequence, with the special comment \"// ... existing code ...\" to represent unchanged code in between edited lines.\n\nExample format:\n// ... existing code ...\nFIRST_EDIT\n// ... existing code ...\nSECOND_EDIT\n// ... existing code ...\nTHIRD_EDIT\n// ... existing code ...\n\nYou should still bias towards repeating as few lines of the original file as possible to convey the change. But, each edit should contain minimally sufficient context of unchanged lines around the code you're editing to resolve ambiguity.\n\nDO NOT omit spans of pre-existing code (or comments) without using the \"// ... existing code ...\" comment to indicate its absence. If you omit the existing code comment, the model may inadvertently delete these lines.\n\nIf you plan on deleting a section, you must provide context before and after to delete it. If the initial code is \"Block 1\\nBlock 2\\nBlock 3\", and you want to remove Block 2, you would output \"// ... existing code ...\\nBlock 1\\nBlock 3\\n// ... existing code ...\".\n\nMake sure it is clear what the edit should be, and where it should be applied. Make edits to a file in a single edit_file call instead of multiple edit_file calls to the same file. The apply model can handle many distinct edits at once.",
        "tags": [
          "fastapply"
        ],
        "summary": "Apply code edit",
        "parameters": [
          {
            "description": "Path to the file to edit (relative to workspace)",
            "name": "path",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ApplyEditRequest"
              }
            }
          },
          "description": "Code edit request",
          "required": true
        },
        "responses": {
          "200": {
            "description": "Code edit applied successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApplyEditResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable entity - failed to process the request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Service unavailable - no provider configured",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/codegen/reranking/{path}": {
      "get": {
        "description": "Uses Relace's code reranking model to find the most relevant files for a given query. This is useful as a first pass in agentic exploration to narrow down the search space.\n\nBased on: https://docs.relace.ai/docs/code-reranker/agent\n\nQuery Construction: The query can be a short question or a more detailed conversation with the user request included. For a first pass, use the full conversation; for subsequent calls, use more targeted questions.\n\nToken Limit and Score Threshold: For 200k token context models like Claude 4 Sonnet, recommended defaults are scoreThreshold=0.5 and tokenLimit=30000.\n\nThe response will be a list of file paths and contents ordered from most relevant to least relevant.",
        "tags": [
          "codegen"
        ],
        "summary": "Code reranking/semantic search",
        "parameters": [
          {
            "description": "Path to search in (relative to workspace)",
            "name": "path",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Natural language query to search for",
            "name": "query",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Minimum relevance score (default: 0.5)",
            "name": "scoreThreshold",
            "in": "query",
            "schema": {
              "type": "number"
            }
          },
          {
            "description": "Maximum tokens to return (default: 30000)",
            "name": "tokenLimit",
            "in": "query",
            "schema": {
              "type": "integer"
            }
          },
          {
            "description": "Regex pattern to filter files (e.g., .*\\\\.ts$ for TypeScript files)",
            "name": "filePattern",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Relevant files found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RerankingResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable entity - failed to process the request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Service unavailable - Relace not configured",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/drives/mount": {
      "get": {
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "description": "Returns a list of all currently mounted drives managed by blfs",
        "tags": [
          "drive"
        ],
        "summary": "List currently mounted drives",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DriveListResponse"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      },
      "post": {
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "description": "Mounts an agent drive using the blfs binary to a local path, optionally mounting a subpath within the drive. Supports optional UID/GID mapping to remap file ownership between the local sandbox and the filer (always mapped to filer UID/GID 0). Mapping values can be set per-request via uidMap/gidMap fields, or globally via BLFS_UID_MAP/BLFS_GID_MAP environment variables (request values take precedence).",
        "tags": [
          "drive"
        ],
        "summary": "Attach a drive to a local path",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DriveMountRequest"
              }
            }
          },
          "description": "Drive attachment parameters",
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DriveMountResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/drives/mount/{mountPath}": {
      "delete": {
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "description": "Unmounts a previously mounted drive from the specified local path",
        "tags": [
          "drive"
        ],
        "summary": "Detach a drive from a local path",
        "parameters": [
          {
            "description": "Mount path to detach (must start with /, e.g. /mnt/test)",
            "name": "mountPath",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DriveUnmountResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/environment/reload": {
      "post": {
        "description": "Re-reads /bl/metadata and applies its environment to the sandbox-api process, so this process and every process started afterwards see the current values. Called by the guest init after an environment update; safe to call manually.",
        "tags": [
          "system"
        ],
        "summary": "Reload environment from guest metadata",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/handler.ReloadResponse"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/filesystem-content-search/{path}": {
      "get": {
        "description": "Searches for text content inside files. Returns each matching line, with the lines around it when contextLines is set.",
        "tags": [
          "filesystem"
        ],
        "summary": "Search for text content in files",
        "parameters": [
          {
            "description": "Directory path to search in",
            "name": "path",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Text to search for",
            "name": "query",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Case sensitive search (default: false)",
            "name": "caseSensitive",
            "in": "query",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "description": "Maximum number of results to return (default: 100)",
            "name": "maxResults",
            "in": "query",
            "schema": {
              "type": "integer"
            }
          },
          {
            "description": "File pattern to include (e.g., *.go)",
            "name": "filePattern",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Comma-separated directory names to skip (default: node_modules,vendor,.git,dist,build,target,__pycache__,.venv,.next,coverage)",
            "name": "excludeDirs",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Lines to include before and after each match in its context field (default: 0, max: 20; invalid values count as 0)",
            "name": "contextLines",
            "in": "query",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Content search results",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ContentSearchResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable entity",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/filesystem-find/{path}": {
      "get": {
        "description": "Finds files and directories using the find command.",
        "tags": [
          "filesystem"
        ],
        "summary": "Find files and directories",
        "parameters": [
          {
            "description": "Path to search in (e.g., /home/user/projects)",
            "name": "path",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Type of search (file or directory)",
            "name": "type",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Comma-separated file patterns to include (e.g., *.go,*.js)",
            "name": "patterns",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Maximum number of results to return (default: 20). If set to 0, all results will be returned.",
            "name": "maxResults",
            "in": "query",
            "schema": {
              "type": "integer"
            }
          },
          {
            "description": "Comma-separated directory names to skip (default: node_modules,vendor,.git,dist,build,target,__pycache__,.venv,.next,coverage). Use empty string to skip no directories.",
            "name": "excludeDirs",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Exclude hidden files and directories (default: true)",
            "name": "excludeHidden",
            "in": "query",
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Find results",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FindResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable entity",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/filesystem-multipart": {
      "get": {
        "description": "List all active multipart uploads",
        "tags": [
          "filesystem"
        ],
        "summary": "List multipart uploads",
        "responses": {
          "200": {
            "description": "List of active uploads",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MultipartListUploadsResponse"
                }
              }
            }
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/filesystem-multipart/initiate/{path}": {
      "post": {
        "description": "Initiate a multipart upload session for a file",
        "tags": [
          "filesystem"
        ],
        "summary": "Initiate multipart upload",
        "parameters": [
          {
            "description": "File path",
            "name": "path",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MultipartInitiateRequest"
              }
            }
          },
          "description": "Optional permissions"
        },
        "responses": {
          "200": {
            "description": "Upload session created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MultipartInitiateResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/filesystem-multipart/{uploadId}/abort": {
      "delete": {
        "description": "Abort a multipart upload and clean up all parts",
        "tags": [
          "filesystem"
        ],
        "summary": "Abort multipart upload",
        "parameters": [
          {
            "description": "Upload ID",
            "name": "uploadId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Upload aborted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SuccessResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Upload not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/filesystem-multipart/{uploadId}/complete": {
      "post": {
        "description": "Complete a multipart upload by assembling all parts",
        "tags": [
          "filesystem"
        ],
        "summary": "Complete multipart upload",
        "parameters": [
          {
            "description": "Upload ID",
            "name": "uploadId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MultipartCompleteRequest"
              }
            }
          },
          "description": "List of parts",
          "required": true
        },
        "responses": {
          "200": {
            "description": "Upload completed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SuccessResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Upload not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/filesystem-multipart/{uploadId}/part": {
      "put": {
        "description": "Upload a single part of a multipart upload. Re-uploading a part number replaces that part. Wait for the previous request for that part to finish before retrying.",
        "tags": [
          "filesystem"
        ],
        "summary": "Upload part",
        "parameters": [
          {
            "description": "Upload ID",
            "name": "uploadId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Part number (1-10000)",
            "name": "partNumber",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "requestBody": {
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "properties": {
                  "file": {
                    "description": "Part data",
                    "type": "string",
                    "format": "binary"
                  }
                },
                "required": [
                  "file"
                ]
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Part uploaded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MultipartUploadPartResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Upload not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/filesystem-multipart/{uploadId}/parts": {
      "get": {
        "description": "List all uploaded parts for a multipart upload",
        "tags": [
          "filesystem"
        ],
        "summary": "List parts",
        "parameters": [
          {
            "description": "Upload ID",
            "name": "uploadId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of parts",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MultipartListPartsResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Upload not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/filesystem-search/{path}": {
      "get": {
        "description": "Ranks the files and directories under a path by how well their relative path fuzzy-matches `query` (fzf algorithm: the query's characters must appear in order, not necessarily next to each other), best match first.\nFuzzy search is for \"jump to file\" lookups from a partial name. The `patterns` parameter is currently ignored by this endpoint; use find for exact glob filtering.",
        "tags": [
          "filesystem"
        ],
        "summary": "Fuzzy search for files and directories",
        "parameters": [
          {
            "description": "Path to search in (e.g., /home/user/projects)",
            "name": "path",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Fuzzy pattern matched against each relative path (e.g., mngo for src/main.go). When omitted, the search path itself is used as the pattern.",
            "name": "query",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Maximum number of results to return (default: 20)",
            "name": "maxResults",
            "in": "query",
            "schema": {
              "type": "integer"
            }
          },
          {
            "description": "Accepted for compatibility but currently ignored; use filesystem-find for glob filtering",
            "name": "patterns",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Comma-separated directory names to skip (default: node_modules,vendor,.git,dist,build,target,__pycache__,.venv,.next,coverage). Use empty string to skip no directories.",
            "name": "excludeDirs",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Exclude hidden files and directories (default: true)",
            "name": "excludeHidden",
            "in": "query",
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Fuzzy search results",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FuzzySearchResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable entity",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/filesystem/tree/{path}": {
      "get": {
        "description": "Get a recursive directory tree structure starting from the specified path",
        "tags": [
          "filesystem"
        ],
        "summary": "Get directory tree",
        "parameters": [
          {
            "description": "Root directory path",
            "name": "path",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Directory tree",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Directory"
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable entity",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      },
      "put": {
        "description": "Create or update multiple files within a directory tree structure. Idempotent: existing files are overwritten, so retrying the same request is safe.",
        "tags": [
          "filesystem"
        ],
        "summary": "Create or update directory tree",
        "parameters": [
          {
            "description": "Root directory path",
            "name": "path",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TreeRequest"
              }
            }
          },
          "description": "Map of file paths to content",
          "required": true
        },
        "responses": {
          "200": {
            "description": "Updated directory tree",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Directory"
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable entity",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      },
      "delete": {
        "description": "Delete a directory tree recursively",
        "tags": [
          "filesystem"
        ],
        "summary": "Delete directory tree",
        "parameters": [
          {
            "description": "Root directory path",
            "name": "path",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Delete directory recursively",
            "name": "recursive",
            "in": "query",
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Directory deleted successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SuccessResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable entity",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/filesystem/{path}": {
      "get": {
        "description": "Get content of a file or listing of a directory. Use Accept header to control response format for files.",
        "tags": [
          "filesystem"
        ],
        "summary": "Get file or directory information",
        "parameters": [
          {
            "description": "File or directory path. Relative paths are resolved against the filesystem working directory. For example, with a working directory of /app, GET /filesystem/workspace resolves to /app/workspace. To access the absolute path /workspace over HTTP, encode its leading slash as %2F: GET /filesystem/%2Fworkspace. The double-slash form GET /filesystem//workspace also addresses /workspace.",
            "name": "path",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Force download mode for files",
            "name": "download",
            "in": "query",
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Directory listing",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Directory"
                }
              },
              "application/octet-stream": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "404": {
            "description": "File or directory not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              },
              "application/octet-stream": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable entity",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              },
              "application/octet-stream": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              },
              "application/octet-stream": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      },
      "put": {
        "description": "Create or update a file or directory.\n\nIdempotent: an existing file is overwritten (truncated, not appended to) and an existing directory is kept, so retrying the same request is safe.\n\nSend either a JSON body (FileRequest) or `multipart/form-data` for binary files. Multipart fields, in any order: `file` (required, the file content), `permissions` (optional octal mode such as `0755`, applied when the file is created, default `0644`; an existing file keeps its mode), `path` (optional, ignored: the target is always the URL path).",
        "tags": [
          "filesystem"
        ],
        "summary": "Create or update a file or directory",
        "parameters": [
          {
            "description": "File or directory path",
            "name": "path",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FileRequest"
              }
            },
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": [
                  "file"
                ],
                "properties": {
                  "file": {
                    "type": "string",
                    "format": "binary",
                    "description": "File content."
                  },
                  "permissions": {
                    "type": "string",
                    "description": "Octal file mode, applied when the file is created."
                  },
                  "path": {
                    "type": "string",
                    "description": "Ignored; the target is the URL path."
                  }
                }
              }
            }
          },
          "description": "File or directory details",
          "required": true
        },
        "responses": {
          "200": {
            "description": "Success message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SuccessResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable entity",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      },
      "delete": {
        "description": "Delete a file or directory",
        "tags": [
          "filesystem"
        ],
        "summary": "Delete file or directory",
        "parameters": [
          {
            "description": "File or directory path",
            "name": "path",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Delete directory recursively",
            "name": "recursive",
            "in": "query",
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SuccessResponse"
                }
              }
            }
          },
          "404": {
            "description": "File or directory not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable entity",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      },
      "head": {
        "description": "Returns the metadata of a file or directory as headers, with no body. This checks stat availability, not permission to read file contents or list a directory. When the path does not exist or its metadata cannot be accessed, the response is an empty 200 without the X-File-Type header.",
        "tags": [
          "filesystem"
        ],
        "summary": "Stat a file or directory",
        "parameters": [
          {
            "description": "File or directory path",
            "name": "path",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Path metadata (X-File-Type is set only when stat succeeds)",
            "headers": {
              "Content-Length": {
                "description": "File size in bytes (files only)",
                "schema": {
                  "type": "integer"
                }
              },
              "Last-Modified": {
                "description": "Modification time (HTTP date)",
                "schema": {
                  "type": "string"
                }
              },
              "X-File-Mode": {
                "description": "Permission bits including sticky, setgid and setuid in octal (e.g., 644 or 1777)",
                "schema": {
                  "type": "string"
                }
              },
              "X-File-Type": {
                "description": "file or directory",
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "/health": {
      "get": {
        "description": "Returns health status and system information including upgrade count and binary details\nAlso includes last upgrade attempt status with detailed error information if available",
        "tags": [
          "system"
        ],
        "summary": "Health check",
        "responses": {
          "200": {
            "description": "Health status",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HealthResponse"
                }
              }
            }
          }
        }
      }
    },
    "/network/process/{pid}/monitor": {
      "post": {
        "description": "Start monitoring for new ports opened by a process",
        "tags": [
          "network"
        ],
        "summary": "Start monitoring ports for a process",
        "parameters": [
          {
            "description": "Process ID",
            "name": "pid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PortMonitorRequest"
              }
            }
          },
          "description": "Port monitor configuration",
          "required": true
        },
        "responses": {
          "200": {
            "description": "Object containing PID and success message",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "400": {
            "description": "Invalid request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable entity",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      },
      "delete": {
        "description": "Stop monitoring for new ports opened by a process",
        "tags": [
          "network"
        ],
        "summary": "Stop monitoring ports for a process",
        "parameters": [
          {
            "description": "Process ID",
            "name": "pid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Object containing PID and success message",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "400": {
            "description": "Invalid process ID",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable entity",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/network/process/{pid}/ports": {
      "get": {
        "description": "Get a list of all open ports for a process",
        "tags": [
          "network"
        ],
        "summary": "Get open ports for a process",
        "parameters": [
          {
            "description": "Process ID",
            "name": "pid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Object containing PID and array of network.PortInfo",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "400": {
            "description": "Invalid process ID",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable entity",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/network/tunnel": {
      "delete": {
        "description": "Stop the network tunnel and restore the original network configuration. WARNING: After disconnecting, the sandbox will lose all outbound internet connectivity (no egress). Inbound connections to the sandbox will still work. Use PUT /network/tunnel/config to re-establish the tunnel.",
        "tags": [
          "network"
        ],
        "summary": "Disconnect tunnel",
        "responses": {
          "200": {
            "description": "Tunnel disconnected",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SuccessResponse"
                }
              }
            }
          },
          "400": {
            "description": "No tunnel is running",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Failed to stop tunnel",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/network/tunnel/config": {
      "put": {
        "description": "Apply a new tunnel configuration on the fly. The existing tunnel is torn down and a new one is established. This endpoint is write-only; there is no corresponding GET to read the config back.",
        "tags": [
          "network"
        ],
        "summary": "Update tunnel configuration",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TunnelConfigRequest"
              }
            }
          },
          "description": "Base64-encoded tunnel configuration",
          "required": true
        },
        "responses": {
          "200": {
            "description": "Configuration applied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SuccessResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request body",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Invalid tunnel configuration",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Failed to apply configuration",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/process": {
      "get": {
        "description": "Get a list of all running and completed processes",
        "tags": [
          "process"
        ],
        "summary": "List all processes",
        "responses": {
          "200": {
            "description": "Process list",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/ProcessResponse"
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "description": "Execute a command and return process information.\n\nStreaming: with `Accept: application/x-ndjson` (or `Accept: text/event-stream`, kept for compatibility) the response is NDJSON (`Content-Type: application/x-ndjson`), not SSE: one JSON object per line, `{\"type\": \"...\", \"data\": \"...\"}`.\n`type` is `stdout` or `stderr` (`data` is a raw output chunk, sent as soon as the process writes it, newlines included; if the process finished before any chunk was streamed, its output is sent instead as one event per line, without the newline), `keepalive` (every 5 seconds, no data), `error` (`data` is the message, ends the stream) or `result` (last event, `data` is the ProcessResponse as a JSON string).",
        "tags": [
          "process"
        ],
        "summary": "Execute a command",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ProcessRequest"
              }
            }
          },
          "description": "Process execution request",
          "required": true
        },
        "responses": {
          "200": {
            "description": "Process information",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProcessResponse"
                }
              },
              "application/x-ndjson": {
                "schema": {
                  "type": "string",
                  "description": "NDJSON stream with one JSON event object per line. Each event has a `type` and optional `data` string; the final `result` event's `data` contains a serialized ProcessResponse."
                }
              }
            }
          },
          "400": {
            "description": "Invalid request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              },
              "application/x-ndjson": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable entity",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              },
              "application/x-ndjson": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              },
              "application/x-ndjson": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/process/{identifier}": {
      "get": {
        "description": "Get information about a process by its PID or name",
        "tags": [
          "process"
        ],
        "summary": "Get process by identifier",
        "parameters": [
          {
            "description": "Process identifier (PID or name)",
            "name": "identifier",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Process information",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProcessResponse"
                }
              }
            }
          },
          "404": {
            "description": "Process not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      },
      "delete": {
        "description": "Request graceful termination. Poll GET /process/{identifier} until terminal status confirms the managed process has exited.",
        "tags": [
          "process"
        ],
        "summary": "Stop a process",
        "parameters": [
          {
            "description": "Process identifier (PID or name)",
            "name": "identifier",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Process stop requested",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SuccessResponse"
                }
              }
            }
          },
          "404": {
            "description": "Process not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable entity",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/process/{identifier}/kill": {
      "delete": {
        "description": "Request forceful termination. Poll GET /process/{identifier} until terminal status confirms the managed process has exited.",
        "tags": [
          "process"
        ],
        "summary": "Kill a process",
        "parameters": [
          {
            "description": "Process identifier (PID or name)",
            "name": "identifier",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Process kill requested",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SuccessResponse"
                }
              }
            }
          },
          "404": {
            "description": "Process not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable entity",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/process/{identifier}/logs": {
      "get": {
        "description": "Get the stdout and stderr output of a process",
        "tags": [
          "process"
        ],
        "summary": "Get process logs",
        "parameters": [
          {
            "description": "Process identifier (PID or name)",
            "name": "identifier",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Process logs",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProcessLogs"
                }
              }
            }
          },
          "404": {
            "description": "Process not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable entity",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/process/{identifier}/logs/stream": {
      "get": {
        "description": "Streams the stdout and stderr output of a process in real time: the output so far, then live output as the process writes it. Closes when the process exits or the client disconnects.\nBy default, output is plain text with `stdout:` or `stderr:` prefixes at the start of each source stream's lines. Partial lines (e.g. prompts) are sent without waiting for a newline; their continuations have no new prefix. The other stream is not held back while a line is incomplete, and chronological order across stdout and stderr is not guaranteed.\nThis format does not provide unambiguous framing: output from the other stream, or a `[keepalive]` marker sent every 30 seconds, can appear inside an unfinished line. A later continuation can therefore lack a prefix identifying its source. Do not rely on this text stream to reconstruct stdout and stderr separately; request NDJSON for source-preserving streaming, or use GET /process/{identifier}/logs for separate output snapshots.\nWith `Accept: application/x-ndjson`, each line is a JSON object with `type` (`stdout`, `stderr`, `keepalive`, `restart`, `truncated`, or `error`) and optional `data`. Output records retain source identity and original bytes, including partial lines and newlines, for both retained history and live output. For `encoding: \"base64\"`, decode `data` before concatenating bytes per source; this occurs for binary data or a UTF-8 character split across chunks. Chunk boundaries are arbitrary and ordering is collection order, not a strict chronology across streams.\n`keepalive` has no output data. A quiet active stream sends an initial keepalive after attachment so clients can receive the response before sending stdin; subsequent keepalives are sent every 30 seconds. `restart` carries a supervisor restart notice, not process output. `truncated` reports a retention or slow-reader gap and must not be appended to stdout/stderr. `error` reports a streaming failure. The connection ends after the final process exit, including automatic restarts; there is no `result` record. Older processes without structured history return HTTP 409 for NDJSON; their text stream remains available.",
        "tags": [
          "process"
        ],
        "summary": "Stream process logs in real time",
        "parameters": [
          {
            "description": "Process identifier (PID or name)",
            "name": "identifier",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Explicit application/x-ndjson opts into structured records; absent or wildcard Accept retains text/plain. Supported explicit media types honor q weights, preferring NDJSON on a tie.",
            "name": "Accept",
            "in": "header",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Process output as prefixed text or NDJSON records",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              },
              "application/x-ndjson": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "Invalid process identifier",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              },
              "application/x-ndjson": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Process not found",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              },
              "application/x-ndjson": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "409": {
            "description": "Structured history unavailable for this older process",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              },
              "application/x-ndjson": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              },
              "application/x-ndjson": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/process/{identifier}/stdin": {
      "post": {
        "description": "Write the raw request body to the stdin of a process started with \"stdin\": true. Bytes are forwarded verbatim, so include the trailing newline your protocol expects. Sequential requests keep their order; each body is written atomically with respect to other writers. The pipe does not survive a sandbox-api restart: once it is gone this returns 409 and the process must be restarted.",
        "tags": [
          "process"
        ],
        "summary": "Write to a process's stdin",
        "parameters": [
          {
            "description": "Process identifier (PID or name)",
            "name": "identifier",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/octet-stream": {
              "schema": {
                "type": "string"
              }
            }
          },
          "description": "Raw bytes to write",
          "required": true
        },
        "responses": {
          "200": {
            "description": "Bytes written",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SuccessResponse"
                }
              }
            }
          },
          "404": {
            "description": "Process not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "409": {
            "description": "Process has no stdin, or stdin is closed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "413": {
            "description": "Body over 8 MiB",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Write failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Process stopped reading its stdin",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      },
      "delete": {
        "description": "Send EOF to the process by closing its stdin pipe. Idempotent. For stdio protocols such as MCP this is the clean shutdown path.",
        "tags": [
          "process"
        ],
        "summary": "Close a process's stdin",
        "parameters": [
          {
            "description": "Process identifier (PID or name)",
            "name": "identifier",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Stdin closed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SuccessResponse"
                }
              }
            }
          },
          "404": {
            "description": "Process not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "409": {
            "description": "Process has no stdin",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/upgrade": {
      "post": {
        "description": "Triggers an upgrade of the sandbox-api process. Returns 200 immediately before upgrading.\nThe upgrade will: download the specified binary from GitHub releases, validate it, and restart.\nAll running processes will be preserved across the upgrade.\nAvailable versions: \"latest\" (default, most recent release), \"develop\", \"main\", or specific tag like \"v1.0.0\"\nYou can also specify a custom baseUrl for forks (defaults to https://github.com/blaxel-ai/sandbox/releases)",
        "tags": [
          "system"
        ],
        "summary": "Upgrade the sandbox-api",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpgradeRequest"
              }
            }
          },
          "description": "Upgrade options"
        },
        "responses": {
          "200": {
            "description": "Upgrade initiated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SuccessResponse"
                }
              }
            }
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/watch/filesystem/{path}": {
      "get": {
        "description": "Streams change events for a directory until the client disconnects.\n\nThe body is JSON lines (sent with `Content-Type: text/plain`): one event object per line, e.g. `{\"op\":\"WRITE\",\"name\":\"main.go\",\"path\":\"/app/src\",\"error\":null}`. `op` is the fsnotify operation (CREATE, WRITE, REMOVE, RENAME or CHMOD, several can be joined with `|`), `name` the base name of the changed entry, `path` the directory containing it, and `error` is always null. A `[keepalive]` line (not JSON) is sent every 30 seconds.\nOnly the directory's direct entries are watched. To also watch every subdirectory, including ones created later, end the path with `/**`. The stream reports subsequent changes without an initial snapshot. When a new directory is detected, synthetic CREATE events are emitted for entries already present inside it to cover changes before its watch was registered.",
        "tags": [
          "filesystem"
        ],
        "summary": "Stream file modification events in a directory",
        "parameters": [
          {
            "description": "Comma-separated substrings; events whose full path contains one are skipped",
            "name": "ignore",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Directory path to watch (append /** to watch subdirectories)",
            "name": "path",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "JSON lines stream of change events",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "Invalid path",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    }
  },
  "servers": [
    {
      "url": "https://{sandbox_host}",
      "description": "Host from the sandbox's returned url, without the scheme or trailing slash.",
      "variables": {
        "sandbox_host": {
          "default": "sandbox.example.com"
        }
      }
    }
  ],
  "components": {
    "securitySchemes": {
      "BearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "Sandbox access token created through POST /v1/token."
      }
    },
    "schemas": {
      "ApplyEditRequest": {
        "type": "object",
        "required": [
          "codeEdit"
        ],
        "properties": {
          "codeEdit": {
            "type": "string",
            "example": "// Add world parameter\nfunction hello(world) {\n  console.log('Hello', world);\n}"
          },
          "model": {
            "type": "string",
            "example": "relace-apply-3"
          }
        }
      },
      "ApplyEditResponse": {
        "type": "object",
        "properties": {
          "message": {
            "type": "string",
            "example": "Code edit applied successfully"
          },
          "originalContent": {
            "type": "string",
            "example": "function hello() {\n  console.log('Hello');\n}"
          },
          "path": {
            "type": "string",
            "example": "src/main.js"
          },
          "provider": {
            "type": "string",
            "example": "Relace"
          },
          "success": {
            "type": "boolean",
            "example": true
          },
          "updatedContent": {
            "type": "string",
            "example": "function hello(world) {\n  console.log('Hello', world);\n}"
          }
        }
      },
      "ArchiveManifest": {
        "type": "object",
        "required": [
          "createdAt",
          "root",
          "version"
        ],
        "properties": {
          "added": {
            "description": "Added and Modified count the archive's payload members.",
            "type": "integer",
            "example": 11
          },
          "apiVersion": {
            "description": "APIVersion is the sandbox-api build that produced the archive.",
            "type": "string",
            "example": "v0.1.0"
          },
          "createdAt": {
            "type": "string"
          },
          "deleted": {
            "description": "Deleted are paths the image has and the sandbox deleted. Tar cannot carry\na deletion, so import applies these from the manifest.",
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "excludes": {
            "description": "Excludes are the paths left out of the comparison.",
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "imageDevice": {
            "description": "ImageDevice is the device the pristine image was read from, for the record:\nit says where the sandbox that exported the archive found its image.",
            "type": "string",
            "example": "/dev/vda"
          },
          "modified": {
            "type": "integer",
            "example": 3
          },
          "payloadBytes": {
            "description": "PayloadBytes is the total content size of the payload members.",
            "type": "integer",
            "example": 3073449
          },
          "processes": {
            "description": "Processes tells whether ProcessesName is present.",
            "type": "boolean",
            "example": true
          },
          "root": {
            "description": "Root is the directory the paths are relative to.",
            "type": "string",
            "example": "/"
          },
          "version": {
            "type": "integer",
            "example": 1
          }
        }
      },
      "ContentSearchMatch": {
        "type": "object",
        "required": [
          "column",
          "line",
          "path",
          "text"
        ],
        "properties": {
          "column": {
            "type": "integer",
            "example": 10
          },
          "context": {
            "description": "The matching line with up to contextLines lines before and after it, newline-separated; omitted when contextLines is 0",
            "type": "string",
            "example": "previous line\ncurrent line\nnext line"
          },
          "line": {
            "type": "integer",
            "example": 42
          },
          "path": {
            "type": "string",
            "example": "src/main.go"
          },
          "text": {
            "type": "string",
            "example": "const searchText = 'example'"
          }
        }
      },
      "ContentSearchResponse": {
        "type": "object",
        "required": [
          "matches",
          "query",
          "total"
        ],
        "properties": {
          "matches": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ContentSearchMatch"
            }
          },
          "query": {
            "type": "string",
            "example": "searchText"
          },
          "total": {
            "type": "integer",
            "example": 5
          }
        }
      },
      "Directory": {
        "type": "object",
        "required": [
          "files",
          "name",
          "path",
          "subdirectories"
        ],
        "properties": {
          "files": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/File"
            }
          },
          "name": {
            "type": "string"
          },
          "path": {
            "type": "string"
          },
          "subdirectories": {
            "description": "@name Subdirectories",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Subdirectory"
            }
          }
        }
      },
      "DriveListResponse": {
        "type": "object",
        "properties": {
          "mounts": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/DriveMountInfo"
            }
          }
        }
      },
      "DriveMountInfo": {
        "type": "object",
        "properties": {
          "driveName": {
            "type": "string"
          },
          "drivePath": {
            "type": "string"
          },
          "gidMap": {
            "description": "The local GID used for this mount",
            "type": "string"
          },
          "mountPath": {
            "type": "string"
          },
          "readOnly": {
            "type": "boolean"
          },
          "uidMap": {
            "description": "The local UID used for this mount",
            "type": "string"
          }
        }
      },
      "DriveMountRequest": {
        "type": "object",
        "required": [
          "driveName",
          "mountPath"
        ],
        "properties": {
          "driveName": {
            "type": "string"
          },
          "drivePath": {
            "description": "Optional, defaults to \"/\"",
            "type": "string"
          },
          "gidMap": {
            "description": "Optional, local GID to map (filer GID is always 0)",
            "type": "string"
          },
          "mountPath": {
            "type": "string"
          },
          "readOnly": {
            "description": "Optional, defaults to false",
            "type": "boolean"
          },
          "uidMap": {
            "description": "Optional, local UID to map (filer UID is always 0)",
            "type": "string"
          }
        }
      },
      "DriveMountResponse": {
        "type": "object",
        "properties": {
          "driveName": {
            "type": "string"
          },
          "drivePath": {
            "type": "string"
          },
          "gidMap": {
            "description": "The local GID used for this mount",
            "type": "string"
          },
          "message": {
            "type": "string"
          },
          "mountPath": {
            "type": "string"
          },
          "readOnly": {
            "type": "boolean"
          },
          "success": {
            "type": "boolean"
          },
          "uidMap": {
            "description": "The local UID used for this mount",
            "type": "string"
          }
        }
      },
      "DriveUnmountResponse": {
        "type": "object",
        "properties": {
          "message": {
            "type": "string"
          },
          "mountPath": {
            "type": "string"
          },
          "success": {
            "type": "boolean"
          }
        }
      },
      "ErrorResponse": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "string",
            "example": "Error message"
          }
        }
      },
      "ExportOptions": {
        "type": "object",
        "properties": {
          "async": {
            "description": "Async starts the export and answers immediately, leaving it to run: an\narchive of a large filesystem takes longer than a request may be held\nopen. Its progress is reported by /archive/status.",
            "type": "boolean",
            "example": false
          },
          "dryRun": {
            "description": "DryRun reports what would be archived, and its exact size, without\nstopping anything and without uploading.",
            "type": "boolean",
            "example": false
          },
          "excludes": {
            "description": "Excludes are added to the paths excluded by default.",
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "headers": {
            "description": "Headers are sent with the upload request as given. A presigned URL only\naccepts the headers it was signed for, so these have to match what the\ncaller signed: sending one that was not signed, or signing one that is not\nsent, is rejected as a signature mismatch. Typical use is a storage class,\nx-amz-storage-class: GLACIER_IR.",
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "imageDevice": {
            "description": "ImageDevice is the device holding the pristine image. It is found on its\nown, wherever the sandbox booted from attached it, and naming one here\nonly overrides that.",
            "type": "string",
            "example": "/dev/vda"
          },
          "imageMountPoint": {
            "description": "ImageMountPoint is a directory where the pristine image is already mounted.\nWhen set the image device is neither mounted nor unmounted.",
            "type": "string",
            "example": "/mnt/lower"
          },
          "multipart": {
            "description": "Multipart uploads the archive part by part instead, which is how an\narchive larger than the 5 GB a single PUT accepts is stored. It takes\nprecedence over URL.",
            "allOf": [
              {
                "$ref": "#/components/schemas/MultipartUpload"
              }
            ]
          },
          "saveProcesses": {
            "description": "SaveProcesses stores the process list in the archive so restore can\nrelaunch the workload. Defaults to true; set it to false to archive\nstorage only.",
            "type": "boolean",
            "example": true
          },
          "stopTimeoutSeconds": {
            "description": "StopTimeoutSeconds bounds the graceful stop of each process.",
            "type": "integer",
            "example": 30
          },
          "url": {
            "description": "URL is a presigned S3 PUT URL the archive is streamed to. Empty is only\nvalid with DryRun, or with Multipart.",
            "type": "string",
            "example": "https://bucket.s3.amazonaws.com/key?..."
          }
        }
      },
      "ExportProgress": {
        "type": "object",
        "properties": {
          "error": {
            "description": "Error is why the export failed, without the presigned URL it used.",
            "type": "string"
          },
          "finishedAt": {
            "type": "string"
          },
          "size": {
            "description": "Size is the archive's exact size, known once the filesystem is scanned.",
            "type": "integer",
            "example": 3074211
          },
          "startedAt": {
            "type": "string"
          },
          "state": {
            "allOf": [
              {
                "$ref": "#/components/schemas/archive.ExportState"
              }
            ],
            "example": "running"
          },
          "uploaded": {
            "description": "Uploaded reports whether the storage holds the archive.",
            "type": "boolean",
            "example": false
          }
        }
      },
      "ExportResult": {
        "type": "object",
        "required": [
          "manifest"
        ],
        "properties": {
          "changes": {
            "description": "Changes lists every path in the archive. Only filled for a dry run,\nwhere it is the point of the call.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/archive.Change"
            }
          },
          "duration": {
            "type": "string",
            "example": "4.2s"
          },
          "manifest": {
            "$ref": "#/components/schemas/ArchiveManifest"
          },
          "size": {
            "description": "Size is the exact number of bytes uploaded, known before the upload\nstarts since the archive is not compressed.",
            "type": "integer",
            "example": 3074211
          },
          "stoppedProcesses": {
            "description": "StoppedProcesses are the processes stopped to freeze the filesystem.",
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "uploaded": {
            "description": "Uploaded is false for a dry run.",
            "type": "boolean",
            "example": true
          }
        }
      },
      "File": {
        "type": "object",
        "required": [
          "group",
          "lastModified",
          "name",
          "owner",
          "path",
          "permissions",
          "size"
        ],
        "properties": {
          "group": {
            "type": "string"
          },
          "lastModified": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "owner": {
            "type": "string"
          },
          "path": {
            "type": "string"
          },
          "permissions": {
            "type": "string"
          },
          "size": {
            "type": "integer"
          }
        }
      },
      "FileRequest": {
        "type": "object",
        "properties": {
          "content": {
            "type": "string",
            "example": "file contents here"
          },
          "isDirectory": {
            "type": "boolean",
            "example": false
          },
          "permissions": {
            "type": "string",
            "example": "0644"
          }
        }
      },
      "FileWithContent": {
        "type": "object",
        "required": [
          "content",
          "group",
          "lastModified",
          "name",
          "owner",
          "path",
          "permissions",
          "size"
        ],
        "properties": {
          "content": {
            "type": "string"
          },
          "group": {
            "type": "string"
          },
          "lastModified": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "owner": {
            "type": "string"
          },
          "path": {
            "type": "string"
          },
          "permissions": {
            "type": "string"
          },
          "size": {
            "type": "integer"
          }
        }
      },
      "FindMatch": {
        "type": "object",
        "required": [
          "path",
          "type"
        ],
        "properties": {
          "path": {
            "type": "string",
            "example": "src/main.go"
          },
          "type": {
            "description": "\"file\" or \"directory\"",
            "type": "string",
            "example": "file"
          }
        }
      },
      "FindResponse": {
        "type": "object",
        "required": [
          "matches",
          "total"
        ],
        "properties": {
          "matches": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FindMatch"
            }
          },
          "total": {
            "type": "integer",
            "example": 5
          }
        }
      },
      "FuzzySearchMatch": {
        "type": "object",
        "required": [
          "path",
          "score",
          "type"
        ],
        "properties": {
          "path": {
            "type": "string",
            "example": "src/main.go"
          },
          "score": {
            "type": "integer",
            "example": 100
          },
          "type": {
            "description": "\"file\" or \"directory\"",
            "type": "string",
            "example": "file"
          }
        }
      },
      "FuzzySearchResponse": {
        "type": "object",
        "required": [
          "matches",
          "total"
        ],
        "properties": {
          "matches": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FuzzySearchMatch"
            }
          },
          "total": {
            "type": "integer",
            "example": 5
          }
        }
      },
      "HealthResponse": {
        "type": "object",
        "required": [
          "arch",
          "buildTime",
          "gitCommit",
          "goVersion",
          "lastUpgrade",
          "os",
          "startedAt",
          "status",
          "upgradeCount",
          "uptime",
          "uptimeSeconds",
          "version"
        ],
        "properties": {
          "arch": {
            "type": "string",
            "example": "amd64"
          },
          "buildTime": {
            "description": "Build time in RFC 3339 (UTC), or \"unknown\" for builds without it",
            "type": "string",
            "example": "2026-01-29T17:36:52Z"
          },
          "gitCommit": {
            "type": "string",
            "example": "abc123"
          },
          "goVersion": {
            "type": "string",
            "example": "go1.25.0"
          },
          "lastUpgrade": {
            "$ref": "#/components/schemas/UpgradeStatus"
          },
          "os": {
            "type": "string",
            "example": "linux"
          },
          "startedAt": {
            "description": "API start time in RFC 3339",
            "type": "string",
            "example": "2026-01-29T18:45:49Z"
          },
          "status": {
            "type": "string",
            "example": "ok"
          },
          "upgradeCount": {
            "type": "integer",
            "example": 0
          },
          "uptime": {
            "type": "string",
            "example": "1h30m"
          },
          "uptimeSeconds": {
            "type": "number",
            "example": 5400.5
          },
          "version": {
            "type": "string",
            "example": "v0.1.0"
          }
        }
      },
      "MultipartCompleteRequest": {
        "type": "object",
        "properties": {
          "parts": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MultipartPartInfo"
            }
          }
        }
      },
      "MultipartInitiateRequest": {
        "type": "object",
        "properties": {
          "permissions": {
            "type": "string",
            "example": "0644"
          }
        }
      },
      "MultipartInitiateResponse": {
        "type": "object",
        "properties": {
          "path": {
            "type": "string",
            "example": "/tmp/largefile.dat"
          },
          "uploadId": {
            "type": "string",
            "example": "550e8400-e29b-41d4-a716-446655440000"
          }
        }
      },
      "MultipartListPartsResponse": {
        "type": "object",
        "properties": {
          "parts": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/filesystem.UploadedPart"
            }
          },
          "uploadId": {
            "type": "string",
            "example": "550e8400-e29b-41d4-a716-446655440000"
          }
        }
      },
      "MultipartListUploadsResponse": {
        "type": "object",
        "properties": {
          "uploads": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/filesystem.MultipartUpload"
            }
          }
        }
      },
      "MultipartPartInfo": {
        "type": "object",
        "properties": {
          "etag": {
            "type": "string",
            "example": "5d41402abc4b2a76b9719d911017c592"
          },
          "partNumber": {
            "type": "integer",
            "example": 1
          }
        }
      },
      "MultipartUpload": {
        "type": "object",
        "properties": {
          "abortUrl": {
            "description": "AbortURL is a presigned DELETE URL that discards the parts already\nuploaded. Without it a failed export leaves them on the storage until a\nlifecycle rule removes them.",
            "type": "string"
          },
          "completeUrl": {
            "description": "CompleteURL is a presigned POST URL that assembles the parts.",
            "type": "string"
          },
          "partSize": {
            "description": "PartSize is the number of bytes sent to every part but the last.",
            "type": "integer",
            "example": 536870912
          },
          "partUrls": {
            "description": "PartURLs are presigned PUT URLs, one per part, in order. Extra ones are\nleft unused.",
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "MultipartUploadPartResponse": {
        "type": "object",
        "properties": {
          "etag": {
            "type": "string",
            "example": "5d41402abc4b2a76b9719d911017c592"
          },
          "partNumber": {
            "type": "integer",
            "example": 1
          },
          "size": {
            "type": "integer",
            "example": 5242880
          }
        }
      },
      "PortMonitorRequest": {
        "type": "object",
        "properties": {
          "callback": {
            "description": "URL to call when a new port is detected",
            "type": "string",
            "example": "http://localhost:3000/callback"
          }
        }
      },
      "ProcessLogs": {
        "type": "object",
        "required": [
          "logs",
          "stderr",
          "stdout"
        ],
        "properties": {
          "logs": {
            "description": "Concatenation of the returned stdout followed by the returned stderr. Output from the two streams is not interleaved.",
            "type": "string",
            "example": "logs output"
          },
          "stderr": {
            "type": "string",
            "example": "stderr output"
          },
          "stdout": {
            "type": "string",
            "example": "stdout output"
          }
        }
      },
      "ProcessRequest": {
        "type": "object",
        "required": [
          "command"
        ],
        "properties": {
          "command": {
            "type": "string",
            "example": "ls -la"
          },
          "env": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            },
            "example": {
              "PORT": "3000"
            }
          },
          "keepAlive": {
            "description": "Disable scale-to-zero while process runs. Default timeout is 600s (10 minutes). Set timeout to 0 for infinite.",
            "type": "boolean",
            "example": false
          },
          "maxRestarts": {
            "description": "Maximum number of restarts on failure. Set to a negative value (e.g. -1) for unlimited restarts.",
            "type": "integer",
            "example": 3
          },
          "name": {
            "type": "string",
            "example": "my-process"
          },
          "restartOnFailure": {
            "type": "boolean",
            "example": true
          },
          "stdin": {
            "description": "Open a writable stdin pipe, fed via POST /process/{identifier}/stdin and closed via DELETE. The pipe does not survive a sandbox-api restart: the process then sees EOF.",
            "type": "boolean",
            "example": false
          },
          "timeout": {
            "description": "Timeout in seconds. When keepAlive is true, defaults to 600s (10 minutes). Set to 0 for infinite (no auto-kill).",
            "type": "integer",
            "example": 30
          },
          "waitForCompletion": {
            "type": "boolean",
            "example": false
          },
          "waitForPorts": {
            "type": "array",
            "items": {
              "type": "integer"
            },
            "example": [
              3000,
              8080
            ]
          },
          "workingDir": {
            "type": "string",
            "example": "/home/user"
          }
        }
      },
      "ProcessResponse": {
        "type": "object",
        "required": [
          "command",
          "completedAt",
          "exitCode",
          "logs",
          "name",
          "pid",
          "startedAt",
          "status",
          "stderr",
          "stdout",
          "workingDir"
        ],
        "properties": {
          "command": {
            "type": "string",
            "example": "ls -la"
          },
          "completedAt": {
            "description": "Completion time, same format as startedAt. Empty string while the process runs",
            "type": "string",
            "example": "Wed, 01 Jan 2023 12:01:00 GMT"
          },
          "exitCode": {
            "type": "integer",
            "example": 0
          },
          "keepAlive": {
            "description": "Whether scale-to-zero is disabled for this process",
            "type": "boolean",
            "example": false
          },
          "logs": {
            "type": "string",
            "example": "logs output"
          },
          "maxRestarts": {
            "type": "integer",
            "example": 3
          },
          "name": {
            "type": "string",
            "example": "my-process"
          },
          "pid": {
            "type": "string",
            "example": "1234"
          },
          "restartCount": {
            "type": "integer",
            "example": 2
          },
          "restartOnFailure": {
            "type": "boolean",
            "example": true
          },
          "startedAt": {
            "description": "Start time as an HTTP date (RFC 1123, e.g. Wed, 01 Jan 2023 12:00:00 GMT)",
            "type": "string",
            "example": "Wed, 01 Jan 2023 12:00:00 GMT"
          },
          "status": {
            "type": "string",
            "enum": [
              "failed",
              "killed",
              "stopped",
              "running",
              "completed"
            ],
            "example": "running"
          },
          "stderr": {
            "type": "string",
            "example": "stderr output"
          },
          "stdin": {
            "description": "Whether the process was started with a writable stdin pipe",
            "type": "boolean",
            "example": false
          },
          "stdout": {
            "type": "string",
            "example": "stdout output"
          },
          "workingDir": {
            "type": "string",
            "example": "/home/user"
          }
        }
      },
      "QuiesceStatus": {
        "type": "object",
        "required": [
          "state"
        ],
        "properties": {
          "export": {
            "description": "Export reports the export started asynchronously, if there was one. It is\nhow a caller that did not wait for the export learns that the archive is\non the storage, or why it is not.",
            "allOf": [
              {
                "$ref": "#/components/schemas/ExportProgress"
              }
            ]
          },
          "readOnlyRoot": {
            "description": "ReadOnlyRoot reports whether the root mount was remounted read-only, which\nis what actually stops writes; false means the freeze relies only on the\nAPI refusing calls, and the reason says why.",
            "type": "boolean",
            "example": true
          },
          "reason": {
            "description": "Reason is a human readable explanation of why the sandbox is frozen.",
            "type": "string",
            "example": "archive export"
          },
          "restore": {
            "description": "Restore reports the archive this sandbox was started from, if it was\nstarted from one: how far its restore has got, and how it ended.",
            "allOf": [
              {
                "$ref": "#/components/schemas/RestoreProgress"
              }
            ]
          },
          "since": {
            "description": "Since is when the sandbox left StateActive.",
            "type": "string"
          },
          "state": {
            "allOf": [
              {
                "$ref": "#/components/schemas/archive.QuiesceState"
              }
            ],
            "example": "quiesced"
          },
          "stoppedProcesses": {
            "description": "StoppedProcesses are the process identifiers stopped while quiescing.",
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "RankedFile": {
        "type": "object",
        "properties": {
          "content": {
            "type": "string"
          },
          "path": {
            "type": "string"
          },
          "score": {
            "type": "number"
          }
        }
      },
      "RerankingResponse": {
        "type": "object",
        "properties": {
          "files": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RankedFile"
            }
          },
          "message": {
            "type": "string",
            "example": "Found 5 relevant files"
          },
          "success": {
            "type": "boolean",
            "example": true
          }
        }
      },
      "RestoreProgress": {
        "type": "object",
        "properties": {
          "deleted": {
            "type": "integer",
            "example": 3
          },
          "downloaded": {
            "description": "Downloaded is how much of the archive has been read so far.",
            "type": "integer",
            "example": 1048576
          },
          "error": {
            "description": "Error is why the restore failed, without the presigned URL it used.",
            "type": "string"
          },
          "finishedAt": {
            "type": "string"
          },
          "restored": {
            "description": "Restored and Deleted count what the archive changed on the filesystem.",
            "type": "integer",
            "example": 1204
          },
          "size": {
            "description": "Size is the archive's size as the storage announced it, and zero when it\nannounced none - a client showing a percentage has to allow for that.",
            "type": "integer",
            "example": 3074211
          },
          "startedAt": {
            "type": "string"
          },
          "state": {
            "allOf": [
              {
                "$ref": "#/components/schemas/archive.RestoreState"
              }
            ],
            "example": "extracting"
          }
        }
      },
      "Subdirectory": {
        "type": "object",
        "required": [
          "name",
          "path"
        ],
        "properties": {
          "name": {
            "type": "string"
          },
          "path": {
            "type": "string"
          }
        }
      },
      "SuccessResponse": {
        "type": "object",
        "required": [
          "message"
        ],
        "properties": {
          "message": {
            "type": "string",
            "example": "File created successfully"
          },
          "path": {
            "type": "string",
            "example": "/path/to/file"
          }
        }
      },
      "TreeRequest": {
        "type": "object",
        "properties": {
          "files": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            },
            "example": {
              "file1.txt": "content1",
              "dir/file2.txt": "content2"
            }
          }
        }
      },
      "TunnelConfigRequest": {
        "type": "object",
        "required": [
          "config"
        ],
        "properties": {
          "config": {
            "description": "Base64-encoded tunnel config JSON",
            "type": "string",
            "example": "eyJsb2NhbF9pcCI6ICIxMC4wLjAuMS8zMiIsIC4uLn0="
          }
        }
      },
      "UpgradeRequest": {
        "type": "object",
        "properties": {
          "baseUrl": {
            "description": "Base URL for releases (useful for forks)",
            "type": "string",
            "example": "https://github.com/blaxel-ai/sandbox/releases"
          },
          "version": {
            "description": "Version to upgrade to: \"latest\" (default), \"develop\", \"main\", or specific tag like \"v1.0.0\"",
            "type": "string",
            "example": "latest"
          }
        }
      },
      "UpgradeStatus": {
        "type": "object",
        "required": [
          "status",
          "step",
          "version"
        ],
        "properties": {
          "binaryPath": {
            "description": "Path to downloaded binary",
            "type": "string",
            "example": "/tmp/sandbox-api-new"
          },
          "bytesDownloaded": {
            "description": "Bytes downloaded",
            "type": "integer",
            "example": 25034936
          },
          "downloadUrl": {
            "description": "URL used for download",
            "type": "string",
            "example": "https://github.com/..."
          },
          "error": {
            "description": "Error message if failed",
            "type": "string",
            "example": "Failed to download binary"
          },
          "lastAttempt": {
            "description": "When the upgrade was attempted",
            "type": "string"
          },
          "status": {
            "description": "Current state (idle, running, completed, failed)",
            "allOf": [
              {
                "$ref": "#/components/schemas/process.UpgradeState"
              }
            ],
            "example": "running"
          },
          "step": {
            "description": "Current/last step (none, starting, download, validate, replace, completed, skipped)",
            "type": "string",
            "example": "download"
          },
          "version": {
            "description": "Version being upgraded to",
            "type": "string",
            "example": "latest"
          }
        }
      },
      "archive.Change": {
        "type": "object",
        "required": [
          "kind",
          "path"
        ],
        "properties": {
          "kind": {
            "allOf": [
              {
                "$ref": "#/components/schemas/archive.ChangeKind"
              }
            ],
            "example": "added"
          },
          "path": {
            "description": "Path is relative to the root, without a leading slash.",
            "type": "string",
            "example": "usr/bin/curl"
          },
          "size": {
            "description": "Size is the file content size in bytes, 0 for anything but a regular file.",
            "type": "integer",
            "example": 256216
          }
        }
      },
      "archive.ChangeKind": {
        "type": "string",
        "enum": [
          "added",
          "modified",
          "deleted"
        ],
        "x-enum-varnames": [
          "ChangeAdded",
          "ChangeModified",
          "ChangeDeleted"
        ]
      },
      "archive.ExportState": {
        "type": "string",
        "enum": [
          "running",
          "succeeded",
          "failed"
        ],
        "x-enum-varnames": [
          "ExportRunning",
          "ExportSucceeded",
          "ExportFailed"
        ]
      },
      "archive.QuiesceState": {
        "type": "string",
        "enum": [
          "active",
          "quiescing",
          "quiesced",
          "restoring"
        ],
        "x-enum-varnames": [
          "StateActive",
          "StateQuiescing",
          "StateQuiesced",
          "StateRestoring"
        ]
      },
      "archive.RestoreState": {
        "type": "string",
        "enum": [
          "downloading",
          "extracting",
          "relaunching",
          "succeeded",
          "failed"
        ],
        "x-enum-varnames": [
          "RestoreDownloading",
          "RestoreExtracting",
          "RestoreRelaunching",
          "RestoreSucceeded",
          "RestoreFailed"
        ]
      },
      "filesystem.MultipartUpload": {
        "type": "object",
        "properties": {
          "initiatedAt": {
            "type": "string"
          },
          "parts": {
            "type": "object",
            "additionalProperties": {
              "$ref": "#/components/schemas/filesystem.UploadedPart"
            }
          },
          "path": {
            "type": "string",
            "example": "/tmp/largefile.dat"
          },
          "permissions": {
            "type": "integer",
            "example": 420
          },
          "uploadId": {
            "type": "string",
            "example": "550e8400-e29b-41d4-a716-446655440000"
          }
        }
      },
      "filesystem.UploadedPart": {
        "type": "object",
        "properties": {
          "etag": {
            "type": "string",
            "example": "5d41402abc4b2a76b9719d911017c592"
          },
          "partNumber": {
            "type": "integer",
            "example": 1
          },
          "size": {
            "type": "integer",
            "example": 5242880
          },
          "uploadedAt": {
            "type": "string"
          }
        }
      },
      "handler.ReloadResponse": {
        "type": "object",
        "properties": {
          "applied": {
            "type": "integer"
          },
          "generation": {
            "type": "integer"
          },
          "removed": {
            "type": "integer"
          }
        }
      },
      "process.UpgradeState": {
        "type": "string",
        "enum": [
          "idle",
          "running",
          "completed",
          "failed"
        ],
        "x-enum-comments": {
          "UpgradeStateCompleted": "Upgrade completed successfully",
          "UpgradeStateFailed": "Upgrade failed",
          "UpgradeStateIdle": "No upgrade in progress",
          "UpgradeStateRunning": "Upgrade is currently running"
        },
        "x-enum-descriptions": [
          "No upgrade in progress",
          "Upgrade is currently running",
          "Upgrade completed successfully",
          "Upgrade failed"
        ],
        "x-enum-varnames": [
          "UpgradeStateIdle",
          "UpgradeStateRunning",
          "UpgradeStateCompleted",
          "UpgradeStateFailed"
        ]
      }
    }
  },
  "security": [
    {
      "BearerAuth": []
    }
  ]
}
