Buckets:
| <meta charset="utf-8" /><meta name="hf:doc:metadata" content="{"title":"Harbor Environment","local":"harbor-environment","sections":[{"title":"Overview","local":"overview","sections":[{"title":"What you get back","local":"what-you-get-back","sections":[],"depth":3}],"depth":2},{"title":"The intercept","local":"the-intercept","sections":[],"depth":2},{"title":"Prerequisites","local":"prerequisites","sections":[{"title":"What startup checks about agents , not just capture","local":"what-startup-checks-about-agents--not-just-capture","sections":[],"depth":3},{"title":"Why --logprobs-mode processed_logprobs is not optional","local":"why---logprobs-mode-processedlogprobs-is-not-optional","sections":[],"depth":3}],"depth":2},{"title":"Quick Start","local":"quick-start","sections":[{"title":"1. See what this machine can do","local":"1-see-what-this-machine-can-do","sections":[],"depth":3},{"title":"2. Run one rollout, no server","local":"2-run-one-rollout-no-server","sections":[],"depth":3},{"title":"3. Serve it","local":"3-serve-it","sections":[],"depth":3}],"depth":2},{"title":"CLI reference","local":"cli-reference","sections":[{"title":"openenv harbor info","local":"openenv-harbor-info","sections":[],"depth":3},{"title":"openenv harbor rollout","local":"openenv-harbor-rollout","sections":[],"depth":3},{"title":"openenv harbor serve","local":"openenv-harbor-serve","sections":[],"depth":3},{"title":"openenv harbor push","local":"openenv-harbor-push","sections":[],"depth":3}],"depth":2},{"title":"Supported harnesses","local":"supported-harnesses","sections":[],"depth":2},{"title":"Supported sandboxes","local":"supported-sandboxes","sections":[],"depth":2},{"title":"Environment details","local":"environment-details","sections":[{"title":"Where the proxy runs","local":"where-the-proxy-runs","sections":[],"depth":3},{"title":"Sandboxes and providers","local":"sandboxes-and-providers","sections":[],"depth":3},{"title":"Rewards","local":"rewards","sections":[],"depth":3},{"title":"Reading a result","local":"reading-a-result","sections":[],"depth":3}],"depth":2},{"title":"Deploying to Hugging Face Spaces","local":"deploying-to-hugging-face-spaces","sections":[],"depth":2},{"title":"Troubleshooting","local":"troubleshooting","sections":[],"depth":2},{"title":"References","local":"references","sections":[],"depth":2}],"depth":1}"/> | |
| <link href="/docs/openenv/pr_1036/en/_app/immutable/entry/start.jDgcebqH.js" rel="modulepreload"> | |
| <link href="/docs/openenv/pr_1036/en/_app/immutable/chunks/cFx4upKA.js" rel="modulepreload"> | |
| <link href="/docs/openenv/pr_1036/en/_app/immutable/chunks/DfHjNWj2.js" rel="modulepreload"> | |
| <link href="/docs/openenv/pr_1036/en/_app/immutable/entry/app.tX8SDxQQ.js" rel="modulepreload"> | |
| <link href="/docs/openenv/pr_1036/en/_app/immutable/chunks/Ba1drWuH.js" rel="modulepreload"> | |
| <link href="/docs/openenv/pr_1036/en/_app/immutable/chunks/CgMaWaPJ.js" rel="modulepreload"> | |
| <link href="/docs/openenv/pr_1036/en/_app/immutable/chunks/DsnmJJEf.js" rel="modulepreload"> | |
| <link href="/docs/openenv/pr_1036/en/_app/immutable/chunks/PGLvW8OU.js" rel="modulepreload"> | |
| <link href="/docs/openenv/pr_1036/en/_app/immutable/nodes/0.D9Ulxib0.js" rel="modulepreload"> | |
| <link href="/docs/openenv/pr_1036/en/_app/immutable/chunks/CFswWuIO.js" rel="modulepreload"> | |
| <link href="/docs/openenv/pr_1036/en/_app/immutable/nodes/2.BoV4WQvv.js" rel="modulepreload"> | |
| <link href="/docs/openenv/pr_1036/en/_app/immutable/chunks/Bln0COW0.js" rel="modulepreload"> | |
| <!--gg71d6--><meta name="hf:doc:metadata" content="{"title":"Harbor Environment","local":"harbor-environment","sections":[{"title":"Overview","local":"overview","sections":[{"title":"What you get back","local":"what-you-get-back","sections":[],"depth":3}],"depth":2},{"title":"The intercept","local":"the-intercept","sections":[],"depth":2},{"title":"Prerequisites","local":"prerequisites","sections":[{"title":"What startup checks about agents , not just capture","local":"what-startup-checks-about-agents--not-just-capture","sections":[],"depth":3},{"title":"Why --logprobs-mode processed_logprobs is not optional","local":"why---logprobs-mode-processedlogprobs-is-not-optional","sections":[],"depth":3}],"depth":2},{"title":"Quick Start","local":"quick-start","sections":[{"title":"1. See what this machine can do","local":"1-see-what-this-machine-can-do","sections":[],"depth":3},{"title":"2. Run one rollout, no server","local":"2-run-one-rollout-no-server","sections":[],"depth":3},{"title":"3. Serve it","local":"3-serve-it","sections":[],"depth":3}],"depth":2},{"title":"CLI reference","local":"cli-reference","sections":[{"title":"openenv harbor info","local":"openenv-harbor-info","sections":[],"depth":3},{"title":"openenv harbor rollout","local":"openenv-harbor-rollout","sections":[],"depth":3},{"title":"openenv harbor serve","local":"openenv-harbor-serve","sections":[],"depth":3},{"title":"openenv harbor push","local":"openenv-harbor-push","sections":[],"depth":3}],"depth":2},{"title":"Supported harnesses","local":"supported-harnesses","sections":[],"depth":2},{"title":"Supported sandboxes","local":"supported-sandboxes","sections":[],"depth":2},{"title":"Environment details","local":"environment-details","sections":[{"title":"Where the proxy runs","local":"where-the-proxy-runs","sections":[],"depth":3},{"title":"Sandboxes and providers","local":"sandboxes-and-providers","sections":[],"depth":3},{"title":"Rewards","local":"rewards","sections":[],"depth":3},{"title":"Reading a result","local":"reading-a-result","sections":[],"depth":3}],"depth":2},{"title":"Deploying to Hugging Face Spaces","local":"deploying-to-hugging-face-spaces","sections":[],"depth":2},{"title":"Troubleshooting","local":"troubleshooting","sections":[],"depth":2},{"title":"References","local":"references","sections":[],"depth":2}],"depth":1}"/><!----> | |
| <link href="/docs/openenv/pr_1036/en/_app/immutable/assets/0.tn0RQdqM.css" rel="modulepreload"> <!--[--><!--[0--><!--[--><!--[0--><!--[--><p></p> <div class="items-center shrink-0 min-w-[100px] max-sm:min-w-[50px] justify-end ml-auto flex" style="float: right; margin-left: 10px; display: inline-flex; position: relative; z-index: 10;"><div class="inline-flex rounded-md max-sm:rounded-sm"><button class="inline-flex items-center gap-1 h-7 max-sm:h-7 px-2 max-sm:px-1.5 text-sm font-medium text-gray-800 border border-r-0 rounded-l-md max-sm:rounded-l-sm border-gray-200 bg-white hover:shadow-inner dark:border-gray-850 dark:bg-gray-950 dark:text-gray-200 dark:hover:bg-gray-800" aria-live="polite"><span class="inline-flex items-center justify-center rounded-md p-0.5 max-sm:p-0 hover:text-gray-800 dark:hover:text-gray-200"><svg class="sm:size-3.5 size-3" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" fill="currentColor" focusable="false" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 32 32"><path d="M28,10V28H10V10H28m0-2H10a2,2,0,0,0-2,2V28a2,2,0,0,0,2,2H28a2,2,0,0,0,2-2V10a2,2,0,0,0-2-2Z" transform="translate(0)"></path><path d="M4,18H2V4A2,2,0,0,1,4,2H18V4H4Z" transform="translate(0)"></path><rect fill="none" width="32" height="32"></rect></svg><!----></span> <span>Copy page</span></button> <button class="inline-flex items-center justify-center w-6 max-sm:w-5 h-7 max-sm:h-7 disabled:pointer-events-none text-sm text-gray-500 hover:text-gray-700 dark:hover:text-white rounded-r-md max-sm:rounded-r-sm border border-l transition border-gray-200 bg-white hover:shadow-inner dark:border-gray-850 dark:bg-gray-950 dark:text-gray-200 dark:hover:bg-gray-800" aria-haspopup="menu" aria-expanded="false" aria-label="Open copy menu"><svg class="transition-transform text-gray-400 overflow-visible sm:size-3.5 size-3 rotate-0" width="1em" height="1em" viewBox="0 0 12 7" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M1 1L6 6L11 1" stroke="currentColor"></path></svg><!----></button></div> <!--[-1--><!--]--></div><!----> <!--[0--><h1 class="relative group"><a id="harbor-environment" class="header-link block pr-1.5 text-lg no-hover:hidden with-hover:absolute with-hover:p-1.5 with-hover:opacity-0 with-hover:group-hover:opacity-100 with-hover:right-full" href="#harbor-environment"><span><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg><!----></span></a> <span>Harbor Environment</span></h1><!--]--><!----> <p><strong>Train one policy against many coding agents.</strong> Pick a Harbor dataset, pick an agent, pick a | |
| sandbox, and get back the exact token ids and per-token logprobs of every model call the agent made, | |
| plus the task’s own reward.</p> <!--[1--><h2 class="relative group"><a id="overview" class="header-link block pr-1.5 text-lg no-hover:hidden with-hover:absolute with-hover:p-1.5 with-hover:opacity-0 with-hover:group-hover:opacity-100 with-hover:right-full" href="#overview"><span><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg><!----></span></a> <span>Overview</span></h2><!--]--><!----> <p>An agent harness is a moving part you probably do not want to own. opencode, codex, claude-code and | |
| gemini-cli each have their own loop, their own tool surface and their own wire format, and a policy | |
| trained against exactly one of them learns that one’s habits.</p> <p>The usual cost of supporting several is one integration per agent. Here it is one integration total:</p> <table><thead><tr><th></th><th></th></tr></thead><tbody><tr><td><strong>16 harnesses</strong></td><td>validated end to end, across 4 wire dialects</td></tr><tr><td><strong>23 sandbox backends</strong></td><td>from Harbor, 4 with credential checks wired in</td></tr><tr><td><strong>any Harbor dataset</strong></td><td>HF repo, local directory, or Harbor registry name</td></tr></tbody></table> <p>All three are chosen <strong>per rollout</strong>, so one server covers the whole matrix and rotating the harness | |
| during training is a config change rather than a new environment.</p> <p>Harbor supplies the tasks, sandboxes, agents and verifiers. This environment adds the OpenEnv | |
| surface: dataset discovery over the Task API, one <code>run_rollout</code> MCP tool, a capture proxy, and a UI.</p> <!--[2--><h3 class="relative group"><a id="what-you-get-back" class="header-link block pr-1.5 text-lg no-hover:hidden with-hover:absolute with-hover:p-1.5 with-hover:opacity-0 with-hover:group-hover:opacity-100 with-hover:right-full" href="#what-you-get-back"><span><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg><!----></span></a> <span>What you get back</span></h3><!--]--><!----> <p>Every rollout carries the reward from the task’s verifier and the full trace: each conversation with | |
| its messages, and per turn the text, tool calls and finish reason.</p> <p>Against vLLM or SGLang you also get the training contract, per model call:</p> <div class="code-block relative "><div class="absolute top-2.5 right-4"><button class="inline-flex items-center relative text-sm focus:text-green-500 cursor-pointer focus:outline-none transition duration-200 ease-in-out opacity-0 mx-0.5 text-gray-600 " title="code excerpt" type="button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" fill="currentColor" focusable="false" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 32 32"><path d="M28,10V28H10V10H28m0-2H10a2,2,0,0,0-2,2V28a2,2,0,0,0,2,2H28a2,2,0,0,0,2-2V10a2,2,0,0,0-2-2Z" transform="translate(0)"></path><path d="M4,18H2V4A2,2,0,0,1,4,2H18V4H4Z" transform="translate(0)"></path><rect fill="none" width="32" height="32"></rect></svg><!----> <div class=" absolute pointer-events-none transition-opacity bg-black text-white py-1 px-2 leading-tight rounded font-normal shadow left-1/2 top-full transform -translate-x-1/2 translate-y-2 opacity-0 "><div class="absolute bottom-full left-1/2 transform -translate-x-1/2 w-0 h-0 border-black border-4 border-t-0" style="border-left-color: transparent; border-right-color: transparent;"></div> Copied</div><!----></button><!----></div> <pre class="language-python "><!---->turn.prompt_token_ids <span class="hljs-comment"># the engine's own tokenisation of everything before this turn</span> | |
| turn.completion_token_ids <span class="hljs-comment"># what it sampled</span> | |
| turn.per_token_logps <span class="hljs-comment"># the behaviour-policy logprob of each sampled token</span><!----></pre></div><!----> <p>Which of the two you got is on the result as <code>rollout_type</code> (<code>"train"</code> or <code>"eval"</code>) and <code>capture_level</code>, decided by probing the endpoint before the server starts. Against a hosted provider | |
| the token fields are empty and <code>rollout_type == "eval"</code>; nothing pretends otherwise, and <code>to_turn_records</code> raises rather than handing a trainer empty lists.</p> <!--[1--><h2 class="relative group"><a id="the-intercept" class="header-link block pr-1.5 text-lg no-hover:hidden with-hover:absolute with-hover:p-1.5 with-hover:opacity-0 with-hover:group-hover:opacity-100 with-hover:right-full" href="#the-intercept"><span><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg><!----></span></a> <span>The intercept</span></h2><!--]--><!----> <p>The agent is a black box. It is a real CLI tool running in a sandbox, and it was never written with | |
| training in mind. So instead of modifying it, an OpenAI-spec proxy is placed between it and your | |
| model, and every call is recorded as it passes.</p> <div class="code-block relative "><div class="absolute top-2.5 right-4"><button class="inline-flex items-center relative text-sm focus:text-green-500 cursor-pointer focus:outline-none transition duration-200 ease-in-out opacity-0 mx-0.5 text-gray-600 " title="code excerpt" type="button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" fill="currentColor" focusable="false" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 32 32"><path d="M28,10V28H10V10H28m0-2H10a2,2,0,0,0-2,2V28a2,2,0,0,0,2,2H28a2,2,0,0,0,2-2V10a2,2,0,0,0-2-2Z" transform="translate(0)"></path><path d="M4,18H2V4A2,2,0,0,1,4,2H18V4H4Z" transform="translate(0)"></path><rect fill="none" width="32" height="32"></rect></svg><!----> <div class=" absolute pointer-events-none transition-opacity bg-black text-white py-1 px-2 leading-tight rounded font-normal shadow left-1/2 top-full transform -translate-x-1/2 translate-y-2 opacity-0 "><div class="absolute bottom-full left-1/2 transform -translate-x-1/2 w-0 h-0 border-black border-4 border-t-0" style="border-left-color: transparent; border-right-color: transparent;"></div> Copied</div><!----></button><!----></div> <pre class=" "><!---->agent <span class="hljs-keyword">in</span> a sandbox | |
| | base URL points <span class="hljs-keyword">at</span> the proxy, API key <span class="hljs-keyword">IS</span> the capture session id | |
| v | |
| capture proxy <span class="hljs-comment">--normalise to chat, ask for token ids--> your endpoint</span> | |
| ^ | | |
| | replay <span class="hljs-keyword">in</span> the agent<span class="hljs-symbol">'s</span> own dialect <<span class="hljs-comment">----------------------+</span> | |
| | | |
| +<span class="hljs-comment">-- every call becomes a node in a rollout graph, linked by token prefix</span> | |
| (by message prefix <span class="hljs-keyword">when</span> the endpoint returns no token ids)<!----></pre></div><!----> <p>Three properties make this work across agents rather than for one:</p> <p><strong>Nothing is tokenised locally.</strong> The engine tokenises each prompt in order to serve it and hands | |
| back <code>prompt_token_ids</code>, so turn <em>k+1</em>’s prompt is by construction the canonical tokenisation of | |
| everything before it, tool results included. Re-rendering a prompt offline with a chat template | |
| drifts from what the model actually saw, and a prompt that differs by one token silently splits one | |
| long conversation into several short ones.</p> <p><strong>Four wire dialects.</strong> Coding agents did not converge on one API. chat-completions, OpenAI | |
| Responses, Anthropic Messages and Google <code>generateContent</code> are all translated to a single upstream | |
| shape and replayed in the dialect the agent expects, streaming included. That is what makes codex, | |
| claude-code and gemini-cli work rather than only the chat-completions agents.</p> <p><strong>The API key is the session id.</strong> One proxy serves many concurrent rollouts with no port each, and | |
| a caller without a registered session is rejected, so the proxy is safe to expose to a sandbox.</p> <p>Turns are linked into a graph by <strong>exact token prefix</strong>: a call whose <code>prompt_token_ids</code> begin with | |
| an existing node’s full sequence becomes its child. Nothing else is consulted, because request ids | |
| and timestamps are per-agent and the prefix is not. Conversations, retries and subagent branches | |
| fall out of that for free, and a branch the agent abandoned is marked discarded so it is never | |
| trained with the reward the main path earned.</p> <!--[1--><h2 class="relative group"><a id="prerequisites" class="header-link block pr-1.5 text-lg no-hover:hidden with-hover:absolute with-hover:p-1.5 with-hover:opacity-0 with-hover:group-hover:opacity-100 with-hover:right-full" href="#prerequisites"><span><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg><!----></span></a> <span>Prerequisites</span></h2><!--]--><!----> <p>You need an OpenAI-compatible endpoint. Which <em>kind</em> of rollout you get depends on what it can | |
| return, and that is probed at startup rather than configured:</p> <table><thead><tr><th></th><th>eval</th><th>train</th></tr></thead><tbody><tr><td>reward, <code>rewards</code> dict, step results</td><td>yes</td><td>yes</td></tr><tr><td>full trace: conversations, per-turn text, tool calls</td><td>yes</td><td>yes</td></tr><tr><td><code>prompt_token_ids</code>, <code>completion_token_ids</code>, <code>per_token_logps</code></td><td>no</td><td>yes</td></tr><tr><td><code>contract.json</code>, TRL rollout func</td><td>no</td><td>yes</td></tr></tbody></table> <p><strong>For trainable rollouts</strong> the endpoint must return token ids <em>and</em> the sampling distribution’s | |
| logprobs. Both are checked by probing, because both fail silently:</p> <div class="code-block relative "><div class="absolute top-2.5 right-4"><button class="inline-flex items-center relative text-sm focus:text-green-500 cursor-pointer focus:outline-none transition duration-200 ease-in-out opacity-0 mx-0.5 text-gray-600 " title="code excerpt" type="button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" fill="currentColor" focusable="false" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 32 32"><path d="M28,10V28H10V10H28m0-2H10a2,2,0,0,0-2,2V28a2,2,0,0,0,2,2H28a2,2,0,0,0,2-2V10a2,2,0,0,0-2-2Z" transform="translate(0)"></path><path d="M4,18H2V4A2,2,0,0,1,4,2H18V4H4Z" transform="translate(0)"></path><rect fill="none" width="32" height="32"></rect></svg><!----> <div class=" absolute pointer-events-none transition-opacity bg-black text-white py-1 px-2 leading-tight rounded font-normal shadow left-1/2 top-full transform -translate-x-1/2 translate-y-2 opacity-0 "><div class="absolute bottom-full left-1/2 transform -translate-x-1/2 w-0 h-0 border-black border-4 border-t-0" style="border-left-color: transparent; border-right-color: transparent;"></div> Copied</div><!----></button><!----></div> <pre class="language-bash "><!---->vllm serve <model> --return-tokens-as-token-ids --logprobs-mode processed_logprobs | |
| <span class="hljs-comment"># or SGLang built from git main (sgl-project/sglang#30917); no serving flag needed</span><!----></pre></div><!----> <p>Without them the endpoint answers every request normally and returns no token ids. Rollouts would | |
| look perfect and contain nothing trainable, and that failure has no loud edge — so the level is | |
| probed before the server binds a port, printed as <code>[EVAL ONLY]</code>, stamped on every result, and no | |
| training contract is ever built from it.</p> <p><strong>For eval rollouts</strong> any reachable OpenAI-spec endpoint works, including hosted ones:</p> <div class="code-block relative "><div class="absolute top-2.5 right-4"><button class="inline-flex items-center relative text-sm focus:text-green-500 cursor-pointer focus:outline-none transition duration-200 ease-in-out opacity-0 mx-0.5 text-gray-600 " title="code excerpt" type="button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" fill="currentColor" focusable="false" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 32 32"><path d="M28,10V28H10V10H28m0-2H10a2,2,0,0,0-2,2V28a2,2,0,0,0,2,2H28a2,2,0,0,0,2-2V10a2,2,0,0,0-2-2Z" transform="translate(0)"></path><path d="M4,18H2V4A2,2,0,0,1,4,2H18V4H4Z" transform="translate(0)"></path><rect fill="none" width="32" height="32"></rect></svg><!----> <div class=" absolute pointer-events-none transition-opacity bg-black text-white py-1 px-2 leading-tight rounded font-normal shadow left-1/2 top-full transform -translate-x-1/2 translate-y-2 opacity-0 "><div class="absolute bottom-full left-1/2 transform -translate-x-1/2 w-0 h-0 border-black border-4 border-t-0" style="border-left-color: transparent; border-right-color: transparent;"></div> Copied</div><!----></button><!----></div> <pre class="language-bash "><!---->openenv harbor serve --llm-url https://api.openai.com/v1 --api-key <span class="hljs-variable">$OPENAI_API_KEY</span> --model gpt-5.6-sol | |
| openenv harbor serve --llm-url https://router.huggingface.co/v1 --api-key <span class="hljs-variable">$HF_API_KEY</span> --model Qwen/Qwen3.6-35B-A3B | |
| openenv harbor serve --llm-url https://api.anthropic.com/v1 --api-key <span class="hljs-variable">$ANTHROPIC_API_KEY</span> --model claude-sonnet-5<!----></pre></div><!----> <p>Anthropic needs no <code>--auth-header</code>: its OpenAI-compatible <code>/v1/chat/completions</code> accepts <code>Authorization: Bearer</code>. Its <code>/v1/models</code> does not — that route wants <code>x-api-key</code> <em>and</em> <code>anthropic-version</code> — so the model list comes back empty and <code>--model</code> is required. An endpoint that | |
| publishes no usable model list is not treated as unreachable for exactly this reason; the completion | |
| probe is what decides.</p> <p><code>--api-key</code> (or <code>$OPENENV_LLM_API_KEY</code>) authenticates the proxy to the endpoint; <code>--auth-header</code> changes the header name when a provider wants something other than <code>Authorization: Bearer</code>. This is | |
| not the key the agent receives — that one is a capture session id, minted per rollout — and it never | |
| leaves the server process.</p> <p>A hosted provider also rejects parameters a local vLLM accepts, per model rather than per endpoint. | |
| Every current OpenAI model refuses <code>max_tokens</code> (wants <code>max_completion_tokens</code>), any <code>temperature</code> other than 1, and <code>logprobs</code> outright, while opencode, codex and qwen-coder all send the first two. <code>gpt-5.6</code> additionally refuses <strong>function tools</strong> on <code>/v1/chat/completions</code> unless <code>reasoning_effort</code> is <code>"none"</code> — which for a coding agent is every call that matters; left unhandled | |
| it presents as a rollout that makes one model call and then idles until the agent timeout.</p> <p>The proxy reads each such 400, applies the one edit the provider names, retries, and caches the fix — | |
| so the agents work unchanged. Every applied fix is reported on the result, at startup and in the UI, | |
| because these are changed experiments rather than cosmetic rewrites: dropping <code>temperature</code> alters | |
| the sampling distribution, and <code>reasoning_effort: "none"</code> turns reasoning off. For <code>gpt-5.6</code> the | |
| better answer is the Responses route the error message itself recommends.</p> <!--[2--><h3 class="relative group"><a id="what-startup-checks-about-agents--not-just-capture" class="header-link block pr-1.5 text-lg no-hover:hidden with-hover:absolute with-hover:p-1.5 with-hover:opacity-0 with-hover:group-hover:opacity-100 with-hover:right-full" href="#what-startup-checks-about-agents--not-just-capture"><span><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg><!----></span></a> <span>What startup checks about agents , not just capture</span></h3><!--]--><!----> <p>The capture probe sends no tools. Every validated harness sends a tool manifest on every call, so a | |
| second, non-fatal probe asks the way a harness asks and reports:</p> <table><thead><tr><th>finding</th><th>meaning</th></tr></thead><tbody><tr><td><code>tools: ok</code></td><td>a tool call came back; agents can work here</td></tr><tr><td><code>no_tool_calling</code> (FATAL)</td><td>the endpoint refuses a manifest outright; no agent rollout is possible</td></tr><tr><td><code>no_tool_call_emitted</code> (WARN)</td><td>manifest accepted, but it answered in prose</td></tr><tr><td><code>behaviour_changed</code> (WARN)</td><td>a compat fix changed how the MODEL behaves, not just a field name</td></tr></tbody></table> <p>The last one is the reason this probe exists. <code>gpt-5.6</code> accepts function tools on <code>/v1/chat/completions</code> only if <code>reasoning_effort</code> is <code>"none"</code>, and with reasoning off it emits one | |
| valid tool call and then agentic loops die: goose and codex each managed a single model call and 0/3 | |
| tasks, while both scored 3/3 against a non-reasoning model on the same endpoint. Without a tool in the | |
| probe body that demand is never made, so <code>harbor info</code> looked healthy and the failure only appeared | |
| minutes into a rollout. Now it is reported before a sandbox is booted.</p> <p>Truncation is deliberately treated as inconclusive rather than a failure: a reasoning model spends | |
| output tokens thinking before it calls anything, and a small cap made <code>Qwen3.6-35B-A3B</code> look | |
| tool-incapable when it in fact worked with all 16 harnesses.</p> <!--[2--><h3 class="relative group"><a id="why---logprobs-mode-processedlogprobs-is-not-optional" class="header-link block pr-1.5 text-lg no-hover:hidden with-hover:absolute with-hover:p-1.5 with-hover:opacity-0 with-hover:group-hover:opacity-100 with-hover:right-full" href="#why---logprobs-mode-processedlogprobs-is-not-optional"><span><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg><!----></span></a> <span>Why --logprobs-mode processed_logprobs is not optional</span></h3><!--]--><!----> <p><code>token_ids</code> comes from the <code>return_token_ids</code> <strong>request</strong> parameter, not from either serving flag, so | |
| a vLLM started with neither flag still returns aligned, negative, correctly-counted logprobs and would | |
| grade as fully trainable. But vLLM’s <code>logprobs_mode</code> defaults to <code>raw_logprobs</code> — the values <em>before</em> temperature and top-k/top-p are applied — and GRPO’s importance ratio needs the logprob under the | |
| policy that actually sampled the token.</p> <p>Startup measures which you have, rather than inferring it: the gap between the top two logprobs is | |
| requested at temperature 1.0 and 2.0. Processed logprobs are <code>logsoftmax(logits / T)</code>, so the gap | |
| scales by <code>1/T</code> while the normalising constant cancels; raw logprobs cannot move at all. Measured on | |
| two live Qwen3.5-4B servers:</p> <table><thead><tr><th></th><th>gap @T=1.0</th><th>gap @T=2.0</th><th>verdict</th></tr></thead><tbody><tr><td><code>--logprobs-mode processed_logprobs</code></td><td>6.7500</td><td>3.3750</td><td><code>processed</code></td></tr><tr><td>default</td><td>6.7500</td><td>6.7500</td><td><code>raw</code></td></tr></tbody></table> <p>A measured <code>raw</code> endpoint is downgraded to EVAL rather than refused — it is still a perfectly good | |
| eval backend — and <code>OPENENV_ALLOW_RAW_LOGPROBS=1</code> overrides that if you know better than the probe. | |
| The gap is compared rather than the values themselves because a data-parallel engine answers | |
| consecutive calls from different replicas; comparing values directly misread one such engine.</p> <p>Install the extra, which brings Harbor and every sandbox backend:</p> <div class="code-block relative "><div class="absolute top-2.5 right-4"><button class="inline-flex items-center relative text-sm focus:text-green-500 cursor-pointer focus:outline-none transition duration-200 ease-in-out opacity-0 mx-0.5 text-gray-600 " title="code excerpt" type="button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" fill="currentColor" focusable="false" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 32 32"><path d="M28,10V28H10V10H28m0-2H10a2,2,0,0,0-2,2V28a2,2,0,0,0,2,2H28a2,2,0,0,0,2-2V10a2,2,0,0,0-2-2Z" transform="translate(0)"></path><path d="M4,18H2V4A2,2,0,0,1,4,2H18V4H4Z" transform="translate(0)"></path><rect fill="none" width="32" height="32"></rect></svg><!----> <div class=" absolute pointer-events-none transition-opacity bg-black text-white py-1 px-2 leading-tight rounded font-normal shadow left-1/2 top-full transform -translate-x-1/2 translate-y-2 opacity-0 "><div class="absolute bottom-full left-1/2 transform -translate-x-1/2 w-0 h-0 border-black border-4 border-t-0" style="border-left-color: transparent; border-right-color: transparent;"></div> Copied</div><!----></button><!----></div> <pre class="language-bash "><!---->pip install <span class="hljs-string">"openenv[harbor]"</span> <span class="hljs-comment"># needs Python 3.12 or newer</span><!----></pre></div><!----> <!--[1--><h2 class="relative group"><a id="quick-start" class="header-link block pr-1.5 text-lg no-hover:hidden with-hover:absolute with-hover:p-1.5 with-hover:opacity-0 with-hover:group-hover:opacity-100 with-hover:right-full" href="#quick-start"><span><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg><!----></span></a> <span>Quick Start</span></h2><!--]--><!----> <!--[2--><h3 class="relative group"><a id="1-see-what-this-machine-can-do" class="header-link block pr-1.5 text-lg no-hover:hidden with-hover:absolute with-hover:p-1.5 with-hover:opacity-0 with-hover:group-hover:opacity-100 with-hover:right-full" href="#1-see-what-this-machine-can-do"><span><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg><!----></span></a> <span>1. See what this machine can do</span></h3><!--]--><!----> <div class="code-block relative "><div class="absolute top-2.5 right-4"><button class="inline-flex items-center relative text-sm focus:text-green-500 cursor-pointer focus:outline-none transition duration-200 ease-in-out opacity-0 mx-0.5 text-gray-600 " title="code excerpt" type="button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" fill="currentColor" focusable="false" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 32 32"><path d="M28,10V28H10V10H28m0-2H10a2,2,0,0,0-2,2V28a2,2,0,0,0,2,2H28a2,2,0,0,0,2-2V10a2,2,0,0,0-2-2Z" transform="translate(0)"></path><path d="M4,18H2V4A2,2,0,0,1,4,2H18V4H4Z" transform="translate(0)"></path><rect fill="none" width="32" height="32"></rect></svg><!----> <div class=" absolute pointer-events-none transition-opacity bg-black text-white py-1 px-2 leading-tight rounded font-normal shadow left-1/2 top-full transform -translate-x-1/2 translate-y-2 opacity-0 "><div class="absolute bottom-full left-1/2 transform -translate-x-1/2 w-0 h-0 border-black border-4 border-t-0" style="border-left-color: transparent; border-right-color: transparent;"></div> Copied</div><!----></button><!----></div> <pre class="language-bash "><!---->openenv harbor info \ | |
| --llm-url <span class="hljs-variable">$LLM</span> \ | |
| --dataset AdithyaSK/data_agent_rl_environment_eval<!----></pre></div><!----> <div class="code-block relative "><div class="absolute top-2.5 right-4"><button class="inline-flex items-center relative text-sm focus:text-green-500 cursor-pointer focus:outline-none transition duration-200 ease-in-out opacity-0 mx-0.5 text-gray-600 " title="code excerpt" type="button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" fill="currentColor" focusable="false" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 32 32"><path d="M28,10V28H10V10H28m0-2H10a2,2,0,0,0-2,2V28a2,2,0,0,0,2,2H28a2,2,0,0,0,2-2V10a2,2,0,0,0-2-2Z" transform="translate(0)"></path><path d="M4,18H2V4A2,2,0,0,1,4,2H18V4H4Z" transform="translate(0)"></path><rect fill="none" width="32" height="32"></rect></svg><!----> <div class=" absolute pointer-events-none transition-opacity bg-black text-white py-1 px-2 leading-tight rounded font-normal shadow left-1/2 top-full transform -translate-x-1/2 translate-y-2 opacity-0 "><div class="absolute bottom-full left-1/2 transform -translate-x-1/2 w-0 h-0 border-black border-4 border-t-0" style="border-left-color: transparent; border-right-color: transparent;"></div> Copied</div><!----></button><!----></div> <pre class=" "><!---->llm <span class="hljs-symbol">Qwen</span>/<span class="hljs-symbol">Qwen3</span><span class="hljs-number">.5</span><span class="hljs-number">-9</span><span class="hljs-symbol">B</span> [ok] | |
| sandboxes <span class="hljs-number">2</span> of <span class="hljs-number">4</span> usable | |
| [ok] e2b | |
| [ok] modal | |
| [--] docker <span class="hljs-symbol">Docker</span> daemon is not running. | |
| [--] daytona <span class="hljs-symbol">SDK</span> not installed (daytona). | |
| datasets <span class="hljs-number">1</span> split(s), <span class="hljs-number">366</span> tasks | |
| harnesses <span class="hljs-number">16</span> validated of <span class="hljs-number">30</span> known<!----></pre></div><!----> <p>Read-only, boots nothing. It tells you which sandboxes have working credentials <strong>and</strong> an | |
| importable SDK, so you find out here rather than 90 seconds into a rollout.</p> <!--[2--><h3 class="relative group"><a id="2-run-one-rollout-no-server" class="header-link block pr-1.5 text-lg no-hover:hidden with-hover:absolute with-hover:p-1.5 with-hover:opacity-0 with-hover:group-hover:opacity-100 with-hover:right-full" href="#2-run-one-rollout-no-server"><span><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg><!----></span></a> <span>2. Run one rollout, no server</span></h3><!--]--><!----> <div class="code-block relative "><div class="absolute top-2.5 right-4"><button class="inline-flex items-center relative text-sm focus:text-green-500 cursor-pointer focus:outline-none transition duration-200 ease-in-out opacity-0 mx-0.5 text-gray-600 " title="code excerpt" type="button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" fill="currentColor" focusable="false" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 32 32"><path d="M28,10V28H10V10H28m0-2H10a2,2,0,0,0-2,2V28a2,2,0,0,0,2,2H28a2,2,0,0,0,2-2V10a2,2,0,0,0-2-2Z" transform="translate(0)"></path><path d="M4,18H2V4A2,2,0,0,1,4,2H18V4H4Z" transform="translate(0)"></path><rect fill="none" width="32" height="32"></rect></svg><!----> <div class=" absolute pointer-events-none transition-opacity bg-black text-white py-1 px-2 leading-tight rounded font-normal shadow left-1/2 top-full transform -translate-x-1/2 translate-y-2 opacity-0 "><div class="absolute bottom-full left-1/2 transform -translate-x-1/2 w-0 h-0 border-black border-4 border-t-0" style="border-left-color: transparent; border-right-color: transparent;"></div> Copied</div><!----></button><!----></div> <pre class="language-bash "><!---->openenv harbor rollout \ | |
| --llm-url <span class="hljs-variable">$LLM</span> \ | |
| --dataset AdithyaSK/data_agent_rl_environment_eval \ | |
| --task-index 0 --harness opencode --sandbox e2b \ | |
| --out rollout.json<!----></pre></div><!----> <div class="code-block relative "><div class="absolute top-2.5 right-4"><button class="inline-flex items-center relative text-sm focus:text-green-500 cursor-pointer focus:outline-none transition duration-200 ease-in-out opacity-0 mx-0.5 text-gray-600 " title="code excerpt" type="button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" fill="currentColor" focusable="false" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 32 32"><path d="M28,10V28H10V10H28m0-2H10a2,2,0,0,0-2,2V28a2,2,0,0,0,2,2H28a2,2,0,0,0,2-2V10a2,2,0,0,0-2-2Z" transform="translate(0)"></path><path d="M4,18H2V4A2,2,0,0,1,4,2H18V4H4Z" transform="translate(0)"></path><rect fill="none" width="32" height="32"></rect></svg><!----> <div class=" absolute pointer-events-none transition-opacity bg-black text-white py-1 px-2 leading-tight rounded font-normal shadow left-1/2 top-full transform -translate-x-1/2 translate-y-2 opacity-0 "><div class="absolute bottom-full left-1/2 transform -translate-x-1/2 w-0 h-0 border-black border-4 border-t-0" style="border-left-color: transparent; border-right-color: transparent;"></div> Copied</div><!----></button><!----></div> <pre class=" "><!---->[opencode / e2b] task 0: 0000_369_369503_qa_1 <span class="hljs-built_in">..</span>. | |
| ok <span class="hljs-attribute">reward</span>=1.00 <span class="hljs-attribute">turns</span>=9 <span class="hljs-attribute">roots</span>=2 multi-turn <span class="hljs-attribute">tokens</span>=1043 <span class="hljs-attribute">atif</span>=match 48s<!----></pre></div><!----> <p>This path involves no env server, which makes it the one to reach for when something breaks: if <code>rollout</code> works and <code>serve</code> does not, the fault is in the serving layer and nothing below it.</p> <!--[2--><h3 class="relative group"><a id="3-serve-it" class="header-link block pr-1.5 text-lg no-hover:hidden with-hover:absolute with-hover:p-1.5 with-hover:opacity-0 with-hover:group-hover:opacity-100 with-hover:right-full" href="#3-serve-it"><span><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg><!----></span></a> <span>3. Serve it</span></h3><!--]--><!----> <div class="code-block relative "><div class="absolute top-2.5 right-4"><button class="inline-flex items-center relative text-sm focus:text-green-500 cursor-pointer focus:outline-none transition duration-200 ease-in-out opacity-0 mx-0.5 text-gray-600 " title="code excerpt" type="button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" fill="currentColor" focusable="false" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 32 32"><path d="M28,10V28H10V10H28m0-2H10a2,2,0,0,0-2,2V28a2,2,0,0,0,2,2H28a2,2,0,0,0,2-2V10a2,2,0,0,0-2-2Z" transform="translate(0)"></path><path d="M4,18H2V4A2,2,0,0,1,4,2H18V4H4Z" transform="translate(0)"></path><rect fill="none" width="32" height="32"></rect></svg><!----> <div class=" absolute pointer-events-none transition-opacity bg-black text-white py-1 px-2 leading-tight rounded font-normal shadow left-1/2 top-full transform -translate-x-1/2 translate-y-2 opacity-0 "><div class="absolute bottom-full left-1/2 transform -translate-x-1/2 w-0 h-0 border-black border-4 border-t-0" style="border-left-color: transparent; border-right-color: transparent;"></div> Copied</div><!----></button><!----></div> <pre class="language-bash "><!---->openenv harbor serve --llm-url <span class="hljs-variable">$LLM</span> --dataset org/train,org/eval<!----></pre></div><!----> <p>You get a Task API for discovery, one long-running <code>run_rollout</code> MCP tool, and a UI at <code>/web</code>.</p> <div class="code-block relative "><div class="absolute top-2.5 right-4"><button class="inline-flex items-center relative text-sm focus:text-green-500 cursor-pointer focus:outline-none transition duration-200 ease-in-out opacity-0 mx-0.5 text-gray-600 " title="code excerpt" type="button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" fill="currentColor" focusable="false" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 32 32"><path d="M28,10V28H10V10H28m0-2H10a2,2,0,0,0-2,2V28a2,2,0,0,0,2,2H28a2,2,0,0,0,2-2V10a2,2,0,0,0-2-2Z" transform="translate(0)"></path><path d="M4,18H2V4A2,2,0,0,1,4,2H18V4H4Z" transform="translate(0)"></path><rect fill="none" width="32" height="32"></rect></svg><!----> <div class=" absolute pointer-events-none transition-opacity bg-black text-white py-1 px-2 leading-tight rounded font-normal shadow left-1/2 top-full transform -translate-x-1/2 translate-y-2 opacity-0 "><div class="absolute bottom-full left-1/2 transform -translate-x-1/2 w-0 h-0 border-black border-4 border-t-0" style="border-left-color: transparent; border-right-color: transparent;"></div> Copied</div><!----></button><!----></div> <pre class="language-python "><!----><span class="hljs-keyword">from</span> harbor_env <span class="hljs-keyword">import</span> HarborEnv | |
| <span class="hljs-keyword">with</span> HarborEnv(base_url=<span class="hljs-string">"http://localhost:8000"</span>) <span class="hljs-keyword">as</span> env: | |
| split = env.splits()[<span class="hljs-number">0</span>][<span class="hljs-string">"name"</span>] | |
| result = env.run_rollout(split=split, task_index=<span class="hljs-number">0</span>, harness=<span class="hljs-string">"opencode"</span>, sandbox=<span class="hljs-string">"e2b"</span>) | |
| <span class="hljs-built_in">print</span>(result.reward, result.n_turns) | |
| <span class="hljs-keyword">for</span> turn <span class="hljs-keyword">in</span> result.turns: | |
| <span class="hljs-built_in">print</span>(<span class="hljs-built_in">len</span>(turn.completion_token_ids), <span class="hljs-built_in">sum</span>(turn.per_token_logps))<!----></pre></div><!----> <p><code>harness</code> and <code>sandbox</code> are per call, so consecutive rollouts against the same server can use | |
| different agents and different backends.</p> <!--[1--><h2 class="relative group"><a id="cli-reference" class="header-link block pr-1.5 text-lg no-hover:hidden with-hover:absolute with-hover:p-1.5 with-hover:opacity-0 with-hover:group-hover:opacity-100 with-hover:right-full" href="#cli-reference"><span><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg><!----></span></a> <span>CLI reference</span></h2><!--]--><!----> <p>Four commands. Every flag below is the complete set, with its type and default. `openenv harbor</p> <command> --help` prints the same thing. <p>Exit codes:</p> <table><thead><tr><th>code</th><th>meaning</th></tr></thead><tbody><tr><td><code>0</code></td><td>success</td></tr><tr><td><code>1</code></td><td>ran, but failed. <code>rollout</code> returns this if <strong>any</strong> rollout in the batch was unusable</td></tr><tr><td><code>2</code></td><td>usage error: a missing or invalid flag. Nothing ran</td></tr></tbody></table> <p>The <code>1</code> and <code>2</code> split matters if you are scripting this: <code>2</code> means the command never started, so | |
| retrying it unchanged will fail the same way.</p> <!--[2--><h3 class="relative group"><a id="openenv-harbor-info" class="header-link block pr-1.5 text-lg no-hover:hidden with-hover:absolute with-hover:p-1.5 with-hover:opacity-0 with-hover:group-hover:opacity-100 with-hover:right-full" href="#openenv-harbor-info"><span><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg><!----></span></a> <span>openenv harbor info</span></h3><!--]--><!----> <p>Report what this machine can run. Read-only: boots no sandbox, starts no server, makes no rollout.</p> <table><thead><tr><th>flag</th><th>type</th><th>default</th><th>meaning</th></tr></thead><tbody><tr><td><code>--llm-url</code></td><td>str</td><td><code>""</code></td><td>OpenAI-spec endpoint. Optional here; without it the LLM section is skipped and the rest still reports</td></tr><tr><td><code>--model</code></td><td>str</td><td><code>""</code></td><td>Served model id. Auto-detected when the endpoint serves exactly one</td></tr><tr><td><code>--dataset</code></td><td>str</td><td>none</td><td>Dataset spec. Repeatable, or comma-separated</td></tr><tr><td><code>--env-file</code></td><td>path</td><td><code>""</code></td><td>dotenv with provider credentials, loaded before the checks</td></tr><tr><td><code>--verbose</code></td><td>flag</td><td>off</td><td>List all 30 harnesses, not only the 16 validated</td></tr><tr><td><code>--json</code></td><td>flag</td><td>off</td><td>Emit machine-readable JSON instead of the text report</td></tr></tbody></table> <div class="code-block relative "><div class="absolute top-2.5 right-4"><button class="inline-flex items-center relative text-sm focus:text-green-500 cursor-pointer focus:outline-none transition duration-200 ease-in-out opacity-0 mx-0.5 text-gray-600 " title="code excerpt" type="button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" fill="currentColor" focusable="false" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 32 32"><path d="M28,10V28H10V10H28m0-2H10a2,2,0,0,0-2,2V28a2,2,0,0,0,2,2H28a2,2,0,0,0,2-2V10a2,2,0,0,0-2-2Z" transform="translate(0)"></path><path d="M4,18H2V4A2,2,0,0,1,4,2H18V4H4Z" transform="translate(0)"></path><rect fill="none" width="32" height="32"></rect></svg><!----> <div class=" absolute pointer-events-none transition-opacity bg-black text-white py-1 px-2 leading-tight rounded font-normal shadow left-1/2 top-full transform -translate-x-1/2 translate-y-2 opacity-0 "><div class="absolute bottom-full left-1/2 transform -translate-x-1/2 w-0 h-0 border-black border-4 border-t-0" style="border-left-color: transparent; border-right-color: transparent;"></div> Copied</div><!----></button><!----></div> <pre class="language-bash "><!---->openenv harbor info --llm-url <span class="hljs-variable">$LLM</span> --dataset org/tasks --json<!----></pre></div><!----> <p>The JSON has four top-level keys: <code>llm</code>, <code>sandboxes</code>, <code>datasets</code>, <code>harnesses</code>. Each sandbox entry is <code>{name, available, detail}</code>, so a script can select a backend without parsing prose:</p> <div class="code-block relative "><div class="absolute top-2.5 right-4"><button class="inline-flex items-center relative text-sm focus:text-green-500 cursor-pointer focus:outline-none transition duration-200 ease-in-out opacity-0 mx-0.5 text-gray-600 " title="code excerpt" type="button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" fill="currentColor" focusable="false" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 32 32"><path d="M28,10V28H10V10H28m0-2H10a2,2,0,0,0-2,2V28a2,2,0,0,0,2,2H28a2,2,0,0,0,2-2V10a2,2,0,0,0-2-2Z" transform="translate(0)"></path><path d="M4,18H2V4A2,2,0,0,1,4,2H18V4H4Z" transform="translate(0)"></path><rect fill="none" width="32" height="32"></rect></svg><!----> <div class=" absolute pointer-events-none transition-opacity bg-black text-white py-1 px-2 leading-tight rounded font-normal shadow left-1/2 top-full transform -translate-x-1/2 translate-y-2 opacity-0 "><div class="absolute bottom-full left-1/2 transform -translate-x-1/2 w-0 h-0 border-black border-4 border-t-0" style="border-left-color: transparent; border-right-color: transparent;"></div> Copied</div><!----></button><!----></div> <pre class="language-bash "><!---->openenv harbor info --llm-url <span class="hljs-variable">$LLM</span> --json \ | |
| | jq -r <span class="hljs-string">'.sandboxes[] | select(.available) | .name'</span><!----></pre></div><!----> <!--[2--><h3 class="relative group"><a id="openenv-harbor-rollout" class="header-link block pr-1.5 text-lg no-hover:hidden with-hover:absolute with-hover:p-1.5 with-hover:opacity-0 with-hover:group-hover:opacity-100 with-hover:right-full" href="#openenv-harbor-rollout"><span><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg><!----></span></a> <span>openenv harbor rollout</span></h3><!--]--><!----> <p>Run rollouts with no env server involved. This is the debugging path: if <code>rollout</code> works and <code>serve</code> does not, the fault is in the serving layer and nothing below it.</p> <table><thead><tr><th>flag</th><th>type</th><th>default</th><th>meaning</th></tr></thead><tbody><tr><td><code>--llm-url</code></td><td>str</td><td><strong>required</strong></td><td>OpenAI-spec endpoint. No default and no env fallback, on purpose</td></tr><tr><td><code>--dataset</code></td><td>str</td><td><strong>required</strong></td><td>Dataset spec. Only the first is used by this command</td></tr><tr><td><code>--task-index</code></td><td>int</td><td><code>0</code></td><td>Index into the split. Stable: index is a task’s identity</td></tr><tr><td><code>-n</code>, <code>--n-tasks</code></td><td>int</td><td><code>1</code></td><td>Run this many consecutive tasks from <code>--task-index</code></td></tr><tr><td><code>--harness</code></td><td>str</td><td><code>opencode</code></td><td>A validated seam name, or <code>module:Class</code> for your own agent</td></tr><tr><td><code>--sandbox</code></td><td>str</td><td><code>e2b</code></td><td>Harbor environment type</td></tr><tr><td><code>--model</code></td><td>str</td><td><code>""</code></td><td>Served model id. Auto-detected when unambiguous</td></tr><tr><td><code>--port</code></td><td>int</td><td><code>8100</code></td><td>Local port for the capture proxy. One per concurrent process</td></tr><tr><td><code>--expose</code></td><td>str</td><td><code>gradio</code></td><td>How the sandbox reaches the proxy: <code>gradio</code>, <code>cloudflare</code>, <code>direct</code></td></tr><tr><td><code>--reward-key</code></td><td>str</td><td><code>""</code></td><td>Which reward key is the training signal, for multi-reward tasks</td></tr><tr><td><code>--trials-dir</code></td><td>path</td><td>tmp</td><td>Where Harbor writes trial artifacts</td></tr><tr><td><code>--keep-sandbox</code></td><td>flag</td><td>off</td><td>Leave sandboxes alive for debugging</td></tr><tr><td><code>--force-build</code></td><td>flag</td><td>off</td><td>Rebuild the sandbox image, bypassing the content-hash cache</td></tr><tr><td><code>--env-file</code></td><td>path</td><td><code>""</code></td><td>dotenv with provider credentials</td></tr><tr><td><code>--out</code></td><td>path</td><td><code>""</code></td><td>Write the full result JSON, token ids and logprobs included</td></tr></tbody></table> <div class="code-block relative "><div class="absolute top-2.5 right-4"><button class="inline-flex items-center relative text-sm focus:text-green-500 cursor-pointer focus:outline-none transition duration-200 ease-in-out opacity-0 mx-0.5 text-gray-600 " title="code excerpt" type="button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" fill="currentColor" focusable="false" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 32 32"><path d="M28,10V28H10V10H28m0-2H10a2,2,0,0,0-2,2V28a2,2,0,0,0,2,2H28a2,2,0,0,0,2-2V10a2,2,0,0,0-2-2Z" transform="translate(0)"></path><path d="M4,18H2V4A2,2,0,0,1,4,2H18V4H4Z" transform="translate(0)"></path><rect fill="none" width="32" height="32"></rect></svg><!----> <div class=" absolute pointer-events-none transition-opacity bg-black text-white py-1 px-2 leading-tight rounded font-normal shadow left-1/2 top-full transform -translate-x-1/2 translate-y-2 opacity-0 "><div class="absolute bottom-full left-1/2 transform -translate-x-1/2 w-0 h-0 border-black border-4 border-t-0" style="border-left-color: transparent; border-right-color: transparent;"></div> Copied</div><!----></button><!----></div> <pre class="language-bash "><!---->openenv harbor rollout --llm-url <span class="hljs-variable">$LLM</span> --dataset org/tasks \ | |
| --task-index 0 -n 5 --harness codex --sandbox modal --out results.json<!----></pre></div><!----> <p><code>-n</code> runs tasks sequentially in one process, reusing one proxy and one forward. To parallelise, run | |
| several processes and <strong>give each its own <code>--port</code></strong>. Two processes sharing a port is refused with | |
| an error naming the process that holds it.</p> <p>Use <code>--force-build</code> when a task has never been built on this account, or when a cached image has | |
| drifted because the task pins its dependencies loosely.</p> <!--[2--><h3 class="relative group"><a id="openenv-harbor-serve" class="header-link block pr-1.5 text-lg no-hover:hidden with-hover:absolute with-hover:p-1.5 with-hover:opacity-0 with-hover:group-hover:opacity-100 with-hover:right-full" href="#openenv-harbor-serve"><span><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg><!----></span></a> <span>openenv harbor serve</span></h3><!--]--><!----> <p>Start the env server: Task API for discovery, one long-running <code>run_rollout</code> MCP tool, and a UI at <code>/web</code>.</p> <table><thead><tr><th>flag</th><th>type</th><th>default</th><th>meaning</th></tr></thead><tbody><tr><td><code>--llm-url</code></td><td>str</td><td><strong>required</strong></td><td>OpenAI-spec endpoint</td></tr><tr><td><code>--dataset</code></td><td>str</td><td>none</td><td>Dataset specs to serve as splits. Repeatable</td></tr><tr><td><code>--model</code></td><td>str</td><td><code>""</code></td><td>Served model id</td></tr><tr><td><code>--host</code></td><td>str</td><td><code>0.0.0.0</code></td><td>Bind address</td></tr><tr><td><code>--port</code></td><td>int</td><td><code>8000</code></td><td>Env server port. Faces the trainer and the browser</td></tr><tr><td><code>--capture-port</code></td><td>int</td><td><code>8100</code></td><td>Capture proxy port. Faces the sandbox</td></tr><tr><td><code>--expose</code></td><td>str</td><td><code>gradio</code></td><td>How the sandbox reaches the proxy</td></tr><tr><td><code>--env-file</code></td><td>path</td><td><code>""</code></td><td>dotenv with provider credentials</td></tr></tbody></table> <p>| <code>--api-key</code> | str | <code>$OPENENV_LLM_API_KEY</code> | Credential for the endpoint, for a hosted provider | | |
| | <code>--auth-header</code> | str | <code>Authorization</code> | Header to send it under, e.g. <code>x-api-key</code> |</p> <p>Refuses to start only if the endpoint is unreachable. One that cannot return token ids starts as an eval deployment and says so.</p> <!--[2--><h3 class="relative group"><a id="openenv-harbor-push" class="header-link block pr-1.5 text-lg no-hover:hidden with-hover:absolute with-hover:p-1.5 with-hover:opacity-0 with-hover:group-hover:opacity-100 with-hover:right-full" href="#openenv-harbor-push"><span><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg><!----></span></a> <span>openenv harbor push</span></h3><!--]--><!----> <p>Deploy the same server to a Hugging Face Space.</p> <table><thead><tr><th>flag</th><th>type</th><th>default</th><th>meaning</th></tr></thead><tbody><tr><td><code>--llm-url</code></td><td>str</td><td><strong>required</strong></td><td>Endpoint the deployed Space will use</td></tr><tr><td><code>--repo-id</code></td><td>str</td><td><strong>required</strong></td><td>Target Space, e.g. <code>you/harbor-env</code></td></tr><tr><td><code>--dataset</code></td><td>str</td><td>none</td><td>Dataset specs. Repeatable</td></tr><tr><td><code>--model</code></td><td>str</td><td><code>""</code></td><td>Served model id</td></tr><tr><td><code>--bucket</code></td><td>str</td><td>Space name</td><td>Storage bucket holding the task suites. <code>none</code> disables the mount and downloads instead</td></tr><tr><td><code>--hardware</code></td><td>str</td><td><code>""</code></td><td>Space hardware, e.g. <code>cpu-basic</code></td></tr><tr><td><code>--private</code></td><td>flag</td><td>off</td><td>Create it private. Rollouts then cannot work, see below</td></tr><tr><td><code>--recreate</code></td><td>flag</td><td>off</td><td>Delete the Space first, then deploy fresh</td></tr><tr><td><code>--dry-run</code></td><td>flag</td><td>off</td><td>Print exactly what would be sent and stop</td></tr><tr><td><code>--env-file</code></td><td>path</td><td><code>""</code></td><td>dotenv whose provider keys become Space <strong>secrets</strong></td></tr></tbody></table> <div class="code-block relative "><div class="absolute top-2.5 right-4"><button class="inline-flex items-center relative text-sm focus:text-green-500 cursor-pointer focus:outline-none transition duration-200 ease-in-out opacity-0 mx-0.5 text-gray-600 " title="code excerpt" type="button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" fill="currentColor" focusable="false" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 32 32"><path d="M28,10V28H10V10H28m0-2H10a2,2,0,0,0-2,2V28a2,2,0,0,0,2,2H28a2,2,0,0,0,2-2V10a2,2,0,0,0-2-2Z" transform="translate(0)"></path><path d="M4,18H2V4A2,2,0,0,1,4,2H18V4H4Z" transform="translate(0)"></path><rect fill="none" width="32" height="32"></rect></svg><!----> <div class=" absolute pointer-events-none transition-opacity bg-black text-white py-1 px-2 leading-tight rounded font-normal shadow left-1/2 top-full transform -translate-x-1/2 translate-y-2 opacity-0 "><div class="absolute bottom-full left-1/2 transform -translate-x-1/2 w-0 h-0 border-black border-4 border-t-0" style="border-left-color: transparent; border-right-color: transparent;"></div> Copied</div><!----></button><!----></div> <pre class="language-bash "><!---->openenv harbor push --llm-url <span class="hljs-variable">$LLM</span> --dataset org/train,org/eval \ | |
| --repo-id you/harbor-env --env-file .<span class="hljs-built_in">env</span> --dry-run<!----></pre></div><!----> <p><code>--private</code> is supported but rollouts will not work on a private Space: the capture proxy is served | |
| at <code><space-url>/capture</code>, and a private Space requires an auth header the sandboxed agent does not | |
| send. Use it only to park a deployment.</p> <!--[1--><h2 class="relative group"><a id="supported-harnesses" class="header-link block pr-1.5 text-lg no-hover:hidden with-hover:absolute with-hover:p-1.5 with-hover:opacity-0 with-hover:group-hover:opacity-100 with-hover:right-full" href="#supported-harnesses"><span><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg><!----></span></a> <span>Supported harnesses</span></h2><!--]--><!----> <p>16 of the 30 known agents are validated end to end. “Validated” means a real rollout produced token | |
| ids and logprobs, and where the agent emits a trajectory, its own record agreed with the capture.</p> <table><thead><tr><th>harness</th><th>dialect</th><th>runs</th></tr></thead><tbody><tr><td><code>opencode</code></td><td>chat-completions</td><td>in sandbox</td></tr><tr><td><code>goose</code></td><td>chat-completions</td><td>in sandbox</td></tr><tr><td><code>qwen-coder</code></td><td>chat-completions</td><td>in sandbox</td></tr><tr><td><code>swe-agent</code></td><td>chat-completions</td><td>in sandbox</td></tr><tr><td><code>mini-swe-agent</code></td><td>chat-completions</td><td>in sandbox</td></tr><tr><td><code>openhands-sdk</code></td><td>chat-completions</td><td>in sandbox</td></tr><tr><td><code>openclaw</code></td><td>chat-completions</td><td>in sandbox</td></tr><tr><td><code>hermes</code></td><td>chat-completions</td><td>in sandbox</td></tr><tr><td><code>kimi-cli</code></td><td>chat-completions</td><td>in sandbox</td></tr><tr><td><code>pi</code></td><td>chat-completions</td><td>in sandbox</td></tr><tr><td><code>vibe</code></td><td>chat-completions</td><td>in sandbox</td></tr><tr><td><code>terminus-2</code></td><td>chat-completions</td><td><strong>host side</strong></td></tr><tr><td><code>codex</code></td><td>OpenAI Responses</td><td>in sandbox</td></tr><tr><td><code>trae-agent</code></td><td>OpenAI Responses</td><td>in sandbox</td></tr><tr><td><code>claude-code</code></td><td>Anthropic Messages</td><td>in sandbox</td></tr><tr><td><code>gemini-cli</code></td><td>Google generateContent</td><td>in sandbox</td></tr></tbody></table> <p>Supporting four dialects rather than chat-completions alone is what makes the last four rows work.</p> <p><code>terminus-2</code> runs in the server process rather than inside the sandbox, so it reaches the proxy on | |
| localhost and needs no public URL.</p> <p>The other 14 known agents have a seam but are untested; run <code>openenv harbor info --verbose</code> to list | |
| them. Anything Harbor supports can be reached with <code>--harness module:Class</code>.</p> <!--[1--><h2 class="relative group"><a id="supported-sandboxes" class="header-link block pr-1.5 text-lg no-hover:hidden with-hover:absolute with-hover:p-1.5 with-hover:opacity-0 with-hover:group-hover:opacity-100 with-hover:right-full" href="#supported-sandboxes"><span><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg><!----></span></a> <span>Supported sandboxes</span></h2><!--]--><!----> <p><code>openenv harbor info</code> checks these four by default and reports why any is unusable:</p> <table><thead><tr><th>sandbox</th><th>credentials</th><th>validated</th></tr></thead><tbody><tr><td><code>e2b</code></td><td><code>E2B_API_KEY</code></td><td>yes, extensively</td></tr><tr><td><code>modal</code></td><td><code>MODAL_TOKEN_ID</code> + <code>MODAL_TOKEN_SECRET</code>, or <code>~/.modal.toml</code></td><td>yes, extensively</td></tr><tr><td><code>docker</code></td><td>none, but the daemon must be running</td><td>works, not swept</td></tr><tr><td><code>daytona</code></td><td><code>DAYTONA_API_KEY</code>, or <code>DAYTONA_JWT_TOKEN</code> + <code>DAYTONA_ORGANIZATION_ID</code></td><td>not swept</td></tr></tbody></table> <p>e2b and modal were compared on identical tasks and came out indistinguishable, which is the check | |
| that matters: a backend-specific capture bug is exactly what a single-backend test hides.</p> <p>Harbor registers 23 backends in total. Any of them can be passed to <code>--sandbox</code>; the four above are | |
| the ones with a credential check wired in.</p> <!--[1--><h2 class="relative group"><a id="environment-details" class="header-link block pr-1.5 text-lg no-hover:hidden with-hover:absolute with-hover:p-1.5 with-hover:opacity-0 with-hover:group-hover:opacity-100 with-hover:right-full" href="#environment-details"><span><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg><!----></span></a> <span>Environment details</span></h2><!--]--><!----> <!--[2--><h3 class="relative group"><a id="where-the-proxy-runs" class="header-link block pr-1.5 text-lg no-hover:hidden with-hover:absolute with-hover:p-1.5 with-hover:opacity-0 with-hover:group-hover:opacity-100 with-hover:right-full" href="#where-the-proxy-runs"><span><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg><!----></span></a> <span>Where the proxy runs</span></h3><!--]--><!----> <p>Locally there are two ports: the env server faces the trainer and the browser, the capture proxy | |
| faces the sandbox and is the only one published. Sharing one port would expose the env server the | |
| moment the proxy became reachable.</p> <p>Hosted, that inverts. A Space has one port and one public URL, so the proxy is mounted on the env | |
| server’s own app at <code>/capture</code> and nothing is forwarded. It still rejects callers without a | |
| registered session id, which is what keeps a public mount from being an open relay.</p> <!--[2--><h3 class="relative group"><a id="sandboxes-and-providers" class="header-link block pr-1.5 text-lg no-hover:hidden with-hover:absolute with-hover:p-1.5 with-hover:opacity-0 with-hover:group-hover:opacity-100 with-hover:right-full" href="#sandboxes-and-providers"><span><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg><!----></span></a> <span>Sandboxes and providers</span></h3><!--]--><!----> <p>Two different things share the word “sandbox”, and mixing them up is a common early confusion:</p> <ul><li><strong>Harbor backends</strong> are where the <em>agent</em> runs. That is what <code>--sandbox</code> selects.</li> <li><strong>OpenEnv providers</strong> (<code>local_docker</code>, <code>hf_sandbox</code>, <code>modal</code>, <code>aca</code>, …) host the <em>env server</em> itself and have no <code>exec</code>.</li></ul> <p>A backend counts as usable only if its class imports <strong>and</strong> Harbor’s own preflight passes. | |
| Credentials alone are not enough: a provider with valid keys but no SDK installed would otherwise | |
| report available and fail at rollout time.</p> <!--[2--><h3 class="relative group"><a id="rewards" class="header-link block pr-1.5 text-lg no-hover:hidden with-hover:absolute with-hover:p-1.5 with-hover:opacity-0 with-hover:group-hover:opacity-100 with-hover:right-full" href="#rewards"><span><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg><!----></span></a> <span>Rewards</span></h3><!--]--><!----> <p>The verifier produces a dictionary. OpenEnv wants one number. The dictionary is forwarded unchanged | |
| and the scalar is chosen by an explicit rule:</p> <ol><li>one key, use it</li> <li>a key named <code>reward</code>, use it</li> <li>otherwise fail and ask for <code>--reward-key</code></li></ol> <p>Combining several keys automatically would be inventing reward semantics, so it refuses instead. | |
| All shaping belongs in the trainer.</p> <p><strong><code>reward=None</code> is not zero.</strong> It means the verifier never ran. A dead sandbox scored as zero looks | |
| like a wrong answer, which is how an infrastructure failure gets mistaken for a model result.</p> <!--[2--><h3 class="relative group"><a id="reading-a-result" class="header-link block pr-1.5 text-lg no-hover:hidden with-hover:absolute with-hover:p-1.5 with-hover:opacity-0 with-hover:group-hover:opacity-100 with-hover:right-full" href="#reading-a-result"><span><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg><!----></span></a> <span>Reading a result</span></h3><!--]--><!----> <table><thead><tr><th>field</th><th>meaning</th></tr></thead><tbody><tr><td><code>ok</code></td><td>the rollout is usable. <code>False</code> means something failed, and <code>error</code> says what</td></tr><tr><td><code>reward</code></td><td>the verifier’s number, or <code>None</code> if it never ran</td></tr><tr><td><code>n_turns</code></td><td>model calls captured</td></tr><tr><td><code>n_roots</code></td><td>independent conversations. More than one means subagents or auxiliary calls</td></tr><tr><td><code>turns[]</code></td><td>per-call token ids, logprobs, text and tool calls</td></tr><tr><td><code>conversations[]</code></td><td>the full message list per conversation, system prompt included</td></tr><tr><td><code>atif</code></td><td><code>match</code>, <code>MISMATCH</code>, or <code>none</code>. See below</td></tr><tr><td><code>findings</code></td><td>warnings worth reading before training on the rollout</td></tr></tbody></table> <p><code>atif</code> is an independent cross-check. Harbor’s own trajectory file records what the <em>harness</em> thought happened; the capture records what crossed the wire. Two measurements of the same rollout | |
| through completely different paths. <code>match</code> means they agree call for call.</p> <p><strong>A failed rollout returns a result, never an exception.</strong> That is deliberate. In an in-process | |
| design one exception on one rank hangs every rank at the distributed barrier, so behind an HTTP | |
| boundary a failure has to come back as <code>ok=False</code> instead.</p> <!--[1--><h2 class="relative group"><a id="deploying-to-hugging-face-spaces" class="header-link block pr-1.5 text-lg no-hover:hidden with-hover:absolute with-hover:p-1.5 with-hover:opacity-0 with-hover:group-hover:opacity-100 with-hover:right-full" href="#deploying-to-hugging-face-spaces"><span><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg><!----></span></a> <span>Deploying to Hugging Face Spaces</span></h2><!--]--><!----> <div class="code-block relative "><div class="absolute top-2.5 right-4"><button class="inline-flex items-center relative text-sm focus:text-green-500 cursor-pointer focus:outline-none transition duration-200 ease-in-out opacity-0 mx-0.5 text-gray-600 " title="code excerpt" type="button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" fill="currentColor" focusable="false" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 32 32"><path d="M28,10V28H10V10H28m0-2H10a2,2,0,0,0-2,2V28a2,2,0,0,0,2,2H28a2,2,0,0,0,2-2V10a2,2,0,0,0-2-2Z" transform="translate(0)"></path><path d="M4,18H2V4A2,2,0,0,1,4,2H18V4H4Z" transform="translate(0)"></path><rect fill="none" width="32" height="32"></rect></svg><!----> <div class=" absolute pointer-events-none transition-opacity bg-black text-white py-1 px-2 leading-tight rounded font-normal shadow left-1/2 top-full transform -translate-x-1/2 translate-y-2 opacity-0 "><div class="absolute bottom-full left-1/2 transform -translate-x-1/2 w-0 h-0 border-black border-4 border-t-0" style="border-left-color: transparent; border-right-color: transparent;"></div> Copied</div><!----></button><!----></div> <pre class="language-bash "><!---->openenv harbor push \ | |
| --llm-url <span class="hljs-variable">$LLM</span> \ | |
| --dataset org/train,org/eval \ | |
| --repo-id you/harbor-env \ | |
| --env-file .<span class="hljs-built_in">env</span><!----></pre></div><!----> <p>Configuration travels as Space variables, provider credentials as Space secrets. Add <code>--dry-run</code> to print exactly what would be sent first, and <code>--recreate</code> to delete and redeploy for a clean test.</p> <p>Two details that matter:</p> <p><strong>Task suites are mounted, not downloaded.</strong> A Harbor suite is thousands of small files and Space | |
| disk is ephemeral, so a download is re-paid on every restart. <code>push</code> syncs the suites into a storage | |
| bucket named after the Space and mounts it at <code>/data</code>. The copy is server side, and re-running <code>push</code> copies only what is new.</p> <p><strong>The Space must be public.</strong> The capture proxy is served at <code><space-url>/capture</code>, and a private | |
| Space requires an auth header that the agent inside the sandbox does not send. This is safe because | |
| the proxy rejects any caller without a registered session id, so a public mount is not an open | |
| relay.</p> <!--[1--><h2 class="relative group"><a id="troubleshooting" class="header-link block pr-1.5 text-lg no-hover:hidden with-hover:absolute with-hover:p-1.5 with-hover:opacity-0 with-hover:group-hover:opacity-100 with-hover:right-full" href="#troubleshooting"><span><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg><!----></span></a> <span>Troubleshooting</span></h2><!--]--><!----> <p><strong>Rollout finishes with zero model calls.</strong> The agent never reached the proxy. Usually the endpoint | |
| URL is wrong, the model name did not resolve, or auth was rejected. Check the <code>findings</code> field, | |
| which names the likely cause.</p> <p><strong><code>llm ... [FAILED]</code> at startup.</strong> The endpoint is unreachable — wrong URL, wrong model name, or | |
| a missing <code>--api-key</code> for a provider that needs one. The findings name which.</p> <p><strong><code>llm ... [EVAL ONLY]</code> at startup.</strong> The endpoint answers but returns no token ids, so rollouts | |
| carry the reward and the trace and nothing trainable. Expected for OpenAI, Anthropic and HF | |
| Inference Providers. If you meant to train, restart the engine with <code>--return-tokens-as-token-ids --logprobs-mode processed_logprobs</code>, or build SGLang from git main — | |
| released SGLang carries only <code>return_prompt_token_ids</code>, which is not enough.</p> <p><strong><code>contract.json</code> is missing after a rollout.</strong> The rollout was an eval rollout; check <code>rollout_type</code> and <code>capture_level</code> on the result. There is deliberately no all-zero contract to | |
| download, because a file named <code>contract.json</code> containing no contract is more convincing than an | |
| empty list.</p> <p><strong>A sandbox shows <code>[--]</code> in <code>info</code>.</strong> The detail column says why, and it is usually a missing | |
| credential or a missing SDK. Install everything with <code>pip install "openenv[harbor]"</code>.</p> <p><strong><code>atif=none</code>.</strong> That harness writes no trajectory file, so no cross-check is possible. Capture is | |
| unaffected.</p> <p><strong>Many roots for one rollout.</strong> Normal for agents that run subagents or auxiliary calls. Each root | |
| is a separate conversation, and only agent conversations are counted as trainable.</p> <p><strong>Exit code 137.</strong> The agent was killed inside the sandbox, almost always by the OOM killer on a | |
| large input. That is a task failure, not a capture failure.</p> <!--[1--><h2 class="relative group"><a id="references" class="header-link block pr-1.5 text-lg no-hover:hidden with-hover:absolute with-hover:p-1.5 with-hover:opacity-0 with-hover:group-hover:opacity-100 with-hover:right-full" href="#references"><span><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg><!----></span></a> <span>References</span></h2><!--]--><!----> <ul><li><a href="https://github.com/laude-institute/harbor" rel="nofollow">Harbor</a>, which provides the datasets, sandboxes, | |
| agents and verifiers</li> <li><a href="https://github.com/NVIDIA-NeMo/ProRL-Agent-Server" rel="nofollow">Polar</a> (<a href="https://arxiv.org/abs/2605.24220" rel="nofollow">paper</a>), the black-box approach this capture layer follows, | |
| and the source of the vendored dialect transformers</li> <li><a href="https://github.com/willccbb/verifiers" rel="nofollow">verifiers</a>, whose <code>Dialect</code> model informed the auxiliary | |
| route and streaming handling</li></ul> <a class="!text-gray-400 !no-underline text-sm flex items-center not-prose mt-4" href="https://github.com/huggingface/openenv/blob/main/docs/source/environments/harbor.md" target="_blank"><svg class="mr-1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" fill="currentColor" focusable="false" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 32 32"><path d="M31,16l-7,7l-1.41-1.41L28.17,16l-5.58-5.59L24,9l7,7z"></path><path d="M1,16l7-7l1.41,1.41L3.83,16l5.58,5.59L8,23l-7-7z"></path><path d="M12.419,25.484L17.639,6.552l1.932,0.518L14.351,26.002z"></path></svg><!----> <span><span class="underline">Update</span> on GitHub</span></a><!----> <p></p><!--]--><!----><!--]--><!--]--><!--]--> <!--[-1--><!--]--><!--]--> | |
| <script> | |
| { | |
| __sveltekit_1ctfzng = { | |
| base: "/docs/openenv/pr_1036/en", | |
| assets: "/docs/openenv/pr_1036/en" | |
| }; | |
| const element = document.currentScript.parentElement; | |
| Promise.all([ | |
| import("/docs/openenv/pr_1036/en/_app/immutable/entry/start.jDgcebqH.js"), | |
| import("/docs/openenv/pr_1036/en/_app/immutable/entry/app.tX8SDxQQ.js") | |
| ]).then(([kit, app]) => { | |
| kit.start(app, element, { | |
| node_ids: [0, 2], | |
| data: [null,null], | |
| form: null, | |
| error: null | |
| }); | |
| }); | |
| } | |
| </script> | |
Xet Storage Details
- Size:
- 95.6 kB
- Xet hash:
- 9ccb4578e4c246472b987cb0c1e33909880e426ca0c48306778c6edc5a423462
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.