Bug Description
SkillOpt v0.2.0 with codex_exec backend as both optimizer and target produces 0 model calls (calls=0, wall=0s) and skips all rollouts, resulting in all-zero scores. When rollouts DO execute (earlier runs), Codex's internal bwrap sandbox blocks file reads even with --sandbox danger-full-access.
Environment
- SkillOpt: 0.2.0 (pip install from
main branch)
- Codex CLI: 0.144.6
- Python: 3.13.5
- OS: Linux 6.8.0-136-generic (Docker container, VPS)
- Kernel:
kernel.unprivileged_userns_clone = 1
Config
env: githubcodereview # custom benchmark
optimizer_backend: codex_exec
target_backend: codex_exec
optimizer_model: gpt-5.5
target_model: gpt-5.5
sandbox: danger-full-access
codex_exec_full_auto: false
num_epochs: 2
batch_size: 2
sel_env_num: 3
test_env_num: 5
eval_test: true
Environment vars also set explicitly:
export CODEX_CLI_BIN=/opt/data/bin/codex
export CODEX_SANDBOX_MODE=danger-full-access
export CODEX_EXEC_FULL_AUTO=false
export CODEX_EXEC_SANDBOX=danger-full-access
Issue 1: Rollouts skipped entirely (calls=0, wall=0s)
Output from skillopt-train:
[gate] metric=hard
[slow update] acceptance=force-accept (unconditional)
============================================================
BASELINE — evaluate initial skill on Selection set (valid_seen)
============================================================
Selection items: 2
[rollout] 1/2 id=cr_009 hard=0
[rollout] 2/2 id=cr_003 hard=0
[baseline result] selection hard=0.0000 soft=0.0000 gate[hard]=0.0000
[skip] all 1 steps complete — jumping to evaluation
[EPOCH 1/1] shuffled_seeds=[1043]
[done] best skill from step 0, score=0.0000
Final summary shows 0 model calls:
Final Summary
steps=1 accept=0 reject=1 skip=0
best_score=0.0000 (step 0) wall=0s
TEST scores:
[1] init/baseline (S_0) : test_hard=0.0000
[2] best-on-val (step 0) : test_hard=0.0000 test_soft=0.0000
[3] final/last skill : test_hard=0.0000 test_soft=0.0000
total tokens: 0 (prompt=0 completion=0 calls=0)
The [skip] all 1 steps complete — jumping to evaluation message suggests the train loop thinks all steps are already done and skips the actual rollout/optimization phase.
Issue 2: bwrap sandbox blocks Codex file reads
In runs where rollouts DO execute (before the skip issue manifests), Codex returns sandbox-blocker messages instead of actual code reviews:
Sample assistant response (from conversation.json):
<answer>
I'm blocked by the execution environment before I can read `skillopt-target` or `task.md`.
The required shell command failed immediately with:
bwrap: No permissions to create a new namespace, likely because the kernel does not allow non-privileged user namespaces.
Because approval is set to `never`, I can't rerun outside the sandbox or change permissions.
</answer>
Key observation: Codex CLI works fine when called directly
codex exec --sandbox danger-full-access --skip-git-repo-check \
--cd /workspace --model gpt-5.5 \
--output-last-message /tmp/out.txt \
"Read task.md and review the diff"
→ Works perfectly (reads files, returns review, 13k tokens used, 8s).
But when SkillOpt's codex_harness.py calls Codex via subprocess (with --full-auto or approval_policy=never), bwrap blocks file access.
CODEX_EXEC_FULL_AUTO=false does not help
Setting CODEX_EXEC_FULL_AUTO=false (env var) is correctly read by backend_config.py (verified via get_codex_exec_config() → full_auto: false), but the bwrap error persists. The harness in codex_harness.py:_run_codex_cli_exec checks config.get("full_auto", True) — but even with full_auto=False, the --sandbox danger-full-access flag alone doesn't prevent bwrap from being invoked by Codex internally.
Expected Behavior
- Rollouts should not be skipped — SkillOpt should call the target model for each evaluation item.
- Codex with
danger-full-access sandbox should be able to read workspace files (task.md, SKILL.md) without bwrap blocking.
Reproduction
-
Install SkillOpt from main:
uv venv .venv --python 3.13
uv pip install git+https://github.com/microsoft/SkillOpt.git@main
-
Create a custom benchmark env (or use any env with codex_exec backend).
-
Run:
export CODEX_CLI_BIN=$(which codex)
export CODEX_EXEC_FULL_AUTO=false
export CODEX_EXEC_SANDBOX=danger-full-access
skillopt-train --config configs/custom.yaml --num_epochs 1
-
Observe: calls=0, wall=0s, all scores 0.0.
Suspected Root Causes
Issue 1 (skip logic):
The [slow update] acceptance=force-accept (unconditional) combined with [skip] all 1 steps complete suggests an off-by-one or state-persistence bug in the epoch/step tracker. Possibly related to eval_test: true causing premature step completion.
Issue 2 (bwrap):
Codex CLI v0.144.6 enforces bwrap sandbox regardless of --sandbox danger-full-access when called via subprocess with --json/--ephemeral flags. SkillOpt's _run_codex_exec in codex_backend.py uses both flags. The _run_codex_cli_exec in codex_harness.py uses --full-auto by default which also triggers bwrap.
Workarounds Attempted
| Setting |
Result |
sandbox: danger-full-access (YAML) |
❌ bwrap still blocks |
CODEX_EXEC_FULL_AUTO=false (env) |
❌ bwrap still blocks |
CODEX_EXEC_SANDBOX=danger-full-access (env) |
❌ bwrap still blocks |
Direct codex exec --sandbox danger-full-access (manual) |
✅ Works |
openai_compatible backend (Gemini OpenAI endpoint) |
Not tested (API credits depleted) |
Impact
Blocks the primary documented use case from the SkillOpt README: "optimize with frontier models, deploy on cheap models" using Codex CLI as the target agent. Custom benchmark environments cannot be evaluated.
Bug Description
SkillOpt v0.2.0 with
codex_execbackend as both optimizer and target produces 0 model calls (calls=0,wall=0s) and skips all rollouts, resulting in all-zero scores. When rollouts DO execute (earlier runs), Codex's internalbwrapsandbox blocks file reads even with--sandbox danger-full-access.Environment
mainbranch)kernel.unprivileged_userns_clone = 1Config
Environment vars also set explicitly:
Issue 1: Rollouts skipped entirely (calls=0, wall=0s)
Output from
skillopt-train:Final summary shows 0 model calls:
The
[skip] all 1 steps complete — jumping to evaluationmessage suggests the train loop thinks all steps are already done and skips the actual rollout/optimization phase.Issue 2: bwrap sandbox blocks Codex file reads
In runs where rollouts DO execute (before the skip issue manifests), Codex returns sandbox-blocker messages instead of actual code reviews:
Sample assistant response (from
conversation.json):Key observation: Codex CLI works fine when called directly
→ Works perfectly (reads files, returns review, 13k tokens used, 8s).
But when SkillOpt's
codex_harness.pycalls Codex via subprocess (with--full-autoorapproval_policy=never), bwrap blocks file access.CODEX_EXEC_FULL_AUTO=falsedoes not helpSetting
CODEX_EXEC_FULL_AUTO=false(env var) is correctly read bybackend_config.py(verified viaget_codex_exec_config()→full_auto: false), but the bwrap error persists. The harness incodex_harness.py:_run_codex_cli_execchecksconfig.get("full_auto", True)— but even withfull_auto=False, the--sandbox danger-full-accessflag alone doesn't prevent bwrap from being invoked by Codex internally.Expected Behavior
danger-full-accesssandbox should be able to read workspace files (task.md,SKILL.md) without bwrap blocking.Reproduction
Install SkillOpt from
main:Create a custom benchmark env (or use any env with
codex_execbackend).Run:
Observe:
calls=0,wall=0s, all scores 0.0.Suspected Root Causes
Issue 1 (skip logic):
The
[slow update] acceptance=force-accept (unconditional)combined with[skip] all 1 steps completesuggests an off-by-one or state-persistence bug in the epoch/step tracker. Possibly related toeval_test: truecausing premature step completion.Issue 2 (bwrap):
Codex CLI v0.144.6 enforces bwrap sandbox regardless of
--sandbox danger-full-accesswhen called via subprocess with--json/--ephemeralflags. SkillOpt's_run_codex_execincodex_backend.pyuses both flags. The_run_codex_cli_execincodex_harness.pyuses--full-autoby default which also triggers bwrap.Workarounds Attempted
sandbox: danger-full-access(YAML)CODEX_EXEC_FULL_AUTO=false(env)CODEX_EXEC_SANDBOX=danger-full-access(env)codex exec --sandbox danger-full-access(manual)openai_compatiblebackend (Gemini OpenAI endpoint)Impact
Blocks the primary documented use case from the SkillOpt README: "optimize with frontier models, deploy on cheap models" using Codex CLI as the target agent. Custom benchmark environments cannot be evaluated.