# Automation

## List automation projects

`GET /automation/projects`

```json
{
  "tags": [
    "Automation"
  ],
  "summary": "List automation projects",
  "description": "Every project saved in the launcher, with its blocks and run settings. These are the same projects the desktop **Automation** section edits.",
  "responses": {
    "200": {
      "description": "Project list.",
      "content": {
        "application/json": {
          "schema": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AutomationProject"
            }
          }
        }
      }
    },
    "401": {
      "$ref": "#/components/responses/Unauthorized"
    }
  }
}
```

## Create project

`POST /automation/projects`

```json
{
  "tags": [
    "Automation"
  ],
  "summary": "Create project",
  "requestBody": {
    "required": false,
    "content": {
      "application/json": {
        "schema": {
          "type": "object",
          "properties": {
            "name": {
              "type": "string",
              "description": "Uses `Untitled` when empty."
            }
          }
        }
      }
    }
  },
  "responses": {
    "200": {
      "description": "Created project.",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/AutomationProject"
          }
        }
      }
    },
    "401": {
      "$ref": "#/components/responses/Unauthorized"
    }
  }
}
```

## Get project

`GET /automation/projects/{id}`

```json
{
  "tags": [
    "Automation"
  ],
  "summary": "Get project",
  "parameters": [
    {
      "name": "id",
      "in": "path",
      "required": true,
      "schema": {
        "type": "string",
        "format": "uuid"
      }
    }
  ],
  "responses": {
    "200": {
      "description": "Project details.",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/AutomationProject"
          }
        }
      }
    },
    "401": {
      "$ref": "#/components/responses/Unauthorized"
    },
    "404": {
      "description": "Project not found.",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/Error"
          }
        }
      }
    }
  }
}
```

## Replace project

`PUT /automation/projects/{id}`

```json
{
  "tags": [
    "Automation"
  ],
  "summary": "Replace project",
  "description": "Replaces the entire project. Send the object returned by `GET`. The path ID takes precedence over the body ID. A missing project returns `404`; use `POST /automation/projects` to create one.",
  "parameters": [
    {
      "name": "id",
      "in": "path",
      "required": true,
      "schema": {
        "type": "string",
        "format": "uuid"
      }
    }
  ],
  "requestBody": {
    "required": true,
    "content": {
      "application/json": {
        "schema": {
          "$ref": "#/components/schemas/AutomationProject"
        }
      }
    }
  },
  "responses": {
    "200": {
      "description": "Saved project.",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/AutomationProject"
          }
        }
      }
    },
    "400": {
      "description": "Invalid project object.",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/Error"
          }
        }
      }
    },
    "401": {
      "$ref": "#/components/responses/Unauthorized"
    },
    "404": {
      "description": "Project not found.",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/Error"
          }
        }
      }
    }
  }
}
```

## Delete a project

`DELETE /automation/projects/{id}`

```json
{
  "tags": [
    "Automation"
  ],
  "summary": "Delete a project",
  "parameters": [
    {
      "name": "id",
      "in": "path",
      "required": true,
      "schema": {
        "type": "string",
        "format": "uuid"
      }
    }
  ],
  "responses": {
    "200": {
      "description": "Deleted.",
      "content": {
        "application/json": {
          "schema": {
            "type": "object",
            "properties": {
              "deleted": {
                "type": "boolean",
                "example": true
              },
              "id": {
                "type": "string",
                "format": "uuid"
              }
            }
          }
        }
      }
    },
    "401": {
      "$ref": "#/components/responses/Unauthorized"
    },
    "404": {
      "description": "Project not found.",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/Error"
          }
        }
      }
    }
  }
}
```

## Duplicate project

`POST /automation/projects/{id}/duplicate`

