Skip to main content
Glama

deploy

Apply a structured ReleaseSpec to publish project changes atomically: database migrations, functions, assets, routes, secrets, and subdomains.

Instructions

Unified apply primitive. Accepts a structured ReleaseSpec — database (migrations + expose), value-free secrets.require/delete declarations, functions, site, site.public_paths, site.embedding (framing opt-in by catalog key, e.g. { frame_ancestors: ['localhost'] }; null = deny), site.sign_in_path (the app's own same-origin sign-in page for MCP authorization, e.g. '/join'; null = hosted page), subdomains, and routes.replace web routes — with explicit replace vs patch semantics per resource. Migration entries use id for immutable versioned SQL or name for generated/idempotent content-tracked SQL; name compiles client-side to _<sha256(sql)[0:16]>. Use site.public_paths for clean static URLs such as /events backed by release asset events.html; explicit mode does not expose /events.html unless separately declared, while mode: 'implicit' restores filename-derived reachability and can widen access. Route entries map exact/final-wildcard browser paths like /admin and /admin/* to Node 22 Fetch Request -> Response functions, or exact GET/HEAD method-aware static aliases such as /events to { type: 'static', file: 'events.html' }; acknowledge an intentionally read-only GET/HEAD wildcard function route with allow_warning_codes: ['WILDCARD_ROUTE_EXCLUDES_MUTATION_METHODS']. Direct /functions/v1/:name remains API-key protected. Secret values are set first with r.secrets.set (a run snippet) or run402 secrets set, never placed in deploy specs. All bytes ride through CAS (no inline-body cap). Returns release_id, URLs, warnings, and a structured progress-event log. Stops before upload/commit on confirmation-required warnings unless reviewed codes are passed with allow_warning_codes or allow_warnings is true.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
baseNoDiff base. Default `{ release: 'current' }`. Use `{ release: 'empty' }` for a fresh deploy that fails if a release already exists.
i18nNoRouted-locale-context release slice. Omit to carry forward from base release; pass null to clear the slice; pass { defaultLocale, locales, detect? } to replace. Drives the negotiated locale that the gateway surfaces to routed HTTP function invocations via x-run402-locale and x-run402-default-locale request headers (omitted entirely when the active release has no i18n slice). Static-route hits do NOT receive locale negotiation.
siteNo
assetsNov1.48 unified-apply assets slice. Asset writes promote inside the same activation transaction as functions/site/secrets so a release flips atomically.
routesNoApply-v1 web routes. Omit or pass null to carry forward base routes; pass { replace: [] } to clear routes; pass { replace: [{ pattern, methods?, target: { type: 'function', name } }] } for functions or exact GET/HEAD { target: { type: 'static', file } } entries for method-aware static route aliases. Prefer site.public_paths for ordinary clean static URLs.
secretsNo
databaseNo
functionsNo
project_idYesProject ID to deploy to (from provision).
subdomainsNoAt most one subdomain per project — multi-element `set` is rejected with SUBDOMAIN_MULTI_NOT_SUPPORTED.
allow_warningsNoContinue past plan warnings that require confirmation. Default false: the tool stops before upload/commit so an agent can set missing secrets or inspect warnings.
idempotency_keyNoOptional client idempotency key. Combined with the project id and gateway-computed manifest digest to deduplicate retries.
allow_warning_codesNoContinue past specific reviewed plan warning codes. Prefer this to allow_warnings when only one known warning class is intentional.

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
errorNo
eventsNo
resultNo
statusYes
warningsNo

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed2 schema fields changedv2.5.7-astro
    • changedInput schema / properties / routes / anyOf
      Previous value: -[
      -  {
      -    "type": "null"
      -  },
      -  {
      -    "additionalProperties": false,
      -    "properties": {
      -      "replace": {
      -        "items": {
      -          "additionalProperties": false,
      -          "properties": {
      -            "acknowledge_readonly": {
      -              "const": true,
      -              "description": "Durable acknowledgement for intentional GET/HEAD final-wildcard function routes such as /share/*.",
      -              "type": "boolean"
      -            },
      -            "methods": {
      -              "description": "Optional method allowlist. Omit to allow all supported methods; do not pass an empty array.",
      -              "items": {
      -                "enum": [
      -                  "GET",
      -                  "HEAD",
      -                  "POST",
      -                  "PUT",
      -                  "PATCH",
      -                  "DELETE",
      -                  "OPTIONS"
      -                ],
      -                "type": "string"
      -              },
      -              "minItems": 1,
      -              "type": "array"
      -            },
      -            "pattern": {
      -              "description": "Route pattern such as /api, /api/*, or /login. Prefix wildcards only use a final /*.",
      -              "type": "string"
      -            },
      -            "target": {
      -              "anyOf": [
      -                {
      -                  "additionalProperties": false,
      -                  "properties": {
      -                    "name": {
      -                      "description": "Materialized release function name, not a file name or handler export.",
      -                      "type": "string"
      -                    },
      -                    "type": {
      -                      "const": "function",
      -                      "type": "string"
      -                    }
      -                  },
      -                  "required": [
      -                    "type",
      -                    "name"
      -                  ],
      -                  "type": "object"
      -                },
      -                {
      -                  "additionalProperties": false,
      -                  "properties": {
      -                    "file": {
      -                      "description": "Materialized static-site file path, relative to the site root. No leading slash, query, fragment, traversal, or directory shorthand.",
      -                      "type": "string"
      -                    },
      -                    "type": {
      -                      "const": "static",
      -                      "type": "string"
      -                    }
      -                  },
      -                  "required": [
      -                    "type",
      -                    "file"
      -                  ],
      -                  "type": "object"
      -                }
      -              ]
      -            }
      -          },
      -          "required": [
      -            "pattern",
      -            "target"
      -          ],
      -          "type": "object"
      -        },
      -        "type": "array"
      -      }
      -    },
      -    "required": [
      -      "replace"
      -    ],
      -    "type": "object"
      -  }
      -]New value: +[
      +  {
      +    "type": "null"
      +  },
      +  {
      +    "additionalProperties": false,
      +    "properties": {
      +      "replace": {
      +        "items": {
      +          "additionalProperties": false,
      +          "properties": {
      +            "methods": {
      +              "description": "Optional method allowlist. Omit to allow all supported methods; do not pass an empty array.",
      +              "items": {
      +                "enum": [
      +                  "GET",
      +                  "HEAD",
      +                  "POST",
      +                  "PUT",
      +                  "PATCH",
      +                  "DELETE",
      +                  "OPTIONS"
      +                ],
      +                "type": "string"
      +              },
      +              "minItems": 1,
      +              "type": "array"
      +            },
      +            "pattern": {
      +              "description": "Route pattern such as /api, /api/*, or /login. Prefix wildcards only use a final /*.",
      +              "type": "string"
      +            },
      +            "target": {
      +              "anyOf": [
      +                {
      +                  "additionalProperties": false,
      +                  "properties": {
      +                    "name": {
      +                      "description": "Materialized release function name, not a file name or handler export.",
      +                      "type": "string"
      +                    },
      +                    "type": {
      +                      "const": "function",
      +                      "type": "string"
      +                    }
      +                  },
      +                  "required": [
      +                    "type",
      +                    "name"
      +                  ],
      +                  "type": "object"
      +                },
      +                {
      +                  "additionalProperties": false,
      +                  "properties": {
      +                    "file": {
      +                      "description": "Materialized static-site file path, relative to the site root. No leading slash, query, fragment, traversal, or directory shorthand.",
      +                      "type": "string"
      +                    },
      +                    "type": {
      +                      "const": "static",
      +                      "type": "string"
      +                    }
      +                  },
      +                  "required": [
      +                    "type",
      +                    "file"
      +                  ],
      +                  "type": "object"
      +                }
      +              ]
      +            }
      +          },
      +          "required": [
      +            "pattern",
      +            "target"
      +          ],
      +          "type": "object"
      +        },
      +        "type": "array"
      +      }
      +    },
      +    "required": [
      +      "replace"
      +    ],
      +    "type": "object"
      +  }
      +]
    • changedInput schema / properties / site / anyOf
      Previous value: -[
      -  {
      -    "additionalProperties": false,
      -    "properties": {
      -      "embedding": {
      -        "anyOf": [
      -          {
      -            "additionalProperties": false,
      -            "properties": {
      -              "frame_ancestors": {
      -                "description": "Platform embedding catalog KEYS (never raw origins). `localhost` expands to http://localhost:* and http://127.0.0.1:*; the gateway rejects unknown keys with INVALID_SPEC naming the valid ones.",
      -                "items": {
      -                  "type": "string"
      -                },
      -                "minItems": 1,
      -                "type": "array"
      -              }
      -            },
      -            "required": [
      -              "frame_ancestors"
      -            ],
      -            "type": "object"
      -          },
      -          {
      -            "type": "null"
      -          }
      -        ],
      -        "description": "tenant-site-embedding: who may put the site in an iframe. The gateway then sends `Content-Security-Policy: frame-ancestors <expanded origins>` and drops X-Frame-Options on every response of the host. Omit to carry the previous release's declaration forward; null returns to the default deny."
      -      },
      -      "public_paths": {
      -        "anyOf": [
      -          {
      -            "additionalProperties": false,
      -            "properties": {
      -              "mode": {
      -                "const": "implicit",
      -                "description": "Restore filename-derived public reachability for static assets.",
      -                "type": "string"
      -              }
      -            },
      -            "required": [
      -              "mode"
      -            ],
      -            "type": "object"
      -          },
      -          {
      -            "additionalProperties": false,
      -            "properties": {
      -              "mode": {
      -                "const": "explicit",
      -                "description": "Use only the complete replace table as direct public static URLs.",
      -                "type": "string"
      -              },
      -              "replace": {
      -                "additionalProperties": {
      -                  "additionalProperties": false,
      -                  "properties": {
      -                    "asset": {
      -                      "description": "Release static asset path, such as events.html. This is not a public URL.",
      -                      "type": "string"
      -                    },
      -                    "cache_class": {
      -                      "description": "Optional static cache class, for example html, immutable_versioned, or revalidating_asset.",
      -                      "type": "string"
      -                    }
      -                  },
      -                  "required": [
      -                    "asset"
      -                  ],
      -                  "type": "object"
      -                },
      -                "description": "Complete map from public browser paths such as /events to release static asset paths such as events.html.",
      -                "type": "object"
      -              }
      -            },
      -            "required": [
      -              "mode",
      -              "replace"
      -            ],
      -            "type": "object"
      -          }
      -        ]
      -      },
      -      "replace": {
      -        "$ref": "#/properties/functions/properties/replace/additionalProperties/properties/files"
      -      }
      -    },
      -    "required": [
      -      "replace"
      -    ],
      -    "type": "object"
      -  },
      -  {
      -    "additionalProperties": false,
      -    "properties": {
      -      "embedding": {
      -        "$ref": "#/properties/site/anyOf/0/properties/embedding",
      -        "description": "tenant-site-embedding: who may put the site in an iframe. The gateway then sends `Content-Security-Policy: frame-ancestors <expanded origins>` and drops X-Frame-Options on every response of the host. Omit to carry the previous release's declaration forward; null returns to the default deny."
      -      },
      -      "patch": {
      -        "additionalProperties": false,
      -        "properties": {
      -          "delete": {
      -            "items": {
      -              "type": "string"
      -            },
      -            "type": "array"
      -          },
      -          "put": {
      -            "$ref": "#/properties/functions/properties/replace/additionalProperties/properties/files"
      -          }
      -        },
      -        "type": "object"
      -      },
      -      "public_paths": {
      -        "$ref": "#/properties/site/anyOf/0/properties/public_paths"
      -      }
      -    },
      -    "required": [
      -      "patch"
      -    ],
      -    "type": "object"
      -  },
      -  {
      -    "additionalProperties": false,
      -    "properties": {
      -      "embedding": {
      -        "$ref": "#/properties/site/anyOf/0/properties/embedding",
      -        "description": "tenant-site-embedding: who may put the site in an iframe. The gateway then sends `Content-Security-Policy: frame-ancestors <expanded origins>` and drops X-Frame-Options on every response of the host. Omit to carry the previous release's declaration forward; null returns to the default deny."
      -      },
      -      "public_paths": {
      -        "$ref": "#/properties/site/anyOf/0/properties/public_paths"
      -      }
      -    },
      -    "required": [
      -      "public_paths"
      -    ],
      -    "type": "object"
      -  },
      -  {
      -    "additionalProperties": false,
      -    "properties": {
      -      "embedding": {
      -        "$ref": "#/properties/site/anyOf/0/properties/embedding"
      -      }
      -    },
      -    "required": [
      -      "embedding"
      -    ],
      -    "type": "object"
      -  }
      -]New value: +[
      +  {
      +    "additionalProperties": false,
      +    "properties": {
      +      "embedding": {
      +        "anyOf": [
      +          {
      +            "additionalProperties": false,
      +            "properties": {
      +              "frame_ancestors": {
      +                "description": "Platform embedding catalog KEYS (never raw origins). `localhost` expands to http://localhost:* and http://127.0.0.1:*; the gateway rejects unknown keys with INVALID_SPEC naming the valid ones.",
      +                "items": {
      +                  "type": "string"
      +                },
      +                "minItems": 1,
      +                "type": "array"
      +              }
      +            },
      +            "required": [
      +              "frame_ancestors"
      +            ],
      +            "type": "object"
      +          },
      +          {
      +            "type": "null"
      +          }
      +        ],
      +        "description": "tenant-site-embedding: who may put the site in an iframe. The gateway then sends `Content-Security-Policy: frame-ancestors <expanded origins>` and drops X-Frame-Options on every response of the host. Omit to carry the previous release's declaration forward; null returns to the default deny."
      +      },
      +      "public_paths": {
      +        "anyOf": [
      +          {
      +            "additionalProperties": false,
      +            "properties": {
      +              "mode": {
      +                "const": "implicit",
      +                "description": "Restore filename-derived public reachability for static assets.",
      +                "type": "string"
      +              }
      +            },
      +            "required": [
      +              "mode"
      +            ],
      +            "type": "object"
      +          },
      +          {
      +            "additionalProperties": false,
      +            "properties": {
      +              "mode": {
      +                "const": "explicit",
      +                "description": "Use only the complete replace table as direct public static URLs.",
      +                "type": "string"
      +              },
      +              "replace": {
      +                "additionalProperties": {
      +                  "additionalProperties": false,
      +                  "properties": {
      +                    "asset": {
      +                      "description": "Release static asset path, such as events.html. This is not a public URL.",
      +                      "type": "string"
      +                    },
      +                    "cache_class": {
      +                      "description": "Optional static cache class, for example html, immutable_versioned, or revalidating_asset.",
      +                      "type": "string"
      +                    }
      +                  },
      +                  "required": [
      +                    "asset"
      +                  ],
      +                  "type": "object"
      +                },
      +                "description": "Complete map from public browser paths such as /events to release static asset paths such as events.html.",
      +                "type": "object"
      +              }
      +            },
      +            "required": [
      +              "mode",
      +              "replace"
      +            ],
      +            "type": "object"
      +          }
      +        ]
      +      },
      +      "replace": {
      +        "$ref": "#/properties/functions/properties/replace/additionalProperties/properties/files"
      +      },
      +      "sign_in_path": {
      +        "description": "The app's own same-origin sign-in page (e.g. \"/join\") that MCP authorization (/_run402/oauth/authorize) sends a signed-out user to, with returnTo appended, instead of the hosted /auth/sign-in. Single leading /, at most 512 chars, no query/fragment, not under /_run402/ or /auth/ (the gateway refuses with INVALID_SPEC on site.sign_in_path). Omit to carry the previous release's value forward; null returns to the hosted page.",
      +        "type": [
      +          "string",
      +          "null"
      +        ]
      +      }
      +    },
      +    "required": [
      +      "replace"
      +    ],
      +    "type": "object"
      +  },
      +  {
      +    "additionalProperties": false,
      +    "properties": {
      +      "embedding": {
      +        "$ref": "#/properties/site/anyOf/0/properties/embedding",
      +        "description": "tenant-site-embedding: who may put the site in an iframe. The gateway then sends `Content-Security-Policy: frame-ancestors <expanded origins>` and drops X-Frame-Options on every response of the host. Omit to carry the previous release's declaration forward; null returns to the default deny."
      +      },
      +      "patch": {
      +        "additionalProperties": false,
      +        "properties": {
      +          "delete": {
      +            "items": {
      +              "type": "string"
      +            },
      +            "type": "array"
      +          },
      +          "put": {
      +            "$ref": "#/properties/functions/properties/replace/additionalProperties/properties/files"
      +          }
      +        },
      +        "type": "object"
      +      },
      +      "public_paths": {
      +        "$ref": "#/properties/site/anyOf/0/properties/public_paths"
      +      },
      +      "sign_in_path": {
      +        "$ref": "#/properties/site/anyOf/0/properties/sign_in_path",
      +        "description": "The app's own same-origin sign-in page (e.g. \"/join\") that MCP authorization (/_run402/oauth/authorize) sends a signed-out user to, with returnTo appended, instead of the hosted /auth/sign-in. Single leading /, at most 512 chars, no query/fragment, not under /_run402/ or /auth/ (the gateway refuses with INVALID_SPEC on site.sign_in_path). Omit to carry the previous release's value forward; null returns to the hosted page."
      +      }
      +    },
      +    "required": [
      +      "patch"
      +    ],
      +    "type": "object"
      +  },
      +  {
      +    "additionalProperties": false,
      +    "properties": {
      +      "embedding": {
      +        "$ref": "#/properties/site/anyOf/0/properties/embedding",
      +        "description": "tenant-site-embedding: who may put the site in an iframe. The gateway then sends `Content-Security-Policy: frame-ancestors <expanded origins>` and drops X-Frame-Options on every response of the host. Omit to carry the previous release's declaration forward; null returns to the default deny."
      +      },
      +      "public_paths": {
      +        "$ref": "#/properties/site/anyOf/0/properties/public_paths"
      +      },
      +      "sign_in_path": {
      +        "$ref": "#/properties/site/anyOf/0/properties/sign_in_path",
      +        "description": "The app's own same-origin sign-in page (e.g. \"/join\") that MCP authorization (/_run402/oauth/authorize) sends a signed-out user to, with returnTo appended, instead of the hosted /auth/sign-in. Single leading /, at most 512 chars, no query/fragment, not under /_run402/ or /auth/ (the gateway refuses with INVALID_SPEC on site.sign_in_path). Omit to carry the previous release's value forward; null returns to the hosted page."
      +      }
      +    },
      +    "required": [
      +      "public_paths"
      +    ],
      +    "type": "object"
      +  },
      +  {
      +    "additionalProperties": false,
      +    "properties": {
      +      "embedding": {
      +        "$ref": "#/properties/site/anyOf/0/properties/embedding"
      +      },
      +      "sign_in_path": {
      +        "$ref": "#/properties/site/anyOf/0/properties/sign_in_path",
      +        "description": "The app's own same-origin sign-in page (e.g. \"/join\") that MCP authorization (/_run402/oauth/authorize) sends a signed-out user to, with returnTo appended, instead of the hosted /auth/sign-in. Single leading /, at most 512 chars, no query/fragment, not under /_run402/ or /auth/ (the gateway refuses with INVALID_SPEC on site.sign_in_path). Omit to carry the previous release's value forward; null returns to the hosted page."
      +      }
      +    },
      +    "required": [
      +      "embedding"
      +    ],
      +    "type": "object"
      +  },
      +  {
      +    "additionalProperties": false,
      +    "properties": {
      +      "sign_in_path": {
      +        "$ref": "#/properties/site/anyOf/0/properties/sign_in_path"
      +      }
      +    },
      +    "required": [
      +      "sign_in_path"
      +    ],
      +    "type": "object"
      +  }
      +]
  2. Changed5 schema fields changed
    • removedInput schema / properties / database / properties / migrations / items / properties / sql_ref / properties / contentType
      Removed value: -{
      -  "type": "string"
      -}
    • addedInput schema / properties / database / properties / migrations / items / properties / sql_ref / properties / content_type
      Added value: +{
      +  "type": "string"
      +}
    • changedInput schema / properties / functions / properties / replace / additionalProperties / properties / source / anyOf
      Previous value: -[
      -  {
      -    "type": "string"
      -  },
      -  {
      -    "additionalProperties": false,
      -    "properties": {
      -      "contentType": {
      -        "description": "MIME type override. Auto-detected from the path's extension when omitted.",
      -        "type": "string"
      -      },
      -      "data": {
      -        "type": "string"
      -      },
      -      "encoding": {
      -        "enum": [
      -          "utf-8",
      -          "base64"
      -        ],
      -        "type": "string"
      -      }
      -    },
      -    "required": [
      -      "data"
      -    ],
      -    "type": "object"
      -  }
      -]New value: +[
      +  {
      +    "type": "string"
      +  },
      +  {
      +    "additionalProperties": false,
      +    "properties": {
      +      "content_type": {
      +        "description": "MIME type override (snake_case, like every wire field). Auto-detected from the path's extension when omitted.",
      +        "type": "string"
      +      },
      +      "data": {
      +        "type": "string"
      +      },
      +      "encoding": {
      +        "enum": [
      +          "utf-8",
      +          "base64"
      +        ],
      +        "type": "string"
      +      }
      +    },
      +    "required": [
      +      "data"
      +    ],
      +    "type": "object"
      +  }
      +]
    • changedInput schema / properties / site / anyOf
      Previous value: -[
      -  {
      -    "additionalProperties": false,
      -    "properties": {
      -      "public_paths": {
      -        "anyOf": [
      -          {
      -            "additionalProperties": false,
      -            "properties": {
      -              "mode": {
      -                "const": "implicit",
      -                "description": "Restore filename-derived public reachability for static assets.",
      -                "type": "string"
      -              }
      -            },
      -            "required": [
      -              "mode"
      -            ],
      -            "type": "object"
      -          },
      -          {
      -            "additionalProperties": false,
      -            "properties": {
      -              "mode": {
      -                "const": "explicit",
      -                "description": "Use only the complete replace table as direct public static URLs.",
      -                "type": "string"
      -              },
      -              "replace": {
      -                "additionalProperties": {
      -                  "additionalProperties": false,
      -                  "properties": {
      -                    "asset": {
      -                      "description": "Release static asset path, such as events.html. This is not a public URL.",
      -                      "type": "string"
      -                    },
      -                    "cache_class": {
      -                      "description": "Optional static cache class, for example html, immutable_versioned, or revalidating_asset.",
      -                      "type": "string"
      -                    }
      -                  },
      -                  "required": [
      -                    "asset"
      -                  ],
      -                  "type": "object"
      -                },
      -                "description": "Complete map from public browser paths such as /events to release static asset paths such as events.html.",
      -                "type": "object"
      -              }
      -            },
      -            "required": [
      -              "mode",
      -              "replace"
      -            ],
      -            "type": "object"
      -          }
      -        ]
      -      },
      -      "replace": {
      -        "$ref": "#/properties/functions/properties/replace/additionalProperties/properties/files"
      -      }
      -    },
      -    "required": [
      -      "replace"
      -    ],
      -    "type": "object"
      -  },
      -  {
      -    "additionalProperties": false,
      -    "properties": {
      -      "patch": {
      -        "additionalProperties": false,
      -        "properties": {
      -          "delete": {
      -            "items": {
      -              "type": "string"
      -            },
      -            "type": "array"
      -          },
      -          "put": {
      -            "$ref": "#/properties/functions/properties/replace/additionalProperties/properties/files"
      -          }
      -        },
      -        "type": "object"
      -      },
      -      "public_paths": {
      -        "$ref": "#/properties/site/anyOf/0/properties/public_paths"
      -      }
      -    },
      -    "required": [
      -      "patch"
      -    ],
      -    "type": "object"
      -  },
      -  {
      -    "additionalProperties": false,
      -    "properties": {
      -      "public_paths": {
      -        "$ref": "#/properties/site/anyOf/0/properties/public_paths"
      -      }
      -    },
      -    "required": [
      -      "public_paths"
      -    ],
      -    "type": "object"
      -  }
      -]New value: +[
      +  {
      +    "additionalProperties": false,
      +    "properties": {
      +      "embedding": {
      +        "anyOf": [
      +          {
      +            "additionalProperties": false,
      +            "properties": {
      +              "frame_ancestors": {
      +                "description": "Platform embedding catalog KEYS (never raw origins). `localhost` expands to http://localhost:* and http://127.0.0.1:*; the gateway rejects unknown keys with INVALID_SPEC naming the valid ones.",
      +                "items": {
      +                  "type": "string"
      +                },
      +                "minItems": 1,
      +                "type": "array"
      +              }
      +            },
      +            "required": [
      +              "frame_ancestors"
      +            ],
      +            "type": "object"
      +          },
      +          {
      +            "type": "null"
      +          }
      +        ],
      +        "description": "tenant-site-embedding: who may put the site in an iframe. The gateway then sends `Content-Security-Policy: frame-ancestors <expanded origins>` and drops X-Frame-Options on every response of the host. Omit to carry the previous release's declaration forward; null returns to the default deny."
      +      },
      +      "public_paths": {
      +        "anyOf": [
      +          {
      +            "additionalProperties": false,
      +            "properties": {
      +              "mode": {
      +                "const": "implicit",
      +                "description": "Restore filename-derived public reachability for static assets.",
      +                "type": "string"
      +              }
      +            },
      +            "required": [
      +              "mode"
      +            ],
      +            "type": "object"
      +          },
      +          {
      +            "additionalProperties": false,
      +            "properties": {
      +              "mode": {
      +                "const": "explicit",
      +                "description": "Use only the complete replace table as direct public static URLs.",
      +                "type": "string"
      +              },
      +              "replace": {
      +                "additionalProperties": {
      +                  "additionalProperties": false,
      +                  "properties": {
      +                    "asset": {
      +                      "description": "Release static asset path, such as events.html. This is not a public URL.",
      +                      "type": "string"
      +                    },
      +                    "cache_class": {
      +                      "description": "Optional static cache class, for example html, immutable_versioned, or revalidating_asset.",
      +                      "type": "string"
      +                    }
      +                  },
      +                  "required": [
      +                    "asset"
      +                  ],
      +                  "type": "object"
      +                },
      +                "description": "Complete map from public browser paths such as /events to release static asset paths such as events.html.",
      +                "type": "object"
      +              }
      +            },
      +            "required": [
      +              "mode",
      +              "replace"
      +            ],
      +            "type": "object"
      +          }
      +        ]
      +      },
      +      "replace": {
      +        "$ref": "#/properties/functions/properties/replace/additionalProperties/properties/files"
      +      }
      +    },
      +    "required": [
      +      "replace"
      +    ],
      +    "type": "object"
      +  },
      +  {
      +    "additionalProperties": false,
      +    "properties": {
      +      "embedding": {
      +        "$ref": "#/properties/site/anyOf/0/properties/embedding",
      +        "description": "tenant-site-embedding: who may put the site in an iframe. The gateway then sends `Content-Security-Policy: frame-ancestors <expanded origins>` and drops X-Frame-Options on every response of the host. Omit to carry the previous release's declaration forward; null returns to the default deny."
      +      },
      +      "patch": {
      +        "additionalProperties": false,
      +        "properties": {
      +          "delete": {
      +            "items": {
      +              "type": "string"
      +            },
      +            "type": "array"
      +          },
      +          "put": {
      +            "$ref": "#/properties/functions/properties/replace/additionalProperties/properties/files"
      +          }
      +        },
      +        "type": "object"
      +      },
      +      "public_paths": {
      +        "$ref": "#/properties/site/anyOf/0/properties/public_paths"
      +      }
      +    },
      +    "required": [
      +      "patch"
      +    ],
      +    "type": "object"
      +  },
      +  {
      +    "additionalProperties": false,
      +    "properties": {
      +      "embedding": {
      +        "$ref": "#/properties/site/anyOf/0/properties/embedding",
      +        "description": "tenant-site-embedding: who may put the site in an iframe. The gateway then sends `Content-Security-Policy: frame-ancestors <expanded origins>` and drops X-Frame-Options on every response of the host. Omit to carry the previous release's declaration forward; null returns to the default deny."
      +      },
      +      "public_paths": {
      +        "$ref": "#/properties/site/anyOf/0/properties/public_paths"
      +      }
      +    },
      +    "required": [
      +      "public_paths"
      +    ],
      +    "type": "object"
      +  },
      +  {
      +    "additionalProperties": false,
      +    "properties": {
      +      "embedding": {
      +        "$ref": "#/properties/site/anyOf/0/properties/embedding"
      +      }
      +    },
      +    "required": [
      +      "embedding"
      +    ],
      +    "type": "object"
      +  }
      +]
    • changedOutput schema / (root)
      Previous value: -nullNew value: +{
      +  "$schema": "http://json-schema.org/draft-07/schema#",
      +  "additionalProperties": true,
      +  "properties": {
      +    "error": {
      +      "additionalProperties": true,
      +      "properties": {
      +        "category": {
      +          "type": "string"
      +        },
      +        "code": {
      +          "type": "string"
      +        },
      +        "column": {
      +          "type": "integer"
      +        },
      +        "details": {},
      +        "fix": {},
      +        "http_status": {
      +          "type": "integer"
      +        },
      +        "line": {
      +          "type": "integer"
      +        },
      +        "logs": {
      +          "items": {
      +            "type": "string"
      +          },
      +          "type": "array"
      +        },
      +        "message": {
      +          "type": "string"
      +        },
      +        "mutation_state": {
      +          "type": "string"
      +        },
      +        "next_actions": {
      +          "items": {
      +            "additionalProperties": true,
      +            "properties": {
      +              "type": {
      +                "type": "string"
      +              }
      +            },
      +            "type": "object"
      +          },
      +          "type": "array"
      +        },
      +        "operation_id": {
      +          "type": "string"
      +        },
      +        "phase": {
      +          "type": "string"
      +        },
      +        "plan_id": {
      +          "type": "string"
      +        },
      +        "resource": {
      +          "type": "string"
      +        },
      +        "retryable": {
      +          "type": "boolean"
      +        },
      +        "safe_to_retry": {
      +          "type": "boolean"
      +        },
      +        "trace_id": {
      +          "type": "string"
      +        }
      +      },
      +      "required": [
      +        "code",
      +        "message",
      +        "next_actions"
      +      ],
      +      "type": "object"
      +    },
      +    "events": {
      +      "items": {
      +        "additionalProperties": true,
      +        "properties": {
      +          "type": {
      +            "type": "string"
      +          }
      +        },
      +        "type": "object"
      +      },
      +      "type": "array"
      +    },
      +    "result": {
      +      "additionalProperties": true,
      +      "properties": {
      +        "next_actions": {
      +          "items": {
      +            "$ref": "#/properties/error/properties/next_actions/items"
      +          },
      +          "type": "array"
      +        },
      +        "operation_id": {
      +          "type": "string"
      +        },
      +        "release_id": {
      +          "type": "string"
      +        },
      +        "urls": {
      +          "additionalProperties": {},
      +          "type": "object"
      +        },
      +        "warnings": {
      +          "items": {
      +            "additionalProperties": true,
      +            "properties": {
      +              "code": {
      +                "type": "string"
      +              }
      +            },
      +            "type": "object"
      +          },
      +          "type": "array"
      +        }
      +      },
      +      "required": [
      +        "release_id",
      +        "operation_id",
      +        "urls"
      +      ],
      +      "type": "object"
      +    },
      +    "status": {
      +      "enum": [
      +        "ok",
      +        "error"
      +      ],
      +      "type": "string"
      +    },
      +    "warnings": {
      +      "items": {
      +        "$ref": "#/properties/result/properties/warnings/items"
      +      },
      +      "type": "array"
      +    }
      +  },
      +  "required": [
      +    "status"
      +  ],
      +  "type": "object"
      +}
  3. Changed3 schema fields changedv4.0.2
    • changedInput schema / properties / database / properties / migrations / items / properties / id / description
      Previous value: -"Stable migration id (e.g. '001_init'). Same id+checksum across re-deploys is a registry noop; same id+different checksum is a hard error."New value: +"Stable versioned migration id (e.g. '001_init'). Same id+checksum across re-deploys is a registry noop; same id+different checksum is a hard error. Use name instead for generated/idempotent SQL."
    • addedInput schema / properties / database / properties / migrations / items / properties / name
      Added value: +{
      +  "description": "Content-tracked migration name for generated/idempotent SQL. The SDK compiles this to <name>_<sha256(sql)[0:16]>; changed content applies once under a new id and identical re-deploys noop. SQL declared with name MUST be idempotent.",
      +  "pattern": "^[a-zA-Z0-9][a-zA-Z0-9_-]{0,63}$",
      +  "type": "string"
      +}
    • removedInput schema / properties / database / properties / migrations / items / required
      Removed value: -[
      -  "id"
      -]
  4. First observedv3.6.0

TDQS

A3.6/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations present, the description carries the full behavioral burden and does so well: it discloses the atomic activation semantics, that the tool halts before upload/commit on confirmation-required warnings, the replace-vs-patch semantics per resource, and the return payload (release_id, URLs, warnings, progress-event log). It also warns that implicit public_paths mode can widen access. The main omission is auth/permission requirements for the deploy operation itself.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness2/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is one enormous unbroken paragraph dense with jargon, with no bullets or line breaks to structure the many orthogonal concepts. Large stretches restate material already present in the schema (public_paths modes, embedding frame-ancestors, sign_in_path constraints, migration name compilation), so several sentences do not earn their place. Only the front-loaded opening sentence is genuinely efficient.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a high-complexity, deeply nested tool, the description covers most of the spec surface — database, secrets, functions, site, subdomains, routes, warnings, and idempotency — and an output schema exists so return values need not be re-explained. Slices like `base`, `i18n`, and `assets` are left entirely to the schema, which is acceptable given the schema's richness, but leaves the description slightly short of fully self-contained.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 69% across 13 nested parameters, so the description must add meaning, and it does: replace vs patch semantics, `id` vs `name` migration identity, client-side compilation of `name` to `<name>_<sha256(sql)[0:16]>`, null-vs-omit carry-forward behavior, and framing opt-in via catalog keys. Some of this duplicates the schema's own field descriptions, and `base`, `i18n`, `assets`, and `idempotency_key` get no prose at all.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb+resource — a unified apply/deploy primitive that accepts a structured ReleaseSpec and flips a release atomically. It enumerates the spec slices it consumes (database, secrets, functions, site, subdomains, routes), so an agent knows what the tool operates on. It does not, however, distinguish itself from plausible siblings like `up` or `run`, so it stops short of a 5.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

There is real prerequisite guidance: secret values must be set first via `r.secrets.set` or `run402 secrets set` and never embedded in the spec, and the tool stops before upload/commit on confirmation-required warnings unless codes are allowed. It also implies routing choices ('Use site.public_paths for clean static URLs'). But it never states when to choose `deploy` over sibling tools such as `up` or `run`, leaving the primary selection decision to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Deploy Server

Other Tools