{
  "openapi": "3.1.0",
  "info": {
    "title": "RSX Node",
    "version": "v1",
    "description": "Control plane for RSX-managed compute nodes: registration, desired state, and reported status."
  },
  "servers": [
    {
      "url": "https://api.rsx.group"
    }
  ],
  "components": {
    "schemas": {
      "NodeAgent": {
        "type": "object",
        "properties": {
          "version": {
            "type": "string",
            "maxLength": 32,
            "example": "0.1.0"
          },
          "commit": {
            "type": "string",
            "maxLength": 64,
            "example": "5036308f9859"
          },
          "builtAt": {
            "type": "string",
            "maxLength": 32,
            "example": "2026-08-30T23:30:34Z"
          }
        },
        "required": [
          "version",
          "commit",
          "builtAt"
        ]
      },
      "NodeSealing": {
        "type": "object",
        "properties": {
          "algorithm": {
            "type": "string",
            "enum": [
              "x25519-hkdf-sha256-aes256gcm"
            ]
          },
          "publicKey": {
            "type": "string",
            "pattern": "^[A-Za-z0-9+/]{43}=$"
          }
        },
        "required": [
          "algorithm",
          "publicKey"
        ]
      },
      "NodePlatform": {
        "type": "object",
        "properties": {
          "os": {
            "type": "string",
            "minLength": 1,
            "example": "macos"
          },
          "architecture": {
            "type": "string",
            "minLength": 1,
            "example": "x86_64"
          },
          "kernel": {
            "type": "string",
            "minLength": 1,
            "maxLength": 64,
            "example": "6.1.0-25-amd64"
          }
        },
        "required": [
          "os",
          "architecture"
        ]
      },
      "NodeRuntime": {
        "type": "object",
        "properties": {
          "docker": {
            "type": "boolean"
          },
          "version": {
            "type": "string",
            "example": "29.6.2"
          }
        },
        "required": [
          "docker",
          "version"
        ]
      },
      "NodeCapacity": {
        "type": "object",
        "properties": {
          "memoryBytes": {
            "type": "integer",
            "minimum": 0,
            "example": 8589934592
          },
          "cpus": {
            "type": "integer",
            "minimum": 0,
            "example": 4
          }
        },
        "required": [
          "memoryBytes",
          "cpus"
        ]
      },
      "NodeFeatures": {
        "type": "object",
        "properties": {
          "build": {
            "type": "boolean"
          },
          "cloudflareTunnel": {
            "type": "boolean"
          },
          "hostMetrics": {
            "type": "boolean"
          }
        },
        "required": [
          "build",
          "cloudflareTunnel"
        ]
      },
      "NodeDeploymentOutcome": {
        "type": "string",
        "enum": [
          "promoted",
          "rolled-back",
          "failed"
        ]
      },
      "NodeWorkloadDeployment": {
        "type": [
          "object",
          "null"
        ],
        "properties": {
          "revision": {
            "type": "string",
            "minLength": 1,
            "maxLength": 128,
            "example": "9a1b2c3"
          },
          "outcome": {
            "$ref": "#/components/schemas/NodeDeploymentOutcome"
          },
          "detail": {
            "type": "string",
            "maxLength": 1024,
            "example": "its health check failed: connection refused"
          },
          "at": {
            "type": "string",
            "format": "date-time",
            "example": "2026-10-09T09:14:02Z"
          }
        },
        "required": [
          "revision",
          "outcome",
          "detail",
          "at"
        ]
      },
      "NodeWorkloadStatus": {
        "type": "object",
        "properties": {
          "workloadId": {
            "type": "string",
            "minLength": 1,
            "example": "roxy"
          },
          "revision": {
            "type": "string",
            "example": "7f31c2a"
          },
          "state": {
            "type": "string",
            "example": "RUNNING"
          },
          "restarts": {
            "type": "integer",
            "minimum": 0,
            "example": 0
          },
          "condition": {
            "type": "string",
            "example": "READY"
          },
          "health": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "STARTING",
              "HEALTHY",
              "UNHEALTHY"
            ]
          },
          "version": {
            "type": [
              "object",
              "null"
            ],
            "properties": {
              "version": {
                "type": [
                  "string",
                  "null"
                ],
                "maxLength": 64
              },
              "commit": {
                "type": [
                  "string",
                  "null"
                ],
                "maxLength": 64
              }
            },
            "required": [
              "version",
              "commit"
            ]
          },
          "deployment": {
            "$ref": "#/components/schemas/NodeWorkloadDeployment"
          }
        },
        "required": [
          "workloadId",
          "revision",
          "state",
          "restarts",
          "condition"
        ]
      },
      "NodeHostUsage": {
        "type": [
          "object",
          "null"
        ],
        "properties": {
          "cpuPercent": {
            "type": [
              "number",
              "null"
            ],
            "minimum": 0,
            "maximum": 100,
            "example": 12.5
          },
          "memory": {
            "type": [
              "object",
              "null"
            ],
            "properties": {
              "usedBytes": {
                "type": "integer",
                "minimum": 0,
                "example": 6442450944
              },
              "totalBytes": {
                "type": "integer",
                "minimum": 0,
                "example": 17179869184
              }
            },
            "required": [
              "usedBytes",
              "totalBytes"
            ]
          },
          "disks": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "path": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 256,
                  "example": "/var/lib/docker"
                },
                "usedBytes": {
                  "type": "integer",
                  "minimum": 0,
                  "example": 48318382080
                },
                "totalBytes": {
                  "type": "integer",
                  "minimum": 0,
                  "example": 107374182400
                }
              },
              "required": [
                "path",
                "usedBytes",
                "totalBytes"
              ]
            },
            "maxItems": 4
          }
        },
        "required": [
          "cpuPercent",
          "memory",
          "disks"
        ]
      },
      "NodeJobRun": {
        "type": [
          "object",
          "null"
        ],
        "properties": {
          "runId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 64,
            "example": "01JD3M4K5N6P7Q8R9S0T1U2V3W"
          },
          "revision": {
            "type": "string",
            "minLength": 1,
            "maxLength": 128,
            "example": "7f31c2a"
          },
          "state": {
            "type": "string",
            "enum": [
              "running",
              "succeeded",
              "failed",
              "timed-out"
            ],
            "example": "succeeded"
          },
          "exitCode": {
            "type": [
              "integer",
              "null"
            ],
            "example": 0
          },
          "startedAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "example": "2026-10-09T09:14:05Z"
          },
          "finishedAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "example": "2026-10-09T09:14:41Z"
          },
          "detail": {
            "type": "string",
            "maxLength": 1024,
            "example": "exited 0 after 36s"
          }
        },
        "required": [
          "runId",
          "revision",
          "state",
          "exitCode",
          "startedAt",
          "finishedAt",
          "detail"
        ]
      },
      "NodeJobStatus": {
        "type": "object",
        "properties": {
          "jobId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 63,
            "example": "roxy-migrate"
          },
          "revision": {
            "type": "string",
            "minLength": 1,
            "maxLength": 128,
            "example": "7f31c2a"
          },
          "run": {
            "$ref": "#/components/schemas/NodeJobRun"
          }
        },
        "required": [
          "jobId",
          "revision",
          "run"
        ]
      },
      "UpdateNodeStatus": {
        "type": "object",
        "properties": {
          "nodeId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 63,
            "pattern": "^[a-z0-9][a-z0-9-]*[a-z0-9]$|^[a-z0-9]$",
            "example": "macbook-dev-01"
          },
          "generation": {
            "type": "integer",
            "minimum": 0,
            "example": 7
          },
          "status": {
            "type": "string",
            "enum": [
              "HEALTHY",
              "DEGRADED"
            ]
          },
          "docker": {
            "type": [
              "string",
              "null"
            ],
            "example": "Docker 29.6.2 on linux/x86_64, 7.4 GiB memory, 12 CPUs"
          },
          "workloads": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/NodeWorkloadStatus"
            }
          },
          "host": {
            "$ref": "#/components/schemas/NodeHostUsage"
          },
          "jobs": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/NodeJobStatus"
            },
            "maxItems": 100
          }
        },
        "required": [
          "nodeId",
          "generation",
          "status",
          "docker",
          "workloads"
        ]
      },
      "NodeStatus": {
        "allOf": [
          {
            "$ref": "#/components/schemas/UpdateNodeStatus"
          },
          {
            "type": [
              "object",
              "null"
            ],
            "properties": {
              "reportedAt": {
                "type": "string",
                "format": "date-time",
                "example": "2026-08-27T09:41:55Z"
              }
            },
            "required": [
              "reportedAt"
            ]
          }
        ]
      },
      "RegisterNode": {
        "type": "object",
        "properties": {
          "nodeId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 63,
            "pattern": "^[a-z0-9][a-z0-9-]*[a-z0-9]$|^[a-z0-9]$",
            "example": "macbook-dev-01"
          },
          "agent": {
            "$ref": "#/components/schemas/NodeAgent"
          },
          "sealing": {
            "$ref": "#/components/schemas/NodeSealing"
          },
          "platform": {
            "$ref": "#/components/schemas/NodePlatform"
          },
          "runtime": {
            "$ref": "#/components/schemas/NodeRuntime"
          },
          "capacity": {
            "$ref": "#/components/schemas/NodeCapacity"
          },
          "features": {
            "$ref": "#/components/schemas/NodeFeatures"
          }
        },
        "required": [
          "nodeId",
          "platform",
          "runtime",
          "capacity",
          "features"
        ]
      },
      "Node": {
        "allOf": [
          {
            "$ref": "#/components/schemas/RegisterNode"
          },
          {
            "type": "object",
            "properties": {
              "registeredAt": {
                "type": "string",
                "format": "date-time",
                "example": "2026-08-27T09:14:02Z"
              },
              "lastSeenAt": {
                "type": "string",
                "format": "date-time",
                "example": "2026-08-27T09:41:55Z"
              },
              "generation": {
                "type": "integer",
                "minimum": 0,
                "example": 7
              }
            },
            "required": [
              "registeredAt",
              "lastSeenAt",
              "generation"
            ]
          }
        ]
      },
      "NodeSummary": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Node"
          },
          {
            "type": "object",
            "properties": {
              "status": {
                "$ref": "#/components/schemas/NodeStatus"
              }
            },
            "required": [
              "status"
            ]
          }
        ]
      },
      "NodeDetail": {
        "allOf": [
          {
            "$ref": "#/components/schemas/NodeSummary"
          },
          {
            "type": "object",
            "properties": {
              "desired": {
                "type": [
                  "string",
                  "null"
                ],
                "example": "{\"generation\":7,\"workloads\":[]}"
              }
            },
            "required": [
              "desired"
            ]
          }
        ]
      },
      "NodeWorkloadRegistryRef": {
        "type": "object",
        "properties": {
          "package": {
            "type": "string",
            "minLength": 1,
            "maxLength": 255,
            "example": "rsx/roxy"
          },
          "version": {
            "type": "string",
            "minLength": 1,
            "maxLength": 128,
            "example": "2.1.0"
          }
        },
        "required": [
          "package",
          "version"
        ]
      },
      "NodeWorkloadSource": {
        "type": "object",
        "properties": {
          "repository": {
            "type": "string",
            "example": "git@github.com:RSXGroup/roxy.git"
          },
          "revision": {
            "type": "string",
            "minLength": 1,
            "maxLength": 64,
            "example": "7f31c2a"
          },
          "build": {
            "type": "string",
            "enum": [
              "registry",
              "local"
            ],
            "default": "registry"
          },
          "registry": {
            "$ref": "#/components/schemas/NodeWorkloadRegistryRef"
          },
          "image": {
            "type": "string",
            "example": "ghcr.io/rsxgroup/roxy@sha256:28bd5fe8b56d1bd048e5babf5b10710ebe0bae67db86916198a6eec434943f8b"
          }
        },
        "required": [
          "revision",
          "image"
        ]
      },
      "NodeWorkloadVolume": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 63,
            "pattern": "^[a-z0-9]([a-z0-9-]*[a-z0-9])?$",
            "example": "roxy-data"
          },
          "path": {
            "type": "string",
            "example": "/app/data"
          }
        },
        "required": [
          "name",
          "path"
        ]
      },
      "NodeWorkloadResources": {
        "type": "object",
        "properties": {
          "memory": {
            "type": "string",
            "pattern": "^\\d+(B|[KMGT]i?)?$",
            "example": "512Mi"
          },
          "cpu": {
            "type": "number",
            "exclusiveMinimum": 0,
            "example": 1
          }
        },
        "default": {}
      },
      "NodeWorkloadHealth": {
        "oneOf": [
          {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "enum": [
                  "process"
                ]
              },
              "settleSeconds": {
                "type": "integer",
                "minimum": 0,
                "maximum": 600,
                "default": 5,
                "example": 5
              }
            },
            "required": [
              "type"
            ]
          },
          {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "enum": [
                  "http"
                ]
              },
              "port": {
                "type": "integer",
                "minimum": 1,
                "maximum": 65535,
                "example": 3000
              },
              "path": {
                "type": "string",
                "maxLength": 256,
                "pattern": "^\\/[A-Za-z0-9/\\-._~%?=&+,:@]*$",
                "default": "/_rsx/health"
              },
              "intervalSeconds": {
                "type": "integer",
                "minimum": 1,
                "maximum": 3600,
                "default": 10
              },
              "timeoutSeconds": {
                "type": "integer",
                "minimum": 1,
                "maximum": 300,
                "default": 3
              },
              "retries": {
                "type": "integer",
                "minimum": 1,
                "maximum": 20,
                "default": 3
              },
              "startSeconds": {
                "type": "integer",
                "minimum": 0,
                "maximum": 3600,
                "default": 60
              }
            },
            "required": [
              "type",
              "port"
            ]
          }
        ],
        "default": {
          "type": "process",
          "settleSeconds": 5
        }
      },
      "NodeWorkloadIngress": {
        "type": "object",
        "properties": {
          "port": {
            "type": "integer",
            "minimum": 1,
            "maximum": 65535,
            "example": 3000
          },
          "hostnames": {
            "type": "array",
            "items": {
              "type": "string",
              "maxLength": 253,
              "pattern": "^([a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?\\.)+[a-z]{2,63}$",
              "example": "logs.rsx.group"
            },
            "minItems": 1,
            "maxItems": 10
          },
          "access": {
            "type": "boolean",
            "default": true
          }
        },
        "required": [
          "port",
          "hostnames"
        ]
      },
      "NodeWorkload": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "minLength": 1,
            "maxLength": 63,
            "pattern": "^[a-z0-9][a-z0-9-]*[a-z0-9]$|^[a-z0-9]$",
            "example": "roxy"
          },
          "state": {
            "type": "string",
            "enum": [
              "running",
              "stopped"
            ],
            "default": "running"
          },
          "source": {
            "$ref": "#/components/schemas/NodeWorkloadSource"
          },
          "env": {
            "type": "object",
            "additionalProperties": {
              "type": "string",
              "maxLength": 4096
            },
            "default": {}
          },
          "volumes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/NodeWorkloadVolume"
            },
            "default": []
          },
          "resources": {
            "$ref": "#/components/schemas/NodeWorkloadResources"
          },
          "restart": {
            "type": "string",
            "enum": [
              "no",
              "always",
              "unless-stopped"
            ],
            "default": "unless-stopped"
          },
          "health": {
            "$ref": "#/components/schemas/NodeWorkloadHealth"
          },
          "command": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "diagnostics": {
            "type": "object",
            "properties": {
              "probes": {
                "type": "object",
                "additionalProperties": {
                  "type": "array",
                  "items": {
                    "type": "string",
                    "maxLength": 1024
                  },
                  "minItems": 1,
                  "maxItems": 32
                },
                "default": {}
              }
            }
          },
          "ingress": {
            "$ref": "#/components/schemas/NodeWorkloadIngress"
          }
        },
        "required": [
          "id",
          "source"
        ]
      },
      "NodeJobTrigger": {
        "type": "object",
        "properties": {
          "github": {
            "type": "object",
            "properties": {
              "repository": {
                "type": "string",
                "minLength": 3,
                "maxLength": 140,
                "pattern": "^[A-Za-z0-9._-]+\\/[A-Za-z0-9._-]+$",
                "example": "RSXGroup/site"
              },
              "refs": {
                "type": "array",
                "items": {
                  "type": "string",
                  "maxLength": 255,
                  "pattern": "^refs\\/(heads|tags)\\/([A-Za-z0-9._/-]+\\*?|\\*)$",
                  "example": "refs/heads/main"
                },
                "minItems": 1,
                "maxItems": 10
              }
            },
            "required": [
              "repository",
              "refs"
            ]
          }
        },
        "required": [
          "github"
        ]
      },
      "NodeJob": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "minLength": 1,
            "maxLength": 63,
            "pattern": "^[a-z0-9][a-z0-9-]*[a-z0-9]$|^[a-z0-9]$",
            "example": "roxy-migrate"
          },
          "source": {
            "$ref": "#/components/schemas/NodeWorkloadSource"
          },
          "command": {
            "type": "array",
            "items": {
              "type": "string",
              "maxLength": 4096
            },
            "minItems": 1,
            "maxItems": 64,
            "example": [
              "node",
              "scripts/migrate.js",
              "--to",
              "latest"
            ]
          },
          "env": {
            "type": "object",
            "additionalProperties": {
              "type": "string",
              "maxLength": 4096
            },
            "default": {}
          },
          "volumes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/NodeWorkloadVolume"
            },
            "default": []
          },
          "resources": {
            "$ref": "#/components/schemas/NodeWorkloadResources"
          },
          "timeoutSeconds": {
            "type": "integer",
            "minimum": 1,
            "maximum": 86400,
            "default": 3600,
            "example": 1800
          },
          "retainRuns": {
            "type": "integer",
            "minimum": 1,
            "maximum": 20,
            "default": 5,
            "example": 5
          },
          "trigger": {
            "$ref": "#/components/schemas/NodeJobTrigger"
          }
        },
        "required": [
          "id",
          "source",
          "command"
        ]
      },
      "UpdateNodeDesiredState": {
        "type": "object",
        "properties": {
          "nodeId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 63,
            "pattern": "^[a-z0-9][a-z0-9-]*[a-z0-9]$|^[a-z0-9]$",
            "example": "macbook-dev-01"
          },
          "workloads": {
            "type": "array",
            "items": {
              "allOf": [
                {
                  "$ref": "#/components/schemas/NodeWorkload"
                },
                {
                  "type": "object",
                  "properties": {
                    "source": {
                      "allOf": [
                        {
                          "$ref": "#/components/schemas/NodeWorkloadSource"
                        },
                        {
                          "type": "object",
                          "properties": {}
                        }
                      ]
                    }
                  }
                }
              ]
            }
          },
          "jobs": {
            "type": "array",
            "items": {
              "allOf": [
                {
                  "$ref": "#/components/schemas/NodeJob"
                },
                {
                  "type": "object",
                  "properties": {
                    "source": {
                      "allOf": [
                        {
                          "$ref": "#/components/schemas/NodeWorkloadSource"
                        },
                        {
                          "type": "object",
                          "properties": {}
                        }
                      ]
                    }
                  }
                }
              ]
            },
            "default": []
          }
        },
        "required": [
          "nodeId",
          "workloads"
        ]
      },
      "NodeCommand": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "01JD3M4K5N6P7Q8R9S0T1U2V3W"
          },
          "kind": {
            "type": "string",
            "enum": [
              "reconcile",
              "restart",
              "redeploy",
              "logs",
              "diagnose",
              "secret",
              "update",
              "reboot",
              "shutdown",
              "run"
            ],
            "example": "restart"
          },
          "arguments": {
            "type": "object",
            "additionalProperties": {},
            "default": {}
          },
          "issuedAt": {
            "type": "string",
            "format": "date-time",
            "example": "2026-08-31T09:14:02Z"
          },
          "issuedBy": {
            "type": "string",
            "example": "paige@rsx.group"
          }
        },
        "required": [
          "id",
          "kind",
          "issuedAt",
          "issuedBy"
        ]
      },
      "NodeCommandRecord": {
        "allOf": [
          {
            "$ref": "#/components/schemas/NodeCommand"
          },
          {
            "type": "object",
            "properties": {
              "state": {
                "type": "string",
                "enum": [
                  "pending",
                  "done",
                  "failed"
                ]
              },
              "ackedAt": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "date-time"
              },
              "detail": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "output": {
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "required": [
              "state",
              "ackedAt",
              "detail",
              "output"
            ]
          }
        ]
      },
      "NodeSealedSecret": {
        "type": "object",
        "properties": {
          "v": {
            "type": "number",
            "enum": [
              1
            ]
          },
          "key": {
            "type": "string",
            "maxLength": 64
          },
          "epk": {
            "type": "string",
            "maxLength": 64
          },
          "nonce": {
            "type": "string",
            "maxLength": 32
          },
          "ct": {
            "type": "string",
            "maxLength": 24000
          }
        },
        "required": [
          "v",
          "key",
          "epk",
          "nonce",
          "ct"
        ]
      },
      "IssueNodeCommand": {
        "oneOf": [
          {
            "type": "object",
            "properties": {
              "nodeId": {
                "type": "string",
                "minLength": 1,
                "maxLength": 63,
                "pattern": "^[a-z0-9][a-z0-9-]*[a-z0-9]$|^[a-z0-9]$",
                "example": "macbook-dev-01"
              },
              "kind": {
                "type": "string",
                "enum": [
                  "reconcile"
                ]
              }
            },
            "required": [
              "nodeId",
              "kind"
            ]
          },
          {
            "type": "object",
            "properties": {
              "nodeId": {
                "type": "string",
                "minLength": 1,
                "maxLength": 63,
                "pattern": "^[a-z0-9][a-z0-9-]*[a-z0-9]$|^[a-z0-9]$",
                "example": "macbook-dev-01"
              },
              "kind": {
                "type": "string",
                "enum": [
                  "restart"
                ]
              },
              "arguments": {
                "type": "object",
                "properties": {
                  "workloadId": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 63,
                    "example": "roxy"
                  },
                  "lines": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 1000,
                    "default": 200
                  }
                },
                "required": [
                  "workloadId"
                ]
              }
            },
            "required": [
              "nodeId",
              "kind",
              "arguments"
            ]
          },
          {
            "type": "object",
            "properties": {
              "nodeId": {
                "type": "string",
                "minLength": 1,
                "maxLength": 63,
                "pattern": "^[a-z0-9][a-z0-9-]*[a-z0-9]$|^[a-z0-9]$",
                "example": "macbook-dev-01"
              },
              "kind": {
                "type": "string",
                "enum": [
                  "redeploy"
                ]
              },
              "arguments": {
                "type": "object",
                "properties": {
                  "workloadId": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 63,
                    "example": "roxy"
                  }
                },
                "required": [
                  "workloadId"
                ]
              }
            },
            "required": [
              "nodeId",
              "kind",
              "arguments"
            ]
          },
          {
            "type": "object",
            "properties": {
              "nodeId": {
                "type": "string",
                "minLength": 1,
                "maxLength": 63,
                "pattern": "^[a-z0-9][a-z0-9-]*[a-z0-9]$|^[a-z0-9]$",
                "example": "macbook-dev-01"
              },
              "kind": {
                "type": "string",
                "enum": [
                  "logs"
                ]
              },
              "arguments": {
                "type": "object",
                "properties": {
                  "workloadId": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 63,
                    "example": "roxy"
                  },
                  "lines": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 1000,
                    "default": 200
                  }
                },
                "required": [
                  "workloadId"
                ]
              }
            },
            "required": [
              "nodeId",
              "kind",
              "arguments"
            ]
          },
          {
            "type": "object",
            "properties": {
              "nodeId": {
                "type": "string",
                "minLength": 1,
                "maxLength": 63,
                "pattern": "^[a-z0-9][a-z0-9-]*[a-z0-9]$|^[a-z0-9]$",
                "example": "macbook-dev-01"
              },
              "kind": {
                "type": "string",
                "enum": [
                  "secret"
                ]
              },
              "arguments": {
                "type": "object",
                "properties": {
                  "workloadId": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 63
                  },
                  "name": {
                    "type": "string",
                    "pattern": "^[A-Z_][A-Z0-9_]*$",
                    "example": "ROXY_ENV"
                  },
                  "sealed": {
                    "$ref": "#/components/schemas/NodeSealedSecret"
                  }
                },
                "required": [
                  "workloadId",
                  "name"
                ]
              }
            },
            "required": [
              "nodeId",
              "kind",
              "arguments"
            ]
          },
          {
            "type": "object",
            "properties": {
              "nodeId": {
                "type": "string",
                "minLength": 1,
                "maxLength": 63,
                "pattern": "^[a-z0-9][a-z0-9-]*[a-z0-9]$|^[a-z0-9]$",
                "example": "macbook-dev-01"
              },
              "kind": {
                "type": "string",
                "enum": [
                  "diagnose"
                ]
              },
              "arguments": {
                "type": "object",
                "properties": {
                  "check": {
                    "type": "string",
                    "enum": [
                      "node",
                      "engine",
                      "workload",
                      "processes",
                      "usage",
                      "history",
                      "probe",
                      "runs",
                      "run"
                    ]
                  },
                  "workloadId": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 63
                  },
                  "probe": {
                    "type": "string",
                    "pattern": "^[a-z0-9-]{1,32}$"
                  },
                  "entries": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 200
                  },
                  "jobId": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 63,
                    "pattern": "^[a-z0-9][a-z0-9-]*[a-z0-9]$|^[a-z0-9]$",
                    "example": "macbook-dev-01"
                  },
                  "runId": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 64
                  },
                  "lines": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 1000
                  }
                },
                "required": [
                  "check"
                ]
              }
            },
            "required": [
              "nodeId",
              "kind",
              "arguments"
            ]
          },
          {
            "type": "object",
            "properties": {
              "nodeId": {
                "type": "string",
                "minLength": 1,
                "maxLength": 63,
                "pattern": "^[a-z0-9][a-z0-9-]*[a-z0-9]$|^[a-z0-9]$",
                "example": "macbook-dev-01"
              },
              "kind": {
                "type": "string",
                "enum": [
                  "update"
                ]
              },
              "arguments": {
                "type": "object",
                "properties": {
                  "version": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 32,
                    "example": "0.1.0"
                  },
                  "url": {
                    "type": "string",
                    "format": "uri",
                    "example": "https://github.com/RSXGroup/RSXNodeCF/releases/download/build-5036308/rsx-node-x86_64-apple-darwin"
                  },
                  "sha256": {
                    "type": "string",
                    "pattern": "^[0-9a-f]{64}$",
                    "example": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
                  }
                },
                "required": [
                  "version",
                  "url",
                  "sha256"
                ]
              }
            },
            "required": [
              "nodeId",
              "kind",
              "arguments"
            ]
          },
          {
            "type": "object",
            "properties": {
              "nodeId": {
                "type": "string",
                "minLength": 1,
                "maxLength": 63,
                "pattern": "^[a-z0-9][a-z0-9-]*[a-z0-9]$|^[a-z0-9]$",
                "example": "macbook-dev-01"
              },
              "kind": {
                "type": "string",
                "enum": [
                  "reboot"
                ]
              }
            },
            "required": [
              "nodeId",
              "kind"
            ]
          },
          {
            "type": "object",
            "properties": {
              "nodeId": {
                "type": "string",
                "minLength": 1,
                "maxLength": 63,
                "pattern": "^[a-z0-9][a-z0-9-]*[a-z0-9]$|^[a-z0-9]$",
                "example": "macbook-dev-01"
              },
              "kind": {
                "type": "string",
                "enum": [
                  "shutdown"
                ]
              }
            },
            "required": [
              "nodeId",
              "kind"
            ]
          },
          {
            "type": "object",
            "properties": {
              "nodeId": {
                "type": "string",
                "minLength": 1,
                "maxLength": 63,
                "pattern": "^[a-z0-9][a-z0-9-]*[a-z0-9]$|^[a-z0-9]$",
                "example": "macbook-dev-01"
              },
              "kind": {
                "type": "string",
                "enum": [
                  "run"
                ]
              },
              "arguments": {
                "type": "object",
                "properties": {
                  "jobId": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 63,
                    "pattern": "^[a-z0-9][a-z0-9-]*[a-z0-9]$|^[a-z0-9]$",
                    "example": "macbook-dev-01"
                  }
                },
                "required": [
                  "jobId"
                ],
                "additionalProperties": false
              }
            },
            "required": [
              "nodeId",
              "kind",
              "arguments"
            ]
          }
        ]
      },
      "NodeTunnelToken": {
        "type": "object",
        "properties": {
          "nodeId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 63,
            "pattern": "^[a-z0-9][a-z0-9-]*[a-z0-9]$|^[a-z0-9]$",
            "example": "macbook-dev-01"
          },
          "tunnelId": {
            "type": "string"
          },
          "token": {
            "type": "string"
          }
        },
        "required": [
          "nodeId",
          "tunnelId",
          "token"
        ]
      },
      "NodeRunRecord": {
        "allOf": [
          {
            "$ref": "#/components/schemas/NodeJobRun"
          },
          {
            "type": "object",
            "properties": {
              "jobId": {
                "type": "string",
                "minLength": 1,
                "maxLength": 63,
                "example": "roxy-migrate"
              },
              "recordedAt": {
                "type": "string",
                "format": "date-time",
                "example": "2026-10-09T09:14:07Z"
              }
            },
            "required": [
              "jobId",
              "recordedAt"
            ]
          }
        ]
      },
      "NodeTriggerMatch": {
        "type": "object",
        "properties": {
          "nodeId": {
            "type": "string"
          },
          "jobId": {
            "type": "string"
          },
          "outcome": {
            "type": "string",
            "enum": [
              "queued",
              "issued",
              "ignored"
            ]
          },
          "detail": {
            "type": "string"
          }
        },
        "required": [
          "nodeId",
          "jobId",
          "outcome",
          "detail"
        ]
      },
      "NodeTriggerResult": {
        "type": "object",
        "properties": {
          "deduped": {
            "type": "boolean"
          },
          "ignored": {
            "type": [
              "string",
              "null"
            ]
          },
          "matched": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/NodeTriggerMatch"
            }
          }
        },
        "required": [
          "deduped",
          "ignored",
          "matched"
        ]
      },
      "NodeGithubPush": {
        "type": "object",
        "properties": {
          "deliveryId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 128
          },
          "repository": {
            "type": "string",
            "minLength": 1,
            "maxLength": 255,
            "example": "RSXGroup/site"
          },
          "ref": {
            "type": "string",
            "minLength": 1,
            "maxLength": 1024,
            "example": "refs/heads/main"
          },
          "commit": {
            "type": "string",
            "minLength": 1,
            "maxLength": 128,
            "example": "7f31c2a9d4e8b1f0c3a5d7e9f2b4c6a8d0e1f3a5"
          },
          "pusher": {
            "type": "string",
            "maxLength": 128,
            "default": ""
          }
        },
        "required": [
          "deliveryId",
          "repository",
          "ref",
          "commit"
        ]
      },
      "NodePendingTrigger": {
        "type": "object",
        "properties": {
          "nodeId": {
            "type": "string"
          },
          "jobId": {
            "type": "string"
          },
          "commit": {
            "type": "string"
          },
          "ref": {
            "type": "string"
          },
          "generation": {
            "type": "integer"
          },
          "actor": {
            "type": "string"
          },
          "pusher": {
            "type": "string"
          },
          "queuedAt": {
            "type": "string",
            "format": "date-time"
          },
          "commandId": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "nodeId",
          "jobId",
          "commit",
          "ref",
          "generation",
          "actor",
          "pusher",
          "queuedAt",
          "commandId"
        ]
      },
      "NodeReleaseAsset": {
        "type": "object",
        "properties": {
          "assetId": {
            "type": "integer"
          },
          "name": {
            "type": "string",
            "example": "rsx-node-x86_64-apple-darwin"
          },
          "size": {
            "type": "integer",
            "minimum": 0
          },
          "sha256": {
            "type": [
              "string",
              "null"
            ]
          },
          "target": {
            "type": [
              "string",
              "null"
            ],
            "example": "x86_64-apple-darwin"
          }
        },
        "required": [
          "assetId",
          "name",
          "size",
          "sha256",
          "target"
        ]
      },
      "NodeRelease": {
        "type": "object",
        "properties": {
          "tag": {
            "type": "string",
            "example": "build-5036308f9859"
          },
          "name": {
            "type": "string"
          },
          "publishedAt": {
            "type": [
              "string",
              "null"
            ]
          },
          "prerelease": {
            "type": "boolean"
          },
          "assets": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/NodeReleaseAsset"
            }
          }
        },
        "required": [
          "tag",
          "name",
          "publishedAt",
          "prerelease",
          "assets"
        ]
      },
      "UpdateNodeFromRelease": {
        "type": "object",
        "properties": {
          "nodeId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 63,
            "pattern": "^[a-z0-9][a-z0-9-]*[a-z0-9]$|^[a-z0-9]$",
            "example": "macbook-dev-01"
          },
          "version": {
            "type": "string",
            "minLength": 1,
            "maxLength": 128,
            "example": "build-7f31c2a"
          },
          "platform": {
            "type": "string",
            "minLength": 1,
            "maxLength": 64,
            "example": "x86_64-apple-darwin"
          },
          "assetId": {
            "type": "integer",
            "example": 284739201
          }
        },
        "required": [
          "nodeId"
        ]
      },
      "NodeAuditEvent": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "018f3b1c-9a2e-7c31-8f4d-2a6b5c7e9d12"
          },
          "actor": {
            "type": "string",
            "example": "ops@rsx.group"
          },
          "action": {
            "type": "string",
            "enum": [
              "node.registered",
              "desired.updated",
              "command.issued",
              "tunnel.token.revealed",
              "tunnel.token.sent",
              "job.triggered",
              "job.trigger.dropped"
            ]
          },
          "targetType": {
            "type": "string",
            "enum": [
              "node"
            ]
          },
          "targetId": {
            "type": "string"
          },
          "targetLabel": {
            "type": [
              "string",
              "null"
            ]
          },
          "at": {
            "type": "string",
            "format": "date-time",
            "example": "2026-09-12T10:16:30.000Z"
          },
          "detail": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "id",
          "actor",
          "action",
          "targetType",
          "targetId",
          "targetLabel",
          "at",
          "detail"
        ]
      },
      "NodeDesiredState": {
        "type": "object",
        "properties": {
          "generation": {
            "type": "integer",
            "minimum": 0,
            "example": 7
          },
          "workloads": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/NodeWorkload"
            }
          },
          "tunnel": {
            "type": "object",
            "properties": {
              "image": {
                "type": "string"
              },
              "revision": {
                "type": "string"
              }
            },
            "required": [
              "image",
              "revision"
            ]
          },
          "jobs": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/NodeJob"
            },
            "default": []
          }
        },
        "required": [
          "generation",
          "workloads"
        ]
      },
      "AckNodeCommand": {
        "type": "object",
        "properties": {
          "nodeId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 63,
            "pattern": "^[a-z0-9][a-z0-9-]*[a-z0-9]$|^[a-z0-9]$",
            "example": "macbook-dev-01"
          },
          "commandId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 64
          },
          "outcome": {
            "type": "string",
            "enum": [
              "done",
              "failed"
            ]
          },
          "detail": {
            "type": "string",
            "maxLength": 2000,
            "default": ""
          },
          "output": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 200000,
            "default": null
          }
        },
        "required": [
          "nodeId",
          "commandId",
          "outcome"
        ]
      }
    },
    "parameters": {}
  },
  "paths": {
    "/node/v1/admin/nodes/list": {
      "get": {
        "operationId": "adminListNodes",
        "summary": "Every node, and what each last reported",
        "tags": [
          "admin"
        ],
        "parameters": [
          {
            "schema": {
              "type": "string"
            },
            "required": false,
            "name": "cursor",
            "in": "query"
          },
          {
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 20
            },
            "required": false,
            "name": "limit",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "Nodes",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/NodeSummary"
                      }
                    },
                    "meta": {
                      "type": "object",
                      "properties": {
                        "cursor": {
                          "type": [
                            "string",
                            "null"
                          ]
                        }
                      },
                      "required": [
                        "cursor"
                      ]
                    }
                  },
                  "required": [
                    "data",
                    "meta"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/node/v1/admin/nodes/get": {
      "get": {
        "operationId": "adminGetNode",
        "summary": "One node: what it is, what it was told, and what it reports",
        "tags": [
          "admin"
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 63,
              "pattern": "^[a-z0-9][a-z0-9-]*[a-z0-9]$|^[a-z0-9]$",
              "example": "macbook-dev-01"
            },
            "required": true,
            "name": "nodeId",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "The node",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/NodeDetail"
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/node/v1/admin/desired/update": {
      "post": {
        "operationId": "adminUpdateNodeDesiredState",
        "summary": "Set what a node should be running",
        "tags": [
          "admin"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateNodeDesiredState"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The new desired state, with the generation it was given",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "generation": {
                          "type": "integer",
                          "minimum": 0
                        },
                        "workloads": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/NodeWorkload"
                          }
                        },
                        "jobs": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/NodeJob"
                          }
                        }
                      },
                      "required": [
                        "generation",
                        "workloads",
                        "jobs"
                      ]
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/node/v1/admin/commands/add": {
      "post": {
        "operationId": "adminIssueNodeCommand",
        "summary": "Ask a node to do something",
        "tags": [
          "admin"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/IssueNodeCommand"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The command, waiting to be collected",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/NodeCommandRecord"
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/node/v1/admin/tunnel/send": {
      "post": {
        "operationId": "adminSendNodeTunnelToken",
        "summary": "Send a node its tunnel token, sealed to its key",
        "tags": [
          "admin"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "nodeId": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 63,
                    "pattern": "^[a-z0-9][a-z0-9-]*[a-z0-9]$|^[a-z0-9]$",
                    "example": "macbook-dev-01"
                  }
                },
                "required": [
                  "nodeId"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The secret command, waiting to be collected",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/NodeCommandRecord"
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/node/v1/admin/tunnel/get": {
      "get": {
        "operationId": "adminGetNodeTunnelToken",
        "summary": "Reveal a node's tunnel token, to seal on it",
        "tags": [
          "admin"
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 63,
              "pattern": "^[a-z0-9][a-z0-9-]*[a-z0-9]$|^[a-z0-9]$",
              "example": "macbook-dev-01"
            },
            "required": true,
            "name": "nodeId",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "The token. Seal it with `rsx-node tunnel token` and do not keep it.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/NodeTunnelToken"
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/node/v1/admin/commands/list": {
      "get": {
        "operationId": "adminListNodeCommands",
        "summary": "What has been asked of a node, and what came of it",
        "tags": [
          "admin"
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 63,
              "pattern": "^[a-z0-9][a-z0-9-]*[a-z0-9]$|^[a-z0-9]$",
              "example": "macbook-dev-01"
            },
            "required": true,
            "name": "nodeId",
            "in": "query"
          },
          {
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 20
            },
            "required": false,
            "name": "limit",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "Recent commands, newest first",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/NodeCommandRecord"
                      }
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/node/v1/admin/runs/list": {
      "get": {
        "operationId": "adminListNodeRuns",
        "summary": "The runs of a node's jobs, and how each ended",
        "tags": [
          "admin"
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 63,
              "pattern": "^[a-z0-9][a-z0-9-]*[a-z0-9]$|^[a-z0-9]$",
              "example": "macbook-dev-01"
            },
            "required": true,
            "name": "nodeId",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 63,
              "pattern": "^[a-z0-9][a-z0-9-]*[a-z0-9]$|^[a-z0-9]$",
              "example": "macbook-dev-01"
            },
            "required": false,
            "name": "jobId",
            "in": "query"
          },
          {
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 20
            },
            "required": false,
            "name": "limit",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "Runs, newest first by when this service first saw each",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/NodeRunRecord"
                      }
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/node/v1/admin/triggers/github": {
      "post": {
        "operationId": "adminReceiveGithubPush",
        "summary": "Start the runs a GitHub push triggers",
        "description": "Called by services/webhooks/v1 for every authenticated push. Matching jobs have the pushed commit written into their revision and `RSX_COMMIT`, `RSX_REF` and `RSX_REPOSITORY`, and are run once the node reports acting on that generation. A delivery id already seen does nothing.",
        "tags": [
          "admin"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/NodeGithubPush"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "What the push did to each matching job",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/NodeTriggerResult"
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/node/v1/admin/triggers/list": {
      "get": {
        "operationId": "adminListNodePendingTriggers",
        "summary": "Pushes waiting to become runs on a node",
        "tags": [
          "admin"
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 63,
              "pattern": "^[a-z0-9][a-z0-9-]*[a-z0-9]$|^[a-z0-9]$",
              "example": "macbook-dev-01"
            },
            "required": true,
            "name": "nodeId",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "One per job at most",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/NodePendingTrigger"
                      }
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/node/v1/admin/triggers/discard": {
      "post": {
        "operationId": "adminDiscardNodePendingTrigger",
        "summary": "Drop a push that is waiting to become a run",
        "tags": [
          "admin"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "nodeId": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 63,
                    "pattern": "^[a-z0-9][a-z0-9-]*[a-z0-9]$|^[a-z0-9]$",
                    "example": "macbook-dev-01"
                  },
                  "jobId": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 63,
                    "pattern": "^[a-z0-9][a-z0-9-]*[a-z0-9]$|^[a-z0-9]$",
                    "example": "macbook-dev-01"
                  }
                },
                "required": [
                  "nodeId",
                  "jobId"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Whether there was one",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "discarded": {
                          "type": "boolean"
                        }
                      },
                      "required": [
                        "discarded"
                      ]
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/node/v1/admin/releases/list": {
      "get": {
        "operationId": "adminListNodeReleases",
        "summary": "Builds of the node that a node could be updated to",
        "tags": [
          "admin"
        ],
        "parameters": [
          {
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 30,
              "default": 10
            },
            "required": false,
            "name": "limit",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "Recent releases, newest first",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/NodeRelease"
                      }
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "501": {
            "description": "This service has no GitHub credentials"
          }
        }
      }
    },
    "/node/v1/admin/commands/update": {
      "post": {
        "operationId": "adminUpdateNodeFromRelease",
        "summary": "Ask a node to update itself to a published build",
        "tags": [
          "admin"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateNodeFromRelease"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The command, waiting to be collected",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/NodeCommandRecord"
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/node/v1/admin/audit/list": {
      "get": {
        "operationId": "adminListNodeAudit",
        "summary": "Who changed what a node runs, and who asked it to do something",
        "description": "Newest first. `desired.updated` is recorded whether it came from the dashboard or from an API key, so `actor` is an operator's name or a key id. A node's first registration is recorded; its heartbeats and status reports are not.",
        "tags": [
          "admin"
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "enum": [
                "node"
              ]
            },
            "required": false,
            "name": "targetType",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 128
            },
            "required": false,
            "name": "targetId",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 320
            },
            "required": false,
            "name": "actor",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "enum": [
                "node.registered",
                "desired.updated",
                "command.issued",
                "tunnel.token.revealed",
                "tunnel.token.sent",
                "job.triggered",
                "job.trigger.dropped"
              ]
            },
            "required": false,
            "name": "action",
            "in": "query"
          },
          {
            "schema": {
              "type": [
                "integer",
                "null"
              ],
              "minimum": 0,
              "default": 0,
              "example": 0
            },
            "required": false,
            "name": "offset",
            "in": "query"
          },
          {
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50,
              "example": 50
            },
            "required": false,
            "name": "limit",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "Audit events",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/NodeAuditEvent"
                      }
                    },
                    "meta": {
                      "type": "object",
                      "properties": {
                        "offset": {
                          "type": "integer"
                        },
                        "limit": {
                          "type": "integer"
                        },
                        "more": {
                          "type": "boolean"
                        }
                      },
                      "required": [
                        "offset",
                        "limit",
                        "more"
                      ]
                    }
                  },
                  "required": [
                    "data",
                    "meta"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/node/v1/nodes/update": {
      "post": {
        "operationId": "updateNode",
        "summary": "Register a node, or update what it reports about itself",
        "tags": [
          "nodes"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RegisterNode"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The node as it is now recorded",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Node"
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/node/v1/desired/get": {
      "get": {
        "operationId": "getNodeDesiredState",
        "summary": "Fetch a node's desired state, if it has changed",
        "tags": [
          "desired"
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 63,
              "pattern": "^[a-z0-9][a-z0-9-]*[a-z0-9]$|^[a-z0-9]$",
              "example": "macbook-dev-01"
            },
            "required": true,
            "name": "nodeId",
            "in": "query"
          },
          {
            "schema": {
              "type": [
                "integer",
                "null"
              ],
              "minimum": 0,
              "default": 0,
              "example": 6
            },
            "required": false,
            "name": "since",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "Desired state, newer than the generation asked about",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/NodeDesiredState"
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "204": {
            "description": "Nothing has changed since that generation"
          }
        }
      }
    },
    "/node/v1/desired/update": {
      "post": {
        "operationId": "updateNodeDesiredState",
        "summary": "Set what a node should be running",
        "tags": [
          "desired"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateNodeDesiredState"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The new desired state, with the generation it was given",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/NodeDesiredState"
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/node/v1/status/update": {
      "post": {
        "operationId": "updateNodeStatus",
        "summary": "Report what a node is actually running",
        "tags": [
          "status"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateNodeStatus"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The report as it was recorded",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "allOf": [
                        {
                          "$ref": "#/components/schemas/NodeStatus"
                        },
                        {
                          "allOf": [
                            {
                              "$ref": "#/components/schemas/UpdateNodeStatus"
                            },
                            {
                              "type": "object",
                              "properties": {
                                "reportedAt": {
                                  "type": "string",
                                  "format": "date-time",
                                  "example": "2026-08-27T09:41:55Z"
                                }
                              },
                              "required": [
                                "reportedAt"
                              ]
                            }
                          ]
                        }
                      ]
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/node/v1/commands/get": {
      "get": {
        "operationId": "getNodeCommands",
        "summary": "Anything asked of this node since it last answered",
        "tags": [
          "commands"
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 63,
              "pattern": "^[a-z0-9][a-z0-9-]*[a-z0-9]$|^[a-z0-9]$",
              "example": "macbook-dev-01"
            },
            "required": true,
            "name": "nodeId",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "Pending commands, oldest first",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/NodeCommand"
                      }
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "204": {
            "description": "Nothing pending"
          }
        }
      }
    },
    "/node/v1/commands/ack": {
      "post": {
        "operationId": "ackNodeCommand",
        "summary": "Record what came of a command",
        "tags": [
          "commands"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AckNodeCommand"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Whether there was a pending command to acknowledge",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "acknowledged": {
                          "type": "boolean"
                        }
                      },
                      "required": [
                        "acknowledged"
                      ]
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/node/v1/nodes/list": {
      "get": {
        "operationId": "listNodes",
        "summary": "List nodes and what each last reported",
        "tags": [
          "nodes"
        ],
        "parameters": [
          {
            "schema": {
              "type": "string"
            },
            "required": false,
            "name": "cursor",
            "in": "query"
          },
          {
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 20
            },
            "required": false,
            "name": "limit",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "Nodes",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/NodeSummary"
                      }
                    },
                    "meta": {
                      "type": "object",
                      "properties": {
                        "cursor": {
                          "type": [
                            "string",
                            "null"
                          ]
                        }
                      },
                      "required": [
                        "cursor"
                      ]
                    }
                  },
                  "required": [
                    "data",
                    "meta"
                  ]
                }
              }
            }
          }
        }
      }
    }
  },
  "webhooks": {}
}