```json
{
  "tags": [
    "Automation"
  ],
  "summary": "Duplicate project",
  "parameters": [
    {
      "name": "id",
      "in": "path",
      "required": true,
      "schema": {
        "type": "string",
        "format": "uuid"
      }
    }
  ],
  "responses": {
    "200": {
      "description": "Duplicated project.",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/AutomationProject"
          }
        }
      }
    },
    "401": {
      "$ref": "#/components/responses/Unauthorized"
    },
    "404": {
      "description": "Project not found.",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/Error"
          }
        }
      }
    }
  }
}
```

## Export project bundle

`GET /automation/projects/{id}/export`

```json
{
  "tags": [
    "Automation"
  ],
  "summary": "Export project bundle",
  "description": "Parameters the project marked secret are emptied on the way out, so a bundle can be handed on without taking a password with it. The import side asks for them again.",
  "parameters": [
    {
      "name": "id",
      "in": "path",
      "required": true,
      "schema": {
        "type": "string",
        "format": "uuid"
      }
    }
  ],
  "responses": {
    "200": {
      "description": "Export bundle.",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/AutomationBundle"
          }
        }
      }
    },
    "401": {
      "$ref": "#/components/responses/Unauthorized"
    },
    "404": {
      "description": "Project not found.",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/Error"
          }
        }
      }
    }
  }
}
```

## Import project bundle

`POST /automation/import`

```json
{
  "tags": [
    "Automation"
  ],
  "summary": "Import project bundle",
  "description": "The bundle arrives as a new project with a new id.",
  "requestBody": {
    "required": true,
    "content": {
      "application/json": {
        "schema": {
          "$ref": "#/components/schemas/AutomationBundle"
        }
      }
    }
  },
  "responses": {
    "200": {
      "description": "Imported project.",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/AutomationProject"
          }
        }
      }
    },
    "400": {
      "description": "Invalid bundle or unsupported format version.",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/Error"
          }
        }
      }
    },
    "401": {
      "$ref": "#/components/responses/Unauthorized"
    }
  }
}
```

## Start project

`POST /automation/projects/{id}/run`

```json
{
  "tags": [
    "Automation"
  ],
  "summary": "Start project",
  "description": "Starts the project and returns immediately. Project blocks start the required browsers. Use `/status` to monitor progress.\n\nReturns `400` if the project is already running or has no enabled steps.",
  "parameters": [
    {
      "name": "id",
      "in": "path",
      "required": true,
      "schema": {
        "type": "string",
        "format": "uuid"
      }
    }
  ],
  "responses": {
    "200": {
      "description": "Project started.",
      "content": {
        "application/json": {
          "schema": {
            "type": "object",
            "properties": {
              "project_id": {
                "type": "string",
                "format": "uuid"
              },
              "running": {
                "type": "boolean",
                "example": true
              }
            }
          }
        }
      }
    },
    "400": {
      "description": "Project is already running or has no enabled steps.",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/Error"
          }
        }
      }
    },
    "401": {
      "$ref": "#/components/responses/Unauthorized"
    },
    "404": {
      "description": "Project not found.",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/Error"
          }
        }
      }
    },
    "501": {
      "description": "This build does not support automation.",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/Error"
          }
        }
      }
    }
  }
}
```

## Stop project

`POST /automation/projects/{id}/stop`

```json
{
  "tags": [
    "Automation"
  ],
  "summary": "Stop project",
  "description": "Requests that the run stop. Each browser finishes its current step before closing. Use `/status` to monitor the `running` field.",
  "parameters": [
    {
      "name": "id",
      "in": "path",
      "required": true,
      "schema": {
        "type": "string",
        "format": "uuid"
      }
    }
  ],
  "responses": {
    "200": {
      "description": "Stop requested.",
      "content": {
        "application/json": {
          "schema": {
            "type": "object",
            "properties": {
              "project_id": {
                "type": "string",
                "format": "uuid"
              },
              "stopping": {
                "type": "boolean",
                "example": true
              }
            }
          }
        }
      }
    },
    "401": {
      "$ref": "#/components/responses/Unauthorized"
    },
    "501": {
      "description": "This build does not support automation.",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/Error"
          }
        }
      }
    }
  }
}
```

