From b692102e8c7c51d0f9870ecf17ee9191899d06c2 Mon Sep 17 00:00:00 2001 From: Zach Kelling Date: Tue, 20 Oct 2026 01:59:31 -0700 Subject: [PATCH] Release 8.5.753 with CLI commands regenerated from the live API CI reads the deployed public API document, but the local helper still fetched a private pinned YAML file. Generate from the public document consistently and refresh its digest, commands, and live evidence together. Testing: workspace suite; corrected evidence provenance and reran CLI/spec regression tests successfully; strict clippy; spec-check; 1025 live probes found no absent coordinates, with 53 inconclusive responses. Risk: medium; generated commands follow current API shapes and remove retired routes. How to revert: revert this commit and install v8.5.752. --- .spec-lock | 7 +- Cargo.lock | 2 +- Cargo.toml | 2 +- Makefile | 66 +++-------------- scripts/generate.sh | 44 +---------- spec/cloud.json | 2 +- spec/live.json | 2 +- src/commands/product/generated.rs | 117 ++++++++++++++++++++---------- 8 files changed, 101 insertions(+), 141 deletions(-) diff --git a/.spec-lock b/.spec-lock index 1a1f8051e..404867c0f 100644 --- a/.spec-lock +++ b/.spec-lock @@ -1,4 +1,5 @@ -ref=86dcaea8092b3597a6325b7abd6df0b820978160 -sha256=8886c3c7b7f8e5feee00b09a36241a3a283fc43a24ccdb1264dc44606115f901 +ref=v8.5.844 +sha256=5ca4ed58f87827cb879e409da8f803ef57b52b29123d2403868ed6af66aa8e2f repo=hanzo-inc/cloud -path=openapi.yaml +path=/v1/openapi.json +url=https://api.hanzo.ai/v1/openapi.json diff --git a/Cargo.lock b/Cargo.lock index bba0a308f..5bc5c66ea 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -886,7 +886,7 @@ dependencies = [ [[package]] name = "hanzo-cli" -version = "8.5.752" +version = "8.5.753" dependencies = [ "anyhow", "assert_cmd", diff --git a/Cargo.toml b/Cargo.toml index 243669a9d..ae4001652 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "hanzo-cli" -version = "8.5.752" +version = "8.5.753" edition = "2021" authors = ["Hanzo AI"] description = "Unified CLI for Hanzo AI development tools" diff --git a/Makefile b/Makefile index 1f1cc84f1..636bd0a58 100644 --- a/Makefile +++ b/Makefile @@ -1,70 +1,24 @@ -# hanzo — the CLI. Five commands matter here, and they are TWO questions asked -# about ONE chain: -# -# hanzoai/cloud@ openapi.yaml the document, pinned in .spec-lock -# │ genspec -# spec/cloud.json the projection -# │ genproduct -# generated.rs the command tree -# · spec/live.json what the server said about all of it -# -# `spec` / `spec-check` IS THE PROJECTION STILL ITS INPUT? Re-derive, refuse a -# delta. Needs the document (network, a token). -# `live` / `live-check` IS THE INPUT STILL TRUE OF PRODUCTION? Ask the running -# server, with a control for every probe, and write down -# the raw answers. Needs the network and nothing else. -# `verify` RULE ON WHAT IS COMMITTED. Both directions, every link of -# the chain, no network at all — which is why `cargo test` -# runs it too, and why it cannot be the gate that gets -# switched off for being slow or flaky. -# -# That split is the whole design. A gate that needs the network in CI gets -# disabled, and a disabled gate is worse than none; a gate that never asks the -# server can only compare derived artifacts with each other, which they satisfy -# whether or not either is still true. So ASKING and RULING are two commands over -# one checked-in body of evidence. -# -# `spec` and `spec-check` both go through scripts/generate.sh, which is also what -# hanzoai/ci's `client:` lane calls — so a maintainer, the push gate and the -# release all run the same derivation. A gate that runs a different generation -# than the writer is a gate that tests something nobody ships. - +# Hanzo CLI checks: generate from the same public API document used by CI. +# The lock records the API release and the digest actually used. spec-check +# refuses changed input; make spec refreshes the projection from that input. SHELL := /bin/bash - -# THE FORGE IS CANONICAL. git.hanzo.ai holds hanzoai/cloud; the GitHub copy is a -# mirror, and a mirror can be behind — universe's was measured 40 chat versions -# and 51 app versions stale on the same day this changed. Verifying the command -# tree against a mirror means a gate that passes on a document production is not -# serving, which is worse than a gate that fails. -# -# The forge serves its API at /v1/, NOT /api/v1/ — asking for /api/v1 returns a -# 404 that reads exactly like a rejected credential and costs an hour. -SPEC_HOST ?= https://git.hanzo.ai/v1 -SPEC_REPO ?= hanzo-inc/cloud -SPEC_PATH ?= openapi.yaml -LOCK := .spec-lock +SPEC_URL ?= https://api.hanzo.ai/v1/openapi.json +LOCK := .spec-lock .PHONY: help spec spec-check live live-check verify test build lint help: ## This. @grep -hE '^[a-z-]+:.*##' $(MAKEFILE_LIST) | sed 's/:.*## /\t/' | expand -t20 -# The document, BY VALUE at the ref this tree names. Fetching it — rather than -# reading api.hanzo.ai — is what makes the check reproducible: the same ref -# always yields the same bytes, and the digest below proves it. A live host -# answers "what is deployed right now", which is a different question and not -# one a committed artifact can be measured against. define fetch_spec ref=$$(sed -n 's/^ref=//p' $(LOCK)); \ want=$$(sed -n 's/^sha256=//p' $(LOCK)); \ -[ -n "$$ref" ] || { echo "no $(LOCK) — this tree does not name a document"; exit 1; }; \ -[ -n "$${SPEC_TOKEN:-}" ] || { echo "SPEC_TOKEN (contents:read on $(SPEC_REPO)) is unset"; exit 1; }; \ -tmp=$$(mktemp); \ -curl -fsSL -H "Authorization: token $$SPEC_TOKEN" \ - "$(SPEC_HOST)/repos/$(SPEC_REPO)/raw/$(SPEC_PATH)?ref=$$ref" -o "$$tmp"; \ +[ -n "$$ref" ] && [ -n "$$want" ] || { echo "$(LOCK) must name the API release and digest"; exit 1; }; \ +tmp=$$(mktemp); trap 'rm -f "$$tmp"' EXIT; \ +curl -fsSL "$(SPEC_URL)" -o "$$tmp"; \ got=$$(sha256sum "$$tmp" | cut -d' ' -f1); \ -[ "$$got" = "$$want" ] || { echo "$(SPEC_REPO)@$$ref:$(SPEC_PATH) hashes to $$got, but $(LOCK) says $$want — the ref moved under this capture"; exit 1; }; \ -export SPEC="$$tmp" SPEC_REF="$$ref" HANZO_SPEC_REPO="$(SPEC_REPO)" +[ "$$got" = "$$want" ] || { echo "API document changed: refresh the lock and projection together (expected $$want, got $$got)"; exit 1; }; \ +export SPEC="$$tmp" SPEC_REF="$$ref" HANZO_SPEC_REPO="hanzo-inc/cloud" endef # Moving the projection forward RE-ASKS THE SERVER in the same breath. Evidence diff --git a/scripts/generate.sh b/scripts/generate.sh index 17d769223..3a0a066aa 100755 --- a/scripts/generate.sh +++ b/scripts/generate.sh @@ -1,34 +1,8 @@ #!/usr/bin/env sh -# The CLI's projection of the Hanzo Cloud API document — the same call site every -# other client repo has, so hanzoai/ci's `client:` lane drives all eight the same -# way. -# -# ONE INPUT, by value: -# $SPEC the document itself, already fetched at a pinned ref and already -# digest-checked by the lane. Never a live host: at generation time -# the deploy this describes has already happened, and asking -# api.hanzo.ai instead would name whatever it is serving now rather -# than the release that handed us this file. -# $SPEC_REF which ref that was. genspec stamps it, with the document's own -# sha256, into the spec's provenance — so `spec/cloud.json` can -# always answer "which release am I?". -# -# One optional argument: `--check` re-asks instead of rewriting (exit 1 on any -# delta). Same binary, same derivation — which is what keeps the gate from -# testing a different generation than the one that writes the file. It is an -# argument and not an env var because that is the spelling every other client -# repo's call site already uses, and one spelling of one idea is the point. -# -# THE SECOND INPUT IS GONE, and with it the clone and the credential. This script -# used to fetch hanzoai/openapi and pin it in `.spec-lock` beside the document, -# because the hand-authored master `hanzo.yaml` was the last source of -# request-body and query SHAPE for cloud's untyped handlers. It had stopped being -# only that: 71 operations entered `spec/cloud.json` on the master's word alone — -# two addressing nothing at all, and sixty-six "confirmed" only by a -# `{wildcardN}` relay door, which answers identically for a real path and an -# invented one. A second authority over what EXISTS is how a CLI grows commands -# no server serves. The document decides existence, prose and shape alike now, so -# there is nothing left to clone and no SPEC_TOKEN to hold. +# Generate from the API document supplied by value in SPEC. SPEC_REF identifies +# the API release that supplied it. CI and make spec-check use the public +# /v1/openapi.json document; .spec-lock records its digest. +# --check refuses any projection change without rewriting files. set -eu cd "$(dirname "$0")/.." @@ -46,13 +20,3 @@ fi cargo run --quiet --features maintainer --bin genspec --locked cargo run --quiet --features maintainer --bin genproduct --locked - -# `.spec-lock` has ONE writer — the nightly re-pin in `.hanzo/workflows/drift.yml`, -# which reads hanzoai/cloud's newest tag, fetches the document at it, and records -# the ref beside the digest of the bytes it actually read. It used to be named as -# hanzoai/ci's client: lane, on the strength of a `repository_dispatch` a cloud -# release was supposed to send; nothing was ever delivered, and on a push that lane -# is check-only at the LOCKED ref, so for 104 runs the lock had no writer at all -# and moved once, by hand. This script writes no half of it: it used to append a -# second (`master=`, the hanzoai/openapi commit it generated against), and there is -# no second half. diff --git a/spec/cloud.json b/spec/cloud.json index 8eaf79a7d..2e5bcd9be 100644 --- a/spec/cloud.json +++ b/spec/cloud.json @@ -1 +1 @@ -{"components":{"schemas":{"CaptureBatch":{"properties":{"batch":{"items":{"$ref":"#/components/schemas/CaptureEvent"},"type":"array"},"events":{"items":{"$ref":"#/components/schemas/CaptureEvent"},"type":"array"}},"type":"object"},"CaptureEvent":{"properties":{"anonymousId":{"type":"string"},"channel":{"type":"string"},"clip":{"$ref":"#/components/schemas/ClipBody"},"currency":{"type":"string"},"distinctId":{"type":"string"},"environment":{"type":"string"},"error":{"$ref":"#/components/schemas/Exception"},"event":{"type":"string"},"groupId":{"type":"string"},"groupType":{"type":"string"},"kind":{"type":"string"},"level":{"type":"string"},"library":{"type":"string"},"libraryVersion":{"type":"string"},"log":{"$ref":"#/components/schemas/LogBody"},"messageId":{"type":"string"},"metric":{"$ref":"#/components/schemas/MetricBody"},"path":{"type":"string"},"personId":{"type":"string"},"product":{"type":"string"},"productId":{"type":"string"},"properties":{"additionalProperties":{},"type":"object"},"quantity":{"type":"integer"},"refCode":{"type":"string"},"referrer":{"type":"string"},"release":{"type":"string"},"resource":{"type":"string"},"revenue":{"type":"number"},"service":{"type":"string"},"sessionId":{"type":"string"},"signupWeek":{"type":"string"},"site":{"type":"string"},"span":{"$ref":"#/components/schemas/SpanBody"},"spanId":{"type":"string"},"timestamp":{"type":"string"},"traceId":{"type":"string"},"type":{"type":"string"},"url":{"type":"string"},"utm":{"$ref":"#/components/schemas/UTM"}},"type":"object"},"CartItemSet":{"properties":{"id":{"description":"ID is the cart to amend, from the path.","type":"string"},"product":{"description":"Product names the catalog product to set, by its id or its URL slug. Give\nthis or Variant, never both; a request naming neither is refused.","type":"string"},"quantity":{"description":"Quantity is how many of that item the cart should hold AFTER this call — it\nis the resulting count, not a delta, so sending 3 twice leaves 3 and not 6.\nZERO REMOVES the line, which is the only way to take an item out.","format":"int64","type":"integer"},"variant":{"description":"Variant names the specific sellable variant to set, by its id or its SKU.\nPrefer it over Product for anything sold in sizes, colours or tiers — the\nprice and the stock are the variant's, not the product's.","type":"string"}},"type":"object"},"CartOpen":{"properties":{"currency":{"description":"Currency is the ISO 4217 code the cart is priced in, lower-cased. Empty\nmeans usd.","type":"string"},"email":{"description":"Email is the shopper's address, for a cart that belongs to someone who has\nnot signed in. It is what a guest checkout and an abandoned-cart follow-up\nkey on. Empty is fine.","type":"string"},"store":{"description":"Store is the storefront this cart is being filled on. Empty uses the org's\ndefault store, which is what a single-storefront merchant always wants.","type":"string"},"user":{"description":"User is the id of the signed-in shopper this cart belongs to, when there is\none. Empty means a guest cart identified only by its own id.","type":"string"}},"type":"object"},"ClipBody":{"properties":{"bytes":{"type":"integer"},"duration":{"type":"integer"},"object":{"type":"string"}},"type":"object"},"CorrectIn":{"properties":{"answer":{"description":"Answer is the right option label; a score's level may be named by its\nindex.","type":"string"},"cohort":{"description":"Cohort groups corrections the org files together.","type":"string"},"decision":{"description":"Decision is the decision's id.","type":"string"},"note":{"description":"Note says why, for the person reading it later.","type":"string"},"question":{"description":"Question is the question's key.","type":"string"}},"type":"object"},"Exception":{"properties":{"frames":{"items":{"$ref":"#/components/schemas/Frame"},"type":"array"},"handled":{"type":"boolean"},"message":{"type":"string"},"stack":{"type":"string"},"type":{"type":"string"}},"type":"object"},"Frame":{"properties":{"column":{"type":"integer"},"file":{"type":"string"},"function":{"type":"string"},"line":{"type":"integer"}},"type":"object"},"LogBody":{"properties":{"body":{"type":"string"},"number":{"type":"integer"},"severity":{"type":"string"}},"type":"object"},"MCPRequest":{"properties":{"id":{},"jsonrpc":{"type":"string"},"method":{"type":"string"},"params":{"additionalProperties":{},"type":"object"}},"type":"object"},"MetricBody":{"properties":{"labels":{"additionalProperties":{},"type":"object"},"name":{"type":"string"},"value":{"type":"number"}},"type":"object"},"PagesDeploy":{"properties":{"branch":{"type":"string"}},"type":"object"},"SpanBody":{"properties":{"duration":{"type":"integer"},"id":{"type":"string"},"kind":{"type":"string"},"parent":{"type":"string"},"status":{"type":"string"},"trace":{"type":"string"}},"type":"object"},"UTM":{"properties":{"campaign":{"type":"string"},"content":{"type":"string"},"medium":{"type":"string"},"source":{"type":"string"},"term":{"type":"string"}},"type":"object"},"account.appearance":{"properties":{"accent":{"description":"Accent is the one hue — a CSS colour token (a hex, or a bounded functional\ncolour like rgb()/oklch()). Anything else is dropped rather than stored.","type":"string"},"density":{"description":"Density is the spacing step: \"compact\", \"default\" or \"comfortable\".","type":"string"},"type":{"description":"Type is the text-size multiplier, clamped to the ramp window [0.85, 1.4].\nAbsent (0) leaves the published default.","format":"double","type":"number"}},"type":"object"},"account.keyBudget":{"properties":{"month":{"description":"Month is per calendar month, UTC.","format":"int64","type":"integer"},"total":{"description":"Total is over the key's whole life.","format":"int64","type":"integer"}},"type":"object"},"account.keyEdit":{"properties":{"budget":{"$ref":"#/components/schemas/account.keyBudget","description":"Budget replaces the key's spend caps, in cents; a zero drops that cap."},"expires":{"description":"Expires replaces when the key stops working, RFC 3339. An empty string means\nnever.","type":"string"},"id":{"description":"ID is the key to edit, from the path.","type":"string"},"limit":{"description":"Limit replaces what the key may reach. An empty list makes it unrestricted.","items":{"type":"string"},"type":"array"},"name":{"description":"Name relabels the key.","type":"string"},"rate":{"description":"Rate replaces the key's requests a minute; zero drops the limit.","format":"int64","type":"integer"}},"type":"object"},"account.keyIn":{"properties":{"budget":{"$ref":"#/components/schemas/account.keyBudget","description":"Budget caps what the key may spend on models, in cents, per calendar month\nand in all; a request past either is refused 402. Omitted means no cap."},"expires":{"description":"Expires is when the key stops working, RFC 3339. Omitted means never.","type":"string"},"limit":{"description":"Limit narrows what the key may reach, as `kind:name` entries: `model:zen5`,\n`project:acme`, `product:commerce`, or `model:*` for a whole kind. It only\never NARROWS — a key never reaches further than the person who made it.\nOmitted makes an unrestricted key.\n\nExample: {\"name\": \"ci\", \"limit\": [\"model:zen5\", \"project:acme\"]}","items":{"type":"string"},"type":"array"},"name":{"description":"Name labels the key. Omitted names it \"key N\".","type":"string"},"rate":{"description":"Rate caps the key's requests a minute; past it a request is refused 429.\nOmitted means no limit of its own.","format":"int64","type":"integer"},"type":{"description":"Type is the key class: \"secret\" (sk-, session-equivalent, belongs on a\nserver) or \"publishable\" (pk-, org-identifying, safe in a browser bundle).\nOmitted means secret.","type":"string"}},"type":"object"},"account.onboardReq":{"properties":{"name":{"description":"Name is the organization's display name. Ignored when personal is true, which\nderives the name from the caller's own username instead.","type":"string"},"personal":{"description":"Personal asks for the caller's own space: the name is derived from their\nusername and the slug auto-suffixes to stay unique. Meaningless — and refused\n— for a caller who already has an organization.","type":"boolean"}},"type":"object"},"ad.campaignInput":{"properties":{"account":{"description":"Account is the provider ad-account this campaign runs on (Meta act_). Optional.","type":"string"},"budget":{"description":"Budget is the campaign budget in MINOR units (cents). Negative values clamp to 0.","format":"int64","type":"integer"},"name":{"description":"Name is the campaign's display label. Required; trimmed and bounded to 1024 bytes.","type":"string"},"objective":{"description":"Objective is the campaign goal as the provider names it. Optional, bounded to 1024 bytes.","type":"string"},"platform":{"description":"Platform is the ad network: meta, google, tiktok or x. Empty defaults to meta.","type":"string"},"spend":{"description":"Spend is the amount spent so far in MINOR units (cents). Negative values clamp to 0.","format":"int64","type":"integer"},"status":{"description":"Status is the lifecycle state: draft, active, paused or completed. Empty defaults to draft.","type":"string"}},"type":"object"},"ad.updateCampaignIn":{"properties":{"account":{"description":"Account is the provider ad-account this campaign runs on (Meta act_). Optional.","type":"string"},"budget":{"description":"Budget is the campaign budget in MINOR units (cents). Negative values clamp to 0.","format":"int64","type":"integer"},"name":{"description":"Name is the campaign's display label. Required; trimmed and bounded to 1024 bytes.","type":"string"},"objective":{"description":"Objective is the campaign goal as the provider names it. Optional, bounded to 1024 bytes.","type":"string"},"platform":{"description":"Platform is the ad network: meta, google, tiktok or x. Empty defaults to meta.","type":"string"},"spend":{"description":"Spend is the amount spent so far in MINOR units (cents). Negative values clamp to 0.","format":"int64","type":"integer"},"status":{"description":"Status is the lifecycle state: draft, active, paused or completed. Empty defaults to draft.","type":"string"}},"type":"object"},"affiliate.applyRequest":{"properties":{"requestedCode":{"description":"RequestedCode is the vanity code the applicant asks for; approval may mint\na different one if it is taken. Body-only: the URL cannot supply it.","type":"string"}},"type":"object"},"affiliate.attributeRequest":{"properties":{"code":{"description":"Code is the affiliate code the referred org arrived with. Body-only: the\nURL cannot supply it.","type":"string"}},"type":"object"},"affiliate.clickRequest":{"properties":{"code":{"description":"Code is the share-link code that was clicked. Body-only: the URL cannot\nsupply it.","type":"string"}},"type":"object"},"affiliate.createLinkRequest":{"properties":{"code":{"description":"Code is an optional vanity code; it must be free across the whole\ndirectory, and omitting it mints a random one. Body-only.","type":"string"},"label":{"description":"Label is cosmetic — trimmed, stripped of control characters, capped — and\nnever part of a code. Body-only: the URL cannot supply it.","type":"string"}},"type":"object"},"affiliate.handleRequest":{"properties":{"handle":{"description":"Handle is the public leaderboard display name; empty opts out. Body-only:\nthe URL cannot supply it.","type":"string"}},"type":"object"},"agent.CodingStartIn":{"properties":{"after":{"description":"After names a previous run's session, and starts this one from where that\none stopped instead of from the repository's default. It is how a follow-up\ninstruction — \"now add tests for it\" — builds on work already done rather\nthan beginning again on a fresh clone: the follow-up resumes the earlier\nrun's sandbox and works in its tree, files, installs and all, while that\nsandbox is kept; one reaped by then is cloned again from the earlier branch.\n\nIt sets the base and nothing else, so this run still writes its OWN branch.\nOne run, one branch: a run that wrote back onto an earlier run's branch\nwould break the rule the forge's ref policy is built on, and would leave\ntwo turns of work with one name to review.\n\nA caller who already knows the branch may pass Base directly; this exists\nbecause the branch is derived from a session id and nobody should have to\nknow how. Base wins if both are given.","type":"string"},"agentRef":{"description":"AgentRef names a configured agent to run as, which is how an org pins a\nharness, a model and a prompt to a name. Empty runs the default agent.","type":"string"},"base":{"description":"Base is the branch to start from. Empty takes the repository's default. The\nrun never writes here — it writes the agent branch it answers with.","type":"string"},"desktop":{"description":"Desktop asks for a run with a SCREEN — an image carrying an X server — for a\ntask that has to drive a browser or another windowed program. False, the\ndefault, is a headless checkout, which is what writing code needs.","type":"boolean"},"effort":{"description":"Effort is how hard that model reasons: low, medium or high. Empty takes the\nmodel's own default. Taken by the dev and codex harnesses, like Model.","type":"string"},"issue":{"description":"Issue is the number of the issue on Repo this run resolves. Its pull\nrequest says `Closes #`, so merging the work closes the issue. Zero is a\nrun no issue asked for.","format":"int64","type":"integer"},"mode":{"description":"Mode is what the run may do to the repository: `build` edits, commits and\npushes its branch; `plan` reads the repository and answers with a plan,\nwriting nothing — its sandbox is handed a credential that can only read and\nno push step runs, and the plan arrives as the run's final status. `setup`\nis a plan put to one question: its agent explores the checkout, installs and\nchecks what it finds, and ends with the codebase's environment, which is kept\nas the proposal at /v1/environment/{repo} until someone saves it. Empty is\n`build`. A plan or a setup runs in our sandbox only: a claimed machine clones\nand pushes with its own credential, so one routed to a machine is refused.","type":"string"},"model":{"description":"Model is the model the run's agent thinks with, by the id GET /v1/models\nlists. Empty takes the platform's coding model. The dev and codex harnesses\ntake it; the others do not think with a model we name, so naming one for\nthem is refused.","type":"string"},"project":{"description":"Project scopes the run to one board's work when the org keeps more than one.\nEmpty is the org's default.","type":"string"},"prompt":{"description":"Prompt is the task, in the words you would use with a colleague who has the\ncheckout open. It is the whole instruction: there is no second field for\ncontext, and a prompt that names files and the outcome it wants gets a run\nthat does not have to guess either.","type":"string"},"reply":{"$ref":"#/components/schemas/agent.Reply","description":"Reply is WHERE THE RUN NARRATES ITSELF, when the surface that started it has\nsomewhere for it to talk. Empty means nobody is listening and the run simply\ndoes not narrate — which is the app surface's case, because /v1/agent/coding\nhands back a session id and the session stream is a better progress feed than\nany message could be.\n\nIT IS NOT A FIELD A MODEL FILLS IN. A run asked for in a conversation is\ndispatched with the address that conversation is happening at, written over\nwhatever arrived here (apps/agents/replyto.go). A model naming a channel is\na model naming a room it was not spoken to in, so the value it chose is\ndiscarded rather than argued with — which is the same rule that left the org\nand the subject off this type entirely."},"repo":{"description":"Repo is what to work on: a repository's name, `owner/name` in the caller's\nown org, or the site a repository serves (`hanzo.ai`), as the person said\nit. The engine resolves it against the org's own repositories — a name that\nmatches none is refused with the nearest ones — and finds the clone URL and\nthe push credential from the org itself, so this says WHICH repository and\nnever how to reach it.\n\nA repository on GitHub is named by GitHub's address, `github.com/owner/name`\n— or `owner/name` when the owner is not the org's own — and runs there\ndirectly: it is admitted when the caller's own connected GitHub may push to\nit, or when the caller administers the org and the org's installation holds\nit, and refused otherwise.\n\nA repository the caller can read and not push to — a public repository, or\none their GitHub reads — is cloned read-only: the run works, commits in its\nworkspace, and pushes nothing; its change is kept as the run's artifacts.\n\nEmpty runs in an empty workspace: a fresh git repository in the sandbox,\nwith nothing cloned and nothing pushed.","type":"string"},"targetId":{"description":"TargetID routes the run to a registered machine the org has claimed instead\nof to a sandbox in our cluster. Empty runs it here, which is the usual case.","type":"string"},"task":{"description":"Task is Prompt under the name a caller asking for work tends to reach for.\nThe two are one field: Prompt wins when both are given.","type":"string"},"timeoutSeconds":{"description":"TimeoutSeconds bounds the whole run. Unset takes the default budget; a run\nthat hits the bound is stopped and reports what it had done by then.","format":"int64","type":"integer"},"tool":{"description":"Tool is which harness runs the prompt — dev | claude | codex | python |\nnode — and Desktop is whether the run needs a screen. Both are empty by\ndefault, which is `dev` with no screen, and that default is what every\ncaller gets until it says otherwise.\n\nThey are two fields because they are two questions. The harness decides\nwhat argv starts; the screen decides which image carries an X server. A\ncaller may want claude WITH a browser it can see, and a single enum would\nhave made that combination unsayable.","type":"string"}},"type":"object"},"agent.GPU":{"properties":{"memory":{"description":"VRAM bytes, 0 = unknown","format":"int64","type":"integer"},"model":{"description":"\"GB10\", \"8060S\", \"RTX 4090\"","type":"string"},"vendor":{"description":"nvidia | amd | apple | intel | ...","type":"string"}},"type":"object"},"agent.Metrics":{"properties":{"at":{"description":"unix seconds, server-stamped","format":"int64","type":"integer"},"cpuTemp":{"description":"CPUTemp is the CPU package temperature in °C.","format":"double","type":"number"},"cpuUtil":{"description":"CPUUtil is the busy fraction of all cores over the sample window, 0..1.","format":"double","type":"number"},"decode":{"description":"Decode is generation throughput over the sample window, in tokens per second.","format":"double","type":"number"},"diskRead":{"description":"DiskRead is the block-device read rate in bytes per second.","format":"double","type":"number"},"diskTotal":{"description":"DiskTotal is the size of those filesystems, in bytes.","format":"int64","type":"integer"},"diskUsed":{"description":"DiskUsed is the space used across local block filesystems, in bytes.","format":"int64","type":"integer"},"diskWrite":{"description":"DiskWrite is the block-device write rate in bytes per second.","format":"double","type":"number"},"gpuMemTotal":{"description":"GPUMemTotal is dedicated VRAM in bytes; absent when the GPU shares system memory (unified).","format":"int64","type":"integer"},"gpuMemUsed":{"description":"GPUMemUsed is the memory held by GPU processes, in bytes.","format":"int64","type":"integer"},"gpuPower":{"description":"GPUPower is the total GPU power draw in watts.","format":"double","type":"number"},"gpuPowerLimit":{"description":"GPUPowerLimit is the total enforced GPU power limit in watts; absent when the driver reports none.","format":"double","type":"number"},"gpuTemp":{"description":"GPUTemp is the hottest GPU's temperature in °C.","format":"double","type":"number"},"gpuUtil":{"description":"0..1 aggregate utilization","format":"double","type":"number"},"kvCache":{"description":"KVCache is the KV-cache occupancy, 0..1.","format":"double","type":"number"},"load1":{"description":"Load1 is the machine's own one-minute load average — a count of runnable and\nuninterruptible tasks, NOT a percentage and NOT already divided by core\ncount, so it is read against Spec.CPUs: 8.0 is idle on 16 cores and swamped\non 4. Coerced finite and non-negative on write, so 0 means either genuinely\nidle or nothing reported.","format":"double","type":"number"},"load15":{"description":"Load15 is the same figure over fifteen. The three together are what separate\na machine that is busy right now from one that has been busy all along —\nwhich is the question a dispatcher is really asking.","format":"double","type":"number"},"load5":{"description":"Load5 is the same figure averaged over five minutes.","format":"double","type":"number"},"memFree":{"description":"bytes","format":"int64","type":"integer"},"memUsed":{"description":"bytes","format":"int64","type":"integer"},"model":{"description":"Model is the model id(s) served on this machine, comma-separated, at most 128 bytes.","type":"string"},"netRx":{"description":"NetRx is the receive rate of physical interfaces in bytes per second.","format":"double","type":"number"},"netTx":{"description":"NetTx is the transmit rate of physical interfaces in bytes per second.","format":"double","type":"number"},"prefill":{"description":"Prefill is prompt (prefill) throughput over the sample window, in tokens per second.","format":"double","type":"number"},"running":{"description":"Running is the number of requests being served now.","format":"int64","type":"integer"},"ttft":{"description":"TTFT is the mean time to first token, in seconds, of requests that started in the window.","format":"double","type":"number"},"waiting":{"description":"Waiting is the number of requests queued.","format":"int64","type":"integer"}},"type":"object"},"agent.Reply":{"properties":{"channel":{"description":"Channel is the room inside that workspace, and it is what decides whether\nthere is an address at all. Empty is the ordinary case: a caller of\n/v1/agent/coding holds a session id and reads the stream instead.","type":"string"},"provider":{"description":"Provider is the transport the conversation is on — slack, discord,\ntelegram, teams — and it is what decides who can carry the text at all. An\naddress without it names a room in no particular workspace.","type":"string"},"thread":{"description":"Thread narrows the address to one thread inside the channel — on Slack the\nparent message's ts, the same value a reply carries as thread_ts. Empty\nputs the text at the top level of the channel.","type":"string"},"turn":{"description":"Turn is the turn that renders a run started here: the session whose one\nmessage the run's progress and its outcome are shown in. A run with a Turn\nposts nothing of its own — one question, one message. The dispatcher writes\nit (apps/agents/replyto.go); a model never does.","type":"string"},"user":{"description":"User is the platform's id for the person the conversation is with — whose\nrun it is. A run's buttons name them to anyone else who presses one; it is\nnever what decides who may (that is the chat identity).","type":"string"}},"type":"object"},"agent.Spec":{"properties":{"arch":{"description":"amd64 | arm64 | ...","type":"string"},"cpus":{"description":"logical cores","format":"int64","type":"integer"},"gpus":{"description":"GPUs is every accelerator the machine advertises, one entry each, capped at\n32 on write. Empty means the probe found none — and that is the answer a\nNeed is checked against, so a machine with no entry here clears no\naccelerator floor. The list is not vendor-filtered: what satisfies a job is\ncounts and VRAM, never a brand (see Need).","items":{"$ref":"#/components/schemas/agent.GPU"},"type":"array"},"memory":{"description":"total RAM, bytes","format":"int64","type":"integer"},"os":{"description":"linux | darwin | windows","type":"string"}},"type":"object"},"agent.controlIn":{"properties":{"id":{"description":"ID is the session to steer, from the path.","type":"string"},"message":{"description":"Message is free text for the running agent, up to 16 KiB. On a stop it is\nrecorded as the cancellation reason.","type":"string"},"payload":{"description":"Payload is a structured argument for the command: any valid JSON up to\n64 KiB, scanned for credentials before it is stored (a hit refuses the\ncommand with 422 and the findings). A task-backed session receives it as\nthe forwarded signal's argument."}},"type":"object"},"agent.createAgentIn":{"properties":{"avatar":{"description":"Avatar and Emoji are how the agent APPEARS. An image wins when both are\ngiven — it is the thing somebody made — and both empty leaves the agent\ndrawn as its initial. Validated by iam/pkg/schema, the same rule a person's\navatar passes, so the 96 KiB bound and the accepted URL forms are stated\nonce for every subject that has a face.","type":"string"},"cap_micro_usd":{"description":"The budget, required. An agent is not creatable without one: a zero cap\nwould mean no limit and no record of its spend, which is what a budget\nexists to remove. Integer micro-USD; the CLI converts dollars before sending.","format":"int64","type":"integer"},"computeRef":{"description":"ComputeRef optionally binds this bot to a visor machine. Opaque here, bounded\nat 256 characters, and not resolved — this package stores the reference and\nthe binding's lifecycle belongs elsewhere.","type":"string"},"description":{"description":"Description is the one line published as the description of the `agent_`\ntool, which is how another agent decides whether to call this one. Optional,\nand worth writing for exactly that reason.","type":"string"},"emoji":{"description":"Emoji is the single glyph shown when there is no image. An image WINS when\nboth are given — it is the thing somebody made — and both empty leaves the\nagent drawn as its initial.","type":"string"},"executionMode":{"description":"ExecutionMode is one-shot or long-running. Empty takes one-shot, which runs\nonly when something POSTs to it. long-running additionally requires Schedule,\nand counts against a per-org cap that answers 409 when it is full.","type":"string"},"instructions":{"description":"Instructions is the system prompt, up to 32 KiB, stored verbatim. This is what\nthe model reads; Description is what other CALLERS read.","type":"string"},"max_task_micro_usd":{"description":"MaxTaskMicroUSD is the ceiling for a single run, in micro-USD. A session\ncannot exceed it even when the period cap still has room, so one runaway\ntask cannot consume a month.","format":"int64","type":"integer"},"model":{"description":"Model names the model to run on. Omit it to take the deployment's configured\ndefault; name one and it is checked against the gateway's served catalogue\nhere, so a model this deployment cannot serve is refused now rather than at\nthe first run. Stored under our own name for it, whatever spelling arrives.","type":"string"},"name":{"description":"Name is the agent's org-unique handle and the only required field. It must\nmatch ^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$, and a name already taken in this org\nis a 409 rather than an overwrite. It is permanent: no update route moves it.","type":"string"},"parent":{"description":"Parent is the agent spawning this one — its id or name, in the caller's\norg. The new agent answers to the org its parent answers to, and a parent\noutside the caller's org is not found: an agent is never spawned into a\nprincipal its creator does not answer to. Omitted for an agent a person\ndefines. Set once; no update moves it.","type":"string"},"period":{"description":"Period is the window the cap resets on: day, week or month.","type":"string"},"schedule":{"description":"Schedule is the 5-field cron a long-running agent fires on, parsed here so a\nbad expression is a 400 and not an agent that silently never runs. Required\nwith long-running; DISCARDED for one-shot rather than stored unused.","type":"string"},"serviceAccountId":{"description":"ServiceAccountID optionally names the IAM agent service account (-)\na scheduled run should be billed AS, so an autonomous run is attributable to a\nprincipal rather than only to the org. Same 256-character bound, also\nunresolved here.","type":"string"},"tools":{"description":"Tools are the tool names this agent may call. Omitted or empty grants NONE —\nthat default is the agent's authority and is not widened anywhere. The single\nentry \"*\" means whatever the fleet's MCP server serves at the time of each run.","items":{"type":"string"},"type":"array"}},"type":"object"},"agent.eventIn":{"properties":{"actor":{"description":"Actor is who produced the turn. Empty takes the validated caller, which is\nwhat an agent writing its own transcript wants; naming one is for a surface\nrecording on somebody else's behalf.","type":"string"},"id":{"description":"ID is the session to append to, from the path.","type":"string"},"kind":{"description":"Kind is what this turn IS: message, tool-call, spawn, log, status, control\nor progress. Anything else is refused — the vocabulary is closed so a\nreader can branch on it.","type":"string"},"payload":{"description":"Payload is the turn's own body, any valid JSON up to 64 KiB. It is SCANNED\nfor credentials before it is stored, and a hit refuses the whole append with\n422 and the findings — this plane never redacts a secret into a transcript\nit then keeps.\n\nIts SHAPE is the writer's business for every kind but one: a `progress`\nturn is the run reporting on itself in a shape this surface publishes —\n{\"pct\":0-100 (optional), \"phase\":\"running|blocked|done\",\n\"activity\":\"≤120 chars\"} — so a malformed one is refused with 400 instead\nof being stored as prose nobody reads."}},"type":"object"},"agent.patchSessionIn":{"properties":{"cwd":{"description":"Cwd is where the session is working NOW.\n\nIt was write-once — captured at register and never again — which is right\nfor a run that starts in a directory and stays there, and wrong for a linked\nshell, which is a place a person moves around in. The console showed the\ndirectory `hanzo link` happened to be run from and kept showing it after the\nshell had walked away, so the field answered \"which work is this\" with an\nanswer that was true once. A pointer, so an unchanged path is an omitted\nfield rather than a repeated write.","type":"string"},"id":{"description":"ID is the session to update, from the path.","type":"string"},"project":{"description":"Project tags the product this session built; Published is the author's\ndecision to let anyone read the story (provenance.go). Both are pointers so\n\"absent\" and \"cleared\" are different requests.","type":"string"},"published":{"description":"Published opens the session's story to the public build route; false withdraws\nit, and withdrawing is always allowed. PUBLISHING is refused unless the\nsession names a Project — the one set in this same request, or the one already\nstored — because that route is keyed on (org, project). It widens READ access\nto what is already there and grants nothing else.","type":"boolean"},"status":{"description":"Status moves the session to running, paused, done or error. A session that has\nalready finished refuses any change with 409 — done and error are monotonic —\nand moving INTO one stamps the end time. This is the surface REPORTING what\nhappened; a control command never writes it.","type":"string"},"target":{"description":"Target re-dispatches a session to a run-target (the #48 association). \"\" detaches.","type":"string"},"terminal":{"description":"Terminal publishes (or, with \"\", withdraws) the URL this session's live\nterminal can be watched at. A pointer so \"absent\" and \"withdrawn\" are\ndifferent requests: a session that stops sharing must be able to say so.","type":"string"},"title":{"description":"Title rewrites the human line, up to 512 characters — usually because the work\nturned out to be something other than what it was opened as.","type":"string"}},"type":"object"},"agent.patchTargetIn":{"properties":{"capacity":{"description":"Capacity rewrites the human summary, up to 256 characters. \"\" clears it.","type":"string"},"host":{"description":"Host re-points the hostname sessions are matched by. Moving it moves the load:\nthe session counts follow the new name from the next read.","type":"string"},"id":{"description":"ID is the target to update, from the path.","type":"string"},"kind":{"description":"Kind re-files it under laptop | cloud | gpu | cluster | machine.","type":"string"},"label":{"description":"Label renames the machine, up to 128 characters. Empty STRING is refused — a\ntarget with no name is a row nobody can pick out of a fleet.","type":"string"},"metrics":{"$ref":"#/components/schemas/agent.Metrics","description":"Metrics replaces the live sample, and sending one IS A HEARTBEAT: the server\nstamps the time and appends the point to the fleet series. Sending an all-zero\nsample CLEARS the heartbeat — the machine goes back to having no liveness fact\nat all, and its stored status is taken at face value again."},"spec":{"$ref":"#/components/schemas/agent.Spec","description":"Spec replaces the static capability whole, sanitized and clamped the same way\na register's is."},"status":{"description":"Status sets operator INTENT: online | offline | draining. Draining is how a\nmachine is taken out of dispatch without ending what is already on it. What\ncomes back may still read offline, because the heartbeat outranks the intent.","type":"string"}},"type":"object"},"agent.registerReq":{"properties":{"account":{"description":"Account is which subscription or API account under that provider served the\nrun, up to 256 characters. It is what lets a revoke of that login stop exactly\nthe sessions it was paying for.","type":"string"},"actor":{"description":"Actor is the \"org/sub\" identity to record the session under, up to 256\ncharacters. Omit it and the calling principal is used, which is almost always\nwhat you want: it is what a login revoke matches on to stop this session.","type":"string"},"agent":{"description":"Agent is the label the surface opening this session calls itself by\n(\"hanzo-dev\"). REQUIRED, up to 128 characters, and free text — nothing\nresolves it against a defined agent.","type":"string"},"budget_micro_usd":{"description":"BudgetMicroUSD caps what this session may spend, integer micro-USD. Zero\nmeans no cap; a cap can be raised or removed later, never added.","format":"int64","type":"integer"},"cwd":{"description":"Cwd is the directory the session starts in, up to 1024 characters. It can be\nmoved later, because a linked shell walks around.","type":"string"},"host":{"description":"Execution context — where this session runs (all optional).","type":"string"},"parentSessionId":{"description":"ParentSessionID makes this a subagent of that session: it inherits the\nparent's root, so one flow stays one tree. The parent must exist IN THE SAME\nORG — a foreign or unknown id is a 400, never a tree across tenants. Empty\nopens a root session.","type":"string"},"project":{"description":"The readable build (provenance.go): which product this session builds, and\nwhether its story may be read by the world.","type":"string"},"provider":{"description":"Account tag — the linked AI account this session ran under (login manager).","type":"string"},"published":{"description":"Published opens this session's story to the public build route. It is refused\nwithout a Project, because that route is keyed on (org, project) — a build\nwith no product is not a story anyone can open. False keeps it org-only.","type":"boolean"},"repo":{"description":"Repo is the code being worked on, up to 512 characters. A label the surface\nstates; nothing resolves it against the forge.","type":"string"},"room":{"description":"Room is the collaborative room this run was started in (HIP-0523), so a\nspace view can list the sessions of one room. It is PROVENANCE and is set\nonly here: there is deliberately no way to move a session to another room, so\nit is absent from the patch input and from UpdateSession's SET list.","type":"string"},"status":{"description":"Status opens the session in one of running, paused, done or error. Empty means\nrunning. A TERMINAL status here (done, error) records a session that has\nalready finished — its end time is stamped now — and nothing can move it\nafterwards.","type":"string"},"target":{"description":"Target names a run-target the org has registered. Unlike Host and Repo it IS\nresolved: a target that does not exist in this org is a 400, so a session can\nnever claim to run on another tenant's machine. Empty names no machine.","type":"string"},"taskRunId":{"description":"TaskRunID is that workflow's particular run, same bound. Recorded, not\nresolved: this surface does not check the workflow exists.","type":"string"},"taskWorkflowId":{"description":"TaskWorkflowID links this session to the hanzoai/tasks workflow that executes\nit, up to 256 characters. Set it and control commands are forwarded to that\nengine; leave it and the running surface polls for them instead.","type":"string"},"terminal":{"description":"Terminal is the URL this session's live terminal is published at, so the\nconsole can watch it. Optional — a session that publishes nothing is still\na session.","type":"string"},"title":{"description":"Title is the human line a card shows, up to 512 characters. Optional, and\nchangeable later.","type":"string"}},"type":"object"},"agent.reportRunIn":{"properties":{"branch":{"description":"Branch, CommitSha and Diffstat describe what the run produced; Error is the\nfailure when OK is false. Each is clamped, never rejected.","type":"string"},"changed":{"description":"Changed says whether the run produced any commit. It is INDEPENDENT of OK: a\nrun can succeed and change nothing (there was nothing to do), and a run can\nfail after committing some of its work. Two questions, two booleans.","type":"boolean"},"commitSha":{"description":"CommitSha is the tip the run pushed, clamped to 128 characters. Empty when it\npushed nothing, which is the same case Changed reports false for.","type":"string"},"diffstat":{"description":"Diffstat is the run's own summary of what it changed, as text, clamped to\n64 KiB. Free-form: it is shown, never parsed.","type":"string"},"error":{"description":"Error is why the run failed, clamped to 64 KiB. It is CLAMPED rather than\nrefused — a truncated reason is worth more than a rejected report, because a\nrejected report leaves the durable workflow waiting forever.","type":"string"},"id":{"description":"ID is the machine reporting, from the path.","type":"string"},"ok":{"description":"OK is whether the run succeeded; Changed whether it produced any commit.","type":"boolean"},"runId":{"description":"RunID is the routed run being completed, from the path.","type":"string"}},"type":"object"},"agent.sessionBudgetIn":{"properties":{"budget_micro_usd":{"description":"BudgetMicroUSD is the new cap, or null to remove the cap for good.","format":"int64","type":"integer"},"id":{"description":"ID is the session, from the path.","type":"string"}},"type":"object"},"agent.targetReq":{"properties":{"capacity":{"description":"Capacity is a human summary of the machine's size, up to 256 characters. Prose\nonly; a scheduler reads Spec.","type":"string"},"host":{"description":"Host is the hostname sessions on this machine will report. It is what makes a\nre-link IDEMPOTENT: the same (org, host, owner) refreshes the existing row and\nanswers 200, while a request with no host always creates a new target and\nanswers 201. It never adopts a row owned by somebody else.","type":"string"},"kind":{"description":"Kind is laptop | cloud | gpu | cluster | machine. Empty registers a `machine`;\nanything outside the five is a 400.","type":"string"},"label":{"description":"Label is the name to show for this machine, up to 128 characters. REQUIRED —\nit is the only field here a person reads.","type":"string"},"metrics":{"$ref":"#/components/schemas/agent.Metrics","description":"Metrics is a live sample, and sending one IS A HEARTBEAT: it refreshes the row\nand starts the 90-second liveness window, and it is appended to the fleet\nseries as one point. Its own `at` is ignored — the server stamps the time, so\na client can never age or backdate its own machine. Omit it to register a\nmachine without claiming it is alive."},"spec":{"$ref":"#/components/schemas/agent.Spec","description":"Spec is the machine's static capability — os, arch, cores, RAM, accelerators.\nEvery field is bounded on write and at most 32 accelerators are accepted, so\nwhat comes back may be clamped. Omit it for a destination nothing probes."},"status":{"description":"Status is online | offline | draining. Empty registers `online`. It states\nINTENT — a heartbeat is what decides whether an online machine is actually\nreachable, so declaring online does not make it so.","type":"string"}},"type":"object"},"agent.updateAgentIn":{"properties":{"avatar":{"description":"Avatar and Emoji re-draw the agent. Sending either replaces the pair, so\nsetting an image clears a glyph and \"\" for both goes back to the initial —\nthere is no state where a row holds two answers.","type":"string"},"cap_micro_usd":{"description":"The budget, any part of it. Changing the period opens a new window.","format":"int64","type":"integer"},"computeRef":{"description":"ComputeRef re-binds (or, with \"\", unbinds) the visor machine. Opaque here.","type":"string"},"description":{"description":"Description replaces the line other agents read in the tool catalogue.","type":"string"},"emoji":{"description":"Emoji re-draws the agent as a glyph. Sending either of the pair replaces\nBOTH, so setting a glyph clears an image and \"\" for both goes back to the\ninitial — there is no state where a row holds two answers.","type":"string"},"executionMode":{"description":"ExecutionMode switches between one-shot and long-running. The RESULTING\nmode+schedule are validated together, so switching to long-running without a\nstored or supplied cron is refused rather than accepted into an agent the\nscheduler would skip forever. A switch INTO long-running counts against the\nper-org cap and can be a 409.","type":"string"},"instructions":{"description":"Instructions replaces the system prompt whole, up to 32 KiB. There is no\nappend: a prompt is one text, and sending \"\" clears it.","type":"string"},"max_task_micro_usd":{"description":"MaxTaskMicroUSD is the ceiling for a single run, in micro-USD. A session\ncannot exceed it even when the period cap still has room, so one runaway\ntask cannot consume a month.","format":"int64","type":"integer"},"model":{"description":"Model re-points the agent at another model, checked against the gateway's\nserved catalogue exactly as create checks it. Empty STRING is refused — say\nnothing to keep the current one. Past runs keep the model that served them.","type":"string"},"period":{"description":"Period is the window the cap resets on: day, week or month.","type":"string"},"ref":{"description":"Ref is the agent to update — its public id or org-unique name, from the path.","type":"string"},"schedule":{"description":"Schedule replaces the cron. It is validated against the mode this update\nleaves behind, and dropped if that mode is one-shot.","type":"string"},"serviceAccountId":{"description":"ServiceAccountID re-points (or, with \"\", clears) the IAM service account a\nscheduled run is billed as. Clearing it puts that spend back on the org.","type":"string"},"tools":{"description":"Tools replaces the whole allow-list, it does not add to it. Sending [] takes\nevery tool away, which is the only way to say that.","items":{"type":"string"},"type":"array"}},"type":"object"},"ai.AnthropicMessage":{"properties":{"content":{},"role":{"type":"string"}},"type":"object"},"ai.AnthropicRequest":{"properties":{"max_tokens":{"type":"integer"},"messages":{"items":{"$ref":"#/components/schemas/ai.AnthropicMessage"},"type":"array"},"model":{"type":"string"},"stream":{"type":"boolean"},"system":{},"temperature":{"type":"number"},"thinking":{},"tool_choice":{},"tools":{"items":{"$ref":"#/components/schemas/ai.AnthropicTool"},"type":"array"}},"type":"object"},"ai.AnthropicTool":{"properties":{"description":{"type":"string"},"input_schema":{},"name":{"type":"string"}},"type":"object"},"ai.DecisionSides":{"properties":{"false":{"description":"A string, an object or an array, kept as written."},"true":{"description":"A string, an object or an array, kept as written."}},"type":"object"},"ai.DecisionsBoolean":{"properties":{"criteria":{"$ref":"#/components/schemas/ai.DecisionSides"},"instructions":{"description":"A string, an object or an array, kept as written."},"labels":{"additionalProperties":{"type":"string"},"type":"object"},"type":{"enum":["boolean"],"type":"string"}},"required":["type"],"type":"object"},"ai.DecisionsChoice":{"properties":{"criteria":{"description":"At least two labels: an object mapping each label to what it means (a string, an object, an array, or null), or an array of labels that need no description."},"instructions":{"description":"A string, an object or an array, kept as written."},"type":{"enum":["choice"],"type":"string"}},"required":["type","criteria"],"type":"object"},"ai.DecisionsNoul":{"properties":{"criteria":{"$ref":"#/components/schemas/ai.DecisionSides"},"instructions":{"description":"A string, an object or an array, kept as written."},"labels":{"additionalProperties":{"type":"string"},"type":"object"},"type":{"enum":["noul"],"type":"string"}},"required":["type"],"type":"object"},"ai.DecisionsQuestion":{"discriminator":{"mapping":{"boolean":"#/components/schemas/ai.DecisionsBoolean","choice":"#/components/schemas/ai.DecisionsChoice","noul":"#/components/schemas/ai.DecisionsNoul","score":"#/components/schemas/ai.DecisionsScore"},"propertyName":"type"},"oneOf":[{"$ref":"#/components/schemas/ai.DecisionsBoolean"},{"$ref":"#/components/schemas/ai.DecisionsNoul"},{"$ref":"#/components/schemas/ai.DecisionsChoice"},{"$ref":"#/components/schemas/ai.DecisionsScore"}]},"ai.DecisionsRequest":{"properties":{"handle":{"type":"string"},"model":{"type":"string"},"observe":{"type":"string"},"provider":{},"questions":{"additionalProperties":{"$ref":"#/components/schemas/ai.DecisionsQuestion"},"maxProperties":100,"minProperties":1,"type":"object"},"session_id":{"type":"string"},"state":{"description":"A string, an object or an array, kept as written."},"trace":{},"user":{"type":"string"}},"required":["model"],"type":"object"},"ai.DecisionsScore":{"properties":{"criteria":{"items":{"description":"A string, an object or an array, kept as written."},"minItems":1,"type":"array"},"instructions":{"description":"A string, an object or an array, kept as written."},"type":{"enum":["score"],"type":"string"}},"required":["type","criteria"],"type":"object"},"ai.RoutingEdit":{"properties":{"base":{"type":"integer"},"catalog":{},"family":{"type":"string"},"model":{"type":"string"},"note":{"type":"string"},"version":{"type":"integer"}},"type":"object"},"ai.RoutingRewardRequest":{"properties":{"rating":{"type":"number"},"request_id":{"type":"string"},"reward":{"type":"number"},"signal":{"enum":["up","accept","regenerate","down","switch","abandon","revert","rating","dismiss"],"type":"string"}},"required":["request_id"],"type":"object"},"aiChatIn":{"properties":{"max_tokens":{"description":"MaxTokens bounds the answer in tokens; 0 leaves it to the model.","format":"int64","type":"integer"},"model":{"description":"Model is the model to answer, by id (zen5, enso, kai, anthropic/claude-sonnet-4.5\n— aiModels lists them). Empty asks the deployment's default Hanzo model.","type":"string"},"prompt":{"description":"Prompt is what to ask.","type":"string"},"system":{"description":"System is the system message ahead of the prompt, when set.","type":"string"}},"type":"object"},"aiDecideIn":{"properties":{"handle":{"description":"Handle decides over a state this org observed earlier, in place of State and\nQuestions.","type":"string"},"model":{"description":"Model is kai, Kai's versioned id kai-<12 hex>, or Jev by its vendor id\n(typesafe/jev-1.13, ~typesafe/jev-latest).","type":"string"},"observe":{"description":"Observe holds the state under this id (1 to 128 of A-Z a-z 0-9 . _ -), so a\nlater decision can name it as its Handle.","type":"string"},"questions":{"additionalProperties":{},"description":"Questions are 1 to 100 named questions, each {\"type\": \"choice\"|\"noul\"|\"score\",\n\"instructions\"?, \"criteria\"?}; a choice names at least 2 labels and a score at\nleast 1 level. Not sent with a Handle.","type":"object"},"state":{"description":"State is what the questions are about: a string, an object or an array, kept\nas written. Not sent with a Handle."}},"type":"object"},"aiLimitsSet":{"properties":{"creditsAfterAllowance":{"description":"CreditsAfterAllowance keeps a model working once the plan's included usage of\nit is spent, paid from prepaid credit (and granted credit where the model takes\nit), when true; when false the conversation moves to a Hanzo model and other\ncalls are refused until the plan resets. Off until the payer turns it on.","type":"boolean"}},"type":"object"},"ask.webQuestion":{"properties":{"language":{"description":"Language narrows the search to a locale, BCP-47-ish (\"en\", \"ja\"). Empty\nmeans no narrowing.","type":"string"},"max_sources":{"description":"MaxSources caps how many pages are read. Empty means the mode's own budget.","format":"int64","type":"integer"},"mode":{"description":"Mode is how much work to do: `search` (fast, one pass), `news` (recency\nbiased), `research` (a plan and several rounds) or `deep` (the widest\nsurvey). Empty means research.","type":"string"},"q":{"description":"Q is the question, in plain language. Required.","type":"string"},"sources":{"description":"Sources narrows where the evidence comes from: any of `web`, `news`,\n`academic`, `github`, `reddit`, `x`. Each becomes a site-scoped search, so\n`[\"x\"]` researches X/Twitter posts rather than the open web.","items":{"type":"string"},"type":"array"}},"type":"object"},"askRequest":{"properties":{"followUps":{"type":"boolean"},"language":{"type":"string"},"maxQueries":{"type":"integer"},"maxSources":{"type":"integer"},"mode":{"type":"string"},"model":{"type":"string"},"q":{"type":"string"},"question":{"type":"string"},"sources":{"items":{"type":"string"},"type":"array"},"stream":{"type":"boolean"},"system":{"type":"string"}},"type":"object"},"author.connectRequest":{"properties":{"githubLogin":{"description":"GithubLogin is the account to link. Used only when IAM holds no linked\naccount for the provider — a linked account is stronger proof and always wins.","type":"string"},"login":{"description":"Login is the provider-neutral alias for GithubLogin, preferred when both are\nsent.","type":"string"},"provider":{"description":"Provider is the forge to enrol with: github (the default) or gitlab.","type":"string"}},"type":"object"},"author.deployRequest":{"properties":{"project":{"description":"Project is the deployed project's id. Required.","type":"string"},"repoUrl":{"description":"RepoURL is the source repository the project was built from. Empty means a\nhand-built project with nothing to attribute — an honest no-op, not an error.","type":"string"}},"type":"object"},"author.verifyRequest":{"properties":{"repoUrl":{"description":"RepoURL is what to claim: a repository (github.com/owner/name) or a whole\nOWNER (github.com/owner, no repository segment). gitlab.com is accepted too.","type":"string"}},"type":"object"},"auto.FlowAction":{"properties":{"displayName":{"type":"string"},"name":{"type":"string"},"nextAction":{"$ref":"#/components/schemas/auto.FlowAction"},"settings":{"$ref":"#/components/schemas/auto.StepSettings"},"skip":{"type":"boolean"},"type":{"description":"PIECE | CODE | ROUTER | LOOP_ON_ITEMS","type":"string"},"valid":{"type":"boolean"}},"type":"object"},"auto.FlowTrigger":{"properties":{"displayName":{"type":"string"},"name":{"type":"string"},"nextAction":{"$ref":"#/components/schemas/auto.FlowAction"},"settings":{"$ref":"#/components/schemas/auto.StepSettings"},"strategy":{"type":"string"},"type":{"description":"PIECE_TRIGGER | EMPTY","type":"string"},"valid":{"type":"boolean"}},"type":"object"},"auto.Schedule":{"properties":{"at":{"description":"At is the local time, HH:MM on a 24-hour clock, for daily, weekdays and\nweekly. Hourly takes its minute, and runs on the hour without one.","type":"string"},"cron":{"description":"Cron is a five-field cron expression (minute hour day-of-month month\nday-of-week), for kind cron only, read in TZ.","type":"string"},"day":{"description":"Day is the weekday a weekly schedule runs on: mon, tue, wed, thu, fri, sat\nor sun.","type":"string"},"kind":{"description":"Kind is manual, hourly, daily, weekdays, weekly or cron. Manual runs only\nwhen asked.","type":"string"},"tz":{"description":"TZ is the IANA time zone every time here is read in. Empty is UTC.","type":"string"}},"type":"object"},"auto.StepSettings":{"properties":{"actionName":{"type":"string"},"input":{"additionalProperties":{},"type":"object"},"pieceName":{"type":"string"},"pieceVersion":{"type":"string"},"triggerName":{"type":"string"}},"type":"object"},"auto.automationIn":{"properties":{"enabled":{"description":"Enabled arms its schedule. Absent is true.","type":"boolean"},"instructions":{"description":"Instructions are what the agent is asked to do each run. Required.","type":"string"},"model":{"description":"Model is the model id to think with. Optional; absent is the default.","type":"string"},"name":{"description":"Name is what it is called. Required.","type":"string"},"notify":{"description":"Notify sends a one-line summary when a run ends.","type":"boolean"},"permissions":{"description":"Permissions is auto (works without stopping) or ask (proposes, changes\nnothing). Absent is ask.","type":"string"},"postTo":{"description":"PostTo are the connected accounts each run's answer is posted to: x,\nlinkedin, facebook. Absent posts nothing.","items":{"type":"string"},"type":"array"},"project":{"description":"Project is a Dev project's slug to work in. Optional.","type":"string"},"schedule":{"$ref":"#/components/schemas/auto.Schedule","description":"Schedule is when it runs. Absent runs it only on demand."}},"type":"object"},"auto.automationPatch":{"properties":{"enabled":{"description":"Enabled arms or disarms its schedule.","type":"boolean"},"id":{"description":"ID is the automation, from the path.","type":"string"},"instructions":{"type":"string"},"model":{"type":"string"},"name":{"type":"string"},"notify":{"type":"boolean"},"permissions":{"type":"string"},"postTo":{"items":{"type":"string"},"type":"array"},"project":{"type":"string"},"schedule":{"$ref":"#/components/schemas/auto.Schedule"}},"type":"object"},"auto.createFlowReq":{"properties":{"displayName":{"description":"DisplayName names the flow's initial draft version.","type":"string"},"externalId":{"description":"ExternalID is the caller's own id for this flow. Optional.","type":"string"},"folderId":{"description":"FolderID groups the flow in the builder's tree. Optional.","type":"string"},"trigger":{"$ref":"#/components/schemas/auto.FlowTrigger","description":"Trigger is the root of the step tree — how the flow starts, and the action\nchain that follows. Optional: a flow may be created empty and edited later."}},"type":"object"},"auto.createVersionIn":{"properties":{"displayName":{"description":"DisplayName names the new version.","type":"string"},"id":{"description":"ID is the flow to add a version to, from the path.","type":"string"},"trigger":{"$ref":"#/components/schemas/auto.FlowTrigger","description":"Trigger is the root of the version's step tree. Optional: a version with no\ntrigger is created invalid, and cannot run until one is set."}},"type":"object"},"auto.patchFlowIn":{"properties":{"externalId":{"description":"ExternalID sets the caller's own id for this flow.","type":"string"},"folderId":{"description":"FolderID moves the flow in the builder's tree.","type":"string"},"id":{"description":"ID is the flow to update, from the path.","type":"string"},"metadata":{"description":"Metadata replaces the caller's opaque JSON."},"publishedVersionId":{"description":"PublishedVersionID pins the version runs execute. It must name a version OF\nTHIS FLOW; empty clears the pin, so runs take the latest version again.","type":"string"}},"type":"object"},"auto.reviewIn":{"properties":{"id":{"description":"ID is the automation, and Run its run in review, from the path.","type":"string"},"post":{"description":"Post posts it when true and discards it when false.","type":"boolean"},"run":{"type":"string"}},"type":"object"},"auto.runIn":{"properties":{"action":{"description":"Action is the name of the provider action to invoke.","type":"string"},"auth":{"description":"Auth is the caller's resolved credential for the provider, handed to the\naction verbatim. Its shape is whatever the provider's auth descriptor\ndeclares (a token string, an object), so it is opaque here."},"id":{"description":"ID is the provider to run, from the path.","type":"string"},"props":{"additionalProperties":{},"description":"Props are the action's input properties, keyed by property name.","type":"object"}},"type":"object"},"benchmark.Preset":{"properties":{"arms":{"description":"the blend — model ids from the arena","items":{"type":"string"},"type":"array"},"at":{"description":"At is when this version was stored. Set by the server; a value sent is not\nread. Zero on the reference blend.","format":"date-time","type":"string"},"by":{"description":"By is the verified user who stored it. Set by the server; a value sent is\nnot read.","type":"string"},"name":{"description":"the part after enso-: lowercase letters, digits and inner hyphens, at most 64","type":"string"},"note":{"description":"why this blend (audit)","type":"string"},"owner":{"description":"the org the blend belongs to: the writer's verified org, never a value sent","type":"string"},"panel":{"description":"fan-out width (>=1)","format":"int64","type":"integer"},"rank":{"description":"escalation order over arms","items":{"type":"string"},"type":"array"}},"type":"object"},"benchmark.publishedClaim":{"properties":{"benchmark":{"description":"Benchmark is the canonical test id the claim is about, from /catalog.","type":"string"},"model":{"description":"Model is the system the score is claimed for.","type":"string"},"protocol":{"description":"Protocol records HOW it was scored — provider-reported, agentic,\nthird-party-leaderboard — because a provider card and a third party running\nits own harness are different kinds of number and must not be blended.","type":"string"},"provider":{"description":"Provider is who the claim belongs to — the lab or leaderboard whose number\nthis is. It joins a claim to the attempts measured for that same model.","type":"string"},"score":{"description":"Score is the reported aggregate, as a percentage.","format":"double","type":"number"},"source":{"description":"Source is the citation the row was read from. A claim without one is a\nnumber nobody can check, so every write requires it.","type":"string"}},"type":"object"},"benchmark.putClaimsIn":{"properties":{"data":{"description":"Data is the claims to record. One row is a correction; many is an import.\nThere is no separate bulk endpoint because there is no separate operation:\nimporting a leaderboard and fixing one number are the same write.","items":{"$ref":"#/components/schemas/benchmark.publishedClaim"},"type":"array"},"visibility":{"description":"Visibility is who may read every row in Data: \"private\", the default, keeps\nthem to the caller's org; \"public\" shows them to anyone. Restating a claim\nwith the other value moves it.","type":"string"}},"type":"object"},"benchmark.suite":{"properties":{"benchmarks":{"description":"Benchmarks are the catalog ids to ask about. At least one is required, and\nevery id must be in the catalog.","items":{"type":"string"},"type":"array"},"model":{"description":"Model is the model to ask about, by the id its attempts are stored under.\nRequired.","type":"string"}},"required":["benchmarks"],"type":"object"},"billing.AlertPatch":{"properties":{"enforce":{"type":"boolean"},"id":{"type":"string"},"project":{"type":"string"},"rateLimitRpm":{"format":"int64","type":"integer"},"service":{"type":"string"},"softPct":{"format":"int64","type":"integer"},"subject":{"type":"string"},"threshold":{"format":"int64","type":"integer"},"title":{"type":"string"}},"type":"object"},"billing.AlertSpec":{"properties":{"currency":{"type":"string"},"enforce":{"type":"boolean"},"project":{"type":"string"},"rateLimitRpm":{"format":"int64","type":"integer"},"service":{"type":"string"},"softPct":{"format":"int64","type":"integer"},"subject":{"type":"string"},"threshold":{"format":"int64","type":"integer"},"title":{"type":"string"}},"type":"object"},"billing.AutoRechargeEdit":{"properties":{"amountCents":{"format":"int64","type":"integer"},"currency":{"type":"string"},"enabled":{"type":"boolean"},"thresholdCents":{"format":"int64","type":"integer"}},"type":"object"},"billing.InvoiceLine":{"properties":{"amount":{"description":"Amount is the line total in whole cents (250000 is $2,500.00).","format":"int64","type":"integer"},"description":{"description":"Description is the human-readable line, e.g. \"Advisory retainer — August\".","type":"string"},"quantity":{"description":"Quantity is the number of units, when the line is metered. Optional.","format":"int64","type":"integer"},"unitPrice":{"description":"UnitPrice is the per-unit price in cents, when the line is metered. Optional.","format":"int64","type":"integer"}},"type":"object"},"billing.ModeIn":{"properties":{"testMode":{"type":"boolean"}},"type":"object"},"billing.Money":{"properties":{"currency":{"type":"string"},"decimal":{"type":"string"}},"required":["decimal","currency"],"type":"object"},"billing.RaiseIn":{"properties":{"currency":{"description":"Currency is the ISO 4217 code, lower-cased. Empty means usd.","type":"string"},"customerEmail":{"description":"CustomerEmail is where the invoice is sent. Optional.","type":"string"},"lines":{"description":"Lines are the charges. The invoice subtotal and amount due are COMPUTED\nfrom these — there is no total field to send, because a total that\ndisagreed with its own lines would bill a number nobody could derive.","items":{"$ref":"#/components/schemas/billing.InvoiceLine"},"type":"array"},"userId":{"description":"UserID identifies the customer being billed, within the caller's own org.\nRequired — an invoice with no addressee is not an invoice.","type":"string"}},"type":"object"},"billing.SubscriptionRef":{"properties":{"atPeriodEnd":{"description":"AtPeriodEnd cancels at the end of the paid period rather than at once. It\ndefaults TRUE on the endpoint, because a customer who cancels has already\npaid for the period they are in.","type":"boolean"},"id":{"type":"string"}},"type":"object"},"billing.cryptoAsset":{"properties":{"amountCents":{"description":"AmountCents is what the payer intends to send, for the record. Optional —\nthe credit is what actually arrives, never what was announced.","format":"int64","type":"integer"},"chain":{"description":"Chain is the network to receive on. Empty takes the rail's default.","type":"string"},"token":{"description":"Token is the asset on that chain. Empty takes the chain's native one.","type":"string"}},"type":"object"},"billing.topupIn":{"properties":{"amountCents":{"description":"AmountCents is how much to charge, in cents of Currency. Required.","format":"int64","type":"integer"},"currency":{"description":"Currency is the ISO-4217 code to charge in. Empty takes the deployment's\nown default.","type":"string"},"paymentMethodId":{"description":"MethodID names a card the subject already saved, for the saved-card endpoint.","type":"string"},"sourceId":{"description":"SourceID is a single-use card token from the payment form, for the token\nendpoint. It is vaulted as part of the charge, so a caller never holds card\nnumbers and this service never sees one.","type":"string"}},"type":"object"},"billing.usageReport":{"properties":{"amount":{"$ref":"#/components/schemas/billing.Money","description":"Amount is what the act costs, as an exact decimal in USD. It must be\ngreater than zero."},"id":{"description":"ID names the act, chosen by the reporting application and stable across its\nretries: the ledger debits one act once. At most 128 printable characters,\nno whitespace. Reusing an ID for a different amount is a 409.","type":"string"},"model":{"description":"Model names the unit the amount prices (a machine size, a model id), and is\nrecorded with the debit.","type":"string"},"org":{"description":"Org is the organization this usage is billed to. It must be the org the\ntoken acts in — the application's own, or one that granted it membership and\nis selected with X-Org-Id — and any other is refused before money moves.","type":"string"},"project":{"description":"Project attributes the debit to one project of the org. Empty is the org's\ndefault project.","type":"string"},"service":{"description":"Service scopes the debit for spend caps and attributes it to a product, as\na lowercase slug. Empty takes the reporting application's name.","type":"string"}},"type":"object"},"books.AskRequest":{"properties":{"from":{"description":"From is the RFC3339 start of the metric window. Empty means all time, treated as a\nsingle reporting period (see monthsBetween).","type":"string"},"question":{"description":"Question is the plain-language question about the org's books, e.g. \"what is my\nMRR?\". Longer than 2000 characters is truncated, never refused.","type":"string"},"to":{"description":"To is the RFC3339 end of the metric window. Empty means up to now.","type":"string"}},"type":"object"},"books.BookRequest":{"properties":{"override":{"description":"Override books this bill even when one of the SAME economic identity\n(vendor, total, issue date) already posted — the explicit human confirmation that a\nsame-looking bill is a genuine second spend, not the same receipt re-scanned.","type":"boolean"},"scanId":{"description":"ScanID is the scanned document's file hash, as GET /v1/books/inbox and the scan\ndraft report it. It is the idempotency key: re-booking the same scan writes nothing.","type":"string"},"voucher":{"$ref":"#/components/schemas/books.Voucher","description":"Voucher is the reviewed voucher to post. Its source is FORCED to (scan, scanId)\nserver-side, so it can never be booked under another source's key."}},"type":"object"},"books.Leg":{"properties":{"account":{"description":"Account is the chart-of-accounts number this side posts to, e.g. \"5300\".","type":"string"},"credit":{"description":"Credit is the leg's credit in exact cents. Set this or Debit, not both.","format":"int64","type":"integer"},"debit":{"description":"Debit is the leg's debit in exact cents. Set this or Credit, not both.","format":"int64","type":"integer"}},"type":"object"},"books.Rule":{"properties":{"category":{"description":"Category is the COA expense account a matching bill books to. An upsert normalizes\na slug (\"cloud\") to its account number.","type":"string"},"pattern":{"description":"Pattern is the merchant substring the rule matches on, case-insensitively. It is\nalso the key an upsert writes by.","type":"string"},"priority":{"description":"Priority breaks ties: when several patterns match, the highest wins.","format":"int64","type":"integer"}},"type":"object"},"books.VendorRow":{"properties":{"aliases":{"description":"Aliases are the other spellings a receipt may print the vendor under; a scan\nmatching any of them resolves to this vendor.","items":{"type":"string"},"type":"array"},"canonical":{"description":"Canonical is the vendor's one true name, and the key an upsert writes by.","type":"string"},"defaultCategory":{"description":"DefaultCategory is the COA expense account new bills from this vendor book to.\nAn upsert normalizes a slug (\"software\") to its account number.","type":"string"}},"type":"object"},"books.Voucher":{"properties":{"description":{"description":"Description is the human line for the event, e.g. the vendor a bill came from.","type":"string"},"legs":{"description":"Legs are the sides of the posting. They must balance: Σdebit == Σcredit, give or\ntake the 2¢ round-off allowance.","items":{"$ref":"#/components/schemas/books.Leg"},"type":"array"},"postingAt":{"description":"PostingAt is the RFC3339 instant the event posts at — the time every statement\nwindow filters on.","type":"string"},"sourceId":{"description":"SourceID is the source event's own id within that namespace. Together with\nSourceKind it is the key that makes a repeat posting a no-op.","type":"string"},"sourceKind":{"description":"SourceKind is the idempotency namespace naming what booked this, e.g. \"scan\".","type":"string"}},"type":"object"},"campaign.ChannelSpec":{"properties":{"account":{"description":"Account is the provider account this channel runs under: an ad-account, a page\nor a mailing-list id. An executor may replace it at launch with the account it\nactually used.","type":"string"},"detail":{"description":"Detail is the last outcome in one secret-free line — the failure reason, or\nwhat the executor reported. Absent when there is nothing to explain.","type":"string"},"externalId":{"description":"ExternalID is the provider-side id of the running execution, recorded by the\norchestrator at launch and handed back verbatim to read spend or to pause.\nServer-owned and absent until this channel has launched; anything a caller\nsends for it is dropped.","type":"string"},"kind":{"description":"Kind is the channel and the identity a campaign holds at most one of: paid,\norganic or email. It picks the executor the launch fans out to.","type":"string"},"platform":{"description":"Platform is the provider within the kind — meta, google, x, instagram, or the\nemail provider.","type":"string"},"status":{"description":"Status is this channel's own launch outcome, not the campaign's: pending (added,\nnever launched), live, paused, failed (Detail says why) or unavailable (no\nexecutor wired on this deployment). Server-owned — a caller can never assert it.","type":"string"}},"type":"object"},"campaign.campaignUpdate":{"properties":{"audience":{"description":"Audience is the segment or audience selector this campaign targets.","type":"string"},"budget":{"description":"Budget is the campaign's total budget in CENTS. Negative reads as 0.","format":"int64","type":"integer"},"channels":{"description":"Channels are the fan-out targets, at most one per kind (paid, organic,\nemail) and at most 12. A channel's status and provider id are server-owned:\nwhatever the caller sends for them is replaced with \"pending\".","items":{"$ref":"#/components/schemas/campaign.ChannelSpec"},"type":"array"},"content":{"description":"Content is the ordered creative set. Content[0] is the active creative and\nthe rest are A/B variants; at most 32, empty entries dropped.","items":{"type":"string"},"type":"array"},"id":{"description":"ID is the campaign to update, from the path.","type":"string"},"name":{"description":"Name is the campaign's display name. Required; trimmed and capped at 2048\ncharacters.","type":"string"},"scheduleAt":{"description":"ScheduleAt is when the campaign should run, in unix seconds. Negative reads\nas 0 (immediately).","format":"int64","type":"integer"}},"type":"object"},"campaign.campaignWrite":{"properties":{"audience":{"description":"Audience is the segment or audience selector this campaign targets.","type":"string"},"budget":{"description":"Budget is the campaign's total budget in CENTS. Negative reads as 0.","format":"int64","type":"integer"},"channels":{"description":"Channels are the fan-out targets, at most one per kind (paid, organic,\nemail) and at most 12. A channel's status and provider id are server-owned:\nwhatever the caller sends for them is replaced with \"pending\".","items":{"$ref":"#/components/schemas/campaign.ChannelSpec"},"type":"array"},"content":{"description":"Content is the ordered creative set. Content[0] is the active creative and\nthe rest are A/B variants; at most 32, empty entries dropped.","items":{"type":"string"},"type":"array"},"name":{"description":"Name is the campaign's display name. Required; trimmed and capped at 2048\ncharacters.","type":"string"},"scheduleAt":{"description":"ScheduleAt is when the campaign should run, in unix seconds. Negative reads\nas 0 (immediately).","format":"int64","type":"integer"}},"type":"object"},"campaign.channelAdd":{"properties":{"account":{"description":"Account is the provider account this channel runs under: an ad-account, a\npage, or a mailing-list id.","type":"string"},"id":{"description":"ID is the campaign to add the channel to, from the path.","type":"string"},"kind":{"description":"Kind is the channel kind and the identity a campaign holds at most one of:\npaid, organic or email.","type":"string"},"platform":{"description":"Platform is the provider within the kind — meta, google, x, instagram, or\nthe email provider.","type":"string"}},"type":"object"},"captable.captableCompanyUpdate":{"properties":{"incorporationCountry":{"description":"IncorporationCountry is the ISO country the entity is incorporated in.\nOptional; omitted, null or empty clears it. Any JSON scalar is accepted\nand stored as its text."},"incorporationState":{"description":"IncorporationState is the state or province of incorporation. Optional;\nomitted, null or empty clears it. Any JSON scalar is accepted and stored\nas its text."},"incorporationType":{"description":"IncorporationType is the entity kind, e.g. LLC or C_CORP. Optional;\nomitted, null or empty clears it. Any JSON scalar is accepted and stored\nas its text."},"name":{"description":"Name is the company's legal name. Required, and it must be a non-empty\nstring — anything else is refused with the cap table's own validation\nerror."}},"type":"object"},"captable.captableConvertibleIn":{"properties":{"additionalTerms":{"description":"AdditionalTerms is free text for anything the fields above do not carry. Optional."},"boardApprovalDate":{"description":"BoardApprovalDate is when the board approved it, YYYY-MM-DD."},"capital":{"description":"Capital is the principal lent, in the company's currency."},"conversionCap":{"description":"ConversionCap is the valuation the note converts at, at most. Optional."},"discountRate":{"description":"DiscountRate is the discount to the next round's price, as a percentage. Optional."},"interestRate":{"description":"InterestRate is the annual interest the principal accrues, as a percentage. Optional."},"issueDate":{"description":"IssueDate is when the note was issued, YYYY-MM-DD."},"publicId":{"description":"PublicID is the note's identifier. It must be UNIQUE within the company; reusing one is refused 409."},"stakeholderId":{"description":"StakeholderID is the lender. It must name a stakeholder of THIS company."},"status":{"description":"Status is DRAFT, ACTIVE, PENDING, EXPIRED or CANCELLED."},"type":{"description":"Type is CCD, OCD or NOTE."}},"type":"object"},"captable.captableEquityPlanIn":{"properties":{"boardApprovalDate":{"description":"BoardApprovalDate is when the board adopted the plan, YYYY-MM-DD."},"comments":{"description":"Comments is a free-text note kept with the plan. Optional."},"defaultCancellatonBehavior":{"description":"DefaultCancellatonBehavior is what happens to cancelled grants: RETIRE, RETURN_TO_POOL, HOLD_AS_CAPITAL_STOCK or DEFINED_PER_PLAN_SECURITY.\n\nThe key is spelled `defaultCancellatonBehavior` — one `l` — because that is\nthe wire, and correcting it here would silently drop the field."},"initialSharesReserved":{"description":"InitialSharesReserved is how many shares the plan may grant. A whole number."},"name":{"description":"Name is the plan's name, e.g. \"2026 Stock Option Plan\"."},"planEffectiveDate":{"description":"PlanEffectiveDate is when the plan takes effect, YYYY-MM-DD. Optional."},"shareClassId":{"description":"ShareClassID is the class the plan grants from. It must name a class of THIS company."}},"type":"object"},"captable.captableInvestmentIn":{"properties":{"amount":{"description":"Amount is the money invested, in the round's own currency. Required and must\nbe positive."},"comments":{"description":"Comments is a free-text note kept with the investment. Optional."},"date":{"description":"Date is when the investment was made, YYYY-MM-DD. Optional: omitted, it is\nrecorded as today."},"id":{"description":"ID is the round to invest in. The URL is the addressing authority — a path\nsegment binds after the body and after the query — so the address decides\nwhich round is written whatever a body claims.","type":"string"},"stakeholderId":{"description":"StakeholderID is the investor. Required, and it must reference a stakeholder\nof the same company."}},"type":"object"},"captable.captableOptionIn":{"properties":{"boardApprovalDate":{"description":"BoardApprovalDate is when the board approved the grant, YYYY-MM-DD."},"cliffYears":{"description":"CliffYears is how long before ANY of the grant vests. A whole number; 0 for no cliff."},"equityPlanId":{"description":"EquityPlanID is the plan the options come from. It must name a plan of THIS company."},"exercisePrice":{"description":"ExercisePrice is the strike price per share, in the company's currency."},"expirationDate":{"description":"ExpirationDate is when unexercised options lapse, YYYY-MM-DD."},"grantId":{"description":"GrantID is the grant's identifier. It must be UNIQUE within the company; reusing one is refused 409."},"issueDate":{"description":"IssueDate is when the grant was made, YYYY-MM-DD."},"notes":{"description":"Notes is a free-text note kept with the grant. Optional."},"quantity":{"description":"Quantity is how many options to grant. A whole number above 0."},"rule144Date":{"description":"Rule144Date is when the Rule 144 holding period starts, YYYY-MM-DD."},"stakeholderId":{"description":"StakeholderID is who receives the grant. It must name a stakeholder of THIS company."},"status":{"description":"Status is DRAFT, ACTIVE, EXERCISED, EXPIRED or CANCELLED."},"type":{"description":"Type is ISO, NSO or RSU."},"vestingStartDate":{"description":"VestingStartDate is when vesting begins, YYYY-MM-DD."},"vestingYears":{"description":"VestingYears is the total vesting period. A whole number."}},"type":"object"},"captable.captableRoundCloseRequest":{"properties":{"closeDate":{"description":"CloseDate is the date to record the round as closed on. Optional: omitted,\nnull or empty records TODAY. Any JSON scalar is accepted and stored as its\ntext, and the text is stored unparsed, so a caller that wants an ISO date\nsends one."},"id":{"description":"ID is the round to close. It is the path segment: the URL is the\naddressing authority, and the org it is resolved in comes from the\ncaller's principal, so an id from another tenant is simply not found.","type":"string"}},"type":"object"},"captable.captableRoundIn":{"properties":{"name":{"description":"Name is the round's name, e.g. \"Series A\"."},"preMoneyValuation":{"description":"PreMoneyValuation is the company's valuation before the new money. Optional."},"pricePerShare":{"description":"PricePerShare is the price investors pay per share. An investment into a round with a price ISSUES the shares it buys; one into a round priced later records the money alone."},"roundType":{"description":"RoundType is PRICED, SAFE or CONVERTIBLE."},"shareClassId":{"description":"ShareClassID is the class investors receive. It must name a class of THIS company."},"targetAmount":{"description":"TargetAmount is how much the round aims to raise, in the company's currency."}},"type":"object"},"captable.captableSafeIn":{"properties":{"additionalTerms":{"description":"AdditionalTerms is free text for anything the fields above do not carry. Optional."},"boardApprovalDate":{"description":"BoardApprovalDate is when the board approved it, YYYY-MM-DD."},"capital":{"description":"Capital is the money invested, in the company's currency."},"discountRate":{"description":"DiscountRate is the discount to the next round's price, as a percentage. Optional."},"issueDate":{"description":"IssueDate is when the SAFE was signed, YYYY-MM-DD."},"publicId":{"description":"PublicID is the SAFE's identifier. It must be UNIQUE within the company; reusing one is refused 409."},"stakeholderId":{"description":"StakeholderID is the investor. It must name a stakeholder of THIS company."},"status":{"description":"Status is DRAFT, ACTIVE, PENDING, EXPIRED or CANCELLED."},"type":{"description":"Type is PRE_MONEY or POST_MONEY — which side of the new money the cap is measured on."},"valuationCap":{"description":"ValuationCap is the valuation the SAFE converts at, at most. Optional; omit for an uncapped SAFE."}},"type":"object"},"captable.captableShareClassAmend":{"properties":{"boardApprovalDate":{"description":"BoardApprovalDate is when the board approved the class, YYYY-MM-DD."},"classType":{"description":"ClassType is COMMON or PREFERRED."},"conversionRights":{"description":"ConversionRights is CONVERTS_TO_FUTURE_ROUND or CONVERTS_TO_SHARE_CLASS_ID. The second requires convertsToShareClassId."},"convertsToShareClassId":{"description":"ConvertsToShareClassID names the class this one converts into. Required when conversionRights is CONVERTS_TO_SHARE_CLASS_ID, ignored otherwise."},"id":{"description":"ID addresses the resource. The URL is the addressing authority — a path\nsegment binds after the body and after the query — so the address decides\nwhich row is written whatever a body claims.","type":"string"},"initialSharesAuthorized":{"description":"InitialSharesAuthorized is how many shares this class may issue. A whole number."},"liquidationPreferenceMultiple":{"description":"LiquidationPreferenceMultiple is the multiple of invested capital paid out before junior classes — 1 for a 1x preference."},"name":{"description":"Name is the share class's name, e.g. \"Series A Preferred\"."},"parValue":{"description":"ParValue is the nominal per-share value on the certificate, in the company's currency."},"participationCapMultiple":{"description":"ParticipationCapMultiple caps participation after the preference is paid, as a multiple of invested capital. 0 for no cap."},"pricePerShare":{"description":"PricePerShare is the issue price for this class, in the company's currency."},"seniority":{"description":"Seniority orders liquidation preference: LOWER is more senior, so 1 is paid before 2."},"stockholderApprovalDate":{"description":"StockholderApprovalDate is when the stockholders approved it, YYYY-MM-DD."},"votesPerShare":{"description":"VotesPerShare is how many votes one share of this class carries. A whole number; 0 for non-voting."}},"type":"object"},"captable.captableShareClassIn":{"properties":{"boardApprovalDate":{"description":"BoardApprovalDate is when the board approved the class, YYYY-MM-DD."},"classType":{"description":"ClassType is COMMON or PREFERRED."},"conversionRights":{"description":"ConversionRights is CONVERTS_TO_FUTURE_ROUND or CONVERTS_TO_SHARE_CLASS_ID. The second requires convertsToShareClassId."},"convertsToShareClassId":{"description":"ConvertsToShareClassID names the class this one converts into. Required when conversionRights is CONVERTS_TO_SHARE_CLASS_ID, ignored otherwise."},"initialSharesAuthorized":{"description":"InitialSharesAuthorized is how many shares this class may issue. A whole number."},"liquidationPreferenceMultiple":{"description":"LiquidationPreferenceMultiple is the multiple of invested capital paid out before junior classes — 1 for a 1x preference."},"name":{"description":"Name is the share class's name, e.g. \"Series A Preferred\"."},"parValue":{"description":"ParValue is the nominal per-share value on the certificate, in the company's currency."},"participationCapMultiple":{"description":"ParticipationCapMultiple caps participation after the preference is paid, as a multiple of invested capital. 0 for no cap."},"pricePerShare":{"description":"PricePerShare is the issue price for this class, in the company's currency."},"seniority":{"description":"Seniority orders liquidation preference: LOWER is more senior, so 1 is paid before 2."},"stockholderApprovalDate":{"description":"StockholderApprovalDate is when the stockholders approved it, YYYY-MM-DD."},"votesPerShare":{"description":"VotesPerShare is how many votes one share of this class carries. A whole number; 0 for non-voting."}},"type":"object"},"captable.captableShareIn":{"properties":{"boardApprovalDate":{"description":"BoardApprovalDate is when the board approved the issuance, YYYY-MM-DD."},"capitalContribution":{"description":"CapitalContribution is cash paid for the shares. Optional."},"certificateId":{"description":"CertificateID is the certificate number. It must be UNIQUE within the company; reusing one is refused 409."},"cliffYears":{"description":"CliffYears is how long before ANY of the grant vests. A whole number; 0 for no cliff."},"companyLegends":{"description":"CompanyLegends are the restrictive legends printed on the certificate.\n\nA LIST, and it must be sent as one: the bundle substitutes an EMPTY list for\nanything that is not an array, so a single string would be accepted and\nsilently discarded — the certificate issued with no legends and nothing\nreporting it.","items":{},"type":"array"},"debtCancelled":{"description":"DebtCancelled is debt forgiven as consideration. Optional."},"ipContribution":{"description":"IPContribution is intellectual property assigned as consideration, valued in the company's currency. Optional."},"issueDate":{"description":"IssueDate is when the shares were issued, YYYY-MM-DD."},"otherContributions":{"description":"OtherContributions is any other consideration, valued in the company's currency. Optional."},"pricePerShare":{"description":"PricePerShare is what was paid per share. Optional."},"quantity":{"description":"Quantity is how many shares to issue. A whole number above 0."},"rule144Date":{"description":"Rule144Date is when the Rule 144 holding period starts, YYYY-MM-DD. Optional."},"shareClassId":{"description":"ShareClassID is the class being issued. It must name a class of THIS company."},"stakeholderId":{"description":"StakeholderID is who receives the shares. It must name a stakeholder of THIS company."},"status":{"description":"Status is ACTIVE, DRAFT, SIGNED or PENDING."},"vestingStartDate":{"description":"VestingStartDate is when vesting begins, YYYY-MM-DD. Optional; defaults to the issue date."},"vestingYears":{"description":"VestingYears is the total vesting period. A whole number; 0 for fully vested at issue."}},"type":"object"},"captable.captableShareTransfer":{"properties":{"certificateId":{"description":"CertificateID names the NEW certificate a partial transfer issues, and is\nrequired for one — a partial transfer without it is refused 400. It is unused\nby a full transfer, which reassigns the existing certificate.\n\nIt must be unique within the company; reusing one is refused 409. Declaring\nit is not optional in the way the tag suggests: omitting this field from the\nGo type would leave `quantity` accepted and every PARTIAL transfer answering\n\"certificateId is required\" with no way for a caller to supply it — the\nsilent-drop failure this whole conversion was blocked on, one field wide."},"quantity":{"description":"Quantity is how many shares to move. OPTIONAL, and its absence is not zero:\nomitted or null transfers the WHOLE certificate. A value outside 1..held is\nrefused, so a partial transfer can never over-issue.\n\nA full transfer REASSIGNS the certificate and mints no new one; a partial\ntransfer splits it and answers with the new share's id. That is the fact a\ncaller needs from the answer, not from this comment."},"shareId":{"description":"ShareID is the certificate being transferred. Required, and it must name a\nshare in the caller org's own company — a share id from another tenant\nresolves to not-found rather than to another company's certificate."},"toStakeholderId":{"description":"ToStakeholderID is who receives them. Required, and it must reference a\nstakeholder of the SAME company; one that does not is refused 400 rather\nthan creating a dangling holder."}},"type":"object"},"captable.captableStakeholderPatch":{"properties":{"city":{"description":"City is the stakeholder's city."},"currentRelationship":{"description":"CurrentRelationship is how the stakeholder relates to the company, e.g.\nFOUNDER, INVESTOR or EMPLOYEE. This route stores it as sent — unlike\nadding a stakeholder, it is not checked against the vocabulary."},"email":{"description":"Email is the stakeholder's email. This route stores it as sent — unlike\nadding a stakeholder, it is not checked for shape or uniqueness."},"id":{"description":"ID is the stakeholder to update. It is the path segment: the URL is the\naddressing authority, and the org it is resolved in comes from the\ncaller's principal, so an id from another tenant is simply not found.","type":"string"},"institutionName":{"description":"InstitutionName names the institution, when the stakeholder is one."},"name":{"description":"Name is the stakeholder's full name."},"stakeholderType":{"description":"StakeholderType is INDIVIDUAL or INSTITUTION. This route stores it as\nsent — unlike adding a stakeholder, it is not checked against the\nvocabulary."},"state":{"description":"State is the stakeholder's state or province."},"streetAddress":{"description":"StreetAddress is the stakeholder's street address."},"taxId":{"description":"TaxID is the stakeholder's tax identifier."},"zipcode":{"description":"Zipcode is the stakeholder's postal code."}},"type":"object"},"channel.allowlistPutIn":{"properties":{"accessGroups":{"additionalProperties":{"additionalProperties":{"items":{"type":"string"},"type":"array"},"type":"object"},"description":"AccessGroups REPLACES the org's named access groups, as\ngroup name -> channel -> entries. Absent or null leaves them alone.","type":"object"},"channel":{"description":"Channel is the transport to edit: discord, github, linear, slack, teams, telegram or whatsapp.\nRequired; an unknown value is a 404.","type":"string"},"dm":{"description":"DM REPLACES the config-managed DM allow entries. Absent or null leaves them\nalone; an empty list clears them. It never touches senders approved through\npairing — a policy edit cannot revoke an approved pairing.","items":{"type":"string"},"type":"array"},"dmPolicy":{"description":"DMPolicy sets how direct messages are admitted: \"pairing\" (a person must be\napproved first), \"allowlist\" (only listed senders) or \"open\". Empty leaves\nit unchanged.","type":"string"},"group":{"description":"Group REPLACES the config-managed group allow entries. Absent or null\nleaves them alone; an empty list clears them.","items":{"type":"string"},"type":"array"},"groupPolicy":{"description":"GroupPolicy sets how group and thread rooms are admitted: \"open\",\n\"allowlist\" or \"disabled\". Empty leaves it unchanged.","type":"string"}},"type":"object"},"channel.approvePairingIn":{"properties":{"channel":{"description":"Channel is the transport the request came in on: discord, slack, teams,\ntelegram or whatsapp.","type":"string"},"code":{"description":"Code is the pairing code from GET /v1/channel/pairing. It is a capability:\nholding it is what authorises the approval, alongside org admin.","type":"string"}},"type":"object"},"channel.channelAgentsPut":{"properties":{"channel":{"description":"Channel is the transport to edit. Required; an unknown value is a 404.","type":"string"},"default":{"description":"Default sets the agent for rooms with no binding of their own; \"hanzo\"\nrestores the built-in. Empty or absent leaves it unchanged.","type":"string"},"rooms":{"additionalProperties":{"type":"string"},"description":"Rooms binds platform room ids to agents; rooms not named are left alone.","type":"object"},"unbind":{"description":"Unbind removes the bindings of these rooms, so they fall back to Default.","items":{"type":"string"},"type":"array"}},"type":"object"},"cloudflare.D1Query":{"properties":{"params":{"description":"Params are the statement's bound values, in the order its `?` placeholders\nappear — a string, a number, a boolean or null, whatever the column takes.\nAbsent means the statement carries no placeholders; bind values here rather\nthan interpolating them into the statement.","items":{},"type":"array"},"sql":{"description":"SQL is the statement to run. Blank (or absent) is refused before anything\nreaches D1.","type":"string"}},"type":"object"},"cloudflare.PagesBuildConfig":{"properties":{"build_command":{"description":"BuildCommand is what Cloudflare runs to build the site (\"npm run build\").\nOmitted means no build step: the repository is published as it stands.","type":"string"},"destination_dir":{"description":"DestinationDir is the directory the build leaves the site in (\"dist\"),\nrelative to RootDir. It is what gets served.","type":"string"},"root_dir":{"description":"RootDir is where in the repository the build runs, for a project that is not at\nthe repository root. Omitted means the root.","type":"string"}},"type":"object"},"cloudflare.PagesD1Binding":{"properties":{"id":{"description":"ID is the D1 database this binding points at, by Cloudflare's uuid. The binding\nname the Worker code reads it as is the map key, not a field here.","type":"string"}},"type":"object"},"cloudflare.PagesDeploymentConfig":{"properties":{"compatibility_date":{"description":"CompatibilityDate pins which Workers runtime behaviour the functions run under,\nas a date (\"2024-01-01\"). It is a pin, not a version: the runtime keeps that\ndate's semantics for code deployed against it.","type":"string"},"compatibility_flags":{"description":"CompatibilityFlags turn individual runtime behaviours on or off ahead of, or\nbehind, the date above (\"nodejs_compat\").","items":{"type":"string"},"type":"array"},"d1_databases":{"additionalProperties":{"$ref":"#/components/schemas/cloudflare.PagesD1Binding"},"description":"D1Databases binds D1 databases in, keyed by binding name.","type":"object"},"env_vars":{"additionalProperties":{"$ref":"#/components/schemas/cloudflare.PagesEnvVar"},"description":"EnvVars are the environment variables the functions see, KEYED BY VARIABLE NAME.\nThe key is the name; the value carries the value and whether it is a secret.","type":"object"},"kv_namespaces":{"additionalProperties":{"$ref":"#/components/schemas/cloudflare.PagesKVBinding"},"description":"KVNamespaces binds KV namespaces into the functions, KEYED BY THE BINDING NAME\nthe code reads (`env.SESSIONS`). Same shape for the two below.","type":"object"},"r2_buckets":{"additionalProperties":{"$ref":"#/components/schemas/cloudflare.PagesR2Binding"},"description":"R2Buckets binds R2 buckets in, keyed by binding name.","type":"object"}},"type":"object"},"cloudflare.PagesDeploymentConfigs":{"properties":{"preview":{"$ref":"#/components/schemas/cloudflare.PagesDeploymentConfig","description":"Preview is the config every branch build other than the production branch runs\nunder. It is a SEPARATE set of bindings and variables, which is what lets a\npreview point at test data."},"production":{"$ref":"#/components/schemas/cloudflare.PagesDeploymentConfig","description":"Production is the config the production branch builds under."}},"type":"object"},"cloudflare.PagesEnvVar":{"properties":{"type":{"description":"Type is \"plain_text\" or \"secret_text\" and decides that: plain text is readable\nafterwards, secret text is write-only. Empty is Cloudflare's default,\nplain_text — so a secret with no type set is stored in the clear.","type":"string"},"value":{"description":"Value is the variable's value. Under type \"secret_text\" Cloudflare encrypts it\non arrival and never reads it back, so a later read of the project shows the\nvariable without this.","type":"string"}},"type":"object"},"cloudflare.PagesKVBinding":{"properties":{"namespace_id":{"description":"NamespaceID is the KV namespace this binding points at, by Cloudflare's id\nrather than its title. The BINDING NAME — what the Worker code reads it as — is\nthe map key this value sits under, not a field here.","type":"string"}},"type":"object"},"cloudflare.PagesProjectCreate":{"properties":{"build_config":{"$ref":"#/components/schemas/cloudflare.PagesBuildConfig","description":"BuildConfig says how to build the site. Omitted means no build step."},"deployment_configs":{"$ref":"#/components/schemas/cloudflare.PagesDeploymentConfigs","description":"DeploymentConfigs carries the preview and production runtime configs — the\nbindings and variables the built site's functions run with."},"name":{"description":"Name is the project name, and it is also the address: the site answers at\n.pages.dev. Cloudflare will not rename a project afterwards.","type":"string"},"production_branch":{"description":"ProductionBranch is which git branch builds to production; every other branch\nbuilds a preview. Omitted leaves Cloudflare's own default.","type":"string"}},"type":"object"},"cloudflare.PagesR2Binding":{"properties":{"name":{"description":"Name is the R2 bucket this binding points at, by bucket name — R2 addresses\nbuckets by name where KV and D1 use ids. The binding name the Worker code reads\nit as is the map key.","type":"string"}},"type":"object"},"cloudflare.WorkerScriptPut":{"properties":{"bindings":{"description":"Bindings are the resources the script can reach (KV, D1, R2, secrets, …), in\nCloudflare's own binding vocabulary, passed through as written: this plane\ndeliberately does not model Cloudflare's shapes. Absent uploads a script with\nNO bindings, which replaces whatever the previous version had."},"compatibilityDate":{"description":"CompatibilityDate pins which Workers runtime behaviour the script runs under,\nas a plain calendar date (\"2024-01-01\"). Absent leaves the account's own\ndefault in force.","type":"string"},"compatibilityFlags":{"description":"CompatibilityFlags turn individual runtime behaviours on or off around that\ndate (\"nodejs_compat\"), in Cloudflare's own flag vocabulary. Absent means the\ndate alone decides.","items":{"type":"string"},"type":"array"},"mainModule":{"description":"MainModule is the module file the runtime starts at. Absent means \"worker.js\".","type":"string"},"script":{"description":"Script means two things on this route, and the document says so in both places\nit appears: the PATH segment names the Worker to publish, and the BODY field\ncarries that Worker's ES-module source — the code itself, never a name or a\nURL. A blank or absent source is refused; there is no empty Worker.","type":"string"}},"type":"object"},"cloudflare.bucketCreateIn":{"properties":{"name":{"description":"Name is the bucket name to create.","type":"string"}},"type":"object"},"cloudflare.databaseCreateIn":{"properties":{"name":{"description":"Name is the database name to create.","type":"string"}},"type":"object"},"cloudflare.domainAddIn":{"properties":{"name":{"description":"Name is the custom domain to attach, e.g. \"www.acme.com\".","type":"string"},"project":{"description":"Project is the Pages project name, from the path.","type":"string"}},"type":"object"},"cloudflare.namespaceCreateIn":{"properties":{"title":{"description":"Title is the namespace's display title. Cloudflare mints the id.","type":"string"}},"type":"object"},"cloudflare.purgeIn":{"properties":{"files":{"description":"Files purges exactly the listed URLs — at most 30, Cloudflare's per-request cap.","items":{"type":"string"},"type":"array"},"purge_everything":{"description":"Everything drops the zone's entire edge cache.","type":"boolean"},"zone":{"description":"Zone is the 32-hex Cloudflare zone id, from the path.","type":"string"}},"type":"object"},"cloudflare.routeCreateIn":{"properties":{"pattern":{"description":"Pattern is the URL pattern to bind, e.g. \"acme.com/api/*\".","type":"string"},"script":{"description":"Script is the Worker script to dispatch to. Omit it to leave the pattern\nbound to no script, which is how Cloudflare expresses \"bypass the Worker here\".","type":"string"},"zone":{"description":"Zone is the 32-hex Cloudflare zone id, from the path.","type":"string"}},"type":"object"},"cloudflare.subdomainSetIn":{"properties":{"enabled":{"description":"Enabled publishes the script on