Summary
skillevaluator tier3 evaluate --env-mode local cannot run any trial. Every agent fails at agent-runtime-preflight with exit 126 and:
Local mode command blocked: environment variable BASH_ENV can execute or alter code before confinement and is not allowed
BASH_ENV is not set in the host environment. SkillEvaluator injects it itself, then rejects it.
Versions
- skillevaluator 0.2.1 (
uv tool install --python 3.13 "skillevaluator[all] @ git+https://github.com/NVIDIA/SkillEvaluator.git", commit ff349e0)
- harbor 0.13.2, skillspector 2.11.2
- macOS (Darwin 25.6.0), arm64, Python 3.13
- agents installed and authenticated:
codex 0.153.4, claude (Claude Code) 2.1.226
Reproduce
skillevaluator create-eval-dataset ./my-skill --full
skillevaluator tier3 evaluate ./my-skill --agents codex --env-mode local --n-attempts 1
Result:
[00:00:03] agent-runtime-preflight: failed - codex runtime preflight failed: Harbor agent-only job
did not complete successfully: 1 errored; first trial: <case>: NonZeroAgentExitCodeError |
Command failed (exit 126): codex --version stdout: None stderr: Local mode command blocked:
environment variable BASH_ENV can execute or alter code before confinement and is not allowed
It fails on codex --version, so nothing agent-specific is involved.
Root cause
tier3/harbor/adapter.py:
_EVALUATOR_MANAGED_RUNTIME_ENV = {
**dict.fromkeys(_RUNTIME_LOADER_ENV_NAMES, ""),
"CLAUDE_CODE_DISABLE_POLICY_SKILLS": "1",
}
_RUNTIME_LOADER_ENV_NAMES contains BASH_ENV, CLASSPATH, LD_PRELOAD, PYTHONPATH and about twenty others. That dict is merged into runtime_env (adapter.py lines 1872 and 4378).
Setting those names to "" is right for the Docker path, where ENV BASH_ENV="" neutralises the variable inside the image. In local mode the same dict reaches LocalEnvironment._exec_env, which calls:
tier3/harbor/local_environment.py
@staticmethod
def _filter_command_env(env: dict[str, str], *, protected: set[str]) -> dict[str, str]:
for key, value in env.items():
normalized = key.upper()
if normalized in _BLOCKED_COMMAND_ENV_NAMES or normalized.startswith(_BLOCKED_COMMAND_ENV_PREFIXES):
raise ValueError(
f"environment variable {key} can execute or alter code before confinement and is not allowed"
)
The check rejects on key presence, regardless of value, and _BLOCKED_COMMAND_ENV_NAMES overlaps _RUNTIME_LOADER_ENV_NAMES (BASH_ENV, CLASSPATH, ENV, GCONV_PATH, LOCPATH, NLSPATH, and more). So the hardening the evaluator applies to itself is what its own guard refuses.
Evidence the host is not the source
$ env | grep -cE '^(BASH_ENV|BASHOPTS)='
0
$ bash -c 'echo "${BASH_ENV-UNSET}"'
UNSET
$ python3 -c "import os; print('BASH_ENV' in os.environ)"
False
The retained Harbor job config also shows every env block empty (/agent/env, /environment/env, /verifier/env all {}), so it is not arriving from the task definition either.
Not a workaround
SKILLEVALUATOR_LOCAL_SANDBOX=off does not help. The command-env filter runs regardless of the sandbox backend, and the failure and message are identical.
Suggested fix
Either:
- Treat an empty value as absent in
_filter_command_env (if normalized in _BLOCKED_... and value != ""), since an empty BASH_ENV cannot execute anything; or
- Do not pass the Docker-shaped loader-reset keys into the local path, and let the local sandbox apply its own reset.
Option 1 keeps the guard meaningful for a genuinely populated variable inherited from a host.
Impact
--env-mode local is documented as the way to run Tier 3 without a container, and it is the only Tier 3 path for a user whose agent CLIs are authenticated by subscription rather than by an API key. As shipped it produces no trials at all.
Happy to test a patch.
Summary
skillevaluator tier3 evaluate --env-mode localcannot run any trial. Every agent fails atagent-runtime-preflightwith exit 126 and:BASH_ENVis not set in the host environment. SkillEvaluator injects it itself, then rejects it.Versions
uv tool install --python 3.13 "skillevaluator[all] @ git+https://github.com/NVIDIA/SkillEvaluator.git", commit ff349e0)codex0.153.4,claude(Claude Code) 2.1.226Reproduce
skillevaluator create-eval-dataset ./my-skill --full skillevaluator tier3 evaluate ./my-skill --agents codex --env-mode local --n-attempts 1Result:
It fails on
codex --version, so nothing agent-specific is involved.Root cause
tier3/harbor/adapter.py:_RUNTIME_LOADER_ENV_NAMEScontainsBASH_ENV,CLASSPATH,LD_PRELOAD,PYTHONPATHand about twenty others. That dict is merged intoruntime_env(adapter.py lines 1872 and 4378).Setting those names to
""is right for the Docker path, whereENV BASH_ENV=""neutralises the variable inside the image. In local mode the same dict reachesLocalEnvironment._exec_env, which calls:tier3/harbor/local_environment.pyThe check rejects on key presence, regardless of value, and
_BLOCKED_COMMAND_ENV_NAMESoverlaps_RUNTIME_LOADER_ENV_NAMES(BASH_ENV,CLASSPATH,ENV,GCONV_PATH,LOCPATH,NLSPATH, and more). So the hardening the evaluator applies to itself is what its own guard refuses.Evidence the host is not the source
The retained Harbor job config also shows every
envblock empty (/agent/env,/environment/env,/verifier/envall{}), so it is not arriving from the task definition either.Not a workaround
SKILLEVALUATOR_LOCAL_SANDBOX=offdoes not help. The command-env filter runs regardless of the sandbox backend, and the failure and message are identical.Suggested fix
Either:
_filter_command_env(if normalized in _BLOCKED_... and value != ""), since an emptyBASH_ENVcannot execute anything; orOption 1 keeps the guard meaningful for a genuinely populated variable inherited from a host.
Impact
--env-mode localis documented as the way to run Tier 3 without a container, and it is the only Tier 3 path for a user whose agent CLIs are authenticated by subscription rather than by an API key. As shipped it produces no trials at all.Happy to test a patch.