## Get project run status

`GET /automation/projects/{id}/status`

```json
{
  "tags": [
    "Automation"
  ],
  "summary": "Get project run status",
  "description": "Returns `null` if the project is not running and has not run since launcher startup. `log` contains the recent entries shown in the fleet window. The full log is stored under `automation-runs/`.",
  "parameters": [
    {
      "name": "id",
      "in": "path",
      "required": true,
      "schema": {
        "type": "string",
        "format": "uuid"
      }
    }
  ],
  "responses": {
    "200": {
      "description": "Run status or `null`.",
      "content": {
        "application/json": {
          "schema": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/AutomationRun"
              },
              {
                "type": "null"
              }
            ]
          }
        }
      }
    },
    "401": {
      "$ref": "#/components/responses/Unauthorized"
    },
    "501": {
      "description": "This build does not support automation.",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/Error"
          }
        }
      }
    }
  }
}
```

## List active runs

`GET /automation/runs`

```json
{
  "tags": [
    "Automation"
  ],
  "summary": "List active runs",
  "responses": {
    "200": {
      "description": "Active run list.",
      "content": {
        "application/json": {
          "schema": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AutomationRun"
            }
          }
        }
      }
    },
    "401": {
      "$ref": "#/components/responses/Unauthorized"
    },
    "501": {
      "description": "This build does not support automation.",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/Error"
          }
        }
      }
    }
  }
}
```

## List installed modules

`GET /automation/modules`

```json
{
  "tags": [
    "Automation"
  ],
  "summary": "List installed modules",
  "description": "Returns WebAssembly modules installed by the operator. Each module adds blocks with the kind `module:<module id>:<block>`. Modules return actions for the runner and do not access the page directly.",
  "responses": {
    "200": {
      "description": "Module list.",
      "content": {
        "application/json": {
          "schema": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AutomationModule"
            }
          }
        }
      }
    },
    "401": {
      "$ref": "#/components/responses/Unauthorized"
    },
    "501": {
      "description": "This build does not support automation.",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/Error"
          }
        }
      }
    }
  }
}
```

## Install module

`POST /automation/modules`

```json
{
  "tags": [
    "Automation"
  ],
  "summary": "Install module",
  "description": "`path` must point to a local `.wasm` file on the launcher host. Modules contain native code created by the operator.",
  "requestBody": {
    "required": true,
    "content": {
      "application/json": {
        "schema": {
          "type": "object",
          "required": [
            "path"
          ],
          "properties": {
            "path": {
              "type": "string",
              "example": "/home/me/module.wasm"
            }
          }
        }
      }
    }
  },
  "responses": {
    "200": {
      "description": "The installed module.",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/AutomationModule"
          }
        }
      }
    },
    "400": {
      "description": "Missing path or unsupported module file.",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/Error"
          }
        }
      }
    },
    "401": {
      "$ref": "#/components/responses/Unauthorized"
    },
    "501": {
      "description": "This build does not support automation.",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/Error"
          }
        }
      }
    }
  }
}
```

## Remove module

`DELETE /automation/modules/{id}`

```json
{
  "tags": [
    "Automation"
  ],
  "summary": "Remove module",
  "description": "Projects that use the module stop working. Existing project definitions are not modified.",
  "parameters": [
    {
      "name": "id",
      "in": "path",
      "required": true,
      "schema": {
        "type": "string"
      }
    }
  ],
  "responses": {
    "200": {
      "description": "Removed.",
      "content": {
        "application/json": {
          "schema": {
            "type": "object",
            "properties": {
              "deleted": {
                "type": "boolean",
                "example": true
              },
              "id": {
                "type": "string"
              }
            }
          }
        }
      }
    },
    "401": {
      "$ref": "#/components/responses/Unauthorized"
    },
    "404": {
      "description": "Module not found.",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/Error"
          }
        }
      }
    },
    "501": {
      "description": "This build does not support automation.",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/Error"
          }
        }
      }
    }
  }
}
```
