Validate Run
Everything a create checks, plus a dry run, for free and in seconds: the spec is compiled and three canned
policies are rolled through it on a CPU — zero action, random actions, and, for a robot that has one, a public
walk that passes the report’s checks — reporting what each reward term pays each of them. Warnings name rewards that pay for the wrong thing
(e.g. idle_policy_scores_high: standing still earns most of the tracking reward) with a patch that fixes
it.
curl --request POST \
--url https://api.kiteml.com/v1/rl_runs/validate \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"budget": {
"iterations": 500,
"max_tokens": 400
},
"description": "Walk forward at a steady pace with a level body and alternating feet.",
"from": {
"policy": "4d574ce4c547"
},
"hardware_tier": "gcp_gpu_l4",
"metadata": {
"example": "rl_runs/walk.json"
},
"outputs": {
"formats": [
"onnx",
"pt",
"torchscript"
],
"videos": [
{
"command": {
"vx": 0.3
},
"seconds": 8
}
]
},
"robot": "open_duck_mini_v2",
"seeds": 1,
"task": {
"commands": {
"vx": [
0.2,
0.4
],
"vy": [
-0.05,
0.05
],
"yaw": [
-0.2,
0.2
]
},
"objective": "velocity"
},
"title": "Open Duck: steady walk (fine-tuned)"
}
'import requests
url = "https://api.kiteml.com/v1/rl_runs/validate"
payload = {
"budget": {
"iterations": 500,
"max_tokens": 400
},
"description": "Walk forward at a steady pace with a level body and alternating feet.",
"from": { "policy": "4d574ce4c547" },
"hardware_tier": "gcp_gpu_l4",
"metadata": { "example": "rl_runs/walk.json" },
"outputs": {
"formats": ["onnx", "pt", "torchscript"],
"videos": [
{
"command": { "vx": 0.3 },
"seconds": 8
}
]
},
"robot": "open_duck_mini_v2",
"seeds": 1,
"task": {
"commands": {
"vx": [0.2, 0.4],
"vy": [-0.05, 0.05],
"yaw": [-0.2, 0.2]
},
"objective": "velocity"
},
"title": "Open Duck: steady walk (fine-tuned)"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
budget: {iterations: 500, max_tokens: 400},
description: 'Walk forward at a steady pace with a level body and alternating feet.',
from: {policy: '4d574ce4c547'},
hardware_tier: 'gcp_gpu_l4',
metadata: {example: 'rl_runs/walk.json'},
outputs: {
formats: ['onnx', 'pt', 'torchscript'],
videos: [{command: {vx: 0.3}, seconds: 8}]
},
robot: 'open_duck_mini_v2',
seeds: 1,
task: {
commands: {vx: [0.2, 0.4], vy: [-0.05, 0.05], yaw: [-0.2, 0.2]},
objective: 'velocity'
},
title: 'Open Duck: steady walk (fine-tuned)'
})
};
fetch('https://api.kiteml.com/v1/rl_runs/validate', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.kiteml.com/v1/rl_runs/validate",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'budget' => [
'iterations' => 500,
'max_tokens' => 400
],
'description' => 'Walk forward at a steady pace with a level body and alternating feet.',
'from' => [
'policy' => '4d574ce4c547'
],
'hardware_tier' => 'gcp_gpu_l4',
'metadata' => [
'example' => 'rl_runs/walk.json'
],
'outputs' => [
'formats' => [
'onnx',
'pt',
'torchscript'
],
'videos' => [
[
'command' => [
'vx' => 0.3
],
'seconds' => 8
]
]
],
'robot' => 'open_duck_mini_v2',
'seeds' => 1,
'task' => [
'commands' => [
'vx' => [
0.2,
0.4
],
'vy' => [
-0.05,
0.05
],
'yaw' => [
-0.2,
0.2
]
],
'objective' => 'velocity'
],
'title' => 'Open Duck: steady walk (fine-tuned)'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.kiteml.com/v1/rl_runs/validate"
payload := strings.NewReader("{\n \"budget\": {\n \"iterations\": 500,\n \"max_tokens\": 400\n },\n \"description\": \"Walk forward at a steady pace with a level body and alternating feet.\",\n \"from\": {\n \"policy\": \"4d574ce4c547\"\n },\n \"hardware_tier\": \"gcp_gpu_l4\",\n \"metadata\": {\n \"example\": \"rl_runs/walk.json\"\n },\n \"outputs\": {\n \"formats\": [\n \"onnx\",\n \"pt\",\n \"torchscript\"\n ],\n \"videos\": [\n {\n \"command\": {\n \"vx\": 0.3\n },\n \"seconds\": 8\n }\n ]\n },\n \"robot\": \"open_duck_mini_v2\",\n \"seeds\": 1,\n \"task\": {\n \"commands\": {\n \"vx\": [\n 0.2,\n 0.4\n ],\n \"vy\": [\n -0.05,\n 0.05\n ],\n \"yaw\": [\n -0.2,\n 0.2\n ]\n },\n \"objective\": \"velocity\"\n },\n \"title\": \"Open Duck: steady walk (fine-tuned)\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.kiteml.com/v1/rl_runs/validate")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"budget\": {\n \"iterations\": 500,\n \"max_tokens\": 400\n },\n \"description\": \"Walk forward at a steady pace with a level body and alternating feet.\",\n \"from\": {\n \"policy\": \"4d574ce4c547\"\n },\n \"hardware_tier\": \"gcp_gpu_l4\",\n \"metadata\": {\n \"example\": \"rl_runs/walk.json\"\n },\n \"outputs\": {\n \"formats\": [\n \"onnx\",\n \"pt\",\n \"torchscript\"\n ],\n \"videos\": [\n {\n \"command\": {\n \"vx\": 0.3\n },\n \"seconds\": 8\n }\n ]\n },\n \"robot\": \"open_duck_mini_v2\",\n \"seeds\": 1,\n \"task\": {\n \"commands\": {\n \"vx\": [\n 0.2,\n 0.4\n ],\n \"vy\": [\n -0.05,\n 0.05\n ],\n \"yaw\": [\n -0.2,\n 0.2\n ]\n },\n \"objective\": \"velocity\"\n },\n \"title\": \"Open Duck: steady walk (fine-tuned)\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.kiteml.com/v1/rl_runs/validate")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"budget\": {\n \"iterations\": 500,\n \"max_tokens\": 400\n },\n \"description\": \"Walk forward at a steady pace with a level body and alternating feet.\",\n \"from\": {\n \"policy\": \"4d574ce4c547\"\n },\n \"hardware_tier\": \"gcp_gpu_l4\",\n \"metadata\": {\n \"example\": \"rl_runs/walk.json\"\n },\n \"outputs\": {\n \"formats\": [\n \"onnx\",\n \"pt\",\n \"torchscript\"\n ],\n \"videos\": [\n {\n \"command\": {\n \"vx\": 0.3\n },\n \"seconds\": 8\n }\n ]\n },\n \"robot\": \"open_duck_mini_v2\",\n \"seeds\": 1,\n \"task\": {\n \"commands\": {\n \"vx\": [\n 0.2,\n 0.4\n ],\n \"vy\": [\n -0.05,\n 0.05\n ],\n \"yaw\": [\n -0.2,\n 0.2\n ]\n },\n \"objective\": \"velocity\"\n },\n \"title\": \"Open Duck: steady walk (fine-tuned)\"\n}"
response = http.request(request)
puts response.read_body{
"action_size": 14,
"control_hz": 50,
"estimate": {
"capped": false,
"minutes_per_run": 9.1,
"object": "rl_estimate",
"runs": 1,
"startup_minutes": 5,
"tokens": 167,
"tokens_per_run": 167
},
"object": "rl_validation",
"observation_size": 57,
"ok": true,
"resolved_params": {
"action_rate_final": 1,
"air_time": 3,
"clearance": 1,
"head_pose": 0,
"pose": 1,
"sigma_lin": 0.1,
"track_lin": 2,
"track_yaw": 2
},
"rollouts": [
{
"falls_per_min": 0,
"nonfinite": 0,
"policy": "zero_action",
"reward_per_step": 5.7444,
"terms": {
"clearance": 0.0003,
"feet": -0.0006,
"head": 0,
"pose": 0.9923,
"regularizers": -0.0005,
"slip": 0,
"track": 2.7529,
"upright": 2
}
},
{
"falls_per_min": 33.75,
"nonfinite": 0,
"policy": "random",
"reward_per_step": 3.3678,
"terms": {
"clearance": 0.143,
"feet": -0.0066,
"head": 0,
"pose": 0.8588,
"regularizers": -1.0664,
"slip": -0.0024,
"track": 1.6334,
"upright": 1.808
}
},
{
"falls_per_min": 0,
"nonfinite": 0,
"policy": "catalog:4d574ce4c547",
"reward_per_step": 6.9638,
"terms": {
"clearance": 0.3969,
"feet": 0.0343,
"head": 0,
"pose": 0.8585,
"regularizers": -0.0768,
"slip": -0.0034,
"track": 3.7559,
"upright": 1.9984
}
}
],
"warnings": []
}{
"error": {
"type": "<string>",
"code": "<string>",
"message": "<string>",
"param": "<string>",
"request_id": "<string>",
"details": {}
}
}{
"error": {
"type": "<string>",
"code": "<string>",
"message": "<string>",
"param": "<string>",
"request_id": "<string>",
"details": {}
}
}{
"error": {
"type": "<string>",
"code": "<string>",
"message": "<string>",
"param": "<string>",
"request_id": "<string>",
"details": {}
}
}{
"error": {
"type": "<string>",
"code": "<string>",
"message": "<string>",
"param": "<string>",
"request_id": "<string>",
"details": {}
}
}{
"error": {
"type": "<string>",
"code": "<string>",
"message": "<string>",
"param": "<string>",
"request_id": "<string>",
"details": {}
}
}Authorizations
A Kite API key (kite_...), from Platform API → Keys in the dashboard.
Headers
The dated contract your code was written against. Without it you get 2026-09-27; every response says which version served it.
2026-09-27 Body
Train a policy. Only robot and task.objective are required.
See GET /v1/rl_runs/catalog
What to learn.
Show child attributes
Show child attributes
The dated trainer to use (default: the latest, or the parent's for a fork or continue of your run). A run keeps its engine
Show child attributes
Show child attributes
A count (1-5) or explicit seeds: one run per seed, sharing a group_id
Start from another policy instead of from scratch.
Show child attributes
Show child attributes
Extras beyond what every run produces (ONNX, the checkpoint, the scene, one clip, the report).
Show child attributes
Show child attributes
See GET /v1/rl_runs/catalog (default gcp_gpu_l4)
public lists the run in the policy catalog once it finishes with a pass verdict
private, public 120What the behavior should look like; the report's judge compares the clip against it
2000Your labels, echoed on the run
Show child attributes
Show child attributes
Echoed on the run and its events
Response
Successful Response
False when a warning is an error
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Every parameter as the run would train with it
Show child attributes
Show child attributes
Show child attributes
Show child attributes
{
"capped": false,
"minutes_per_run": 9.1,
"object": "rl_estimate",
"runs": 1,
"startup_minutes": 5,
"tokens": 167,
"tokens_per_run": 167
}
rl_validation "rl_validation"curl --request POST \
--url https://api.kiteml.com/v1/rl_runs/validate \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"budget": {
"iterations": 500,
"max_tokens": 400
},
"description": "Walk forward at a steady pace with a level body and alternating feet.",
"from": {
"policy": "4d574ce4c547"
},
"hardware_tier": "gcp_gpu_l4",
"metadata": {
"example": "rl_runs/walk.json"
},
"outputs": {
"formats": [
"onnx",
"pt",
"torchscript"
],
"videos": [
{
"command": {
"vx": 0.3
},
"seconds": 8
}
]
},
"robot": "open_duck_mini_v2",
"seeds": 1,
"task": {
"commands": {
"vx": [
0.2,
0.4
],
"vy": [
-0.05,
0.05
],
"yaw": [
-0.2,
0.2
]
},
"objective": "velocity"
},
"title": "Open Duck: steady walk (fine-tuned)"
}
'import requests
url = "https://api.kiteml.com/v1/rl_runs/validate"
payload = {
"budget": {
"iterations": 500,
"max_tokens": 400
},
"description": "Walk forward at a steady pace with a level body and alternating feet.",
"from": { "policy": "4d574ce4c547" },
"hardware_tier": "gcp_gpu_l4",
"metadata": { "example": "rl_runs/walk.json" },
"outputs": {
"formats": ["onnx", "pt", "torchscript"],
"videos": [
{
"command": { "vx": 0.3 },
"seconds": 8
}
]
},
"robot": "open_duck_mini_v2",
"seeds": 1,
"task": {
"commands": {
"vx": [0.2, 0.4],
"vy": [-0.05, 0.05],
"yaw": [-0.2, 0.2]
},
"objective": "velocity"
},
"title": "Open Duck: steady walk (fine-tuned)"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
budget: {iterations: 500, max_tokens: 400},
description: 'Walk forward at a steady pace with a level body and alternating feet.',
from: {policy: '4d574ce4c547'},
hardware_tier: 'gcp_gpu_l4',
metadata: {example: 'rl_runs/walk.json'},
outputs: {
formats: ['onnx', 'pt', 'torchscript'],
videos: [{command: {vx: 0.3}, seconds: 8}]
},
robot: 'open_duck_mini_v2',
seeds: 1,
task: {
commands: {vx: [0.2, 0.4], vy: [-0.05, 0.05], yaw: [-0.2, 0.2]},
objective: 'velocity'
},
title: 'Open Duck: steady walk (fine-tuned)'
})
};
fetch('https://api.kiteml.com/v1/rl_runs/validate', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.kiteml.com/v1/rl_runs/validate",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'budget' => [
'iterations' => 500,
'max_tokens' => 400
],
'description' => 'Walk forward at a steady pace with a level body and alternating feet.',
'from' => [
'policy' => '4d574ce4c547'
],
'hardware_tier' => 'gcp_gpu_l4',
'metadata' => [
'example' => 'rl_runs/walk.json'
],
'outputs' => [
'formats' => [
'onnx',
'pt',
'torchscript'
],
'videos' => [
[
'command' => [
'vx' => 0.3
],
'seconds' => 8
]
]
],
'robot' => 'open_duck_mini_v2',
'seeds' => 1,
'task' => [
'commands' => [
'vx' => [
0.2,
0.4
],
'vy' => [
-0.05,
0.05
],
'yaw' => [
-0.2,
0.2
]
],
'objective' => 'velocity'
],
'title' => 'Open Duck: steady walk (fine-tuned)'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.kiteml.com/v1/rl_runs/validate"
payload := strings.NewReader("{\n \"budget\": {\n \"iterations\": 500,\n \"max_tokens\": 400\n },\n \"description\": \"Walk forward at a steady pace with a level body and alternating feet.\",\n \"from\": {\n \"policy\": \"4d574ce4c547\"\n },\n \"hardware_tier\": \"gcp_gpu_l4\",\n \"metadata\": {\n \"example\": \"rl_runs/walk.json\"\n },\n \"outputs\": {\n \"formats\": [\n \"onnx\",\n \"pt\",\n \"torchscript\"\n ],\n \"videos\": [\n {\n \"command\": {\n \"vx\": 0.3\n },\n \"seconds\": 8\n }\n ]\n },\n \"robot\": \"open_duck_mini_v2\",\n \"seeds\": 1,\n \"task\": {\n \"commands\": {\n \"vx\": [\n 0.2,\n 0.4\n ],\n \"vy\": [\n -0.05,\n 0.05\n ],\n \"yaw\": [\n -0.2,\n 0.2\n ]\n },\n \"objective\": \"velocity\"\n },\n \"title\": \"Open Duck: steady walk (fine-tuned)\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.kiteml.com/v1/rl_runs/validate")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"budget\": {\n \"iterations\": 500,\n \"max_tokens\": 400\n },\n \"description\": \"Walk forward at a steady pace with a level body and alternating feet.\",\n \"from\": {\n \"policy\": \"4d574ce4c547\"\n },\n \"hardware_tier\": \"gcp_gpu_l4\",\n \"metadata\": {\n \"example\": \"rl_runs/walk.json\"\n },\n \"outputs\": {\n \"formats\": [\n \"onnx\",\n \"pt\",\n \"torchscript\"\n ],\n \"videos\": [\n {\n \"command\": {\n \"vx\": 0.3\n },\n \"seconds\": 8\n }\n ]\n },\n \"robot\": \"open_duck_mini_v2\",\n \"seeds\": 1,\n \"task\": {\n \"commands\": {\n \"vx\": [\n 0.2,\n 0.4\n ],\n \"vy\": [\n -0.05,\n 0.05\n ],\n \"yaw\": [\n -0.2,\n 0.2\n ]\n },\n \"objective\": \"velocity\"\n },\n \"title\": \"Open Duck: steady walk (fine-tuned)\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.kiteml.com/v1/rl_runs/validate")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"budget\": {\n \"iterations\": 500,\n \"max_tokens\": 400\n },\n \"description\": \"Walk forward at a steady pace with a level body and alternating feet.\",\n \"from\": {\n \"policy\": \"4d574ce4c547\"\n },\n \"hardware_tier\": \"gcp_gpu_l4\",\n \"metadata\": {\n \"example\": \"rl_runs/walk.json\"\n },\n \"outputs\": {\n \"formats\": [\n \"onnx\",\n \"pt\",\n \"torchscript\"\n ],\n \"videos\": [\n {\n \"command\": {\n \"vx\": 0.3\n },\n \"seconds\": 8\n }\n ]\n },\n \"robot\": \"open_duck_mini_v2\",\n \"seeds\": 1,\n \"task\": {\n \"commands\": {\n \"vx\": [\n 0.2,\n 0.4\n ],\n \"vy\": [\n -0.05,\n 0.05\n ],\n \"yaw\": [\n -0.2,\n 0.2\n ]\n },\n \"objective\": \"velocity\"\n },\n \"title\": \"Open Duck: steady walk (fine-tuned)\"\n}"
response = http.request(request)
puts response.read_body{
"action_size": 14,
"control_hz": 50,
"estimate": {
"capped": false,
"minutes_per_run": 9.1,
"object": "rl_estimate",
"runs": 1,
"startup_minutes": 5,
"tokens": 167,
"tokens_per_run": 167
},
"object": "rl_validation",
"observation_size": 57,
"ok": true,
"resolved_params": {
"action_rate_final": 1,
"air_time": 3,
"clearance": 1,
"head_pose": 0,
"pose": 1,
"sigma_lin": 0.1,
"track_lin": 2,
"track_yaw": 2
},
"rollouts": [
{
"falls_per_min": 0,
"nonfinite": 0,
"policy": "zero_action",
"reward_per_step": 5.7444,
"terms": {
"clearance": 0.0003,
"feet": -0.0006,
"head": 0,
"pose": 0.9923,
"regularizers": -0.0005,
"slip": 0,
"track": 2.7529,
"upright": 2
}
},
{
"falls_per_min": 33.75,
"nonfinite": 0,
"policy": "random",
"reward_per_step": 3.3678,
"terms": {
"clearance": 0.143,
"feet": -0.0066,
"head": 0,
"pose": 0.8588,
"regularizers": -1.0664,
"slip": -0.0024,
"track": 1.6334,
"upright": 1.808
}
},
{
"falls_per_min": 0,
"nonfinite": 0,
"policy": "catalog:4d574ce4c547",
"reward_per_step": 6.9638,
"terms": {
"clearance": 0.3969,
"feet": 0.0343,
"head": 0,
"pose": 0.8585,
"regularizers": -0.0768,
"slip": -0.0034,
"track": 3.7559,
"upright": 1.9984
}
}
],
"warnings": []
}{
"error": {
"type": "<string>",
"code": "<string>",
"message": "<string>",
"param": "<string>",
"request_id": "<string>",
"details": {}
}
}{
"error": {
"type": "<string>",
"code": "<string>",
"message": "<string>",
"param": "<string>",
"request_id": "<string>",
"details": {}
}
}{
"error": {
"type": "<string>",
"code": "<string>",
"message": "<string>",
"param": "<string>",
"request_id": "<string>",
"details": {}
}
}{
"error": {
"type": "<string>",
"code": "<string>",
"message": "<string>",
"param": "<string>",
"request_id": "<string>",
"details": {}
}
}{
"error": {
"type": "<string>",
"code": "<string>",
"message": "<string>",
"param": "<string>",
"request_id": "<string>",
"details": {}
}
}