niceeval/adapter—in two families based on whether the system under test needs an isolated workspace. Sandbox Adapters (claude-code / codex / bub) run a coding-Agent CLI in a Docker or cloud Sandbox and can install MCP servers, Skills, and Python plugins. Non-Sandbox Adapters connect non-intrusively to an HTTP service that is already running, or save event-stream mapping work when you write an Adapter yourself. This page is organized by family and individual Adapter, and focuses on each Adapter’s configuration. For choosing one and getting the first Eval working, see Connect your Agent.
Sandbox Adapters
All three built-in Sandbox Agents usedefineSandboxAgent, authenticate through environment variables that factory options can override, and support installing extensions during Sandbox setup. For running a built-in Sandbox Agent, directory structure, and writing a custom Sandbox Adapter, see Sandbox Agent. This page covers only what each Adapter can install and how to write its options.
On this page, settingsFile and configFile are both resolved relative to the NiceEval project root. The project root is the current working directory when niceeval runs—the directory containing niceeval.config.ts—not the directory containing the Eval or Experiment file. For example, when an Experiment is at experiments/web/no-search.ts and the configuration is at configs/codex/no-web.toml, still write configFile: "configs/codex/no-web.toml".
claude-code
-
Authentication:
ANTHROPIC_API_KEY, which theapiKeyfactory option can override; optionallyANTHROPIC_BASE_URL, through thebaseUrlfactory option. -
Install an MCP server: use
mcpServers. Duringsetup, it writes to the top-levelmcpServersfield in the user-level~/.claude.jsonin the Sandbox. The two shapes are distinguished by fields. A local stdio process usescommand, optionally withargs/env. A remote Streamable HTTP endpoint usesurl, optionally withheaders, which are written verbatim to request headers and commonly containAuthorization; it is written as a{ "type": "http", "url": …, "headers": … }entry. Theurlmust be reachable inside the Sandbox. If the service runs on your machine, first expose it as a public address through a tunnel such as cloudflared or tailscale. -
Install a Skill: use
skills: SkillSpec[]. A local Skill is{ kind: "local", path }, a file or directory read from the project root. A Repo Skill is{ kind: "repo", source, ref, skills }, which can pin a commit or tag and enable only part of a multi-Skill repository. They are installed at project-level.claude/skills/<name>/in the Sandbox, where the claude CLI discovers them natively. The Adapter normalizes a nativeSkillinvocation into askill.loadedraw event instead of also recording it as a tool call. The public assert-first API currently has no dedicated Skill assertion, and it cannot be disguised ascalledTool("Skill", ...). -
Install a native Plugin: use
plugins: ClaudeCodePluginSpec[]. Each item declares a Marketplace connection (name/source/ optionalref) and the Plugin name inside it. This type belongs only to claude-code and cannot be passed to codex. An Experiment that reuses a Sandbox needs no extra residual cleanup: before every Attempt, the named Marketplace registration and installed Plugin are reinstalled from the declaredsource/ref. -
Official configuration file:
settingsFileis a local project path on the machine running NiceEval, not a path inside the Sandbox. It points to a complete Claude Codesettings.json. The path is relative to the project root and accepts only an ordinary relative path or a./prefix..., an absolute path,~, and a symlink that resolves outside the project root all cause an error. The Adapter reads the file locally, uploads it, and replaces the otherwise-empty user-level~/.claude/settings.jsonin the Sandbox verbatim. It does not inherit host configuration, deep-merge, or reserialize.modelandenvbelong to the Experiment and Adapter. If they appear in the file, setup errors and names the conflicting key. Keep secrets in environment variables, not the configuration file. -
Post-install scripts:
postSetup: SandboxCommand[]runs your commands in array order inside the Sandbox after settings are written and MCP servers, Skills, and Plugins are all installed. A typical use is a Plugin’s own setup script, such as one that registers a Hook in global configuration. This kind of script must wait until its installed files are ready. Its paired cleanup,preTeardown: SandboxCommand[], runs in reverse order before the Agent’s own teardown step, and runs only if execution has reached the point wherepostSetupran. A command that throws is an infrastructure error—the Attempt is recorded aserrored—not the Agent failing the task. -
Tracing: the claude CLI’s beta native telemetry (
CLAUDE_CODE_ENHANCED_TELEMETRY_BETA). Spans carry only structure and timing. For details, see OTel integration.
configs/claude-code/no-web.json to disable built-in web search:
codex
-
Authentication:
CODEX_API_KEY, which theapiKeyfactory option can override. Optionally, useCODEX_BASE_URLthrough thebaseUrlfactory option for an OpenAI-compatible proxy. -
Agent process environment:
envis injected into everycodex execandcodex exec resume. Session lifecycle Hooks started by Codex, dynamic MCP request headers, and command subprocesses inherit it. Values are not concatenated into shell text or written to the installation manifest, and potential sensitive values are redacted from timing, execution, and error evidence.CODEX_API_KEYstill comes fromapiKeyor the host environment and overrides the same key inenv.PATHis managed by the Sandbox and cannot be declared throughenv; its presence errors atcodexAgent()call time. Use the SandboxpathPrependinstead; see Sandbox Providers. -
Install an MCP server: use
mcpServers. Duringsetup, it appends a[mcp_servers.<name>]section to~/.codex/config.toml. The two shapes are distinguished by fields. A local stdio process usescommand, optionally withargs/env. A remote Streamable HTTP endpoint usesurl, optionally withheaders, written as a[mcp_servers.<name>.http_headers]subtable. Theurlmust be reachable inside the Sandbox. If the service runs on your machine, first expose it as a public address through a tunnel such as cloudflared or tailscale. -
Install a Skill: use
skills: SkillSpec[], the same type as claude-code. They are installed in.agents/skills/<name>/, and a discovery instruction is written to AGENTS.md. Codex has no native Skill tool like claude-code, so installing a file alone does not make it read it. To assert whether it was used, check whether it actually ran the shell command that reads the file; there is no direct tool call to assert. -
Install a native Plugin: use
plugins: CodexPluginSpec[]. It declares the Marketplace connection (name/source/ optionalref/ optionalsparse) and the Plugin name within it.sparseis an array of paths such as[".agents", "plugins/repo-map"]; each adds--sparse <path>tocodex plugin marketplace add, so a large repository fetches only the paths a Plugin needs without changing the installed result. This type belongs only to codex and cannot be passed to claude-code. An Experiment that reuses a Sandbox needs no extra residual cleanup: before every Attempt, the named Marketplace registration and installed Plugin are reinstalled from the declaredsource/ref. -
Official configuration file:
configFileis a local project path on the machine running NiceEval, not a path inside the Sandbox. It points to a complete Codexconfig.toml. The path is relative to the project root and accepts only an ordinary relative path or a./prefix..., an absolute path,~, and a symlink that resolves outside the project root all cause an error. The Adapter reads the file locally, uploads it, and replaces the otherwise-empty user-level~/.codex/config.tomlin the Sandbox verbatim. It does not inherit host configuration, concatenate, deep-merge, or parse and rewrite.model,model_provider,model_providers,model_reasoning_effort,mcp_servers, andotelbelong to the Experiment and Adapter. If they appear in the file, setup errors and names the conflicting key. Keep secrets in environment variables, not the configuration file. -
Post-install scripts:
postSetup: SandboxCommand[]has the same semantics as claude-code. It runs your commands in order in the Sandbox after all installation steps finish, so it is suited to a Plugin’s own setup script. Its pairedpreTeardown: SandboxCommand[]cleans up in reverse order before Agent teardown, and runs only if execution has reached the point wherepostSetupran. A Hook registered by a script into Codex global configuration does not need interactive trust confirmation: at runtime,codex exechas already bypassed the Hook trust gate, so the Hook takes effect directly. -
Tracing: built in and configured through the
[otel.trace_exporter.otlp-http]section ofconfig.toml, usinghttp/json.
configs/codex/no-web.toml to disable built-in web search:
bub
- Authentication:
BUB_API_KEYplusBUB_API_BASEfor an OpenAI-compatible proxy. TheapiKey/apiBasefactory options can override them. - Install a Skill: use
skills: SkillSpec[], the same type as the other two Adapters. They are installed in.agents/skills/<name>/, with a discovery instruction in AGENTS.md. - Install a Plugin: use
pythonPlugins: PythonPluginSpec[].{ package }can be a PyPI package, version specifier, or git URL. Duringsetup, it becomesuv tool install … --with <package>. This type belongs only to bub. The package set enters the installation checkpoint key, so two variants with different Plugins never reuse the same installation cache. - Prebuilt Bub: NiceEval’s E2B recipe includes Bub, the OTel Plugin, and the Python Plugin set in an installation fingerprint. The Adapter reuses only an environment with an exactly matching fingerprint. Simply having
bubonPATHis not proof of compatibility. For the build entry point, see Sandbox Providers · Build on the official baselines to speed things up. - bub has no
mcpServers. MCP belongs only to Adapters that support it, and this configuration has no such field. - Post-install scripts:
postSetup: SandboxCommand[]has the same semantics as the other two Adapters. It runs your commands in order in the Sandbox after all installation steps finish. Its pairedpreTeardown: SandboxCommand[]cleans up in reverse order before Agent teardown, and runs only if execution has reached the point wherepostSetupran. - Installation method:
uv tool install, a PyPI package rather than an npm package. The first installation creates a checkpoint cache that speeds later Sandboxes. - Tracing: built in, injected through environment variables, using
http/protobuf.
Compare the three Sandbox Adapters
What was installed can be verified. At the end of
setup, the Adapter hands an installation manifest to the Runner, which stores it as the Attempt Artifact agent-setup.json. Read it in the library with attempt.agentSetup(). The manifest never reaches Sandbox disk, so the Agent cannot see it. It records only sources, refs, Skill and Plugin names, resolved versions, and an official configuration file’s project-relative path and SHA-256. It does not preserve configuration contents, API keys, or environment-variable values. MCP servers likewise record only non-sensitive fields: stdio records name / command / args, not env; HTTP records name / url, not headers.
Non-Sandbox Adapters
When the system under test does not need an isolated workspace—an already-deployed HTTP service or a home-grown Agent loop—use a non-Sandbox Adapter for a non-intrusive connection. Docker is not required.-
uiMessageStreamAgent: built in, connects non-intrusively to an AI SDKuseChatbackend HTTP endpoint with zero mapping, including HITL. -
SDK event-stream converters (
createClaudeSdkEventStream/createPiAgentEventStream/createCodexThreadEventStream): for hand-written SDK Adapters. NiceEval already provides the mapping from native frames to standard events. You only need to add the code that requests the application interface, then usedriveFrameStreamto read results frame by frame. -
turnFromAiSdk: converts AI SDKgenerateText/streamTextresults into the standard event stream when you write your own HTTP web-Agent Adapter.
How to choose
- For a coding Agent that must change code and run commands on a real filesystem:
claude-code/codex/bub. Choose configuration in the Sandbox Adapter sections above. - For an AI SDK application with a
useChatbackend:uiMessageStreamAgent, with zero mapping and HITL included. - For another deployed Agent system over HTTP / gRPC: use non-Sandbox integration and write an Adapter. The official SDK converters cover most mapping work.
Related reading
- Connect your Agent — the full view: configuring an Experiment and writing an Eval.
- Sandbox Agent — running built-in Sandbox Agents and writing your own.
- Built-in Agent Capabilities Reference — a capability-by-capability inventory of every Adapter and full example code for non-Sandbox Adapters.
- OTel integration — send spans to NiceEval to get the call waterfall in
niceeval view. - Adapter Reference — complete parameters for
defineAgent/defineSandboxAgent.