Integrate Existing Agents
You can use an existing agent in NeMo Gym, integrate an external one, or build your own from scratch.
To use an agent that Gym does not integrate yet, see Add an agent that is not listed.
Built-in agents
SimpleAgent is a native NeMo Gym agent that handles general-purpose multi-step tool calling with configurable max steps, and works with any Resources server out of the box. NeMo Gym also includes agents that integrate external tools: for example, MiniSWEAgent wraps an external coding harness running in Docker containers and converts its output back into the NeMo Gym format, and claude_code_agent runs the Claude Code CLI. Because every Gym model server speaks Anthropic Messages, you can point Claude Code at any backend — see Anthropic Messages.
Sandboxed harnesses
These adapters run a harness inside a sandbox. The single_agent_turn Environment Server drives them with a task sandbox when the Resources server supplies one; otherwise a configured provider creates an agent-owned sandbox. The harbor Environment Server drives them in the sandbox of a Harbor task folder. Each row summarizes the adapter’s README; the README is the reference for supported features, runtime requirements, and limits.
Declared means the benchmark’s Resources server lists the agent in allowed_agents. Gym rejects any other pairing unless you pass --allow-unsupported-pairing. Declared support is not a validation: it says nothing about accuracy or training readiness. Check that a pairing works with a real model and the benchmark’s verifier before you rely on it.
On Harbor task folders, you pick the harness with gym eval run <folder> --agent <harness>, and the allowed_agents lists above do not apply: a dataset limits harnesses with allowed_agents in the [gym] table of its dataset.toml. terminus_2_sandboxed_agent and miniswe_sandboxed_agent also run task folders. For tasks declaring a stdio MCP server or a skills_dir, use --agent mini_swe_agent/mini_swe_agent_sandboxed; the older miniswe_sandboxed_agent remains compatible but is deprecated.
Copilot pairings remain experimental pending full benchmark qualification and benchmark-owner review. Use --allow-unsupported-pairing for validation runs; the SWE-bench Pro pairing also requires task-network access to install its runtime.
The allowed_agents lists also name older adapters, such as opencode_sandboxed_agent and terminus_2_sandboxed_agent. They run the whole episode themselves behind a legacy_agent Environment Server, and shipped recipes such as terminal_bench_2_1/opencode use them. To run them or swap one for another, see Compare Harnesses.
This legacy /run path is deprecated and will be removed after the Environment Server migration. Do not build new benchmarks, agents, or configs on opencode_sandboxed_agent, pi_sandboxed_agent, hermes_sandboxed_agent, or miniswe_sandboxed_agent, or on the /run path of terminus_2_sandboxed_agent. Use a harness from the table above instead. Each of these agents logs a deprecation warning when it starts on this path. Episode sessions of terminus_2_sandboxed_agent, which task folders use, are not deprecated.
Both paths of miniswe_sandboxed_agent are superseded by mini_swe_agent agent sessions. For Harbor task folders without [agent].user, switch to --agent mini_swe_agent/mini_swe_agent_sandboxed with the same model and sandbox options. Existing configurations remain available, and no adapter removal date is set. Tasks with [agent].user must keep the older adapter because the replacement refuses a task user. Legacy /run benchmark presets, including Terminal-Bench-Science, must keep their current adapter until their environment-server migration; changing only the agent name is insufficient. Migration does not establish new benchmark qualification or guarantee identical scores.
Kilo MCP and sandbox ownership
Kilo’s session adapter accepts remote MCP grants from Resources. Set the Environment Server’s resources_tool_transports: [mcp] to expose Resources tools through MCP. Grant URLs and headers must be reachable and valid from the task sandbox. Required direct HTTP grants are still rejected; this does not make a recipe configured with [direct_http] compatible with Kilo.
The adapter configures Kilo’s remote MCP clients with each grant’s URL and headers and disables interactive OAuth. Before accepting a session with required MCP grants, it runs a supervised CLI check that connects to those servers and discovers tools without requesting a model completion. The activation’s CLI process connects again, and the bundled plugin confirms the required connections before its first model request. Kilo does not refresh connection status after that, so a server lost mid-run surfaces as failed tool calls. A failed connection or a missing readiness receipt fails the session or activation. Optional MCP connection failures do not fail this readiness check. Kilo cancels an MCP tool call after kilo_config.experimental.mcp_timeout milliseconds; kilocode_sandboxed.yaml sets 300000 (five minutes) instead of the MCP SDK’s 60-second default, so keep it above your slowest Resources tool and within timeout. Static servers in kilo_config.mcp remain available, but their names must not collide with grant names, including after Kilo replaces punctuation other than - and _ with _.
When Resources supplies sandbox_access, Kilo borrows that sandbox and leaves its destruction to Resources. When Resources supplies no sandbox, configure an agent-owned sandbox explicitly. For example, add these imports and overrides to an experiment that already defines policy_model, policy_model_name, and the Environment Server’s Resources/agent bindings:
The Docker provider needs a local Docker daemon. Configure the Gym host and network so the sandbox can reach both the Gym Model Server and the MCP endpoints; a host loopback URL is not reachable from Docker’s default bridge network. The Linux image must meet Kilo’s runtime requirements, including network access for the pinned CLI installation.
Agent-owned sandboxes inherit provider metadata defaults, then sandbox_config.metadata, with Gym’s agent/session/rollout labels taking precedence. The agent stops its sandbox on close or failed setup. If neither Resources sandbox access nor sandbox_provider is available, seed fails with a configuration error.
Pi and OpenCode prompt and tool controls
Both pi_agent and opencode_agent accept system_prompt_mode: append|replace,
defaulting to append. Replacement uses the harness’s custom system prompt for
the combined configured system prompt, request instructions and input system
instructions. It keeps the user’s task separate. Append mode retains each
adapter’s existing behavior. These controls apply to local calls and sandbox
sessions; OpenCode continuations retain their established instructions.
The harness may still add environment context, such as the date or working directory.
OpenCode replacement selects its build agent, overriding a different default
agent. Remove --agent selectors from extra_args in replacement mode; use
append mode to retain custom agent selection.
Replacement prompt text is passed literally, including {env:...} and {file:...}
sequences. Other OpenCode configuration keeps its native substitution behavior.
Pi’s enable_tools defaults to true. Setting it to false disables Pi’s
built-in tools through --no-builtin-tools; separately configured MCP tools and
session grants remain available and retain their validation. For a run with no
tools, also omit MCP configuration and grants. For OpenCode, withhold tools with
opencode_config.permission rules, for example task: deny. To withhold every
tool, also deny edit and bash through their own maps (edit: {"**": deny},
bash: {"*": deny}): opencode_agent’s permission profile allows them after its
"*" rule, and a "*": deny override keeps that rule’s place before them. Do not
use an opencode_config.tools map with opencode_agent: OpenCode places its keys
before the profile’s "*": allow, which then overrides them (see the
opencode_agent README).
Record prompt replacement and tool selection as evaluation treatments: they can change results relative to the harness’s default coding behavior.
Run an integrated agent on a benchmark
An experiment is a few composable YAML files: the model and provider, the benchmark, the agent, and the Environment Server that binds them. To change the agent or the benchmark, replace one file; the others stay as they are.
Harbor task folders need none of these files: gym eval run <folder> --agent <harness> writes the agent and Environment Server blocks to results/harbor/<taskset>/run_config_<harness>.yaml. See Run an agent.
Configure an experiment
The following evaluation example pairs SWE-bench Pro with Hermes. Before you start, install a current Gym checkout with the agent session adapters, Gym’s development environment, and the benchmark’s preparation dependencies. Save the four files below under experiments/onboarding/, and run all commands from the repository root. Entries in config_paths are relative to the root.
You also need a running vLLM-compatible model endpoint and an OpenSandbox deployment. Export the following variables in your shell:
POLICY_BASE_URL,POLICY_API_KEY, andPOLICY_MODEL_NAMEfor the model endpoint.OPENSANDBOX_DOMAINandOPENSANDBOX_API_KEYfor the sandbox provider.GYM_HOST, a bindable address of the Gym host that task sandboxes can reach. Do not use a loopback address or0.0.0.0, because sandboxes cannot call back to them.
On Linux, you can find a candidate IPv4 address by running this command on the Gym node:
Use the result only if it is a local interface address that the task sandboxes can reach. If the command returns no address, or the host has several interfaces with different routes to the sandboxes, set GYM_HOST explicitly to the right address. Hostname resolution alone does not prove connectivity.
The sandbox must reach the Gym Model Server’s allocated port, and the Gym Model Server must reach the upstream endpoint. Keep credentials out of committed YAML files.
Give the benchmark and the harness stable instance names. The outer keys, benchmark and agent, are instance names that references and the CLI use. The inner keys, such as swebench_pro and hermes_agent, select implementation directories. _inherit_from reuses the imported template and applies your overrides; it does not start an extra copy of the server.
The benchmark supplies the task sandbox. Its imported configuration sets sandbox_provider: sandbox, image selection, resources, and verification settings. The agent imports its runtime settings and the model_server: {type: responses_api_models, name: policy_model} binding. resources_server: null leaves benchmark selection to the Environment Server.
With taskset: onboarding, collation wraps each prepared row in task_id and task_input and keeps the benchmark’s task fields. environment_server_routes maps that taskset to the experiment instance, whose implementation is single_agent_turn. The collector assigns the episode identity and calls the instance’s /run endpoint. environment_routing_mode: taskset rejects flat rows submitted by mistake. For the row contract, see taskset data declarations.
Prepare the dataset and inspect the resolved configuration:
Then run one task. This command collates the declared benchmark data into materialized task rows, starts the servers, collects rollouts, and shuts the servers down:
The taskset route selects the Environment Server, and its agent_server reference selects the harness, so you do not need an --agent option. The source JSONL is not modified. The collated input for this run is written to results/onboarding/swe-pro-hermes/rollouts/preprocessed_datasets/benchmark.jsonl.
Before you increase concurrency, inspect the response, reward, failure sidecar, and cleanup evidence. When you raise --concurrency, raise max_concurrent_episodes to match and set queue_timeout_seconds above the expected episode duration; otherwise queued episodes fail admission after 60 seconds. A configuration that resolves has not yet been validated: resolution does not check task-image installation, model and tool behavior, or verification.
For callers that still submit flat rows, single_agent_turn_legacy wraps the same session lifecycle as a migration adapter. Name both resources_server and agent_server in its block. The separate legacy_agent implementation delegates to the agent’s old /run endpoint and names only agent_server. New experiments should use the taskset configuration above.
Swap the agent or the benchmark
Wait for the experiment to finish and its servers to shut down before you change the configuration. Then resolve and run it again. Use a new output directory for each variant, so that resume does not pick up another experiment’s results.
Replace Hermes with Pi. Replace the whole agent.yaml with the following file. Remove Hermes-only settings such as enabled_toolsets. The agent instance name does not change, so run.yaml, the taskset route, and the SWE-bench Pro preparation and input stay the same.
Before you run, check Pi’s runtime and request requirements: the same model and input must satisfy the new adapter’s contract. Repeat the resolve and run commands with the output path results/onboarding/swe-pro-pi/rollouts.jsonl. Pi uses its own sandbox tools, so resources_tool_transports: [] still applies.
Replace SWE-bench Pro with Terminal Bench 2.1. Replace the whole benchmark.yaml with the following file, and keep whichever agent.yaml you selected. The dataset declaration selects the new preparation script and input, and taskset: onboarding keeps the route to experiment. The prepared rows supply each task’s image (docker_image), the new Resources Server configuration supplies its resource requirements and verifier, and run.yaml still references benchmark. Repeat the prepare, resolve, and run commands with a new output directory.
The Terminal Bench 2.1 pairing with Hermes is experimental. The benchmark’s allowed_agents list includes pi_agent, but does not include hermes_agent.
Before you try a pairing, review the benchmark’s session and tool contract and the selected agent’s task-image and runtime support. To run with Hermes, add --allow-unsupported-pairing to the gym eval run command; Pi does not need it. gym eval prepare and gym env resolve neither check the pairing nor accept the flag, and gym eval run checks it only when it dispatches rollouts, after the servers start. The flag waives every allowed_agents and allowed_model_types check in the run, not only this one. Validate a representative rollout with a real model and verifier before you claim support. Do not remove the benchmark’s guard, and do not add the agent to the benchmark’s allowed_agents only because its configuration resolves.
To swap a component, change the imported configuration and its matching implementation block together. Keep task data and preparation in the benchmark declaration, and keep harness selection in the Environment Server’s agent_server reference. The --agent-type shortcut for legacy agent-to-Resources bindings does not replace these edits. To compare agents on the same endpoint, keep the model and provider file unchanged. To compare models or providers, change that file in a separate experiment.
For where the harness runs and who cleans up, including borrowed and agent-owned sandboxes and host execution, see Select an execution mode.
Run Codex on Terminal-Bench-Science
Terminal-Bench-Science v0.1 ships a ready-made Codex profile, terminal_bench_science/codex, so you do not write the four files above. Unlike the Terminal Bench 2.1 adapters, its Resources Server is terminal_bench_4: it provisions each pinned task, lends the task sandbox to codex_agent, and grades in a separate offline verifier sandbox. The profile composes single_agent_turn_legacy, so it reads flat rows rather than a taskset. Like the other session paths, it is for evaluation only.
Before you run it:
- Build the task images. Upstream publishes none. Build each task’s agent and verifier image, push them to a registry that your sandbox deployment can pull from, and pass them as a
tbsci_task_imagesmap or astbsci_agent_imageandtbsci_verifier_imagetemplates. See Images. - Prepare the rows. Each row carries the task’s official instruction, read from the pinned package after its hashes are checked. The check needs
pathspec, which Gym’s own environment leaves out, sogym eval prepare --benchmark terminal_bench_science/codexruns it in the Resources Server’s environment and sets that environment up first if needed, as the README shows. - Bind Gym to a reachable address. Codex calls Gym’s model server from inside the task sandbox, so pass
++default_hostwith an address that the sandboxes can reach, as withGYM_HOSTabove.
codex_deepseek_flash.yaml is the run configuration for the leaderboard’s DeepSeek V4.1 Flash row, served by your own chat-completions server. Pass your images in a second --config file, here tbsci-images.yaml, that sets tbsci_task_images:
The profile runs one trial per task. The leaderboard’s protocol is three trials per task, 210 in all: add ++num_repeats=3. For the Codex defaults and the model server settings, see Codex with DeepSeek V4.1 Flash.
Resuming harness sessions
OpenCode can resume its saved session across multiple activations in either
an owned or borrowed sandbox. Opt in during /v1/agent_sessions seed with
continuation: {mode: resume_harness_session}. Existing adapters reject continuation
requirements they cannot satisfy before preparing the sandbox.
Use the existing /v1/responses request body and session cookie. Send
x-ng-agent-activation: 1 for the first input delta, 2 for the next, and so on.
Identical requests at the same index replay the original response. Conflicting
retries, skipped indices, and overlapping new activations fail. The existing
metadata.agent_timeout_sec sets the per-activation budget, including preparation,
queueing and staging. Setup and cleanup retain their separate bounds.
Adapters that support continuation override _agent_continuation_capabilities() to return
the supported mode and observations, implement _validate_agent_activation() before
binding an index, _activate_agent_session_state() for execution, and
_continuation_close_timeout() for their cleanup bound. The ordinary responses()
handler delegates to activate_agent_session() only for opted-in sessions; its
existing HTTP signature remains unchanged. The shared ledger protects active work
from a disconnected waiter and fences it during close. These guarantees are
process-local, separate from checkpoint recovery.
SandboxSession still launches once by default. An adapter that supports continuation may call
begin_activation() with a fresh supervisor directory after the previous process
has confirmed cleanup. Saved harness session storage remains outside these launch
directories. Finalization stays private to the lifecycle; close removes the retained
session directory tree before releasing the connection.
Emit one invocation per activation, recording harness_session_id as context, and tag
each trajectory turn with its activation. OpenCode’s header plugin uses that
activation-scoped invocation identity to attribute captured model calls. Responses
carry only new output, usage and evidence; close supplies the cumulative record.
cleanup_confirmed is omitted when an adapter does not report it. A final negative
termination receipt fails the activation and skips verification; close releases
the borrowed connection and returns cleanup_confirmed: false. Failures to release
the connection remain retryable.
NOOA worker checkpoints
The NOOA sandbox worker
publishes checkpoint.json as partial evidence at model-response and completed-tool boundaries.
It projects and deeply copies the evidence on the rollout event loop, then uses a single background
writer for JSON serialization, file writes, fsync, and atomic replacement. Projection and copying
still run synchronously and grow with transcript length, including JSON conversion within trajectory
projection. The writer never reads the live trace.
Only one snapshot is being written and one latest snapshot can be pending. New boundaries replace
the pending snapshot; writes remain ordered. Normal completion flushes the pending evidence before
publishing result.json. Cancellation waits for writes to finish before shutdown returns. An abrupt
kill may lose the pending or in-progress update, but leaves the previous published checkpoint valid.
Checkpoint failures are logged and do not fail an otherwise successful run.
Checkpoints carry partial: true and an incomplete response; they do not establish completion or
authorize grading. A valid final result takes precedence. Missing or malformed final evidence with
unsuccessful worker termination is an infrastructure failure. Callers must enforce a process deadline,
including enough shutdown grace for pending writes; the worker has no independent deadline. Artifacts
use mode 0600 and require the worker UID or privileged access for collection.
Tools in Agent vs. Resources Server
Existing agents may come with predefined tools, allowing you to leverage them directly and use the Resources server to supplement with any additional external tools. When building a new environment, prefer defining tools in the Resources server rather than the Agent server. This separation of concerns allows different agents to share the same Resources server without duplicating tool logic.
Add an agent that is not listed
- To score an agent you already run, without rewriting it, drive it through a Remote Agent.
- To get Gym’s models, tools, sandboxes, and observability, write an adapter with Add or Update a Harness. It also describes the session contract that an adapter implements.
See Choose a Path to compare the options.