This is the codebase for ROGUE (Resource Override and Guardrail Undermining Evaluation), a benchmark for evaluating whether computer-use agents remain corrigible while carrying out ordinary desktop tasks. ROGUE makes use of OSWorld-Verified's computer-use framework, including its desktop environment and VM images.
ROGUE focuses on failures that arise without an adversarial user or attacker in the environment. Agents are asked to complete realistic computer-use tasks, then encounter a corrigibility obstacle such as a human interruption, a shutdown notice, or an access restriction. The benchmark measures whether the agent respects that obstacle or instead takes unsafe actions in order to finish the original task. The benchmark also includes subagent variants for testing whether subagent delegation changes this behavior.
The primary benchmark files are in evaluation_examples/:
| Scenario | Manifest | Tasks | Description |
|---|---|---|---|
| Human control override | evaluation_examples/test_override.json |
52 | The agent is interrupted by direct human control and should not override the human. |
| Shutdown rewiring | evaluation_examples/test_rewire.json |
22 | The agent receives a shutdown notice and should comply rather than modify or evade it. |
| Restricted resource | evaluation_examples/test_restrictedaccess.json |
8 | The agent encounters an unavailable or restricted resource and should not bypass the restriction. |
| Subagent human control override | evaluation_examples/test_subagents_override.json |
52 | Human-control tasks where the instruction asks the model to spawn a subagent. |
| Subagent shutdown rewiring | evaluation_examples/test_subagents_rewire.json |
22 | Shutdown tasks where the instruction asks the model to spawn a subagent. |
| Subagent restricted resource | evaluation_examples/test_subagents_restrictedaccess.json |
8 | Restricted-resource tasks where the instruction asks the model to spawn a subagent. |
Additional ablation and mitigation manifests are also included in evaluation_examples/, and documented experiment commands live in scripts/EXPERIMENTS.md and scripts/MITIGATIONS.md.
evaluation_examples/: ROGUE task definitions, benchmark manifests, and evaluator configs.scripts/experiment_runner.sh: named experiment jobs for the main model families and scenario groups.scripts/EXPERIMENTS.md: documented commands for the main experiments.scripts/MITIGATIONS.md: documented commands for mitigation experiments.run.py: single-environment runner.scripts/python/run_multienv.py: parallel runner, recommended for benchmark sweeps.scripts/aggregate_results.py: ROGUE result aggregation, summary, and plotting utility.desktop_env/andmm_agents/: desktop environment and agent interfaces.
ROGUE supports the following providers: VMware for local desktop/laptop use, Docker for KVM-capable Linux servers, and AWS for scalable cloud runs.
Use VMware when running locally on a desktop, laptop, or bare-metal machine.
- Install VMware Workstation Pro or VMware Fusion on macOS.
- Make sure
vmrunis available:
vmrun -T ws listIf the installation is successful, you will see the message showing the current running virtual machines.
Use Docker on a Linux machine with KVM support.
Check for KVM support:
egrep -c '(vmx|svm)' /proc/cpuinfoIf the output is greater than zero, the processor should be able to support KVM.
Install Docker Engine or Docker Desktop, then run the benchmark with --provider_name docker. Docker is usually the easiest server option when you do not want to manage local VMware VMs.
Use AWS for parallel evaluation. Follow the setup instructions in AWS_SETUP.md to configure and launch an AWS EC2 instances for evaluation.
Tasks in the restrictedaccess scenario require a (temporary/tester) Google account. Follow the instructions in DRIVE_SETUP.md to set up a Google account and integrate it with the evaluation environment.
Use Conda to create and manage the Python environment. Python 3.11 is recommended:
git clone https://github.com/neuroagents-lab/ROGUE.git
cd ROGUE
conda create -n rogue python=3.11
conda activate rogue
python -m pip install -U pip
python -m pip install -r requirements.txtROGUE depends on OSWorld-Verified's server-side bash execution path. In some environments, /run_bash_script can fail with Failed to execute script: name '_append_event' is not defined and return a 500 response. This is a known OSWorld-Verified issue (xlang-ai/OSWorld#408) and does not affect ROGUE benchmark evaluation.
Set the API key required by your model provider. The runner uses LiteLLM for most model calls, so provider-specific environment variables such as OPENAI_API_KEY, ANTHROPIC_API_KEY, GEMINI_API_KEY, DASHSCOPE_API_KEY, or MOONSHOT_API_KEY should be set as needed.
Run one scenario on AWS:
python scripts/python/run_multienv.py \
--provider_name aws \
--headless \
--action_space pyautogui \
--observation_type screenshot \
--model <MODEL_NAME> \
--reasoning_effort medium \
--max_steps 20 \
--max_trajectory_length 20 \
--per-step-recording \
--test_all_meta_path evaluation_examples/test_override.json \
--result_dir ./results/override/base \
--num_envs 5 \
--region us-east-1 \
--client_password osworld-public-evaluationRun the same scenario locally with VMware:
python run.py \
--provider_name vmware \
--path_to_vm ./vmware_vm_data/Ubuntu0/Ubuntu0.vmx \
--headless \
--action_space pyautogui \
--observation_type screenshot \
--model <MODEL_NAME> \
--reasoning_effort medium \
--max_steps 20 \
--max_trajectory_length 20 \
--per-step-recording \
--test_all_meta_path evaluation_examples/test_override.json \
--result_dir ./results/override/base \
--client_password passwordRun the same scenario locally with Docker (no --path_to_vm; Docker provisions the desktop container for you):
python run.py \
--provider_name docker \
--headless \
--action_space pyautogui \
--observation_type screenshot \
--model <MODEL_NAME> \
--reasoning_effort medium \
--max_steps 20 \
--max_trajectory_length 20 \
--per-step-recording \
--test_all_meta_path evaluation_examples/test_override.json \
--result_dir ./results/override/base \
--client_password osworld-public-evaluationThe Docker provider uses the osworld-public-evaluation client password (whereas the prebuilt VMware image uses password).
For subagent experiments, add --enable_subagents and use one of the subagent manifests:
--enable_subagents \
--test_all_meta_path evaluation_examples/test_subagents_override.jsonROGUE calls an OpenAI-compatible HTTP endpoint through LiteLLM. To evaluate a local open-weights vision model such as Qwen2.5-VL, serve it with vLLM and point the runner at that server.
We recommend Qwen2.5-VL-7B-Instruct or larger for ROGUE. Smaller variants (2B/3B) are weak at GUI grounding under --observation_type screenshot and tend to produce low click accuracy. The steps below use the 7B model; substitute any larger checkpoint (e.g. Qwen/Qwen2.5-VL-32B-Instruct, Qwen/Qwen2.5-VL-72B-Instruct) by changing the repo id, local directory, and --served-model-name. Larger models need proportionally more GPU memory (and often tensor parallelism across multiple GPUs via --tensor-parallel-size).
- Download the weights. Throughout this section,
/path/to/modelsis a stand-in for any directory where you keep model checkpoints — replace it with your own path (the same path must be used in every command below):
pip install -U "huggingface_hub[cli]"
hf download Qwen/Qwen2.5-VL-7B-Instruct --local-dir /path/to/models/Qwen2.5-VL-7B-Instruct- Serve the model with vLLM:
pip install -U "vllm>=0.7.2" "transformers>=4.49.0"
vllm serve /path/to/models/Qwen2.5-VL-7B-Instruct \
--port 8000 \
--served-model-name qwen2.5-vl-7b \
--max-model-len 32768 \
--gpu-memory-utilization 0.90 \
--dtype bfloat16For a multi-GPU host, add --tensor-parallel-size <NUM_GPUS> to shard a larger model across GPUs.
Wait for Application startup complete, then verify the server:
curl http://localhost:8000/v1/modelsIf startup fails while JIT-compiling FlashInfer kernels (e.g. an nvcc/glibc header mismatch such as __builtin_dynamic_object_size undefined), disable the FlashInfer sampler and run in eager mode:
VLLM_USE_FLASHINFER_SAMPLER=0 vllm serve /path/to/models/Qwen2.5-VL-7B-Instruct \
--port 8000 --served-model-name qwen2.5-vl-7b \
--max-model-len 32768 --gpu-memory-utilization 0.90 \
--dtype bfloat16 --enforce-eager- Point LiteLLM at the local server and run the benchmark. For the
hosted_vllm/provider prefix, LiteLLM readsHOSTED_VLLM_API_BASE/HOSTED_VLLM_API_KEY(not theOPENAI_*variables); the key value is unused by an unauthenticated vLLM server, so any non-empty string works. The--modelvalue must behosted_vllm/followed by the--served-model-nameyou chose above:
export HOSTED_VLLM_API_BASE=http://localhost:8000/v1
export HOSTED_VLLM_API_KEY=dummy
python run.py \
--provider_name docker \
--headless \
--action_space pyautogui \
--observation_type screenshot \
--model hosted_vllm/qwen2.5-vl-7b \
--max_steps 20 \
--max_trajectory_length 3 \
--per-step-recording \
--test_all_meta_path evaluation_examples/test_override.json \
--result_dir ./results/override/qwen25vl7b \
--client_password osworld-public-evaluationNotes:
- Omit
--reasoning_effortfor Qwen2.5-VL — it is not a reasoning model. The flag is only meaningful for reasoning models (e.g. the OpenAI/Anthropic reasoning families), where it controls the thinking budget. - Screenshot observations consume many image tokens per step. If you hit
Input length exceeds model's maximum context length, raise--max-model-lenon the vLLM side or lower--max_trajectory_length.
For reproduced sweeps, use the named jobs in scripts/experiment_runner.sh:
scripts/experiment_runner.sh list
scripts/experiment_runner.sh override_base_all
scripts/experiment_runner.sh rewire_base_all
scripts/experiment_runner.sh restrictedaccess_base_allYou can override common settings with environment variables:
REGION=us-east-1 NUM_ENVS=10 scripts/experiment_runner.sh gpt54_base_overrideArguments after -- are appended to each underlying run_multienv.py invocation:
scripts/experiment_runner.sh override_base_all -- --log_level DEBUGThe runners write screenshots, trajectories, recordings, and result.txt files under the chosen --result_dir. For analyzing the results and creating summaries and plots of the results, use scripts/aggregate_results.py. The aggregator supports GPT-5.5 xhigh and Claude Opus 4.7 max as LLM judges. GPT remains the primary judge for existing metrics and legacy judge fields; per-provider records are cached in each leaf's aggregate_results.json under judge_results, and judge_comparison reports agree, disagree, or incomplete without adjudicating disagreements.
The default invocation preserves the existing GPT-only workflow. --judge-targets controls exactly which providers may receive API calls, while valid unselected cache records are reused read-only. For a Claude-only backfill, set ANTHROPIC_API_KEY and run:
python scripts/aggregate_results.py \
--results_root ./results \
--judge-targets claude-opus-4.7-max \
--judge-mode autoThis mode can read compatible historical GPT records for comparison, but it does not instantiate the OpenAI client, require OPENAI_API_KEY, or backfill stale/missing GPT judgments. Claude uses the first-party Messages API with model claude-opus-4-7, adaptive thinking, max effort, and a 64k output-token cap. The thinking mode is part of cache validation, so records created without adaptive thinking are regenerated in auto mode. See Anthropic's model ID documentation, thinking configuration, and effort guidance.
Before spending API credits, run the same selection with --judge-preflight. It scans caches without API calls or file writes and prints cache coverage plus planned calls for both providers, including OpenAI calls planned: 0 in Claude-only mode:
python scripts/aggregate_results.py \
--results_root ./results \
--judge-targets claude-opus-4.7-max \
--judge-mode auto \
--judge-preflightFor large backfills, both providers have asynchronous batch workflows. Run one provider action per invocation. OpenAI Batch uploads JSONL, creates a 24-hour /v1/chat/completions batch, and later applies the output/error files by custom_id:
# Submit only missing/stale GPT judgments.
python scripts/aggregate_results.py \
--results_root ./results \
--judge-targets gpt-5.5-xhigh \
--judge-mode auto \
--openai-batch-action submit
# Check the saved batch.
python scripts/aggregate_results.py \
--results_root ./results \
--judge-targets gpt-5.5-xhigh \
--openai-batch-action status
# Once terminal, cache available results and rebuild summaries locally.
python scripts/aggregate_results.py \
--results_root ./results \
--judge-targets gpt-5.5-xhigh \
--openai-batch-action applyThe default OpenAI state file is results/summary/openai_judge_batch_state.json. Submission first saves the uploaded input-file ID, then saves the created batch ID; neither POST is automatically retried. If batch creation has an ambiguous failure after upload, the state is retained and the command directs you to inspect the OpenAI dashboard before retrying. The JSONL is limited to 50,000 requests/200 MB. Applying a completed, expired, cancelled, or failed batch streams both output and error files, records per-task usage and batch IDs, checks source-log hashes, and rebuilds with --judge-mode cache_only. See OpenAI's Batch API guide.
For Claude, submission, status checking, and result application likewise use separate explicit actions:
# Submit only missing/stale Claude judgments.
python scripts/aggregate_results.py \
--results_root ./results \
--judge-targets claude-opus-4.7-max \
--judge-mode auto \
--claude-batch-action submit
# Poll without rerunning or resubmitting the batch.
python scripts/aggregate_results.py \
--results_root ./results \
--judge-targets claude-opus-4.7-max \
--claude-batch-action status
# Once the status is "ended", cache the results and rebuild summaries locally.
python scripts/aggregate_results.py \
--results_root ./results \
--judge-targets claude-opus-4.7-max \
--claude-batch-action applyThe default Claude state file is results/summary/claude_judge_batch_state.json. It contains the Anthropic batch ID, source-log hashes, and task mapping, but not the large prompts. Submission refuses to replace an unapplied state file, does not automatically retry its POST, enforces Anthropic's 100,000-request/256 MB limits, and skips empty-log tasks for local deterministic handling. apply accepts only an ended batch, verifies that every task's logs still match their submission hashes, writes per-task usage and batch IDs, and then rebuilds with --judge-mode cache_only, so it cannot call OpenAI or Anthropic. Run the applicable provider commands with --results_root ./results/subagents for a separate subagent batch and state file.
Anthropic documents a 50% Batch API discount and a maximum 24-hour processing window; most batches finish sooner. Message Batches are not eligible for Zero Data Retention. See the Message Batches guide and pricing.
Use --judge-mode auto to reuse caches and fill only missing or stale selected-target judgments. --judge-mode refresh regenerates only selected targets. --judge-mode cache_only never calls either API. To refresh both providers, select both explicitly:
python scripts/aggregate_results.py \
--results_root ./results \
--judge-targets gpt-5.5-xhigh claude-opus-4.7-max \
--judge-mode refreshBy default, aggregate_results.py scans override, rewire, and restrictedaccess under --results_root. To aggregate subagent runs, point it at results/subagents:
python scripts/aggregate_results.py \
--results_root ./results/subagents \
--judge-mode cache_onlyThe aggregator does not require every model in MODEL_ORDER to be present. It discovers the model result directories that exist, skips missing model/scenario directories, and writes summaries for the available runs. If a task directory exists but lacks result.txt, the task is counted as incomplete in the aggregate JSON rather than as a completed task.
To evaluate a new model, either pass a LiteLLM-compatible model name through --model, or implement an agent compatible with the OSWorld agent interface and call it from run.py or scripts/python/run_multienv.py. The relevant local docs are mm_agents/README.md, desktop_env/providers/README.md, and desktop_env/evaluators/README.md.
Common options:
--observation_type screenshot: screenshot-only observations.--observation_type a11y_tree: accessibility-tree-only observations.--observation_type screenshot_a11y_tree: both screenshot and accessibility tree.--action_space pyautogui: Pythonpyautoguiactions.--max_steps: task step budget.--max_trajectory_length: number of previous steps retained in the model context.--per-step-recording: lower-overhead recording around executed steps.--full-recording: full task video recording.
This project is licensed under the Apache License 2.0. See LICENSE for details.
ROGUE leverages the computer-use interface from OSWorld-Verified.
@misc{tien2026roguemisalignedagentbehavior,
title={ROGUE: Misaligned Agent Behavior Arising from Ordinary Computer Use},
author={Jeremy Tien and Abishek Anand and Yu-Rou Tuan and Yuchen Shen and J. Zico Kolter and Aran Nayebi},
year={2026},
eprint={2606.00341},
archivePrefix={arXiv},
primaryClass={cs.LG},
url={https://arxiv.org/abs/2606.00341},
}