Supervaizer
Created: 2024-12-28 Updated: 2026-10-11
Supervaizer is the Python controller SDK for exposing AI agents to Supervaize Studio through the Supervaizer v2 operation contract.
Supervaizer v2 is layered on:
- A2A for discovery, Agent Cards, JSON-RPC controller calls, and SSE events
- A2UI for agent-authored UI surface documents rendered by Studio
- Supervaizer v2 semantics for Jobs, Cases, Steps, Resources, Datasets, Surfaces, Actions, Artifacts, and
job.syncconvergence
Supervaizer does not contain agent business logic. Agents declare their resources, surfaces, actions, and artifacts; Studio consumes that declaration as a generic operations UI.
Beta: Supervaizer v2 is under active development. Protocol versions are pinned in the registration contract and incompatible versions should fail explicitly.
Start Here
- Product feature map — workflows, routes, and the pytest that covers each one
- Supervaizer v2 concepts
- Protocols: A2A, A2UI, AG-UI, and Supervaizer v2
- CLI reference
- API surfaces and authentication
- Admin interface and workbench
- Hello World example repository
- Built-in local Hello World agent
Quick Start
1. Install
pip install supervaizer
For local development from this repository:
just install-dev # uv sync --extra dev
2. Run The Built-In V2 Hello World Agent
The fastest way to see the v2 controller is local mode:
supervaizer start --local
Local mode runs the agents from your supervaizer_control.py plus the built-in Hello World agent (disable it with SUPERVAIZER_DISABLE_HELLO_WORLD=true); with no control file it starts Hello World alone. Hello World declares:
- a v2 Agent Card
job.startandcase.step.awaitingA2UI surfacesjob.start,job.start.preview,job.sync, andstep.awaiting.submitactions- one generated resource action,
resource.hello_messages.list - a minimal HITL review step when human review is enabled
Local mode binds to 127.0.0.1, skips Studio registration, and uses the API key local-dev. It also bypasses Studio workspace authorization for /a2a actions and surfaces, so X-API-Key alone is enough:
curl -s http://127.0.0.1:8000/a2a \
-H "X-API-Key: local-dev" -H "Content-Type: application/json" \
-d '{"jsonrpc": "2.0", "id": 1, "method": "supervaizer/action.invoke",
"params": {"request_id": "r1", "actor": {"user_id": "me"},
"workspace": {"id": "local"}, "mission_id": "m1",
"agent_slug": "hello-world-ai-agent", "surface": "job.start",
"action": "job.start", "input": {"count": 1}, "job_id": "job-1"}}'
Handlers receive an unverified workspace_authorization whose grant_id is local-mode, and the server logs a startup warning. The bypass applies only while the server has no Studio account, workspace auth is not enabled, and issuer, audience, public key, and JWKS URL are all empty. SUPERVAIZER_WORKSPACE_AUTH_LEEWAY_SECONDS does not count, and SUPERVAIZER_WORKSPACE_AUTH_REQUIRED=false leaves the bypass on. Otherwise every call needs a real Studio token. JSON-RPC -32030 then carries error.data.code workspace_authorization_missing when the verifier is enabled and the header is absent, or workspace_authorization_not_configured when no verifier is enabled. Never expose a local-mode port: anyone who reaches it can run your agents with the well-known key. --host 0.0.0.0, --host ::, and an empty host bind 127.0.0.1; any other --host is kept.
Open these endpoints:
| URL | Purpose | Access |
|---|---|---|
http://127.0.0.1:8000/docs |
FastAPI Swagger docs | public |
http://127.0.0.1:8000/.well-known/agents.json |
A2A discovery | public |
http://127.0.0.1:8000/.well-known/health |
Controller health | public |
POST http://127.0.0.1:8000/a2a |
A2A JSON-RPC controller endpoint | X-API-Key (write scope); workspace token outside local mode |
GET http://127.0.0.1:8000/a2a/events |
SSE stream for v2 effects | X-API-Key (read scope) |
http://127.0.0.1:8000/manage |
Admin interface and agent workbench | Tailscale IP, or loopback in local mode |
3. Inspect The Hello World Example
The built-in agent is the v2 reference implementation:
- Local built-in implementation: src/supervaizer/examples/hello_world_agent.py
- Local server registration: src/supervaizer/examples/local_server.py
- Public repository: supervaize/supervaize_hello_world. It shows the standalone project layout but still uses the v1
AgentMethodFieldstyle; model new agents on the built-in v2 agent instead.
Run the standalone example:
git clone https://github.com/supervaize/supervaize_hello_world.git
cd supervaize_hello_world
uv venv
source .venv/bin/activate
uv pip install -e .
supervaizer start
4. Add A V2 Controller To Your Agent
Run supervaizer scaffold to create supervaizer_control.py, or write the file yourself. It is a complete v2 agent: one registration, one surface, and one action. The scaffolded file also builds a Studio Account from the environment; local mode ignores it.
from typing import Any
from supervaizer import (
Agent,
Server,
V2ActionRequest,
V2SurfaceRequest,
build_v2_agent_registration,
)
agent = Agent(
name="My Agent",
version="0.1.0",
description="My Supervaizer v2 agent.",
supervaizer_v2_registration=build_v2_agent_registration(
agent_slug="my-agent", # must equal Agent.slug, the slugified name
display_name="My Agent",
a2ui_catalog_version="my-agent-ui.1", # bump when your surfaces change
surfaces=["job.start"],
actions=["job.start"],
),
)
server = Server(agents=[agent])
@server.v2_surface("job.start", agent_slug=agent.slug)
def job_start_form(request: V2SurfaceRequest) -> dict[str, Any]:
return {
"surface": request.surface,
"document": {
"type": "Form",
"title": "Start job",
"fields": [
{"id": "goal", "label": "Goal", "type": "string", "required": True}
],
"submit": {"action": "job.start", "label": "Start"},
},
}
@server.v2_action("job.start", agent_slug=agent.slug)
def start_job(request: V2ActionRequest) -> dict[str, Any]:
job_id = request.job_id or "local-job"
return {
"status": "ok",
"effects": [{"type": "job.started", "job_id": job_id, "status": "completed"}],
"job_state": {
"job": {
"id": job_id,
"mission_id": request.mission_id,
"agent_slug": request.agent_slug,
"status": "completed",
"source": {"type": "fresh_start"},
},
"cases": [
{
"id": "case-1",
"title": request.input["goal"],
"status": "completed",
"steps": [
{"id": "step-1", "activity": "operation", "status": "completed"}
],
}
],
},
}
Start it in local mode. The CLI loads supervaizer_control.py, finds the Server, and launches it:
supervaizer start --local
Load the surface:
curl -s http://127.0.0.1:8000/a2a \
-H "X-API-Key: local-dev" -H "Content-Type: application/json" \
-d '{"jsonrpc": "2.0", "id": 1, "method": "supervaizer/surface.load",
"params": {"request_id": "r1", "actor": {"user_id": "me"},
"workspace": {"id": "local"}, "mission_id": "m1",
"agent_slug": "my-agent", "surface": "job.start"}}'
| Part | Role |
|---|---|
build_v2_agent_registration |
Declares the surfaces Studio can show and the actions Studio can call. |
@server.v2_surface |
Returns the A2UI document for one declared surface. |
@server.v2_action |
Runs one declared action. Returns effects and an optional job_state snapshot. |
Rules that prevent the usual first errors:
agent_slugin the registration must equalAgent.slug(the slugifiedname). A mismatch fails atAgentcreation.- Register one handler for each declared action and each surface you serve. A missing action handler answers JSON-RPC error
-32010; a missing surface handler answers-32011. - Pass
agent_slugto each handler decorator. Local mode adds the built-in Hello World agent, so the server holds two agents and cannot infer the slug. - A bare action id defaults to
mutating=True, scope="job". Declare a read-only action withV2ActionDefinition(id=..., mutating=False, scope=...).
Add these when you need them:
- Status convergence: declare
job_policy={"sync": {"action": "job.sync"}}and register ajob.synchandler. - Human review: return a step with
status="awaiting"and anawaitingobject. Declare thecase.step.awaitingsurface and thestep.awaiting.submitaction. - Business objects: declare
resources=[...]. The SDK derives theresource.<id>.<operation>actions; you register their handlers.
The built-in Hello World agent shows all three. Supervaizer v2 concepts holds the full model.
5. Connect To Studio
Studio-managed operation needs a supervisor_account on the Server, the controller's own API key, and workspace authorization trust material. The scaffold template (supervaizer scaffold) reads these variables:
export SUPERVAIZE_API_KEY=... # agent -> Studio calls
export SUPERVAIZE_WORKSPACE_ID=...
export SUPERVAIZE_API_URL=https://app.supervaize.com
export SUPERVAIZER_API_KEY=... # Studio -> controller calls (X-API-Key); generated if unset
export SUPERVAIZER_PUBLIC_URL=https://your-controller.example.com
# Workspace authorization: required when A2A is enabled and the controller registers with Studio
export SUPERVAIZER_WORKSPACE_AUTH_REQUIRED=true
export SUPERVAIZER_WORKSPACE_AUTH_ISSUER=https://studio.supervaize.com
export SUPERVAIZER_WORKSPACE_AUTH_JWKS_URL=https://app.supervaize.com/w/your-workspace-slug/api/v1/workspace-agent-grants/jwks/ # or SUPERVAIZER_WORKSPACE_AUTH_PUBLIC_KEY=<PEM>
Copy the generated workspace values from Studio's Developer → Environment variables section. SUPERVAIZE_WORKSPACE_ID must be the workspace slug shown there; the API key's user must belong to that workspace and retain Developer access. A mismatch can make SERVER_REGISTER return HTTP 403. The issuer must match Studio's token issuer. The JWKS URL is public and supplies the signing key. Workspace authorization is separate from SUPERVAIZE_API_KEY and SUPERVAIZER_API_KEY.
In your own control file, build the account explicitly; Server does not read the SUPERVAIZE_* variables itself:
import os
from supervaizer import Account, Server
account = Account(
workspace_id=os.environ["SUPERVAIZE_WORKSPACE_ID"],
api_key=os.environ["SUPERVAIZE_API_KEY"],
api_url=os.environ.get("SUPERVAIZE_API_URL", "https://app.supervaize.com"),
)
server = Server(agents=[agent], supervisor_account=account)
Without the three SUPERVAIZER_WORKSPACE_AUTH_* variables, a Studio-registered controller refuses to launch (Studio-registered Supervaizer v2 A2A requires workspace authorization). Local mode does not need them. See docs/2026_05_WORKSPACE_AGENT_GRANTS.md.
Then start the controller:
supervaizer start
Studio registration remains the trust bootstrap. It owns server identity, public key exchange, and encrypted payload handling. The A2A Agent Card advertises the v2 operational contract after Studio knows the controller.
V2 Concepts
| Concept | Meaning |
|---|---|
| Job | Committed work that Studio tracks for an agent. |
| Case | A unit of work inside a Job, grouped by lane (default work). |
| Step | An observable activity inside a Case: activity, status, optional awaiting, and outputs. |
| Surface | A named UI entry point. Its handler returns an A2UI document. |
| Action | A typed command invoked through A2A JSON-RPC. Its handler returns effects and an optional job_state. |
| Resource, Dataset | Agent-owned business objects and queryable data that Studio renders generically. |
| Artifact | An agent-owned output, referenced from Step outputs. |
Failure is a status, not a step kind. Human review is status="awaiting" plus an awaiting object. Dynamic UI behavior is A2UI local logic or a typed action call, never a callback.
The full model, the standard surface and action ids, and the protocol split are in docs/2026_05_SUPERVAIZER_v2.md and docs/2026_05_PROTOCOLS.md.
CLI
Common commands:
supervaizer start
supervaizer start --local
supervaizer start --host 0.0.0.0 --port 8000
See docs/2025_08_CLI.md for the full CLI reference and environment variables.
Deployment
Install deployment extras:
pip install "supervaizer[deploy]"
Preview, smoke-test in Docker, and deploy:
supervaizer deploy plan --platform cloud-run --name my-agent --project-id my-gcp-project
supervaizer deploy local --name my-agent --generate-api-key
supervaizer deploy up --platform cloud-run --name my-agent --project-id my-gcp-project --region us-central1
deploy up builds the image, pushes it to the platform registry, and, when --generate-api-key or --generate-rsa is set, stores SUPERVAIZER_API_KEY and SUPERVAIZER_PRIVATE_KEY as platform secrets. Targets: Google Cloud Run, AWS App Runner, and DigitalOcean App Platform.
Cloud Run services start private, and the runtime service account needs access to those secrets. App Runner has no ECR or instance role, so treat that platform as experimental. deploy up prints failures and still exits 0. Options, registries, and the full limit list are in the CLI reference.
See:
Admin Interface
The admin interface and agent workbench are mounted at /manage (admin_interface=True, the default). Access is restricted to Tailscale addresses (100.64.0.0/10), plus loopback in local mode; no API key is used. The workbench starts v1 jobs only; a v2-only agent is operated through POST /a2a. See docs/2025_08_ADMIN_README.md.
Development
Run tests and checks:
just test # pytest, no coverage
just precommit # ruff check, ruff format, mypy, hooks
Contributing
Supervaizer is public SDK infrastructure. Keep public contracts typed, generic, and free of agent-specific business logic. If a protocol field changes, update the producer and consumer documentation together.
Please see CONTRIBUTING.md for contribution details.
License
This project is licensed under the Mozilla Public License 2.0.
Metadata
Release files for supervaizer 1.8.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| supervaizer-1.8.0.tar.gz | 214.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| supervaizer-1.8.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 494.6 kB
Release files / supervaizer-1.8.0.tar.gz
| Download URL | supervaizer-1.8.0.tar.gz |
|---|---|
| Size | 214.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
e167e0571a6d7e48de5981a962bdf5963d2a5b9570774fcae1ab9c1ba0319618
|
|
BLAKE2b-256 checksum How to use checksums |
9a9295414f101335bc2d1bc00f9fe11a87641308e8cfcd13b7e0f73d11beec40
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 11, 2026.
Transparency logRelease files / supervaizer-1.8.0-py3-none-any.whl
| Download URL | supervaizer-1.8.0-py3-none-any.whl |
|---|---|
| Size | 280.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
68f7d868378c7616628dd49d85e2fcc2446af6e300c4ba6d22f980f14fc0db80
|
|
BLAKE2b-256 checksum How to use checksums |
171ede43d7840b47ae4949150b74f7b0fc9665732e47eb758ec0a99f94cd9fb2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 11, 2026.
Transparency log