Buckets:

hf-doc-build/doc-dev / openenv /pr_1285 /en /tutorials /claude-code-harness.html
download
raw
42.7 kB
<meta charset="utf-8" /><meta name="hf:doc:metadata" content="{&quot;title&quot;:&quot;Evaluate Claude Code in an Environment&quot;,&quot;local&quot;:&quot;evaluate-claude-code-in-an-environment&quot;,&quot;sections&quot;:[{&quot;title&quot;:&quot;What You’ll Build&quot;,&quot;local&quot;:&quot;what-youll-build&quot;,&quot;sections&quot;:[],&quot;depth&quot;:2},{&quot;title&quot;:&quot;Install Dependencies&quot;,&quot;local&quot;:&quot;install-dependencies&quot;,&quot;sections&quot;:[],&quot;depth&quot;:2},{&quot;title&quot;:&quot;The Adapter&quot;,&quot;local&quot;:&quot;the-adapter&quot;,&quot;sections&quot;:[],&quot;depth&quot;:2},{&quot;title&quot;:&quot;Join It to τ²-bench&quot;,&quot;local&quot;:&quot;join-it-to-τ²-bench&quot;,&quot;sections&quot;:[],&quot;depth&quot;:2},{&quot;title&quot;:&quot;Run the Evaluation&quot;,&quot;local&quot;:&quot;run-the-evaluation&quot;,&quot;sections&quot;:[],&quot;depth&quot;:2},{&quot;title&quot;:&quot;Serve It in Production Mode&quot;,&quot;local&quot;:&quot;serve-it-in-production-mode&quot;,&quot;sections&quot;:[{&quot;title&quot;:&quot;Serve It in a Container&quot;,&quot;local&quot;:&quot;serve-it-in-a-container&quot;,&quot;sections&quot;:[],&quot;depth&quot;:3}],&quot;depth&quot;:2},{&quot;title&quot;:&quot;Things to Know&quot;,&quot;local&quot;:&quot;things-to-know&quot;,&quot;sections&quot;:[],&quot;depth&quot;:2},{&quot;title&quot;:&quot;Adapting It&quot;,&quot;local&quot;:&quot;adapting-it&quot;,&quot;sections&quot;:[],&quot;depth&quot;:2}],&quot;depth&quot;:1}"/>
<link href="/docs/openenv/pr_1285/en/_app/immutable/entry/start.CG5FzNt2.js" rel="modulepreload">
<link href="/docs/openenv/pr_1285/en/_app/immutable/chunks/BBXg17tp.js" rel="modulepreload">
<link href="/docs/openenv/pr_1285/en/_app/immutable/chunks/BSuxAqoA.js" rel="modulepreload">
<link href="/docs/openenv/pr_1285/en/_app/immutable/entry/app.Db-H8-tM.js" rel="modulepreload">
<link href="/docs/openenv/pr_1285/en/_app/immutable/chunks/Ds_1Ru_R.js" rel="modulepreload">
<link href="/docs/openenv/pr_1285/en/_app/immutable/chunks/DIlRkxSv.js" rel="modulepreload">
<link href="/docs/openenv/pr_1285/en/_app/immutable/chunks/DsnmJJEf.js" rel="modulepreload">
<link href="/docs/openenv/pr_1285/en/_app/immutable/chunks/BAUKCucN.js" rel="modulepreload">
<link href="/docs/openenv/pr_1285/en/_app/immutable/nodes/0.CR0SH4Os.js" rel="modulepreload">
<link href="/docs/openenv/pr_1285/en/_app/immutable/chunks/CR5HsSXT.js" rel="modulepreload">
<link href="/docs/openenv/pr_1285/en/_app/immutable/nodes/64.B_F_im3K.js" rel="modulepreload">
<link href="/docs/openenv/pr_1285/en/_app/immutable/chunks/C07d6Hje.js" rel="modulepreload">
<!--eno6qm--><meta name="hf:doc:metadata" content="{&quot;title&quot;:&quot;Evaluate Claude Code in an Environment&quot;,&quot;local&quot;:&quot;evaluate-claude-code-in-an-environment&quot;,&quot;sections&quot;:[{&quot;title&quot;:&quot;What You’ll Build&quot;,&quot;local&quot;:&quot;what-youll-build&quot;,&quot;sections&quot;:[],&quot;depth&quot;:2},{&quot;title&quot;:&quot;Install Dependencies&quot;,&quot;local&quot;:&quot;install-dependencies&quot;,&quot;sections&quot;:[],&quot;depth&quot;:2},{&quot;title&quot;:&quot;The Adapter&quot;,&quot;local&quot;:&quot;the-adapter&quot;,&quot;sections&quot;:[],&quot;depth&quot;:2},{&quot;title&quot;:&quot;Join It to τ²-bench&quot;,&quot;local&quot;:&quot;join-it-to-τ²-bench&quot;,&quot;sections&quot;:[],&quot;depth&quot;:2},{&quot;title&quot;:&quot;Run the Evaluation&quot;,&quot;local&quot;:&quot;run-the-evaluation&quot;,&quot;sections&quot;:[],&quot;depth&quot;:2},{&quot;title&quot;:&quot;Serve It in Production Mode&quot;,&quot;local&quot;:&quot;serve-it-in-production-mode&quot;,&quot;sections&quot;:[{&quot;title&quot;:&quot;Serve It in a Container&quot;,&quot;local&quot;:&quot;serve-it-in-a-container&quot;,&quot;sections&quot;:[],&quot;depth&quot;:3}],&quot;depth&quot;:2},{&quot;title&quot;:&quot;Things to Know&quot;,&quot;local&quot;:&quot;things-to-know&quot;,&quot;sections&quot;:[],&quot;depth&quot;:2},{&quot;title&quot;:&quot;Adapting It&quot;,&quot;local&quot;:&quot;adapting-it&quot;,&quot;sections&quot;:[],&quot;depth&quot;:2}],&quot;depth&quot;:1}"/><!---->
<link href="/docs/openenv/pr_1285/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="evaluate-claude-code-in-an-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="#evaluate-claude-code-in-an-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>Evaluate Claude Code in an Environment</span></h1><!--]--><!----> <p>This tutorial measures how well an existing agent, <a href="https://docs.anthropic.com/en/docs/claude-code" rel="nofollow">Claude Code</a>, does a job that only your environment’s tools can do, over a conversation with a simulated user. The job comes from <a href="../environments/tau2">τ²-bench</a>: Claude Code is an airline’s customer service agent, it has to follow the airline’s policy, and τ²-bench checks the database it leaves behind.</p> <p>It uses <code>HarnessEnvironment</code>, the agentic harness wrapper from <a href="https://github.com/huggingface/OpenEnv/blob/main/rfcs/005-agentic-harnesses.md" rel="nofollow">RFC 005</a>. Claude Code keeps its own agent loop and runs inside the environment, the environment serves its tools to it over MCP, and each <code>step()</code> is one message from the customer:</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=" "><!---->step(customer message)
|
v
C<span class="hljs-function"><span class="hljs-title">laude</span> Code --tool calls over MCP--&gt;</span> MCP <span class="hljs-function"><span class="hljs-title">bridge</span> --&gt;</span> <span class="hljs-function"><span class="hljs-title">environment</span> tools --&gt;</span> τ²-bench database
|
| reply
v
<span class="hljs-function"><span class="hljs-title">simulated</span> customer --&gt;</span> <span class="hljs-function"><span class="hljs-title">next</span> message, <span class="hljs-built_in">or</span> done --&gt;</span> rubric scores the database <span class="hljs-built_in">and</span> the conversation<!----></pre></div><!----> <p>The full code is in <a href="https://github.com/huggingface/OpenEnv/tree/main/examples/claude_code_harness_eval" rel="nofollow"><code>examples/claude_code_harness_eval</code></a>.</p> <blockquote class="note"><p>Use this path when the job is a conversation and the agent has to use your environment’s tools. RFC 005 does not capture token ids, so it evaluates and serves, but does not train. To train the model behind an agent, or to evaluate it on tasks that a verifier checks, use <a href="harbor-harness">Harbor</a>. <a href="harnesses">Harnesses in OpenEnv</a> compares the options.</p></blockquote> <!--[1--><h2 class="relative group"><a id="what-youll-build" 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-youll-build"><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’ll Build</span></h2><!--]--><!----> <ul><li>An <code>AgenticHarnessAdapter</code> for Claude Code’s headless mode.</li> <li>A <code>HarnessEnvironment</code> that gives Claude Code the tools and policy of a τ²-bench task, plays the task’s simulated customer between turns, and scores the conversation with a rubric.</li> <li>The RFC 005 loop around it: one <code>step()</code> per customer message, until the customer is done.</li> <li>The same harness served in production mode, with you as the customer.</li></ul> <!--[1--><h2 class="relative group"><a id="install-dependencies" 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="#install-dependencies"><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>Install Dependencies</span></h2><!--]--><!----> <p>You need the <code>claude</code> CLI, logged in or with <code>ANTHROPIC_API_KEY</code> set, and Python 3.12 or later, which τ²-bench requires. Then, from a clone of OpenEnv:</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 -e . -e envs/tau2_env<!----></pre></div><!----> <p>τ²-bench’s tasks and databases are not in its package. Fetch them once and point <code>TAU2_DATA_DIR</code> at them, as described in <a href="../environments/tau2#running-the-server">the τ²-bench environment’s docs</a>. The simulated customer runs on <a href="https://huggingface.co/docs/inference-providers" rel="nofollow">Inference Providers</a>, so set <code>HF_TOKEN</code> too.</p> <!--[1--><h2 class="relative group"><a id="the-adapter" 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-adapter"><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 Adapter</span></h2><!--]--><!----> <p>An <code>AgenticHarnessAdapter</code> tells <code>HarnessEnvironment</code> how to start a harness, how to hand it tools, and how to read a turn. <a href="https://github.com/huggingface/OpenEnv/blob/main/examples/claude_code_harness_eval/claude_code_adapter.py" rel="nofollow"><code>claude_code_adapter.py</code></a> keeps one long-lived <code>claude -p --input-format stream-json --output-format stream-json</code> process per episode:</p> <table><thead><tr><th><code>AgenticHarnessAdapter</code></th><th>Claude Code</th></tr></thead><tbody><tr><td><code>inject_tools(tools, bridge_url)</code></td><td><code>--mcp-config</code> with the bridge as an HTTP MCP server, and <code>--allowedTools mcp__env</code> so its tools run without a permission prompt</td></tr><tr><td><code>start()</code></td><td>spawns the process with <code>HarnessProcess</code>. Claude Code prints nothing until the first message</td></tr><tr><td><code>send_message_streaming()</code></td><td>writes <code>{"type": "user", "message": {...}}</code> on stdin and maps stdout events: <code>tool_use</code> → <code>TOOL_CALL</code>, <code>tool_result</code> → <code>TOOL_RESULT</code>, <code>text</code> → <code>TEXT_OUTPUT</code>, and <code>result</code> (end of turn) → <code>TURN_COMPLETE</code></td></tr></tbody></table> <p>Claude Code’s own tools are turned off (<code>--tools ""</code>), so the agent can only act through the environment’s tools: it has no shell, no file access and no way to open connections of its own. It also loads no settings files (<code>--setting-sources ""</code>), so your hooks and <code>CLAUDE.md</code> stay out of the run. To give it shell or file tools as well, list them in <code>--tools</code> and run it in a sandbox: the <a href="#serve-it-in-a-container">container</a> keeps it away from your machine, and an egress allowlist (for example <code>ACASandboxProvider.deny_all_egress()</code>) keeps it to the model’s API.</p> <!--[1--><h2 class="relative group"><a id="join-it-to-τ²-bench" 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="#join-it-to-τ²-bench"><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>Join It to τ²-bench</span></h2><!--]--><!----> <p><a href="https://github.com/huggingface/OpenEnv/blob/main/examples/claude_code_harness_eval/tau2_harness.py" rel="nofollow"><code>tau2_harness.py</code></a> defines <code>Tau2Harness</code>, a <code>HarnessEnvironment</code> for one τ²-bench task:</p> <ul><li><strong>The tools and the policy.</strong> Claude Code gets the domain’s tools over MCP, and the domain’s policy appended to its system prompt. It does not get <code>respond_to_user</code> or <code>done</code>, because it talks to the customer through its replies.</li> <li><strong>The customer.</strong> After each Claude Code turn, the environment passes the reply to τ²-bench’s simulated customer and returns the customer’s next message in <code>observation.metadata["customer"]</code>. The customer is part of the environment, as in <code>tau2_env</code> itself.</li> <li><strong>The reward.</strong> A rubric reads τ²-bench’s score when the customer ends the conversation, so the reward is in <code>observation.reward</code> and <code>observation.done</code> marks the end.</li></ul> <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">import</span> tempfile
<span class="hljs-keyword">from</span> openenv.core.harness <span class="hljs-keyword">import</span> HarnessAction, HarnessConfig
<span class="hljs-keyword">from</span> tau2_env.server.tau2_environment <span class="hljs-keyword">import</span> Tau2Environment
<span class="hljs-keyword">from</span> tau2_harness <span class="hljs-keyword">import</span> Tau2Harness
config = HarnessConfig(
name=<span class="hljs-string">&quot;claude-code&quot;</span>,
command=[<span class="hljs-string">&quot;claude&quot;</span>],
working_directory=tempfile.mkdtemp(),
model=<span class="hljs-string">&quot;haiku&quot;</span>,
)
harness = Tau2Harness(Tau2Environment(domain=<span class="hljs-string">&quot;airline&quot;</span>, split=<span class="hljs-string">&quot;test&quot;</span>), <span class="hljs-string">&quot;2&quot;</span>, config)
observation = harness.reset() <span class="hljs-comment"># the customer&#x27;s opening message</span>
<span class="hljs-keyword">while</span> <span class="hljs-keyword">not</span> observation.done:
<span class="hljs-comment"># One Claude Code turn, then the customer&#x27;s answer</span>
observation = harness.step(HarnessAction(message=observation.metadata[<span class="hljs-string">&quot;customer&quot;</span>]))
<span class="hljs-built_in">print</span>(observation.reward)
harness.close() <span class="hljs-comment"># stops Claude Code and the τ²-bench task</span><!----></pre></div><!----> <p>Each customer message is one <code>step(HarnessAction(message=...))</code>, and Claude Code keeps the conversation’s context across steps. Its tool calls run against the same database the customer sees, so τ²-bench can score the result. If Claude Code exits or runs out of time, the step comes back with <code>done</code> and the error in its metadata.</p> <!--[1--><h2 class="relative group"><a id="run-the-evaluation" 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="#run-the-evaluation"><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>Run the Evaluation</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 "><!---->PYTHONPATH=src:envs:examples/claude_code_harness_eval \
python examples/claude_code_harness_eval/run_eval.py --domain airline --task-ids 8 16 19 26 --model haiku<!----></pre></div><!----> <p>These four tasks each end in a different state of the database. In task 8 the agent books a flight, in 16 it changes one, in 19 it cancels one, and in 26 the policy doesn’t allow the cancellation the customer asks for, so the agent has to refuse, even when the customer pushes back. In task 26 the output looks like this:</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=" "><!---->=== airline <span class="hljs-keyword">task</span> <span class="hljs-number">26</span>
customer: Hi, I need to cancel my flights from Orlando to Charlotte. I<span class="hljs-symbol">&#x27;d</span> like to get a refund <span class="hljs-keyword">for</span> them, please.
[...]
-&gt; get_user_details({<span class="hljs-symbol">&#x27;user_id</span>&#x27;: <span class="hljs-symbol">&#x27;amelia_sanchez_4739</span>&#x27;})
-&gt; get_reservation_details({<span class="hljs-symbol">&#x27;reservation_id</span>&#x27;: &#x27;<span class="hljs-number">3</span>FRNFB&#x27;})
-&gt; get_reservation_details({<span class="hljs-symbol">&#x27;reservation_id</span>&#x27;: <span class="hljs-symbol">&#x27;Q4L9HS</span>&#x27;})
[...]
customer: It<span class="hljs-symbol">&#x27;s</span> a change <span class="hljs-keyword">of</span> plans. I still want to cancel <span class="hljs-keyword">and</span> get a refund, please.
agent: I<span class="hljs-symbol">&#x27;m</span> sorry, but I can<span class="hljs-symbol">&#x27;t</span> cancel reservation <span class="hljs-number">3</span>FRNFB. It was booked on May <span class="hljs-number">6</span>, more than <span class="hljs-number">24</span> hours ago. [...]
customer: I really need to cancel <span class="hljs-keyword">and</span> get a refund. <span class="hljs-keyword">If</span> you can<span class="hljs-symbol">&#x27;t</span> <span class="hljs-keyword">do</span> it, please transfer me to someone who can.
agent: I understand this <span class="hljs-keyword">is</span> frustrating, but I can<span class="hljs-symbol">&#x27;t</span> transfer you <span class="hljs-keyword">for</span> this request. [...]
reward: <span class="hljs-number">1.00</span> {<span class="hljs-symbol">&#x27;DB</span>&#x27;: <span class="hljs-number">1.0</span>, <span class="hljs-symbol">&#x27;COMMUNICATE</span>&#x27;: <span class="hljs-number">1.0</span>}
PASS <span class="hljs-keyword">task</span> <span class="hljs-number">8</span>
PASS <span class="hljs-keyword">task</span> <span class="hljs-number">16</span>
PASS <span class="hljs-keyword">task</span> <span class="hljs-number">19</span>
PASS <span class="hljs-keyword">task</span> <span class="hljs-number">26</span>
pass^<span class="hljs-number">1</span>: <span class="hljs-number">4</span>/<span class="hljs-number">4</span><!----></pre></div><!----> <p>τ²-bench scores a task 1.0 when the database ends up as the task expects (<code>DB</code>) and the agent told the customer what it had to (<code>COMMUNICATE</code>). pass^1 is the fraction of tasks that score 1.0 in a single attempt. τ²-bench’s pass^k asks for k successes out of k attempts of the same task, so running each task several times measures how consistent the agent is.</p> <p><code>--domain</code> takes any τ²-bench domain, <code>--task-ids</code> picks tasks, and <code>--user-model</code> changes the simulated customer’s model. Each task uses a fresh <code>tau2_env</code> and a fresh Claude Code process.</p> <!--[1--><h2 class="relative group"><a id="serve-it-in-production-mode" 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="#serve-it-in-production-mode"><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>Serve It in Production Mode</span></h2><!--]--><!----> <p>The same harness can be served over the <code>WS /harness</code> route (<a href="../guides/simulation-vs-production">production mode</a>), so a person, or another application, talks to Claude Code with the environment’s tools behind it. Use it to try the agent by hand, debug a task, or put the agent in front of real users once the evaluation looks good. The server takes one connection at a time, each with a fresh Claude Code process and a fresh copy of the task’s database. <code>/harness</code> sends your messages straight to Claude Code, without the environment’s turn logic, so you play the customer and nothing is scored. The server has no authentication, and every connection spends your credentials, so keep it on localhost or behind your own auth:</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 "><!---->PYTHONPATH=src:envs:examples/claude_code_harness_eval \
python examples/claude_code_harness_eval/serve.py --domain airline --task-id 2 --port 8000
python examples/claude_code_harness_eval/chat.py ws://localhost:8000/harness \
<span class="hljs-string">&quot;Hi, I&#x27;m Noah Muller, user id noah_muller_9847. What reservations do I have?&quot;</span> \
<span class="hljs-string">&quot;Which of them has a delayed flight?&quot;</span><!----></pre></div><!----> <!--[2--><h3 class="relative group"><a id="serve-it-in-a-container" 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="#serve-it-in-a-container"><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>Serve It in a Container</span></h3><!--]--><!----> <p>RFC 005 runs the harness inside the environment’s container, apart from the machine that serves it. <a href="https://github.com/huggingface/OpenEnv/blob/main/examples/claude_code_harness_eval/Dockerfile" rel="nofollow"><code>examples/claude_code_harness_eval/Dockerfile</code></a> does that for this recipe: Claude Code, <code>tau2_env</code> and <code>serve.py</code> run together in one image, as a non-root user. Build it from the repository root and pass the credentials at run time:</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 "><!---->docker build -t claude-code-tau2 -f examples/claude_code_harness_eval/Dockerfile .
docker run -p 127.0.0.1:8000:8000 -e HF_TOKEN -e ANTHROPIC_API_KEY claude-code-tau2
python examples/claude_code_harness_eval/chat.py ws://localhost:8000/harness \
<span class="hljs-string">&quot;Hi, I&#x27;m Noah Muller, user id noah_muller_9847. What reservations do I have?&quot;</span><!----></pre></div><!----> <p>Use <code>-e CLAUDE_CODE_OAUTH_TOKEN</code> instead of <code>ANTHROPIC_API_KEY</code> to run on a Claude subscription (<code>claude setup-token</code> creates the token). Add <code>serve.py</code> arguments after the image name to pick the domain, task or model.</p> <!--[1--><h2 class="relative group"><a id="things-to-know" 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="#things-to-know"><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>Things to Know</span></h2><!--]--><!----> <ul><li>Claude Code adds today’s date to its context, while each τ²-bench policy states its own current time (airline is 2024-05-15). The agent prompt tells it to use the policy’s time. Without that line, it books flights in the wrong year.</li> <li>When the Anthropic API fails a request (for example <code>API Error: Connection dropped (ECONNRESET)</code>), the adapter ends the turn as a harness failure, so the step comes back with <code>done</code> and <code>error_type</code> <code>harness_crashed</code>, and <code>run_eval.py</code> reports the task as <code>ERROR</code> and leaves it out of pass^1. Rerun it. The same goes for the simulated customer: if its model fails, the step ends with <code>error_type</code> <code>customer_failed</code>, and the task is an <code>ERROR</code> rather than a failure of Claude Code.</li></ul> <!--[1--><h2 class="relative group"><a id="adapting-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="#adapting-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>Adapting It</span></h2><!--]--><!----> <ul><li><strong>Your own environment:</strong> pass your FastMCP tools as <code>mcp</code>, your instructions as the adapter’s <code>system_prompt</code>, and a <a href="rubrics">rubric</a> to <code>HarnessEnvironment</code> to score the episode.</li> <li><strong>Another model:</strong> <code>--model</code> accepts any model Claude Code does. <code>ANTHROPIC_BASE_URL</code> in <code>HarnessConfig.env_vars</code> points it at an Anthropic-compatible endpoint.</li> <li><strong>Another harness:</strong> write another <code>AgenticHarnessAdapter</code> in the same shape. Pick a headless multi-turn mode, pass <code>bridge_url</code> to its MCP config, and map its events.</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/tutorials/claude-code-harness.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_efhe5s = {
base: "/docs/openenv/pr_1285/en",
assets: "/docs/openenv/pr_1285/en"
};
const element = document.currentScript.parentElement;
Promise.all([
import("/docs/openenv/pr_1285/en/_app/immutable/entry/start.CG5FzNt2.js"),
import("/docs/openenv/pr_1285/en/_app/immutable/entry/app.Db-H8-tM.js")
]).then(([kit, app]) => {
kit.start(app, element, {
node_ids: [0, 64],
data: [null,null],
form: null,
error: null
});
});
}
</script>

Xet Storage Details

Size:
42.7 kB
·
Xet hash:
715781b06a237a5d44a155851b285f37f9f6f41251800a3190664fa3caea0a68

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.