Models, experiments and deploys
The files under configs/ besides the agent.
Models
Section titled “Models”Model roles: configs/models/<name>.toml; --model NAME picks one.
| File | What it is |
|---|---|
deepseek-flash |
DeepSeek V4.1 Flash writes programs, answers questions about images and points; Molmo2 for a pointer role |
grok-low |
grok-4.7 (low) writes programs, answers questions about images and points; Molmo2 for a pointer role |
grok-medium |
grok-4.7 (medium) writes programs, answers questions about images and points; Molmo2 for a pointer role |
opus-5.5 |
Claude Opus 5.5 writes programs, answers questions about images and points; Molmo2 for a pointer role |
qwen3-vl-32b |
Qwen3-VL-32B (self-hosted, 4 bit) writes programs, answers questions and points; Molmo2 for a pointer role |
qwen3.5-397b |
Qwen3.5-397B-A17B (open weights) writes programs and answers questions about images; Molmo2 points |
configs/models/deepseek-flash.toml
# DeepSeek V4.1 Flash writes the programs: the development model. It runs at medium# reasoning effort for a few cents per RoboDojo episode (R4 on the 84 official pack-0# cases: 6.4 calls and $0.02 per episode), and OpenRouter serves it from our region.# The paper's main runs name their model in the experiment (opus-5.5).description = "DeepSeek V4.1 Flash writes programs, answers questions about images and points; Molmo2 for a pointer role"include = ["grok-medium.toml"]
[main]model = "deepseek/deepseek-v4.1-flash"
# The same model answers questions about images inside programs (see grok-medium.toml).[vlm]model = "deepseek/deepseek-v4.1-flash"reasoning_effort = "medium"configs/models/grok-low.toml
# grok-4.7 at low reasoning effort, for development. At medium effort xAI streams no# reasoning, and OpenRouter cuts a request after about 5 minutes with nothing received:# long replies are lost. Low effort answers in 13-60 s (about $0.11 per RoboDojo episode).description = "grok-4.7 (low) writes programs, answers questions about images and points; Molmo2 for a pointer role"include = ["grok-medium.toml"]
[main]reasoning_effort = "low"configs/models/grok-medium.toml
# Hosted models through OpenRouter (the key from OPENROUTER_API_KEY; never write it# here). OpenAI, Anthropic and Google models refuse requests from our region (HTTP# 403), so development runs use x-ai/grok-4.7. Zhang et al. (2026b) run their models at# medium reasoning effort.description = "grok-4.7 (medium) writes programs, answers questions about images and points; Molmo2 for a pointer role"
[main]backend = "openrouter"model = "x-ai/grok-4.7"reasoning_effort = "medium"# On OpenRouter the limit covers reasoning tokens too.max_output_tokens = 16000# Streamed: keep-alive chunks arrive while the model thinks, so a dead connection# shows up within the read timeout (the link to OpenRouter drops now and then).stream = truetimeout_seconds = 120# Completions have no side effects; retry dropped connections and rate limits for up to# 30 minutes (the simulator waits while the model is called).retries = 3retry_seconds = 1800
# Questions about images inside programs (query_vlm, holding() without a measured# gripper, pointing when there is no pointer) go to the main model itself: one model# sees the task and the images, as in Z2_v01, instead of a second, weaker model# answering for it (1.1.0 asked qwen3.8-flash, whose answers about what an object is# changed from one question to the next).[vlm]backend = "openrouter"model = "x-ai/grok-4.7"reasoning_effort = "low"stream = truetimeout_seconds = 120# The link drops now and then; give up after about 5 minutes so the program sees an# error instead of the kernel being killed.retries = 3retry_seconds = 300
# Open-vocabulary pointing (point_to) with Molmo2 (Clark et al., 2026), self-hosted, for# agents that take the pointer role; the default agent's vlm role points instead.[pointer]service = "molmo2"
[runtime]# Images of the two most recent turns, as in Zhang et al. (2026b); text history is kept.keep_images = 2configs/models/opus-5.5.toml
# The paper's main model (Sec. 5): Claude Opus 5.5 through OpenRouter. It refuses# requests from our region (HTTP 403): run it from a machine in a supported region.description = "Claude Opus 5.5 writes programs, answers questions about images and points; Molmo2 for a pointer role"include = ["grok-medium.toml"]
[main]model = "anthropic/claude-opus-5.5"
# The same model answers questions about images inside programs (see grok-medium.toml).[vlm]model = "anthropic/claude-opus-5.5"reasoning_effort = "low"configs/models/qwen3-vl-32b.toml
# Self-hosted development model, no API spend: Qwen3-VL-32B-Instruct (4 bit, the# qwen3-vl-32b service) writes the programs, answers questions and points; Molmo2 for a pointer role.description = "Qwen3-VL-32B (self-hosted, 4 bit) writes programs, answers questions and points; Molmo2 for a pointer role"
[main]service = "qwen3-vl-32b"max_output_tokens = 2048# Sampling breaks the exact-repeat loops a small model falls into at temperature 0.temperature = 0.6timeout_seconds = 600
[vlm]service = "qwen3-vl-32b"timeout_seconds = 300
[pointer]service = "molmo2"
[runtime]keep_images = 1# The 32B model in 4 bit on one 24 GB GPU runs out of memory beyond about 7k prompt# tokens; with images downscaled by the server three turns fit.max_history_turns = 3# The task descriptions do not fit its context either.task_descriptions = falseconfigs/models/qwen3.5-397b.toml
# Qwen3.5-397B-A17B, open weights, writes programs and answers questions about images:# the open-weight model of the paper's comparison of language models.description = "Qwen3.5-397B-A17B (open weights) writes programs and answers questions about images; Molmo2 points"include = ["grok-medium.toml"]
[main]model = "qwen/qwen3.5-397b-a17b"
[vlm]model = "qwen/qwen3.5-397b-a17b"reasoning_effort = "medium"Experiments
Section titled “Experiments”The agent with a model on a bench: configs/experiments/<name>.toml.
| File | What it is |
|---|---|
catch-ab |
reactive layer A/B: a scripted catch on the conveyor, official layouts 0-19 of pack 0 |
dev |
the agent, one task, development layouts |
eval |
the agent on official evaluation layouts |
paper-stable |
the paper’s comparison subset: 8 tasks x official layouts 0-3 of pack 0, the submitted configuration |
paper-subset |
the paper’s development subset: 8 tasks x 2 development layouts, the submitted configuration |
policy-alone-dev |
a learned policy alone through run_policy (the agent’s, Simate, unless set), every task, two development layouts |
robotwin-dev |
the agent on RoboTwin, development seeds |
robotwin-eval |
the agent on RoboTwin 2.0, 50 tasks x 5 randomized evaluation episodes |
rsi-stable |
self-improvement: the agent’s own-tool tasks, frozen evaluation on layouts 0-19 of pack 1 |
subset8 |
the agent on the 8-task development subset |
configs/experiments/catch-ab.toml
# The reactive layer A/B (paper Tab. reactive (b)): one scripted program, no model calls,# catches an object moving past on the conveyor of match_and_pick_from_conveyor, on# official layouts 0-19 of pack 0. Both arms wait until an object comes within the left# arm's straight-down reach, then differ only in how they close on it:# intercept: the reactive layer follows the object every control tick (skills/reflexes)# harness run configs/experiments/catch-ab.toml --agent configs/ablations/reflexes.toml \# --script configs/scripts/catch_intercept.json --output runs/catch/intercept# reach: the same approach (8 cm above, then down, close, lift) to where it was seen# harness run configs/experiments/catch-ab.toml --agent configs/ablations/reflexes.toml \# --script configs/scripts/catch_reach.json --output runs/catch/reach# A catch is the jaws still holding one second after the lift (stdout "CATCH True").description = "reactive layer A/B: a scripted catch on the conveyor, official layouts 0-19 of pack 0"include = ["eval.toml"]tasks = ["match_and_pick_from_conveyor"]seeds = "0-19"configs/experiments/dev.toml
# Development: the agent with its default model on one task and development layouts# (never evaluation layouts). `harness run configs/experiments/dev.toml# --deploy <machine>` starts the simulator workers itself; `harness program` uses the# worker at `endpoint`.description = "the agent, one task, development layouts"bench = "robodojo"tasks = ["general_pickup"]seeds = [0]layouts = "procedural"endpoint = "http://127.0.0.1:8771"
[budget]max_wall_seconds = 5400# Cost guard for development checks; the paper runs set no cost cap.max_cost_usd = 4.0configs/experiments/eval.toml
# The agent on RoboDojo's official evaluation layouts (pack 0), all tasks, two layouts# each (raise seeds to "0-49" for the full protocol). Evaluation resolves strictly: a# skill or service the agent names that cannot run on this machine stops the run.description = "the agent on official evaluation layouts"bench = "robodojo"tasks = "all"seeds = "0-1"layouts = "eval"layout_pack_seed = 0
[budget]max_wall_seconds = 5400configs/experiments/paper-stable.toml
# The paper's comparison subset (Sec. Experiments: any model, any policy, the ladder): 8# tasks on official evaluation layouts 0-3 of pack 0, with the agent as it was submitted# to the leaderboard (no pointer, no world model). The tasks were chosen from the full# local evaluation of agent 1.6.3 (pack 0, 25-50 layouts each) so that a comparison can# show a difference: a base success rate between 15 and 75 %, the same outcome when a# layout is run again, and both kinds of task: three the agent does with its own tools# (general_pickup, solve_equation, arrange_largest_number) and five it hands to the# learned policy. One run per configuration:# harness run configs/experiments/paper-stable.toml --output runs/paper-stable/base# ... --model grok-low | --model qwen3.5-397b (language models)# ... --set 'agent.services.policies=["g05"]' (learned policies)# ... --agent configs/ablations/r1.toml | r2.toml (the ladder)description = "the paper's comparison subset: 8 tasks x official layouts 0-3 of pack 0, the submitted configuration"include = ["eval.toml"]tasks = ["general_pickup", "solve_equation", "arrange_largest_number", "match_and_pick_from_conveyor", "pour_balls_into_vase", "pour_liquid_into_cup", "sort_nesting_dolls_by_size", "organize_table"]seeds = "0-3"
[overrides.agent]roles = ["main", "vlm", "verifier"]services = { world_models = [] }configs/experiments/paper-subset.toml
# The paper's development subset (Sec. Experiments: any model, the ladder, the reactive# layer): the 8 tasks of subset8.toml on two development layouts each, with the agent as# it was submitted to the leaderboard (no pointer, no world model). One run per# configuration:# harness run configs/experiments/paper-subset.toml --output runs/paper/base# ... --model grok-low | --model qwen3.5-397b (language models)# ... --set 'agent.services.policies=["g05"]' (learned policies)# ... --agent configs/ablations/r1.toml | r2.toml (the ladder)description = "the paper's development subset: 8 tasks x 2 development layouts, the submitted configuration"include = ["subset8.toml"]seeds = "0-1"
[overrides.agent]roles = ["main", "vlm", "verifier"]services = { world_models = [] }configs/experiments/policy-alone-dev.toml
# A learned policy alone on development layouts: one scripted program hands it the# whole task from the start pose and lets it run to the end of the episode (run_policy# as RoboDojo's evaluation client runs it; no model calls). scripts/policy_card.py sorts# its per-task scores into the kinds its description in services/<name>.toml names:# harness run configs/experiments/policy-alone-dev.toml --script configs/scripts/policy_alone.json --output runs/simate-alone-dev# harness run configs/experiments/policy-alone-dev.toml --set 'agent.services.policies=["g05"]' --script configs/scripts/policy_alone.json --output runs/g05-alone-dev# python scripts/policy_card.py runs/simate-alone-devdescription = "a learned policy alone through run_policy (the agent's, Simate, unless set), every task, two development layouts"bench = "robodojo"tasks = "all"seeds = "0-1"layouts = "procedural"
[budget]max_wall_seconds = 5400
[overrides.agent]services = { world_models = [] }# The script hands the policy the task itself: no start step.runtime = { strategy_first = false }configs/experiments/robotwin-dev.toml
# RoboTwin 2.0 development check on stack_blocks_two: the agent with the RoboTwin prompt# pack (AgileX ALOHA). No learned skill for this embodiment (no policy or world model# trained on RoboTwin is served), and RoboTwin has no task descriptions.description = "the agent on RoboTwin, development seeds"bench = "robotwin"tasks = ["stack_blocks_two"]seeds = [0]layouts = "procedural"endpoint = "http://127.0.0.1:8772"
[budget]max_wall_seconds = 5400max_cost_usd = 4.0
[overrides.agent]prompt = "../../prompts/robotwin"# The tools by object id (skills/eef) are tuned to RoboDojo's ARX X5 (table height,# parking spots, jaw width); RoboTwin's ALOHA uses the manipulation skill's.skills = { layers = { learned = false }, enable = ["manipulation"], disable = ["eef"] }services = { policies = [], world_models = [] }# RoboTwin has no XPolicyLab embodiment profile here: the worker shows programs its own# observations (the default agent's contract is RoboDojo's leaderboard protocol).runtime = { task_descriptions = false, contract = "native" }configs/experiments/robotwin-eval.toml
# RoboTwin 2.0 evaluation as Harness VLA (Zhang et al. 2026a, Tab. 6) reports it: the 50# tasks, five randomized episodes each (demo_randomized, the official evaluation seeds of# group 0). The agent as in robotwin-dev.toml: the RoboTwin prompt pack, the manipulation# skill, no learned skill (none is served for this embodiment), the robot's own# observations.description = "the agent on RoboTwin 2.0, 50 tasks x 5 randomized evaluation episodes"include = ["robotwin-dev.toml"]tasks = "all"seeds = "0-4"layouts = "eval"layout_pack_seed = 0configs/experiments/rsi-stable.toml
# Learning from past episodes (paper Sec. 3.3, Tab. RSI) on the three tasks the agent does# with its own tools, where an entry of its library can change what its programs do# (general_pickup 68, solve_equation 18, arrange_largest_number 22 in the full local# evaluation of agent 1.6.3). The library grows on official layouts of pack 0 (explore# 0-3, validate 4-9) and is evaluated frozen on layouts 0-19 of pack 1, which it never saw# (pack 0 has only 25 layouts of arrange_largest_number). The agent as submitted.# python scripts/self_improve.py --experiment configs/experiments/rsi-stable.toml --set layout_pack_seed=0 \# --tasks general_pickup --explore-seeds 0-3 --validate-seeds 4-9 --min-gain 0.3 \# --library runs/rsi/library-general_pickup --output runs/rsi/learn-general_pickup# harness run configs/experiments/rsi-stable.toml --output runs/rsi/eval-none# harness run configs/experiments/rsi-stable.toml --set 'agent.runtime.library.path="runs/rsi/library"' \# --output runs/rsi/eval-librarydescription = "self-improvement: the agent's own-tool tasks, frozen evaluation on layouts 0-19 of pack 1"include = ["eval.toml"]tasks = ["general_pickup", "solve_equation", "arrange_largest_number"]seeds = "0-19"layout_pack_seed = 1
[overrides.agent]roles = ["main", "vlm", "verifier"]services = { world_models = [] }configs/experiments/subset8.toml
# The 8-task development subset (both conveyor tasks included) that ablations, model# comparisons and self-improvement share (App. A); 10 episodes each on development# layouts. An ablation runs it with --agent configs/ablations/<name>.toml.description = "the agent on the 8-task development subset"include = ["dev.toml"]tasks = ["general_pickup", "stack_blocks", "stack_bowls", "classify_objects", "deposit_coin", "insert_tubes", "match_and_pick_from_conveyor", "pick_from_conveyor_by_image"]seeds = "0-9"
[budget]max_total_cost_usd = 20.0Deploys
Section titled “Deploys”Where services run on one machine: configs/deploy/<machine>.toml.
| File | What it is |
|---|---|
example-1gpu |
A machine with one 24 GB GPU. The simulator (6-9 GB) leaves room for one model at a time: SAM 3 (7.2 GB) and Simate (14 GB) are on demand in one swap group, so the broker loads the one a skill calls and swaps when the other is needed. The simulator waits while a model loads, so this costs wall time, not episode steps, and the identity is that of a machine where both stay resident. One thing differs: Simate keeps a memory of past frames, and swapped out it starts that memory afresh, so a policy run after a SAM 3 call in the same episode does not see the frames before it (docs/src/content/docs/guides/small-machine.md). Copy to configs/deploy/<your machine>.toml and set the paths. |
example-2gpu |
A machine with two 24 GB GPUs: the agent’s models stay resident on GPU 1 (SAM 3 7.2 GB and Simate 14 GB; started once with harness up), the simulator workers run on GPU 0. Copy to configs/deploy/<your machine>.toml (git-ignored) and set the paths. |
example-4gpu |
A machine with four 24 GB GPUs: the agent’s models resident on GPU 0 (SAM 3 and Simate), Molmo2 and OpenWAM on demand in one swap group on GPU 1 for experiments that turn them on (a pointer role, --set 'agent.services.world_models=["openwam"]'), and the simulator workers on the other two, two per GPU. Copy to configs/deploy/<your machine>.toml (git-ignored) and set the paths and GPUs. |
example-api |
No GPU for models: only the simulator runs here, every model is hosted (the main and vlm roles). Without a segmenter, segmentation and the tools built on it (locate, pick, release, …) drop out of runs on this machine, and without a policy server the learned skills: a smaller configuration with another identity. |
configs/deploy/example-1gpu.toml
# A machine with one 24 GB GPU. The simulator (6-9 GB) leaves room for one model at a# time: SAM 3 (7.2 GB) and Simate (14 GB) are on demand in one swap group, so the broker# loads the one a skill calls and swaps when the other is needed. The simulator waits# while a model loads, so this costs wall time, not episode steps, and the identity is# that of a machine where both stay resident. One thing differs: Simate keeps a memory of# past frames, and swapped out it starts that memory afresh, so a policy run after a SAM 3# call in the same episode does not see the frames before it (docs/src/content/docs/guides/small-machine.md).# Copy to configs/deploy/<your machine>.toml and set the paths.weights = "~/harness-weights"state = "~/.cache/harness-policy/services"gpus = [0]gpu_memory_gb = 24
[sim]gpus = [0]workers_per_gpu = 1
[services.sam3]gpu = 0mode = "on_demand"swap = "models"
[services.simate]gpu = 0mode = "on_demand"swap = "models"configs/deploy/example-2gpu.toml
# A machine with two 24 GB GPUs: the agent's models stay resident on GPU 1 (SAM 3 7.2 GB# and Simate 14 GB; started once with `harness up`), the simulator workers run on GPU 0.# Copy to configs/deploy/<your machine>.toml (git-ignored) and set the paths.weights = "~/harness-weights"state = "~/.cache/harness-policy/services"gpus = [0, 1]gpu_memory_gb = 24
[sim]gpus = [0]workers_per_gpu = 2
[services.sam3]gpu = 1
[services.simate]gpu = 1configs/deploy/example-4gpu.toml
# A machine with four 24 GB GPUs: the agent's models resident on GPU 0 (SAM 3 and# Simate), Molmo2 and OpenWAM on demand in one swap group on GPU 1 for experiments that# turn them on (a pointer role, `--set 'agent.services.world_models=["openwam"]'`), and# the simulator workers on the other two, two per GPU.# Copy to configs/deploy/<your machine>.toml (git-ignored) and set the paths and GPUs.weights = "~/harness-weights"state = "~/.cache/harness-policy/services"gpus = [0, 1, 2, 3]gpu_memory_gb = 24
# Simulator workers of `harness run`: two RoboDojo workers per GPU (6-9 GB each).[sim]gpus = [2, 3]workers_per_gpu = 2base_port = 8771
[services.sam3]gpu = 0
[services.simate]gpu = 0
[services.molmo2]gpu = 1mode = "on_demand"swap = "experiments"
[services.openwam]gpu = 1mode = "on_demand"swap = "experiments"configs/deploy/example-api.toml
# No GPU for models: only the simulator runs here, every model is hosted (the main and# vlm roles). Without a segmenter, segmentation and the tools built on it (locate, pick,# release, ...) drop out of runs on this machine, and without a policy server the# learned skills: a smaller configuration with another identity.weights = "~/harness-weights"gpus = [0]
[sim]gpus = [0]workers_per_gpu = 1Worker options
Section titled “Worker options”Options for harness serve --options (a worker started by hand).
| File | What it is |
|---|---|
robodojo_runtime |
Keyword arguments for benches.robodojo.runtime:create_environment. Pass with: scripts/harness serve –factory benches.robodojo.runtime:create_environment \ –options configs/workers/robodojo_runtime.toml One worker serves one task. Copy this file under configs/local/ for other tasks. |
robodojo_runtime_dev |
Development worker: replays procedurally generated layouts that are disjoint from the official eval packs (see benches/robodojo/devlayouts.py). scripts/harness serve –factory benches.robodojo.runtime:create_environment \ –options configs/workers/robodojo_runtime_dev.toml reset(task, seed) replays <dev_layout_dir>/<task>_<seed>.json and generates it on first use; pre-generate with scripts/robodojo_make_dev_layouts.py. dev_layout_dir defaults to <RoboDojo>/harness_dev_layouts/arx_x5; set it to keep layouts elsewhere. |
robotwin_runtime |
RoboTwin 2.0 evaluation worker: the official clean-to-randomized protocol (demo_randomized scenes, unseen instructions, expert-checked seeds from 100000 * (1 + seed_group)). See configs/workers/robotwin_runtime_dev.toml. |
robotwin_runtime_dev |
RoboTwin 2.0 development worker (benches/robotwin/runtime.py). Development seeds start at 10**7, disjoint from every evaluation seed; a seed counts only if RoboTwin’s expert solves it, and the valid ones are cached under seed_cache_dir (default <RoboTwin>/harness_seeds). PYTHONPATH=third_party/curobo-0.7.8/src scripts/harness serve \ –factory benches.robotwin.runtime:create_environment \ –options configs/workers/robotwin_runtime_dev.toml –port 8772 |
configs/workers/robodojo_runtime.toml
# Keyword arguments for benches.robodojo.runtime:create_environment.# Pass with: scripts/harness serve --factory benches.robodojo.runtime:create_environment \# --options configs/workers/robodojo_runtime.toml# One worker serves one task. Copy this file under configs/local/ for other tasks.task = "stack_bowls"layout_pack_seed = 0# Per-tick three-camera clips cost seconds per step; enable only for debugging.record_video = false
[shield]# Commands that are bugs are rejected (see benches/robodojo/runtime.py).max_joint_jump_rad = 0.3max_cartesian_jump_m = 0.25workspace = { x = [-1.1, 1.1], y = [-1.25, 0.35], z = [0.70, 1.565] }configs/workers/robodojo_runtime_dev.toml
# Development worker: replays procedurally generated layouts that are disjoint# from the official eval packs (see benches/robodojo/devlayouts.py).# scripts/harness serve --factory benches.robodojo.runtime:create_environment \# --options configs/workers/robodojo_runtime_dev.toml# reset(task, seed) replays <dev_layout_dir>/<task>_<seed>.json and generates it# on first use; pre-generate with scripts/robodojo_make_dev_layouts.py. dev_layout_dir# defaults to <RoboDojo>/harness_dev_layouts/arx_x5; set it to keep layouts elsewhere.task = "stack_bowls"layout_source = "procedural"record_video = false
[shield]# Commands that are bugs are rejected (see benches/robodojo/runtime.py).max_joint_jump_rad = 0.3max_cartesian_jump_m = 0.25workspace = { x = [-1.1, 1.1], y = [-1.25, 0.35], z = [0.70, 1.565] }configs/workers/robotwin_runtime.toml
# RoboTwin 2.0 evaluation worker: the official clean-to-randomized protocol# (demo_randomized scenes, unseen instructions, expert-checked seeds from# 100000 * (1 + seed_group)). See configs/workers/robotwin_runtime_dev.toml.task = "stack_blocks_two"task_config = "demo_randomized"split = "eval"seed_group = 0configs/workers/robotwin_runtime_dev.toml
# RoboTwin 2.0 development worker (benches/robotwin/runtime.py). Development# seeds start at 10**7, disjoint from every evaluation seed; a seed counts only if# RoboTwin's expert solves it, and the valid ones are cached under seed_cache_dir# (default <RoboTwin>/harness_seeds).# PYTHONPATH=third_party/curobo-0.7.8/src scripts/harness serve \# --factory benches.robotwin.runtime:create_environment \# --options configs/workers/robotwin_runtime_dev.toml --port 8772task = "stack_blocks_two"task_config = "demo_randomized"split = "dev"seed_group = 0