Buckets:

HuggingFaceDocBuilder's picture
download
raw
58.7 kB
import{s as nt,n as at,o as pt}from"../chunks/scheduler.2b22cead.js";import{S as it,i as Mt,e as p,s as n,c as o,h as ot,a as i,d as s,b as a,f as ms,g as c,j as M,k as Se,l as Ts,m as t,n as y,t as r,o as d,p as m}from"../chunks/index.1a0e8013.js";import{C as ct,H as T}from"../chunks/Heading.0262ca46.js";import{C as J}from"../chunks/CodeBlock.98ef6f09.js";import{E as yt}from"../chunks/MermaidChart.svelte_svelte_type_style_lang.e23afded.js";function rt(Js){let j,$e,Qe,_e,b,He,v,Fe,I,js="<strong>Part 4 of 5</strong> in the OpenEnv Getting Started Series",ze,f,ws="This guide walks you through creating a custom environment using the <code>OpenEnv</code> framework and the <code>openenv</code> CLI.",Le,B,us="The CLI handles scaffolding, builds, validation, and deployment so you can stay focused on environment logic.",xe,w,Us='<p><strong>New to OpenEnv?</strong> If you’re just getting started, we recommend completing the <a href="../tutorials/index">Getting Started tutorials</a> first. They provide a conceptual introduction to OpenEnv and reinforcement learning fundamentals. This guide is for developers ready to build production-quality environments.</p>',qe,C,Oe,Z,hs="Already familiar with OpenEnv? Here’s the 8-step process at a glance:",De,k,bs="<thead><tr><th>Step</th> <th>Command / Action</th> <th>Description</th></tr></thead> <tbody><tr><td>1</td> <td><code>openenv init my_env</code></td> <td>Scaffold new environment</td></tr> <tr><td>2</td> <td>Edit <code>models.py</code></td> <td>Define Action &amp; Observation dataclasses</td></tr> <tr><td>3</td> <td>Edit <code>server/my_environment.py</code></td> <td>Implement <code>reset()</code> and <code>step()</code> methods</td></tr> <tr><td>4</td> <td>Edit <code>client.py</code></td> <td>Implement <code>_step_payload()</code>, <code>_parse_result()</code>, <code>_parse_state()</code></td></tr> <tr><td>5</td> <td><code>openenv serve</code></td> <td>Start local dev server for testing</td></tr> <tr><td>6</td> <td><code>openenv validate</code></td> <td>Validate environment structure</td></tr> <tr><td>7</td> <td><code>openenv push</code></td> <td>Deploy to Hugging Face Hub</td></tr> <tr><td>8</td> <td>Share the URL!</td> <td>Others use via <code>MyEnv.from_hub(&quot;you/my-env&quot;)</code></td></tr></tbody>",Pe,E,Ke,G,vs="<thead><tr><th>Command</th> <th>Description</th></tr></thead> <tbody><tr><td><code>openenv init NAME</code></td> <td>Scaffold new environment</td></tr> <tr><td><code>openenv serve</code></td> <td>Start local dev server</td></tr> <tr><td><code>openenv build</code></td> <td>Build Docker image</td></tr> <tr><td><code>openenv validate --verbose</code></td> <td>Validate environment structure</td></tr> <tr><td><code>openenv push</code></td> <td>Deploy to Hugging Face Hub</td></tr> <tr><td><code>openenv push --repo-id NAME</code></td> <td>Deploy to specific repo</td></tr> <tr><td><code>openenv push --private</code></td> <td>Deploy as private environment</td></tr> <tr><td><code>openenv push --registry ghcr.io/ORG</code></td> <td>Push to GitHub Container Registry</td></tr></tbody>",el,u,Is='<p>For a hands-on tutorial that builds a complete environment step-by-step, see <a href="../tutorials/index">Building Environments</a> in the Getting Started series.</p>',ll,sl,tl,A,nl,g,fs="A typical workflow looks like:",al,W,Bs="<li>Scaffold a new environment with <code>openenv init</code>.</li> <li>Customize your models, environment logic, and FastAPI server.</li> <li>Implement a typed <code>EnvClient</code> (WebSocket-based for persistent sessions).</li> <li>Configure dependencies and the Dockerfile once.</li> <li>Use the CLI (<code>openenv build</code>, <code>openenv validate</code>, <code>openenv push</code>) to package and share your work.</li>",pl,U,Cs="<p>These integrations are handled automatically by the <code>openenv</code> CLI when you run <code>openenv init</code>.</p>",il,R,Ml,X,Zs='<li>Python 3.11+ and <a href="https://github.com/astral-sh/uv" rel="nofollow"><code>uv</code></a> for dependency locking</li> <li>Docker Desktop / Docker Engine</li> <li>The OpenEnv library installed: <code>pip install https://github.com/huggingface/OpenEnv.git</code></li>',ol,V,cl,N,ks="Let’s walk through the process of building a custom environment with OpenEnv.",yl,Q,rl,Y,dl,S,Es="The command creates a fully-typed template with <code>openenv.yaml</code>, <code>pyproject.toml</code>, <code>uv.lock</code>, Docker assets, and stub implementations. If you’re working inside this repo, move the generated folder under <code>envs/</code>.",ml,$,Gs="Typical layout:",Tl,_,Jl,H,As="Python classes are generated for the action, observation, environment, and client. For example, you will find <code>MyEnvironment</code>, <code>MyAction</code>, <code>MyObservation</code>, and <code>MyEnv</code> (client) in the <code>my_env</code> directory based on the name you provided. The environment uses the core <code>State</code> class from <code>openenv.core.env_server.types</code>.",jl,F,wl,z,gs="Edit <code>models.py</code> to describe your action and observation using Pydantic:",ul,L,Ul,x,hl,q,Ws="Customize <code>server/my_environment.py</code> by extending <code>Environment</code>:",bl,O,vl,D,Il,P,Rs="<code>server/app.py</code> should expose the environment through <code>create_app</code>.",fl,K,Xs="<strong>Important:</strong> You must pass a class or factory function (not an instance) to enable WebSocket-based concurrent sessions:",Bl,ee,Cl,le,Vs="For environments with constructor arguments, create a factory function:",Zl,se,kl,te,El,ne,Ns="<code>client.py</code> extends <code>EnvClient</code> so users can interact with your server via WebSocket for persistent sessions:",Gl,ae,Al,pe,Qs="The <code>EnvClient</code> maintains a persistent WebSocket connection to the server, enabling efficient multi-step interactions with lower latency compared to HTTP. Each client instance gets its own dedicated environment session on the server.",gl,ie,Wl,Me,Ys="The CLI template ships with <code>pyproject.toml</code> and <code>server/Dockerfile</code>. You should manage your python dependencies with <code>uv</code> or <code>pip</code> in the <code>pyproject.toml</code> file. Other dependencies should be installed in the Dockerfile.",Rl,oe,Ss="Keep building from the <code>openenv-base</code> image so shared tooling stays available:",Xl,h,Ne,$s="Dockerfile",ds,ce,Vl,ye,_s="If you introduced extra dependencies in the Dockerfile, you should install them in the Dockerfile before removing temp files.",Nl,re,Ql,de,Hs="From the environment directory:",Yl,me,Sl,Te,Fs="<code>openenv build</code> understands both standalone environments and in-repo ones. Useful flags:",$l,Je,zs="<li><code>--tag/-t</code>: override the default <code>openenv-&lt;env_name&gt;</code> tag</li> <li><code>--build-arg KEY=VALUE</code>: pass multiple Docker build arguments</li> <li><code>--dockerfile</code> / <code>--context</code>: custom locations when experimenting</li> <li><code>--no-cache</code>: force fresh dependency installs</li>",_l,je,Ls="<code>openenv validate</code> checks for required files, ensures the Dockerfile/server entrypoints function, and lists supported deployment modes. The command exits non-zero if issues are found so you can wire it into CI.",Hl,we,Fl,ue,xs="Once validation passes, the CLI can deploy directly to Hugging Face Spaces or any registry:",zl,Ue,Ll,he,qs="Key options:",xl,be,Os="<li><code>--directory</code>: path to the environment (defaults to <code>cwd</code>)</li> <li><code>--repo-id</code>: explicit Hugging Face space name</li> <li><code>--registry</code>: push to Docker Hub, GHCR, etc.</li> <li><code>--interface/--no-interface</code>: toggle the optional web UI</li> <li><code>--base-image</code>: override the Dockerfile <code>FROM</code></li> <li><code>--private</code>: mark the space as private</li> <li><code>--env-var/-e KEY=VALUE</code>: set a public Space variable (repeatable); overrides matching keys from <code>variables:</code> in <code>openenv.yaml</code></li> <li><code>--secret KEY=VALUE</code>: set a private Space secret (repeatable); value is never logged</li>",ql,ve,Ds=`The command validates your <code>openenv.yaml</code>, injects Hugging Face frontmatter when needed, and uploads the prepared bundle.
Space variables and secrets are only applied on direct Hugging Face Space pushes;
they are not available for <code>--registry</code>, and they cannot be staged through
<code>--create-pr</code>.`,Ol,Ie,Dl,fe,Ps=`For defaults that belong with the environment (game name, benchmark, max
steps…), add a <code>variables:</code> block to <code>openenv.yaml</code>; <code>openenv push</code> will apply
them to the Space automatically:`,Pl,Be,Kl,Ce,Ks=`CLI <code>-e</code> overrides matching keys. Put secrets (API keys, tokens) <strong>only</strong> on
the CLI via <code>--secret KEY=VALUE</code> — never in the yaml.`,es,Ze,ls,ke,et="To trigger Docker builds on every push to <code>main</code>, add your environment to the matrix in <code>.github/workflows/docker-build.yml</code>:",ss,Ee,ts,Ge,ns,Ae,lt="Here is a simple example of using your environment:",as,ge,ps,We,is,Re,st="Your next steps are to:",Ms,Xe,tt='<li><a href="https://colab.research.google.com/github/huggingface/OpenEnv/blob/main/examples/OpenEnv_Tutorial.ipynb" rel="nofollow">Try out the end-to-end tutorial</a></li>',os,Ve,cs,Ye,ys;return b=new ct({props:{containerStyle:"float: right; margin-left: 10px; display: inline-flex; position: relative; z-index: 10;"}}),v=new T({props:{title:"Packaging & Deploying",local:"packaging--deploying",headingTag:"h1"}}),C=new T({props:{title:"Quick Reference Card",local:"quick-reference-card",headingTag:"h2"}}),E=new T({props:{title:"CLI Quick Reference",local:"cli-quick-reference",headingTag:"h3"}}),A=new T({props:{title:"Overview",local:"overview",headingTag:"h2"}}),R=new T({props:{title:"Prerequisites",local:"prerequisites",headingTag:"h3"}}),V=new T({props:{title:"Step-by-Step Guide",local:"step-by-step-guide",headingTag:"h2"}}),Q=new T({props:{title:"1. Scaffold with openenv init",local:"1-scaffold-with-openenv-init",headingTag:"h3"}}),Y=new J({props:{code:"JTIzJTIwUnVuJTIwZnJvbSUyMGFueXdoZXJlJTIwJUUyJTgwJTkzJTIwZGVmYXVsdHMlMjB0byUyMGN1cnJlbnQlMjBkaXJlY3RvcnklMEFvcGVuZW52JTIwaW5pdCUyMG15X2VudiUwQSUwQSUyMyUyME9wdGlvbmFsbHklMjBjaG9vc2UlMjBhbiUyMG91dHB1dCUyMGRpcmVjdG9yeSUwQW9wZW5lbnYlMjBpbml0JTIwbXlfZW52JTIwLS1vdXRwdXQtZGlyJTIwJTJGVXNlcnMlMkZ5b3UlMkZlbnZz",highlighted:`<span class="hljs-comment"># Run from anywhere – defaults to current directory</span>
openenv init my_env
<span class="hljs-comment"># Optionally choose an output directory</span>
openenv init my_env --output-dir /Users/you/envs`,lang:"bash",wrap:!1}}),_=new J({props:{code:"bXlfZW52JTJGJTBBJUUyJTk0JTlDJUUyJTk0JTgwJUUyJTk0JTgwJTIwX19pbml0X18ucHklMEElRTIlOTQlOUMlRTIlOTQlODAlRTIlOTQlODAlMjBSRUFETUUubWQlMEElRTIlOTQlOUMlRTIlOTQlODAlRTIlOTQlODAlMjBjbGllbnQucHklMEElRTIlOTQlOUMlRTIlOTQlODAlRTIlOTQlODAlMjBtb2RlbHMucHklMEElRTIlOTQlOUMlRTIlOTQlODAlRTIlOTQlODAlMjBvcGVuZW52LnlhbWwlMEElRTIlOTQlOUMlRTIlOTQlODAlRTIlOTQlODAlMjBweXByb2plY3QudG9tbCUwQSVFMiU5NCU5QyVFMiU5NCU4MCVFMiU5NCU4MCUyMHV2LmxvY2slMEElRTIlOTQlOTQlRTIlOTQlODAlRTIlOTQlODAlMjBzZXJ2ZXIlMkYlMEElMjAlMjAlMjAlMjAlRTIlOTQlOUMlRTIlOTQlODAlRTIlOTQlODAlMjBfX2luaXRfXy5weSUwQSUyMCUyMCUyMCUyMCVFMiU5NCU5QyVFMiU5NCU4MCVFMiU5NCU4MCUyMGFwcC5weSUwQSUyMCUyMCUyMCUyMCVFMiU5NCU5QyVFMiU5NCU4MCVFMiU5NCU4MCUyMG15X2Vudmlyb25tZW50LnB5JTBBJTIwJTIwJTIwJTIwJUUyJTk0JTlDJUUyJTk0JTgwJUUyJTk0JTgwJTIwcmVxdWlyZW1lbnRzLnR4dCUwQSUyMCUyMCUyMCUyMCVFMiU5NCU5NCVFMiU5NCU4MCVFMiU5NCU4MCUyMERvY2tlcmZpbGU=",highlighted:`my_env/
├── __init__<span class="hljs-selector-class">.py</span>
├── README<span class="hljs-selector-class">.md</span>
├── client<span class="hljs-selector-class">.py</span>
├── models<span class="hljs-selector-class">.py</span>
├── openenv<span class="hljs-selector-class">.yaml</span>
├── pyproject<span class="hljs-selector-class">.toml</span>
├── uv<span class="hljs-selector-class">.lock</span>
└── server/
├── __init__<span class="hljs-selector-class">.py</span>
├── app<span class="hljs-selector-class">.py</span>
├── my_environment<span class="hljs-selector-class">.py</span>
├── requirements<span class="hljs-selector-class">.txt</span>
└── Dockerfile`,lang:"",wrap:!1}}),F=new T({props:{title:"2. Define Models",local:"2-define-models",headingTag:"h3"}}),L=new J({props:{code:"JTIzJTIwbW9kZWxzLnB5JTBBZnJvbSUyMHB5ZGFudGljJTIwaW1wb3J0JTIwRmllbGQlMEFmcm9tJTIwb3BlbmVudi5jb3JlLmVudl9zZXJ2ZXIudHlwZXMlMjBpbXBvcnQlMjBBY3Rpb24lMkMlMjBPYnNlcnZhdGlvbiUwQSUwQWNsYXNzJTIwTXlBY3Rpb24oQWN0aW9uKSUzQSUwQSUyMCUyMCUyMCUyMCUyMiUyMiUyMllvdXIlMjBjdXN0b20lMjBhY3Rpb24uJTIyJTIyJTIyJTBBJTIwJTIwJTIwJTIwY29tbWFuZCUzQSUyMHN0ciUyMCUzRCUyMEZpZWxkKC4uLiUyQyUyMGRlc2NyaXB0aW9uJTNEJTIyQ29tbWFuZCUyMHRvJTIwZXhlY3V0ZSUyMiklMEElMjAlMjAlMjAlMjBwYXJhbWV0ZXJzJTNBJTIwZGljdCUyMCUzRCUyMEZpZWxkKGRlZmF1bHRfZmFjdG9yeSUzRGRpY3QlMkMlMjBkZXNjcmlwdGlvbiUzRCUyMkNvbW1hbmQlMjBwYXJhbWV0ZXJzJTIyKSUwQSUwQWNsYXNzJTIwTXlPYnNlcnZhdGlvbihPYnNlcnZhdGlvbiklM0ElMEElMjAlMjAlMjAlMjAlMjIlMjIlMjJZb3VyJTIwY3VzdG9tJTIwb2JzZXJ2YXRpb24uJTIyJTIyJTIyJTBBJTIwJTIwJTIwJTIwcmVzdWx0JTNBJTIwc3RyJTIwJTNEJTIwRmllbGQoLi4uJTJDJTIwZGVzY3JpcHRpb24lM0QlMjJSZXN1bHQlMjBvZiUyMHRoZSUyMGFjdGlvbiUyMiklMEElMjAlMjAlMjAlMjBzdWNjZXNzJTNBJTIwYm9vbCUyMCUzRCUyMEZpZWxkKC4uLiUyQyUyMGRlc2NyaXB0aW9uJTNEJTIyV2hldGhlciUyMHRoZSUyMGFjdGlvbiUyMHN1Y2NlZWRlZCUyMik=",highlighted:`<span class="hljs-comment"># models.py</span>
<span class="hljs-keyword">from</span> pydantic <span class="hljs-keyword">import</span> Field
<span class="hljs-keyword">from</span> openenv.core.env_server.types <span class="hljs-keyword">import</span> Action, Observation
<span class="hljs-keyword">class</span> <span class="hljs-title class_">MyAction</span>(<span class="hljs-title class_ inherited__">Action</span>):
<span class="hljs-string">&quot;&quot;&quot;Your custom action.&quot;&quot;&quot;</span>
command: <span class="hljs-built_in">str</span> = Field(..., description=<span class="hljs-string">&quot;Command to execute&quot;</span>)
parameters: <span class="hljs-built_in">dict</span> = Field(default_factory=<span class="hljs-built_in">dict</span>, description=<span class="hljs-string">&quot;Command parameters&quot;</span>)
<span class="hljs-keyword">class</span> <span class="hljs-title class_">MyObservation</span>(<span class="hljs-title class_ inherited__">Observation</span>):
<span class="hljs-string">&quot;&quot;&quot;Your custom observation.&quot;&quot;&quot;</span>
result: <span class="hljs-built_in">str</span> = Field(..., description=<span class="hljs-string">&quot;Result of the action&quot;</span>)
success: <span class="hljs-built_in">bool</span> = Field(..., description=<span class="hljs-string">&quot;Whether the action succeeded&quot;</span>)`,lang:"python",wrap:!1}}),x=new T({props:{title:"3. Implement Environment Logic",local:"3-implement-environment-logic",headingTag:"h3"}}),O=new J({props:{code:"JTIzJTIwc2VydmVyJTJGbXlfZW52aXJvbm1lbnQucHklMEFmcm9tJTIwdXVpZCUyMGltcG9ydCUyMHV1aWQ0JTBBZnJvbSUyMG9wZW5lbnYuY29yZS5lbnZfc2VydmVyLmludGVyZmFjZXMlMjBpbXBvcnQlMjBFbnZpcm9ubWVudCUwQWZyb20lMjBvcGVuZW52LmNvcmUuZW52X3NlcnZlci50eXBlcyUyMGltcG9ydCUyMFN0YXRlJTBBZnJvbSUyMG1vZGVscyUyMGltcG9ydCUyME15QWN0aW9uJTJDJTIwTXlPYnNlcnZhdGlvbiUwQSUwQWNsYXNzJTIwTXlFbnZpcm9ubWVudChFbnZpcm9ubWVudCklM0ElMEElMjAlMjAlMjAlMjBkZWYlMjBfX2luaXRfXyhzZWxmKSUzQSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMHNlbGYuX3N0YXRlJTIwJTNEJTIwU3RhdGUoZXBpc29kZV9pZCUzRHN0cih1dWlkNCgpKSUyQyUyMHN0ZXBfY291bnQlM0QwKSUwQSUwQSUyMCUyMCUyMCUyMGRlZiUyMHJlc2V0KHNlbGYpJTIwLSUzRSUyME15T2JzZXJ2YXRpb24lM0ElMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjBzZWxmLl9zdGF0ZSUyMCUzRCUyMFN0YXRlKGVwaXNvZGVfaWQlM0RzdHIodXVpZDQoKSklMkMlMjBzdGVwX2NvdW50JTNEMCklMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjByZXR1cm4lMjBNeU9ic2VydmF0aW9uKHJlc3VsdCUzRCUyMlJlYWR5JTIyJTJDJTIwc3VjY2VzcyUzRFRydWUlMkMlMjBkb25lJTNERmFsc2UlMkMlMjByZXdhcmQlM0QwLjApJTBBJTBBJTIwJTIwJTIwJTIwZGVmJTIwc3RlcChzZWxmJTJDJTIwYWN0aW9uJTNBJTIwTXlBY3Rpb24pJTIwLSUzRSUyME15T2JzZXJ2YXRpb24lM0ElMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjMlMjBJbXBsZW1lbnQlMjB5b3VyJTIwbG9naWMlMjBoZXJlJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwc2VsZi5fc3RhdGUuc3RlcF9jb3VudCUyMCUyQiUzRCUyMDElMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjByZXN1bHQlMjAlM0QlMjBzZWxmLl9leGVjdXRlX2NvbW1hbmQoYWN0aW9uLmNvbW1hbmQpJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwcmV0dXJuJTIwTXlPYnNlcnZhdGlvbihyZXN1bHQlM0RyZXN1bHQlMkMlMjBzdWNjZXNzJTNEVHJ1ZSUyQyUyMGRvbmUlM0RGYWxzZSUyQyUyMHJld2FyZCUzRDEuMCklMEElMEElMjAlMjAlMjAlMjAlNDBwcm9wZXJ0eSUwQSUyMCUyMCUyMCUyMGRlZiUyMHN0YXRlKHNlbGYpJTIwLSUzRSUyMFN0YXRlJTNBJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwcmV0dXJuJTIwc2VsZi5fc3RhdGU=",highlighted:`<span class="hljs-comment"># server/my_environment.py</span>
<span class="hljs-keyword">from</span> uuid <span class="hljs-keyword">import</span> uuid4
<span class="hljs-keyword">from</span> openenv.core.env_server.interfaces <span class="hljs-keyword">import</span> Environment
<span class="hljs-keyword">from</span> openenv.core.env_server.types <span class="hljs-keyword">import</span> State
<span class="hljs-keyword">from</span> models <span class="hljs-keyword">import</span> MyAction, MyObservation
<span class="hljs-keyword">class</span> <span class="hljs-title class_">MyEnvironment</span>(<span class="hljs-title class_ inherited__">Environment</span>):
<span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self</span>):
self._state = State(episode_id=<span class="hljs-built_in">str</span>(uuid4()), step_count=<span class="hljs-number">0</span>)
<span class="hljs-keyword">def</span> <span class="hljs-title function_">reset</span>(<span class="hljs-params">self</span>) -&gt; MyObservation:
self._state = State(episode_id=<span class="hljs-built_in">str</span>(uuid4()), step_count=<span class="hljs-number">0</span>)
<span class="hljs-keyword">return</span> MyObservation(result=<span class="hljs-string">&quot;Ready&quot;</span>, success=<span class="hljs-literal">True</span>, done=<span class="hljs-literal">False</span>, reward=<span class="hljs-number">0.0</span>)
<span class="hljs-keyword">def</span> <span class="hljs-title function_">step</span>(<span class="hljs-params">self, action: MyAction</span>) -&gt; MyObservation:
<span class="hljs-comment"># Implement your logic here</span>
self._state.step_count += <span class="hljs-number">1</span>
result = self._execute_command(action.command)
<span class="hljs-keyword">return</span> MyObservation(result=result, success=<span class="hljs-literal">True</span>, done=<span class="hljs-literal">False</span>, reward=<span class="hljs-number">1.0</span>)
<span class="hljs-meta"> @property</span>
<span class="hljs-keyword">def</span> <span class="hljs-title function_">state</span>(<span class="hljs-params">self</span>) -&gt; State:
<span class="hljs-keyword">return</span> self._state`,lang:"python",wrap:!1}}),D=new T({props:{title:"4. Create the FastAPI Server",local:"4-create-the-fastapi-server",headingTag:"h3"}}),ee=new J({props:{code:"JTIzJTIwc2VydmVyJTJGYXBwLnB5JTBBZnJvbSUyMG9wZW5lbnYuY29yZS5lbnZfc2VydmVyJTIwaW1wb3J0JTIwY3JlYXRlX2FwcCUwQWZyb20lMjAuLm1vZGVscyUyMGltcG9ydCUyME15QWN0aW9uJTJDJTIwTXlPYnNlcnZhdGlvbiUwQWZyb20lMjAubXlfZW52aXJvbm1lbnQlMjBpbXBvcnQlMjBNeUVudmlyb25tZW50JTBBJTBBJTIzJTIwUGFzcyUyMHRoZSUyMGNsYXNzJTIwKGZhY3RvcnkpJTIwLSUyMGVhY2glMjBXZWJTb2NrZXQlMjBzZXNzaW9uJTIwZ2V0cyUyMGl0cyUyMG93biUyMGluc3RhbmNlJTBBYXBwJTIwJTNEJTIwY3JlYXRlX2FwcChNeUVudmlyb25tZW50JTJDJTIwTXlBY3Rpb24lMkMlMjBNeU9ic2VydmF0aW9uJTJDJTIwZW52X25hbWUlM0QlMjJteV9lbnYlMjIp",highlighted:`<span class="hljs-comment"># server/app.py</span>
<span class="hljs-keyword">from</span> openenv.core.env_server <span class="hljs-keyword">import</span> create_app
<span class="hljs-keyword">from</span> ..models <span class="hljs-keyword">import</span> MyAction, MyObservation
<span class="hljs-keyword">from</span> .my_environment <span class="hljs-keyword">import</span> MyEnvironment
<span class="hljs-comment"># Pass the class (factory) - each WebSocket session gets its own instance</span>
app = create_app(MyEnvironment, MyAction, MyObservation, env_name=<span class="hljs-string">&quot;my_env&quot;</span>)`,lang:"python",wrap:!1}}),se=new J({props:{code:"JTIzJTIwc2VydmVyJTJGYXBwLnB5JTBBaW1wb3J0JTIwb3MlMEFmcm9tJTIwb3BlbmVudi5jb3JlLmVudl9zZXJ2ZXIlMjBpbXBvcnQlMjBjcmVhdGVfYXBwJTBBZnJvbSUyMC4ubW9kZWxzJTIwaW1wb3J0JTIwTXlBY3Rpb24lMkMlMjBNeU9ic2VydmF0aW9uJTBBZnJvbSUyMC5teV9lbnZpcm9ubWVudCUyMGltcG9ydCUyME15RW52aXJvbm1lbnQlMEElMEElMjMlMjBSZWFkJTIwY29uZmlnJTIwZnJvbSUyMGVudmlyb25tZW50JTIwdmFyaWFibGVzJTBBYXBpX2tleSUyMCUzRCUyMG9zLmdldGVudiglMjJNWV9BUElfS0VZJTIyKSUwQXRpbWVvdXQlMjAlM0QlMjBpbnQob3MuZ2V0ZW52KCUyMk1ZX1RJTUVPVVQlMjIlMkMlMjAlMjIzMCUyMikpJTBBJTBBZGVmJTIwY3JlYXRlX215X2Vudmlyb25tZW50KCklM0ElMEElMjAlMjAlMjAlMjAlMjIlMjIlMjJGYWN0b3J5JTIwZnVuY3Rpb24lMjB0aGF0JTIwY3JlYXRlcyUyME15RW52aXJvbm1lbnQlMjB3aXRoJTIwY29uZmlnLiUyMiUyMiUyMiUwQSUyMCUyMCUyMCUyMHJldHVybiUyME15RW52aXJvbm1lbnQoYXBpX2tleSUzRGFwaV9rZXklMkMlMjB0aW1lb3V0JTNEdGltZW91dCklMEElMEElMjMlMjBQYXNzJTIwdGhlJTIwZmFjdG9yeSUyMGZ1bmN0aW9uJTBBYXBwJTIwJTNEJTIwY3JlYXRlX2FwcChjcmVhdGVfbXlfZW52aXJvbm1lbnQlMkMlMjBNeUFjdGlvbiUyQyUyME15T2JzZXJ2YXRpb24lMkMlMjBlbnZfbmFtZSUzRCUyMm15X2VudiUyMik=",highlighted:`<span class="hljs-comment"># server/app.py</span>
<span class="hljs-keyword">import</span> os
<span class="hljs-keyword">from</span> openenv.core.env_server <span class="hljs-keyword">import</span> create_app
<span class="hljs-keyword">from</span> ..models <span class="hljs-keyword">import</span> MyAction, MyObservation
<span class="hljs-keyword">from</span> .my_environment <span class="hljs-keyword">import</span> MyEnvironment
<span class="hljs-comment"># Read config from environment variables</span>
api_key = os.getenv(<span class="hljs-string">&quot;MY_API_KEY&quot;</span>)
timeout = <span class="hljs-built_in">int</span>(os.getenv(<span class="hljs-string">&quot;MY_TIMEOUT&quot;</span>, <span class="hljs-string">&quot;30&quot;</span>))
<span class="hljs-keyword">def</span> <span class="hljs-title function_">create_my_environment</span>():
<span class="hljs-string">&quot;&quot;&quot;Factory function that creates MyEnvironment with config.&quot;&quot;&quot;</span>
<span class="hljs-keyword">return</span> MyEnvironment(api_key=api_key, timeout=timeout)
<span class="hljs-comment"># Pass the factory function</span>
app = create_app(create_my_environment, MyAction, MyObservation, env_name=<span class="hljs-string">&quot;my_env&quot;</span>)`,lang:"python",wrap:!1}}),te=new T({props:{title:"5. Implement the Client",local:"5-implement-the-client",headingTag:"h3"}}),ae=new J({props:{code:"JTIzJTIwY2xpZW50LnB5JTBBZnJvbSUyMG9wZW5lbnYuY29yZS5lbnZfY2xpZW50JTIwaW1wb3J0JTIwRW52Q2xpZW50JTBBZnJvbSUyMG9wZW5lbnYuY29yZS5jbGllbnRfdHlwZXMlMjBpbXBvcnQlMjBTdGVwUmVzdWx0JTBBZnJvbSUyMC5tb2RlbHMlMjBpbXBvcnQlMjBNeUFjdGlvbiUyQyUyME15T2JzZXJ2YXRpb24lMkMlMjBNeVN0YXRlJTBBJTBBY2xhc3MlMjBNeUVudihFbnZDbGllbnQlNUJNeUFjdGlvbiUyQyUyME15T2JzZXJ2YXRpb24lMkMlMjBNeVN0YXRlJTVEKSUzQSUwQSUyMCUyMCUyMCUyMGRlZiUyMF9zdGVwX3BheWxvYWQoc2VsZiUyQyUyMGFjdGlvbiUzQSUyME15QWN0aW9uKSUyMC0lM0UlMjBkaWN0JTNBJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwcmV0dXJuJTIwJTdCJTIyY29tbWFuZCUyMiUzQSUyMGFjdGlvbi5jb21tYW5kJTJDJTIwJTIycGFyYW1ldGVycyUyMiUzQSUyMGFjdGlvbi5wYXJhbWV0ZXJzJTdEJTBBJTBBJTIwJTIwJTIwJTIwZGVmJTIwX3BhcnNlX3Jlc3VsdChzZWxmJTJDJTIwcGF5bG9hZCUzQSUyMGRpY3QpJTIwLSUzRSUyMFN0ZXBSZXN1bHQlNUJNeU9ic2VydmF0aW9uJTVEJTNBJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwb2JzX2RhdGElMjAlM0QlMjBwYXlsb2FkLmdldCglMjJvYnNlcnZhdGlvbiUyMiUyQyUyMCU3QiU3RCklMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjBvYnMlMjAlM0QlMjBNeU9ic2VydmF0aW9uKCUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMHJlc3VsdCUzRG9ic19kYXRhLmdldCglMjJyZXN1bHQlMjIlMkMlMjAlMjIlMjIpJTJDJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwc3VjY2VzcyUzRG9ic19kYXRhLmdldCglMjJzdWNjZXNzJTIyJTJDJTIwRmFsc2UpJTJDJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwZG9uZSUzRHBheWxvYWQuZ2V0KCUyMmRvbmUlMjIlMkMlMjBGYWxzZSklMkMlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjByZXdhcmQlM0RwYXlsb2FkLmdldCglMjJyZXdhcmQlMjIpJTJDJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwKSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMHJldHVybiUyMFN0ZXBSZXN1bHQoJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwb2JzZXJ2YXRpb24lM0RvYnMlMkMlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjByZXdhcmQlM0RwYXlsb2FkLmdldCglMjJyZXdhcmQlMjIpJTJDJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwZG9uZSUzRHBheWxvYWQuZ2V0KCUyMmRvbmUlMjIlMkMlMjBGYWxzZSklMkMlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjApJTBBJTBBJTIwJTIwJTIwJTIwZGVmJTIwX3BhcnNlX3N0YXRlKHNlbGYlMkMlMjBwYXlsb2FkJTNBJTIwZGljdCklMjAtJTNFJTIwU3RhdGUlM0ElMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjByZXR1cm4lMjBTdGF0ZSglMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjBlcGlzb2RlX2lkJTNEcGF5bG9hZC5nZXQoJTIyZXBpc29kZV9pZCUyMiklMkMlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjBzdGVwX2NvdW50JTNEcGF5bG9hZC5nZXQoJTIyc3RlcF9jb3VudCUyMiUyQyUyMDApJTJDJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwKQ==",highlighted:`<span class="hljs-comment"># client.py</span>
<span class="hljs-keyword">from</span> openenv.core.env_client <span class="hljs-keyword">import</span> EnvClient
<span class="hljs-keyword">from</span> openenv.core.client_types <span class="hljs-keyword">import</span> StepResult
<span class="hljs-keyword">from</span> .models <span class="hljs-keyword">import</span> MyAction, MyObservation, MyState
<span class="hljs-keyword">class</span> <span class="hljs-title class_">MyEnv</span>(EnvClient[MyAction, MyObservation, MyState]):
<span class="hljs-keyword">def</span> <span class="hljs-title function_">_step_payload</span>(<span class="hljs-params">self, action: MyAction</span>) -&gt; <span class="hljs-built_in">dict</span>:
<span class="hljs-keyword">return</span> {<span class="hljs-string">&quot;command&quot;</span>: action.command, <span class="hljs-string">&quot;parameters&quot;</span>: action.parameters}
<span class="hljs-keyword">def</span> <span class="hljs-title function_">_parse_result</span>(<span class="hljs-params">self, payload: <span class="hljs-built_in">dict</span></span>) -&gt; StepResult[MyObservation]:
obs_data = payload.get(<span class="hljs-string">&quot;observation&quot;</span>, {})
obs = MyObservation(
result=obs_data.get(<span class="hljs-string">&quot;result&quot;</span>, <span class="hljs-string">&quot;&quot;</span>),
success=obs_data.get(<span class="hljs-string">&quot;success&quot;</span>, <span class="hljs-literal">False</span>),
done=payload.get(<span class="hljs-string">&quot;done&quot;</span>, <span class="hljs-literal">False</span>),
reward=payload.get(<span class="hljs-string">&quot;reward&quot;</span>),
)
<span class="hljs-keyword">return</span> StepResult(
observation=obs,
reward=payload.get(<span class="hljs-string">&quot;reward&quot;</span>),
done=payload.get(<span class="hljs-string">&quot;done&quot;</span>, <span class="hljs-literal">False</span>),
)
<span class="hljs-keyword">def</span> <span class="hljs-title function_">_parse_state</span>(<span class="hljs-params">self, payload: <span class="hljs-built_in">dict</span></span>) -&gt; State:
<span class="hljs-keyword">return</span> State(
episode_id=payload.get(<span class="hljs-string">&quot;episode_id&quot;</span>),
step_count=payload.get(<span class="hljs-string">&quot;step_count&quot;</span>, <span class="hljs-number">0</span>),
)`,lang:"python",wrap:!1}}),ie=new T({props:{title:"6. Configure Dependencies & Dockerfile",local:"6-configure-dependencies--dockerfile",headingTag:"h3"}}),ce=new J({props:{code:"JTIzJTIwQ29weXJpZ2h0JTIwKGMpJTIwTWV0YSUyMFBsYXRmb3JtcyUyQyUyMEluYy4lMjBhbmQlMjBhZmZpbGlhdGVzLiUwQSUyMyUyMEFsbCUyMHJpZ2h0cyUyMHJlc2VydmVkLiUwQSUyMyUwQSUyMyUyMFRoaXMlMjBzb3VyY2UlMjBjb2RlJTIwaXMlMjBsaWNlbnNlZCUyMHVuZGVyJTIwdGhlJTIwQlNELXN0eWxlJTIwbGljZW5zZSUyMGZvdW5kJTIwaW4lMjB0aGUlMEElMjMlMjBMSUNFTlNFJTIwZmlsZSUyMGluJTIwdGhlJTIwcm9vdCUyMGRpcmVjdG9yeSUyMG9mJTIwdGhpcyUyMHNvdXJjZSUyMHRyZWUuJTBBJTBBJTIzJTIwTXVsdGktc3RhZ2UlMjBidWlsZCUyMHVzaW5nJTIwb3BlbmVudi1iYXNlJTBBJTIzJTIwVGhpcyUyMERvY2tlcmZpbGUlMjBpcyUyMGZsZXhpYmxlJTIwYW5kJTIwd29ya3MlMjBmb3IlMjBib3RoJTNBJTBBJTIzJTIwLSUyMEluLXJlcG8lMjBlbnZpcm9ubWVudHMlMjAod2l0aCUyMGxvY2FsJTIwc3JjJTJGY29yZSklMEElMjMlMjAtJTIwU3RhbmRhbG9uZSUyMGVudmlyb25tZW50cyUyMCh3aXRoJTIwb3BlbmVudiUyMGZyb20lMjBwaXApJTBBJTIzJTIwVGhlJTIwYnVpbGQlMjBzY3JpcHQlMjAob3BlbmVudiUyMGJ1aWxkKSUyMGhhbmRsZXMlMjBjb250ZXh0JTIwZGV0ZWN0aW9uJTIwYW5kJTIwc2V0cyUyMGFwcHJvcHJpYXRlJTIwYnVpbGQlMjBhcmdzLiUwQSUwQUFSRyUyMEJBU0VfSU1BR0UlM0RvcGVuZW52LWJhc2UlM0FsYXRlc3QlMEFGUk9NJTIwJTI0JTdCQkFTRV9JTUFHRSU3RCUyMEFTJTIwYnVpbGRlciUwQSUwQVdPUktESVIlMjAlMkZhcHAlMEElMEElMjMlMjBCdWlsZCUyMGFyZ3VtZW50JTIwdG8lMjBjb250cm9sJTIwd2hldGhlciUyMHdlJ3JlJTIwYnVpbGRpbmclMjBzdGFuZGFsb25lJTIwb3IlMjBpbi1yZXBvJTBBQVJHJTIwQlVJTERfTU9ERSUzRGluLXJlcG8lMEFBUkclMjBFTlZfTkFNRSUzRF9fRU5WX05BTUVfXyUwQSUwQSUyMyUyMENvcHklMjBlbnZpcm9ubWVudCUyMGNvZGUlMjAoYWx3YXlzJTIwYXQlMjByb290JTIwb2YlMjBidWlsZCUyMGNvbnRleHQpJTBBQ09QWSUyMC4lMjAlMkZhcHAlMkZlbnYlMEElMEElMjMlMjBGb3IlMjBpbi1yZXBvJTIwYnVpbGRzJTJDJTIwb3BlbmVudiUyMGlzJTIwYWxyZWFkeSUyMGluJTIwdGhlJTIwcHlwcm9qZWN0LnRvbWwlMjBkZXBlbmRlbmNpZXMlMEElMjMlMjBGb3IlMjBzdGFuZGFsb25lJTIwYnVpbGRzJTJDJTIwb3BlbmVudiUyMHdpbGwlMjBiZSUyMGluc3RhbGxlZCUyMGZyb20lMjBwaXAlMjB2aWElMjBweXByb2plY3QudG9tbCUwQVdPUktESVIlMjAlMkZhcHAlMkZlbnYlMEElMEElMjMlMjBJbnN0YWxsJTIwZGVwZW5kZW5jaWVzJTIwdXNpbmclMjB1diUyMHN5bmMlMEElMjMlMjBJZiUyMHV2LmxvY2slMjBleGlzdHMlMkMlMjB1c2UlMjBpdCUzQiUyMG90aGVyd2lzZSUyMHJlc29sdmUlMjBvbiUyMHRoZSUyMGZseSUwQVJVTiUyMC0tbW91bnQlM0R0eXBlJTNEY2FjaGUlMkN0YXJnZXQlM0QlMkZyb290JTJGLmNhY2hlJTJGdXYlMjAlNUMlMEElMjAlMjAlMjAlMjBpZiUyMCU1QiUyMC1mJTIwdXYubG9jayUyMCU1RCUzQiUyMHRoZW4lMjAlNUMlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjB1diUyMHN5bmMlMjAtLWZyb3plbiUyMC0tbm8taW5zdGFsbC1wcm9qZWN0JTIwLS1uby1lZGl0YWJsZSUzQiUyMCU1QyUwQSUyMCUyMCUyMCUyMGVsc2UlMjAlNUMlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjB1diUyMHN5bmMlMjAtLW5vLWluc3RhbGwtcHJvamVjdCUyMC0tbm8tZWRpdGFibGUlM0IlMjAlNUMlMEElMjAlMjAlMjAlMjBmaSUwQSUwQVJVTiUyMC0tbW91bnQlM0R0eXBlJTNEY2FjaGUlMkN0YXJnZXQlM0QlMkZyb290JTJGLmNhY2hlJTJGdXYlMjAlNUMlMEElMjAlMjAlMjAlMjBpZiUyMCU1QiUyMC1mJTIwdXYubG9jayUyMCU1RCUzQiUyMHRoZW4lMjAlNUMlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjB1diUyMHN5bmMlMjAtLWZyb3plbiUyMC0tbm8tZWRpdGFibGUlM0IlMjAlNUMlMEElMjAlMjAlMjAlMjBlbHNlJTIwJTVDJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwdXYlMjBzeW5jJTIwLS1uby1lZGl0YWJsZSUzQiUyMCU1QyUwQSUyMCUyMCUyMCUyMGZpJTBBJTBBJTIzJTIwRmluYWwlMjBydW50aW1lJTIwc3RhZ2UlMEFGUk9NJTIwJTI0JTdCQkFTRV9JTUFHRSU3RCUwQSUwQVdPUktESVIlMjAlMkZhcHAlMEElMEElMjMlMjBDb3B5JTIwdGhlJTIwdmlydHVhbCUyMGVudmlyb25tZW50JTIwZnJvbSUyMGJ1aWxkZXIlMEFDT1BZJTIwLS1mcm9tJTNEYnVpbGRlciUyMCUyRmFwcCUyRmVudiUyRi52ZW52JTIwJTJGYXBwJTJGLnZlbnYlMEElMEElMjMlMjBDb3B5JTIwdGhlJTIwZW52aXJvbm1lbnQlMjBjb2RlJTBBQ09QWSUyMC0tZnJvbSUzRGJ1aWxkZXIlMjAlMkZhcHAlMkZlbnYlMjAlMkZhcHAlMkZlbnYlMEElMEElMjMlMjBTZXQlMjBQQVRIJTIwdG8lMjB1c2UlMjB0aGUlMjB2aXJ0dWFsJTIwZW52aXJvbm1lbnQlMEFFTlYlMjBQQVRIJTNEJTIyJTJGYXBwJTJGLnZlbnYlMkZiaW4lM0ElMjRQQVRIJTIyJTBBJTBBJTIzJTIwU2V0JTIwUFlUSE9OUEFUSCUyMHNvJTIwaW1wb3J0cyUyMHdvcmslMjBjb3JyZWN0bHklMEFFTlYlMjBQWVRIT05QQVRIJTNEJTIyJTJGYXBwJTJGZW52JTNBJTI0UFlUSE9OUEFUSCUyMiUwQSUwQSUyMyUyMEhlYWx0aCUyMGNoZWNrJTBBSEVBTFRIQ0hFQ0slMjAtLWludGVydmFsJTNEMzBzJTIwLS10aW1lb3V0JTNEM3MlMjAtLXN0YXJ0LXBlcmlvZCUzRDVzJTIwLS1yZXRyaWVzJTNEMyUyMCU1QyUwQSUyMCUyMCUyMCUyMENNRCUyMGN1cmwlMjAtZiUyMGh0dHAlM0ElMkYlMkZsb2NhbGhvc3QlM0E4MDAwJTJGaGVhbHRoJTIwJTdDJTdDJTIwZXhpdCUyMDElMEElMEElMjMlMjBSdW4lMjB0aGUlMjBGYXN0QVBJJTIwc2VydmVyJTBBJTIzJTIwVGhlJTIwbW9kdWxlJTIwcGF0aCUyMGlzJTIwY29uc3RydWN0ZWQlMjB0byUyMHdvcmslMjB3aXRoJTIwdGhlJTIwJTJGYXBwJTJGZW52JTIwc3RydWN0dXJlJTBBQ01EJTIwJTVCJTIyc2glMjIlMkMlMjAlMjItYyUyMiUyQyUyMCUyMmNkJTIwJTJGYXBwJTJGZW52JTIwJTI2JTI2JTIwdXZpY29ybiUyMHNlcnZlci5hcHAlM0FhcHAlMjAtLWhvc3QlMjAwLjAuMC4wJTIwLS1wb3J0JTIwODAwMCUyMiU1RCUwQQ==",highlighted:`<span class="hljs-comment"># Copyright (c) Meta Platforms, Inc. and affiliates.</span>
<span class="hljs-comment"># All rights reserved.</span>
<span class="hljs-comment">#</span>
<span class="hljs-comment"># This source code is licensed under the BSD-style license found in the</span>
<span class="hljs-comment"># LICENSE file in the root directory of this source tree.</span>
<span class="hljs-comment"># Multi-stage build using openenv-base</span>
<span class="hljs-comment"># This Dockerfile is flexible and works for both:</span>
<span class="hljs-comment"># - In-repo environments (with local src/core)</span>
<span class="hljs-comment"># - Standalone environments (with openenv from pip)</span>
<span class="hljs-comment"># The build script (openenv build) handles context detection and sets appropriate build args.</span>
<span class="hljs-keyword">ARG</span> BASE_IMAGE=openenv-base:latest
<span class="hljs-keyword">FROM</span> \${BASE_IMAGE} AS builder
<span class="hljs-keyword">WORKDIR</span><span class="language-bash"> /app</span>
<span class="hljs-comment"># Build argument to control whether we&#x27;re building standalone or in-repo</span>
<span class="hljs-keyword">ARG</span> BUILD_MODE=in-repo
<span class="hljs-keyword">ARG</span> ENV_NAME=__ENV_NAME__
<span class="hljs-comment"># Copy environment code (always at root of build context)</span>
<span class="hljs-keyword">COPY</span><span class="language-bash"> . /app/env</span>
<span class="hljs-comment"># For in-repo builds, openenv is already in the pyproject.toml dependencies</span>
<span class="hljs-comment"># For standalone builds, openenv will be installed from pip via pyproject.toml</span>
<span class="hljs-keyword">WORKDIR</span><span class="language-bash"> /app/env</span>
<span class="hljs-comment"># Install dependencies using uv sync</span>
<span class="hljs-comment"># If uv.lock exists, use it; otherwise resolve on the fly</span>
<span class="hljs-keyword">RUN</span><span class="language-bash"> --mount=<span class="hljs-built_in">type</span>=cache,target=/root/.cache/uv \\
<span class="hljs-keyword">if</span> [ -f uv.lock ]; <span class="hljs-keyword">then</span> \\
uv <span class="hljs-built_in">sync</span> --frozen --no-install-project --no-editable; \\
<span class="hljs-keyword">else</span> \\
uv <span class="hljs-built_in">sync</span> --no-install-project --no-editable; \\
<span class="hljs-keyword">fi</span></span>
<span class="hljs-keyword">RUN</span><span class="language-bash"> --mount=<span class="hljs-built_in">type</span>=cache,target=/root/.cache/uv \\
<span class="hljs-keyword">if</span> [ -f uv.lock ]; <span class="hljs-keyword">then</span> \\
uv <span class="hljs-built_in">sync</span> --frozen --no-editable; \\
<span class="hljs-keyword">else</span> \\
uv <span class="hljs-built_in">sync</span> --no-editable; \\
<span class="hljs-keyword">fi</span></span>
<span class="hljs-comment"># Final runtime stage</span>
<span class="hljs-keyword">FROM</span> \${BASE_IMAGE}
<span class="hljs-keyword">WORKDIR</span><span class="language-bash"> /app</span>
<span class="hljs-comment"># Copy the virtual environment from builder</span>
<span class="hljs-keyword">COPY</span><span class="language-bash"> --from=builder /app/env/.venv /app/.venv</span>
<span class="hljs-comment"># Copy the environment code</span>
<span class="hljs-keyword">COPY</span><span class="language-bash"> --from=builder /app/env /app/env</span>
<span class="hljs-comment"># Set PATH to use the virtual environment</span>
<span class="hljs-keyword">ENV</span> PATH=<span class="hljs-string">&quot;/app/.venv/bin:$PATH&quot;</span>
<span class="hljs-comment"># Set PYTHONPATH so imports work correctly</span>
<span class="hljs-keyword">ENV</span> PYTHONPATH=<span class="hljs-string">&quot;/app/env:$PYTHONPATH&quot;</span>
<span class="hljs-comment"># Health check</span>
<span class="hljs-keyword">HEALTHCHECK</span><span class="language-bash"> --interval=30s --<span class="hljs-built_in">timeout</span>=3s --start-period=5s --retries=3 \\
CMD curl -f http://localhost:8000/health || <span class="hljs-built_in">exit</span> 1</span>
<span class="hljs-comment"># Run the FastAPI server</span>
<span class="hljs-comment"># The module path is constructed to work with the /app/env structure</span>
<span class="hljs-keyword">CMD</span><span class="language-bash"> [<span class="hljs-string">&quot;sh&quot;</span>, <span class="hljs-string">&quot;-c&quot;</span>, <span class="hljs-string">&quot;cd /app/env &amp;&amp; uvicorn server.app:app --host 0.0.0.0 --port 8000&quot;</span>]</span>
`,lang:"dockerfile",wrap:!1}}),re=new T({props:{title:"7. Build & Validate with the CLI",local:"7-build--validate-with-the-cli",headingTag:"h3"}}),me=new J({props:{code:"Y2QlMjBlbnZzJTJGbXlfZW52JTBBb3BlbmVudiUyMGJ1aWxkJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIzJTIwQnVpbGRzJTIwRG9ja2VyJTIwaW1hZ2UlMjAoYXV0by1kZXRlY3RzJTIwY29udGV4dCklMEFvcGVuZW52JTIwdmFsaWRhdGUlMjAtLXZlcmJvc2U=",highlighted:`<span class="hljs-built_in">cd</span> envs/my_env
openenv build <span class="hljs-comment"># Builds Docker image (auto-detects context)</span>
openenv validate --verbose`,lang:"bash",wrap:!1}}),we=new T({props:{title:"8. Push & Share with openenv push",local:"8-push--share-with-openenv-push",headingTag:"h3"}}),Ue=new J({props:{code:"JTIzJTIwUHVzaCUyMHRvJTIwSEYlMjBTcGFjZXMlMjAoYXV0byUyMGVuYWJsZXMlMjB3ZWIlMjBVSSUyMGFuZCUyMHByb21wdHMlMjBmb3IlMjBsb2dpbiUyMGlmJTIwbmVlZGVkKSUwQW9wZW5lbnYlMjBwdXNoJTBBJTBBJTIzJTIwUHVzaCUyMHRvJTIwYSUyMHNwZWNpZmljJTIwcmVwbyUyMG9yJTIwbmFtZXNwYWNlJTBBb3BlbmVudiUyMHB1c2glMjAtLXJlcG8taWQlMjBteS1vcmclMkZteS1lbnYlMEElMEElMjMlMjBQdXNoJTIwdG8lMjBEb2NrZXIlMkZnaGNyJTIwKGludGVyZmFjZSUyMGRpc2FibGVkJTIwYnklMjBkZWZhdWx0KSUwQW9wZW5lbnYlMjBwdXNoJTIwLS1yZWdpc3RyeSUyMGdoY3IuaW8lMkZteS1vcmclMjAtLXRhZyUyMG15LWVudiUzQWxhdGVzdCUwQSUwQSUyMyUyMEN1c3RvbWl6ZSUyMGltYWdlJTIwYmFzZSUyMG9yJTIwdmlzaWJpbGl0eSUwQW9wZW5lbnYlMjBwdXNoJTIwLS1iYXNlLWltYWdlJTIwZ2hjci5pbyUyRm1ldGEtcHl0b3JjaCUyRm9wZW5lbnYtYmFzZSUzQWxhdGVzdCUyMC0tcHJpdmF0ZSUwQSUwQSUyMyUyMENvbmZpZ3VyZSUyMFNwYWNlJTIwdmFyaWFibGVzJTIwYW5kJTIwc2VjcmV0cyUyMGF0JTIwcHVzaCUyMHRpbWUlMEFvcGVuZW52JTIwcHVzaCUyMC1lJTIwT1BFTlNQSUVMX0dBTUUlM0R0aWNfdGFjX3RvZSUyMC0tc2VjcmV0JTIwT1BFTkFJX0FQSV9LRVklM0Rzay0uLi4=",highlighted:`<span class="hljs-comment"># Push to HF Spaces (auto enables web UI and prompts for login if needed)</span>
openenv push
<span class="hljs-comment"># Push to a specific repo or namespace</span>
openenv push --repo-id my-org/my-env
<span class="hljs-comment"># Push to Docker/ghcr (interface disabled by default)</span>
openenv push --registry ghcr.io/my-org --tag my-env:latest
<span class="hljs-comment"># Customize image base or visibility</span>
openenv push --base-image ghcr.io/meta-pytorch/openenv-base:latest --private
<span class="hljs-comment"># Configure Space variables and secrets at push time</span>
openenv push -e OPENSPIEL_GAME=tic_tac_toe --secret OPENAI_API_KEY=sk-...`,lang:"bash",wrap:!1}}),Ie=new T({props:{title:"Declaring public variables in openenv.yaml",local:"declaring-public-variables-in-openenvyaml",headingTag:"h4"}}),Be=new J({props:{code:"dmFyaWFibGVzJTNBJTBBJTIwJTIwT1BFTlNQSUVMX0dBTUUlM0ElMjBjYXRjaA==",highlighted:`<span class="hljs-attr">variables:</span>
<span class="hljs-attr">OPENSPIEL_GAME:</span> <span class="hljs-string">catch</span>`,lang:"yaml",wrap:!1}}),Ze=new T({props:{title:"9. Automate Builds (optional)",local:"9-automate-builds-optional",headingTag:"h3"}}),Ee=new J({props:{code:"c3RyYXRlZ3klM0ElMEElMjAlMjBtYXRyaXglM0ElMEElMjAlMjAlMjAlMjBpbWFnZSUzQSUwQSUyMCUyMCUyMCUyMCUyMCUyMC0lMjBuYW1lJTNBJTIwZWNoby1lbnYlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjBkb2NrZXJmaWxlJTNBJTIwZW52cyUyRmVjaG9fZW52JTJGc2VydmVyJTJGRG9ja2VyZmlsZSUwQSUyMCUyMCUyMCUyMCUyMCUyMC0lMjBuYW1lJTNBJTIwY2hhdC1lbnYlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjBkb2NrZXJmaWxlJTNBJTIwZW52cyUyRmNoYXRfZW52JTJGc2VydmVyJTJGRG9ja2VyZmlsZSUwQSUyMCUyMCUyMCUyMCUyMCUyMC0lMjBuYW1lJTNBJTIwY29kaW5nLWVudiUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMGRvY2tlcmZpbGUlM0ElMjBlbnZzJTJGY29kaW5nX2VudiUyRnNlcnZlciUyRkRvY2tlcmZpbGUlMEElMjAlMjAlMjAlMjAlMjAlMjAtJTIwbmFtZSUzQSUyMG15LWVudiUyMCUyMCUyMyUyMEFkZCUyMHlvdXIlMjBlbnZpcm9ubWVudCUyMGhlcmUlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjBkb2NrZXJmaWxlJTNBJTIwZW52cyUyRm15X2VudiUyRnNlcnZlciUyRkRvY2tlcmZpbGU=",highlighted:`<span class="hljs-attr">strategy:</span>
<span class="hljs-attr">matrix:</span>
<span class="hljs-attr">image:</span>
<span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">echo-env</span>
<span class="hljs-attr">dockerfile:</span> <span class="hljs-string">envs/echo_env/server/Dockerfile</span>
<span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">chat-env</span>
<span class="hljs-attr">dockerfile:</span> <span class="hljs-string">envs/chat_env/server/Dockerfile</span>
<span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">coding-env</span>
<span class="hljs-attr">dockerfile:</span> <span class="hljs-string">envs/coding_env/server/Dockerfile</span>
<span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">my-env</span> <span class="hljs-comment"># Add your environment here</span>
<span class="hljs-attr">dockerfile:</span> <span class="hljs-string">envs/my_env/server/Dockerfile</span>`,lang:"yaml",wrap:!1}}),Ge=new T({props:{title:"Use Your Environment",local:"use-your-environment",headingTag:"h3"}}),ge=new J({props:{code:"ZnJvbSUyMGVudnMubXlfZW52JTIwaW1wb3J0JTIwTXlBY3Rpb24lMkMlMjBNeUVudiUwQSUwQSUyMyUyMENyZWF0ZSUyMGVudmlyb25tZW50JTIwZnJvbSUyMERvY2tlciUyMGltYWdlJTBBY2xpZW50JTIwJTNEJTIwTXlFbnYuZnJvbV9kb2NrZXJfaW1hZ2UoJTIybXktZW52JTNBbGF0ZXN0JTIyKSUwQSUyMyUyME9yJTJDJTIwY29ubmVjdCUyMHRvJTIwdGhlJTIwcmVtb3RlJTIwc3BhY2UlMjBvbiUyMEh1Z2dpbmclMjBGYWNlJTBBY2xpZW50JTIwJTNEJTIwTXlFbnYuZnJvbV9odWIoJTIybXktb3JnJTJGbXktZW52JTIyKSUwQSUyMyUyME9yJTJDJTIwY29ubmVjdCUyMHRvJTIwdGhlJTIwbG9jYWwlMjBzZXJ2ZXIlMEFjbGllbnQlMjAlM0QlMjBNeUVudihiYXNlX3VybCUzRCUyMmh0dHAlM0ElMkYlMkZsb2NhbGhvc3QlM0E4MDAwJTIyKSUwQSUwQSUyMyUyMFVzZSUyMGNvbnRleHQlMjBtYW5hZ2VyJTIwZm9yJTIwYXV0b21hdGljJTIwY2xlYW51cCUyMChyZWNvbW1lbmRlZCklMEF3aXRoJTIwY2xpZW50JTNBJTBBJTIwJTIwJTIwJTIwJTIzJTIwUmVzZXQlMEElMjAlMjAlMjAlMjByZXN1bHQlMjAlM0QlMjBjbGllbnQucmVzZXQoKSUwQSUyMCUyMCUyMCUyMHByaW50KHJlc3VsdC5vYnNlcnZhdGlvbi5yZXN1bHQpJTIwJTIwJTIzJTIwJTIyUmVhZHklMjIlMEElMEElMjAlMjAlMjAlMjAlMjMlMjBFeGVjdXRlJTIwYWN0aW9ucyUwQSUyMCUyMCUyMCUyMHJlc3VsdCUyMCUzRCUyMGNsaWVudC5zdGVwKE15QWN0aW9uKGNvbW1hbmQlM0QlMjJ0ZXN0JTIyJTJDJTIwcGFyYW1ldGVycyUzRCU3QiU3RCkpJTBBJTIwJTIwJTIwJTIwcHJpbnQocmVzdWx0Lm9ic2VydmF0aW9uLnJlc3VsdCklMEElMjAlMjAlMjAlMjBwcmludChyZXN1bHQub2JzZXJ2YXRpb24uc3VjY2VzcyklMEElMEElMjAlMjAlMjAlMjAlMjMlMjBHZXQlMjBzdGF0ZSUwQSUyMCUyMCUyMCUyMHN0YXRlJTIwJTNEJTIwY2xpZW50LnN0YXRlKCklMEElMjAlMjAlMjAlMjBwcmludChzdGF0ZS5lcGlzb2RlX2lkKSUwQSUyMCUyMCUyMCUyMHByaW50KHN0YXRlLnN0ZXBfY291bnQpJTBBJTBBJTIzJTIwT3IlMjBtYW51YWxseSUyMG1hbmFnZSUyMHRoZSUyMGNvbm5lY3Rpb24lMEF0cnklM0ElMEElMjAlMjAlMjAlMjBjbGllbnQlMjAlM0QlMjBNeUVudihiYXNlX3VybCUzRCUyMmh0dHAlM0ElMkYlMkZsb2NhbGhvc3QlM0E4MDAwJTIyKSUwQSUyMCUyMCUyMCUyMHJlc3VsdCUyMCUzRCUyMGNsaWVudC5yZXNldCgpJTBBJTIwJTIwJTIwJTIwcmVzdWx0JTIwJTNEJTIwY2xpZW50LnN0ZXAoTXlBY3Rpb24oY29tbWFuZCUzRCUyMnRlc3QlMjIlMkMlMjBwYXJhbWV0ZXJzJTNEJTdCJTdEKSklMEFmaW5hbGx5JTNBJTBBJTIwJTIwJTIwJTIwY2xpZW50LmNsb3NlKCk=",highlighted:`<span class="hljs-keyword">from</span> envs.my_env <span class="hljs-keyword">import</span> MyAction, MyEnv
<span class="hljs-comment"># Create environment from Docker image</span>
client = MyEnv.from_docker_image(<span class="hljs-string">&quot;my-env:latest&quot;</span>)
<span class="hljs-comment"># Or, connect to the remote space on Hugging Face</span>
client = MyEnv.from_hub(<span class="hljs-string">&quot;my-org/my-env&quot;</span>)
<span class="hljs-comment"># Or, connect to the local server</span>
client = MyEnv(base_url=<span class="hljs-string">&quot;http://localhost:8000&quot;</span>)
<span class="hljs-comment"># Use context manager for automatic cleanup (recommended)</span>
<span class="hljs-keyword">with</span> client:
<span class="hljs-comment"># Reset</span>
result = client.reset()
<span class="hljs-built_in">print</span>(result.observation.result) <span class="hljs-comment"># &quot;Ready&quot;</span>
<span class="hljs-comment"># Execute actions</span>
result = client.step(MyAction(command=<span class="hljs-string">&quot;test&quot;</span>, parameters={}))
<span class="hljs-built_in">print</span>(result.observation.result)
<span class="hljs-built_in">print</span>(result.observation.success)
<span class="hljs-comment"># Get state</span>
state = client.state()
<span class="hljs-built_in">print</span>(state.episode_id)
<span class="hljs-built_in">print</span>(state.step_count)
<span class="hljs-comment"># Or manually manage the connection</span>
<span class="hljs-keyword">try</span>:
client = MyEnv(base_url=<span class="hljs-string">&quot;http://localhost:8000&quot;</span>)
result = client.reset()
result = client.step(MyAction(command=<span class="hljs-string">&quot;test&quot;</span>, parameters={}))
<span class="hljs-keyword">finally</span>:
client.close()`,lang:"python",wrap:!1}}),We=new T({props:{title:"Nice work! You’ve now built and used your own OpenEnv environment.",local:"nice-work-youve-now-built-and-used-your-own-openenv-environment",headingTag:"h2"}}),Ve=new yt({props:{source:"https://github.com/huggingface/openenv/blob/main/docs/source/getting_started/environment-builder.md"}}),{c(){j=p("meta"),$e=n(),Qe=p("p"),_e=n(),o(b.$$.fragment),He=n(),o(v.$$.fragment),Fe=n(),I=p("p"),I.innerHTML=js,ze=n(),f=p("p"),f.innerHTML=ws,Le=n(),B=p("p"),B.textContent=us,xe=n(),w=p("blockquote"),w.innerHTML=Us,qe=n(),o(C.$$.fragment),Oe=n(),Z=p("p"),Z.textContent=hs,De=n(),k=p("table"),k.innerHTML=bs,Pe=n(),o(E.$$.fragment),Ke=n(),G=p("table"),G.innerHTML=vs,el=n(),u=p("blockquote"),u.innerHTML=Is,ll=n(),sl=p("hr"),tl=n(),o(A.$$.fragment),nl=n(),g=p("p"),g.textContent=fs,al=n(),W=p("ol"),W.innerHTML=Bs,pl=n(),U=p("blockquote"),U.innerHTML=Cs,il=n(),o(R.$$.fragment),Ml=n(),X=p("ul"),X.innerHTML=Zs,ol=n(),o(V.$$.fragment),cl=n(),N=p("p"),N.textContent=ks,yl=n(),o(Q.$$.fragment),rl=n(),o(Y.$$.fragment),dl=n(),S=p("p"),S.innerHTML=Es,ml=n(),$=p("p"),$.textContent=Gs,Tl=n(),o(_.$$.fragment),Jl=n(),H=p("p"),H.innerHTML=As,jl=n(),o(F.$$.fragment),wl=n(),z=p("p"),z.innerHTML=gs,ul=n(),o(L.$$.fragment),Ul=n(),o(x.$$.fragment),hl=n(),q=p("p"),q.innerHTML=Ws,bl=n(),o(O.$$.fragment),vl=n(),o(D.$$.fragment),Il=n(),P=p("p"),P.innerHTML=Rs,fl=n(),K=p("p"),K.innerHTML=Xs,Bl=n(),o(ee.$$.fragment),Cl=n(),le=p("p"),le.textContent=Vs,Zl=n(),o(se.$$.fragment),kl=n(),o(te.$$.fragment),El=n(),ne=p("p"),ne.innerHTML=Ns,Gl=n(),o(ae.$$.fragment),Al=n(),pe=p("p"),pe.innerHTML=Qs,gl=n(),o(ie.$$.fragment),Wl=n(),Me=p("p"),Me.innerHTML=Ys,Rl=n(),oe=p("p"),oe.innerHTML=Ss,Xl=n(),h=p("details"),Ne=p("summary"),Ne.textContent=$s,ds=n(),o(ce.$$.fragment),Vl=n(),ye=p("p"),ye.textContent=_s,Nl=n(),o(re.$$.fragment),Ql=n(),de=p("p"),de.textContent=Hs,Yl=n(),o(me.$$.fragment),Sl=n(),Te=p("p"),Te.innerHTML=Fs,$l=n(),Je=p("ul"),Je.innerHTML=zs,_l=n(),je=p("p"),je.innerHTML=Ls,Hl=n(),o(we.$$.fragment),Fl=n(),ue=p("p"),ue.textContent=xs,zl=n(),o(Ue.$$.fragment),Ll=n(),he=p("p"),he.textContent=qs,xl=n(),be=p("ul"),be.innerHTML=Os,ql=n(),ve=p("p"),ve.innerHTML=Ds,Ol=n(),o(Ie.$$.fragment),Dl=n(),fe=p("p"),fe.innerHTML=Ps,Pl=n(),o(Be.$$.fragment),Kl=n(),Ce=p("p"),Ce.innerHTML=Ks,es=n(),o(Ze.$$.fragment),ls=n(),ke=p("p"),ke.innerHTML=et,ss=n(),o(Ee.$$.fragment),ts=n(),o(Ge.$$.fragment),ns=n(),Ae=p("p"),Ae.textContent=lt,as=n(),o(ge.$$.fragment),ps=n(),o(We.$$.fragment),is=n(),Re=p("p"),Re.textContent=st,Ms=n(),Xe=p("ul"),Xe.innerHTML=tt,os=n(),o(Ve.$$.fragment),cs=n(),Ye=p("p"),this.h()},l(e){const l=ot("svelte-u9bgzb",document.head);j=i(l,"META",{name:!0,content:!0}),l.forEach(s),$e=a(e),Qe=i(e,"P",{}),ms(Qe).forEach(s),_e=a(e),c(b.$$.fragment,e),He=a(e),c(v.$$.fragment,e),Fe=a(e),I=i(e,"P",{"data-svelte-h":!0}),M(I)!=="svelte-16obzct"&&(I.innerHTML=js),ze=a(e),f=i(e,"P",{"data-svelte-h":!0}),M(f)!=="svelte-ctnfvd"&&(f.innerHTML=ws),Le=a(e),B=i(e,"P",{"data-svelte-h":!0}),M(B)!=="svelte-a8bq9v"&&(B.textContent=us),xe=a(e),w=i(e,"BLOCKQUOTE",{class:!0,"data-svelte-h":!0}),M(w)!=="svelte-r906iz"&&(w.innerHTML=Us),qe=a(e),c(C.$$.fragment,e),Oe=a(e),Z=i(e,"P",{"data-svelte-h":!0}),M(Z)!=="svelte-1nsuea4"&&(Z.textContent=hs),De=a(e),k=i(e,"TABLE",{"data-svelte-h":!0}),M(k)!=="svelte-1ig457w"&&(k.innerHTML=bs),Pe=a(e),c(E.$$.fragment,e),Ke=a(e),G=i(e,"TABLE",{"data-svelte-h":!0}),M(G)!=="svelte-1gg898p"&&(G.innerHTML=vs),el=a(e),u=i(e,"BLOCKQUOTE",{class:!0,"data-svelte-h":!0}),M(u)!=="svelte-1c5nyvq"&&(u.innerHTML=Is),ll=a(e),sl=i(e,"HR",{}),tl=a(e),c(A.$$.fragment,e),nl=a(e),g=i(e,"P",{"data-svelte-h":!0}),M(g)!=="svelte-1rxjx2x"&&(g.textContent=fs),al=a(e),W=i(e,"OL",{"data-svelte-h":!0}),M(W)!=="svelte-18h6ho"&&(W.innerHTML=Bs),pl=a(e),U=i(e,"BLOCKQUOTE",{class:!0,"data-svelte-h":!0}),M(U)!=="svelte-id12cf"&&(U.innerHTML=Cs),il=a(e),c(R.$$.fragment,e),Ml=a(e),X=i(e,"UL",{"data-svelte-h":!0}),M(X)!=="svelte-ghdn1o"&&(X.innerHTML=Zs),ol=a(e),c(V.$$.fragment,e),cl=a(e),N=i(e,"P",{"data-svelte-h":!0}),M(N)!=="svelte-u52you"&&(N.textContent=ks),yl=a(e),c(Q.$$.fragment,e),rl=a(e),c(Y.$$.fragment,e),dl=a(e),S=i(e,"P",{"data-svelte-h":!0}),M(S)!=="svelte-czocs9"&&(S.innerHTML=Es),ml=a(e),$=i(e,"P",{"data-svelte-h":!0}),M($)!=="svelte-1e70fkc"&&($.textContent=Gs),Tl=a(e),c(_.$$.fragment,e),Jl=a(e),H=i(e,"P",{"data-svelte-h":!0}),M(H)!=="svelte-1csvp49"&&(H.innerHTML=As),jl=a(e),c(F.$$.fragment,e),wl=a(e),z=i(e,"P",{"data-svelte-h":!0}),M(z)!=="svelte-ewzzeg"&&(z.innerHTML=gs),ul=a(e),c(L.$$.fragment,e),Ul=a(e),c(x.$$.fragment,e),hl=a(e),q=i(e,"P",{"data-svelte-h":!0}),M(q)!=="svelte-1kzvzkk"&&(q.innerHTML=Ws),bl=a(e),c(O.$$.fragment,e),vl=a(e),c(D.$$.fragment,e),Il=a(e),P=i(e,"P",{"data-svelte-h":!0}),M(P)!=="svelte-yy593y"&&(P.innerHTML=Rs),fl=a(e),K=i(e,"P",{"data-svelte-h":!0}),M(K)!=="svelte-1bx2epd"&&(K.innerHTML=Xs),Bl=a(e),c(ee.$$.fragment,e),Cl=a(e),le=i(e,"P",{"data-svelte-h":!0}),M(le)!=="svelte-pom1de"&&(le.textContent=Vs),Zl=a(e),c(se.$$.fragment,e),kl=a(e),c(te.$$.fragment,e),El=a(e),ne=i(e,"P",{"data-svelte-h":!0}),M(ne)!=="svelte-hx7m3p"&&(ne.innerHTML=Ns),Gl=a(e),c(ae.$$.fragment,e),Al=a(e),pe=i(e,"P",{"data-svelte-h":!0}),M(pe)!=="svelte-1gtng2a"&&(pe.innerHTML=Qs),gl=a(e),c(ie.$$.fragment,e),Wl=a(e),Me=i(e,"P",{"data-svelte-h":!0}),M(Me)!=="svelte-az7dkj"&&(Me.innerHTML=Ys),Rl=a(e),oe=i(e,"P",{"data-svelte-h":!0}),M(oe)!=="svelte-1gnchy7"&&(oe.innerHTML=Ss),Xl=a(e),h=i(e,"DETAILS",{});var rs=ms(h);Ne=i(rs,"SUMMARY",{"data-svelte-h":!0}),M(Ne)!=="svelte-ycltuu"&&(Ne.textContent=$s),ds=a(rs),c(ce.$$.fragment,rs),rs.forEach(s),Vl=a(e),ye=i(e,"P",{"data-svelte-h":!0}),M(ye)!=="svelte-19ugog0"&&(ye.textContent=_s),Nl=a(e),c(re.$$.fragment,e),Ql=a(e),de=i(e,"P",{"data-svelte-h":!0}),M(de)!=="svelte-u4crad"&&(de.textContent=Hs),Yl=a(e),c(me.$$.fragment,e),Sl=a(e),Te=i(e,"P",{"data-svelte-h":!0}),M(Te)!=="svelte-wir32s"&&(Te.innerHTML=Fs),$l=a(e),Je=i(e,"UL",{"data-svelte-h":!0}),M(Je)!=="svelte-1ddboft"&&(Je.innerHTML=zs),_l=a(e),je=i(e,"P",{"data-svelte-h":!0}),M(je)!=="svelte-1i9gylz"&&(je.innerHTML=Ls),Hl=a(e),c(we.$$.fragment,e),Fl=a(e),ue=i(e,"P",{"data-svelte-h":!0}),M(ue)!=="svelte-l2ct19"&&(ue.textContent=xs),zl=a(e),c(Ue.$$.fragment,e),Ll=a(e),he=i(e,"P",{"data-svelte-h":!0}),M(he)!=="svelte-ctgyqz"&&(he.textContent=qs),xl=a(e),be=i(e,"UL",{"data-svelte-h":!0}),M(be)!=="svelte-nchqxm"&&(be.innerHTML=Os),ql=a(e),ve=i(e,"P",{"data-svelte-h":!0}),M(ve)!=="svelte-1bgmmlj"&&(ve.innerHTML=Ds),Ol=a(e),c(Ie.$$.fragment,e),Dl=a(e),fe=i(e,"P",{"data-svelte-h":!0}),M(fe)!=="svelte-x39e7s"&&(fe.innerHTML=Ps),Pl=a(e),c(Be.$$.fragment,e),Kl=a(e),Ce=i(e,"P",{"data-svelte-h":!0}),M(Ce)!=="svelte-12uu88k"&&(Ce.innerHTML=Ks),es=a(e),c(Ze.$$.fragment,e),ls=a(e),ke=i(e,"P",{"data-svelte-h":!0}),M(ke)!=="svelte-tsfsth"&&(ke.innerHTML=et),ss=a(e),c(Ee.$$.fragment,e),ts=a(e),c(Ge.$$.fragment,e),ns=a(e),Ae=i(e,"P",{"data-svelte-h":!0}),M(Ae)!=="svelte-xtyn70"&&(Ae.textContent=lt),as=a(e),c(ge.$$.fragment,e),ps=a(e),c(We.$$.fragment,e),is=a(e),Re=i(e,"P",{"data-svelte-h":!0}),M(Re)!=="svelte-15prqjs"&&(Re.textContent=st),Ms=a(e),Xe=i(e,"UL",{"data-svelte-h":!0}),M(Xe)!=="svelte-1qkff8e"&&(Xe.innerHTML=tt),os=a(e),c(Ve.$$.fragment,e),cs=a(e),Ye=i(e,"P",{}),ms(Ye).forEach(s),this.h()},h(){Se(j,"name","hf:doc:metadata"),Se(j,"content",dt),Se(w,"class","note"),Se(u,"class","tip"),Se(U,"class","note")},m(e,l){Ts(document.head,j),t(e,$e,l),t(e,Qe,l),t(e,_e,l),y(b,e,l),t(e,He,l),y(v,e,l),t(e,Fe,l),t(e,I,l),t(e,ze,l),t(e,f,l),t(e,Le,l),t(e,B,l),t(e,xe,l),t(e,w,l),t(e,qe,l),y(C,e,l),t(e,Oe,l),t(e,Z,l),t(e,De,l),t(e,k,l),t(e,Pe,l),y(E,e,l),t(e,Ke,l),t(e,G,l),t(e,el,l),t(e,u,l),t(e,ll,l),t(e,sl,l),t(e,tl,l),y(A,e,l),t(e,nl,l),t(e,g,l),t(e,al,l),t(e,W,l),t(e,pl,l),t(e,U,l),t(e,il,l),y(R,e,l),t(e,Ml,l),t(e,X,l),t(e,ol,l),y(V,e,l),t(e,cl,l),t(e,N,l),t(e,yl,l),y(Q,e,l),t(e,rl,l),y(Y,e,l),t(e,dl,l),t(e,S,l),t(e,ml,l),t(e,$,l),t(e,Tl,l),y(_,e,l),t(e,Jl,l),t(e,H,l),t(e,jl,l),y(F,e,l),t(e,wl,l),t(e,z,l),t(e,ul,l),y(L,e,l),t(e,Ul,l),y(x,e,l),t(e,hl,l),t(e,q,l),t(e,bl,l),y(O,e,l),t(e,vl,l),y(D,e,l),t(e,Il,l),t(e,P,l),t(e,fl,l),t(e,K,l),t(e,Bl,l),y(ee,e,l),t(e,Cl,l),t(e,le,l),t(e,Zl,l),y(se,e,l),t(e,kl,l),y(te,e,l),t(e,El,l),t(e,ne,l),t(e,Gl,l),y(ae,e,l),t(e,Al,l),t(e,pe,l),t(e,gl,l),y(ie,e,l),t(e,Wl,l),t(e,Me,l),t(e,Rl,l),t(e,oe,l),t(e,Xl,l),t(e,h,l),Ts(h,Ne),Ts(h,ds),y(ce,h,null),t(e,Vl,l),t(e,ye,l),t(e,Nl,l),y(re,e,l),t(e,Ql,l),t(e,de,l),t(e,Yl,l),y(me,e,l),t(e,Sl,l),t(e,Te,l),t(e,$l,l),t(e,Je,l),t(e,_l,l),t(e,je,l),t(e,Hl,l),y(we,e,l),t(e,Fl,l),t(e,ue,l),t(e,zl,l),y(Ue,e,l),t(e,Ll,l),t(e,he,l),t(e,xl,l),t(e,be,l),t(e,ql,l),t(e,ve,l),t(e,Ol,l),y(Ie,e,l),t(e,Dl,l),t(e,fe,l),t(e,Pl,l),y(Be,e,l),t(e,Kl,l),t(e,Ce,l),t(e,es,l),y(Ze,e,l),t(e,ls,l),t(e,ke,l),t(e,ss,l),y(Ee,e,l),t(e,ts,l),y(Ge,e,l),t(e,ns,l),t(e,Ae,l),t(e,as,l),y(ge,e,l),t(e,ps,l),y(We,e,l),t(e,is,l),t(e,Re,l),t(e,Ms,l),t(e,Xe,l),t(e,os,l),y(Ve,e,l),t(e,cs,l),t(e,Ye,l),ys=!0},p:at,i(e){ys||(r(b.$$.fragment,e),r(v.$$.fragment,e),r(C.$$.fragment,e),r(E.$$.fragment,e),r(A.$$.fragment,e),r(R.$$.fragment,e),r(V.$$.fragment,e),r(Q.$$.fragment,e),r(Y.$$.fragment,e),r(_.$$.fragment,e),r(F.$$.fragment,e),r(L.$$.fragment,e),r(x.$$.fragment,e),r(O.$$.fragment,e),r(D.$$.fragment,e),r(ee.$$.fragment,e),r(se.$$.fragment,e),r(te.$$.fragment,e),r(ae.$$.fragment,e),r(ie.$$.fragment,e),r(ce.$$.fragment,e),r(re.$$.fragment,e),r(me.$$.fragment,e),r(we.$$.fragment,e),r(Ue.$$.fragment,e),r(Ie.$$.fragment,e),r(Be.$$.fragment,e),r(Ze.$$.fragment,e),r(Ee.$$.fragment,e),r(Ge.$$.fragment,e),r(ge.$$.fragment,e),r(We.$$.fragment,e),r(Ve.$$.fragment,e),ys=!0)},o(e){d(b.$$.fragment,e),d(v.$$.fragment,e),d(C.$$.fragment,e),d(E.$$.fragment,e),d(A.$$.fragment,e),d(R.$$.fragment,e),d(V.$$.fragment,e),d(Q.$$.fragment,e),d(Y.$$.fragment,e),d(_.$$.fragment,e),d(F.$$.fragment,e),d(L.$$.fragment,e),d(x.$$.fragment,e),d(O.$$.fragment,e),d(D.$$.fragment,e),d(ee.$$.fragment,e),d(se.$$.fragment,e),d(te.$$.fragment,e),d(ae.$$.fragment,e),d(ie.$$.fragment,e),d(ce.$$.fragment,e),d(re.$$.fragment,e),d(me.$$.fragment,e),d(we.$$.fragment,e),d(Ue.$$.fragment,e),d(Ie.$$.fragment,e),d(Be.$$.fragment,e),d(Ze.$$.fragment,e),d(Ee.$$.fragment,e),d(Ge.$$.fragment,e),d(ge.$$.fragment,e),d(We.$$.fragment,e),d(Ve.$$.fragment,e),ys=!1},d(e){e&&(s($e),s(Qe),s(_e),s(He),s(Fe),s(I),s(ze),s(f),s(Le),s(B),s(xe),s(w),s(qe),s(Oe),s(Z),s(De),s(k),s(Pe),s(Ke),s(G),s(el),s(u),s(ll),s(sl),s(tl),s(nl),s(g),s(al),s(W),s(pl),s(U),s(il),s(Ml),s(X),s(ol),s(cl),s(N),s(yl),s(rl),s(dl),s(S),s(ml),s($),s(Tl),s(Jl),s(H),s(jl),s(wl),s(z),s(ul),s(Ul),s(hl),s(q),s(bl),s(vl),s(Il),s(P),s(fl),s(K),s(Bl),s(Cl),s(le),s(Zl),s(kl),s(El),s(ne),s(Gl),s(Al),s(pe),s(gl),s(Wl),s(Me),s(Rl),s(oe),s(Xl),s(h),s(Vl),s(ye),s(Nl),s(Ql),s(de),s(Yl),s(Sl),s(Te),s($l),s(Je),s(_l),s(je),s(Hl),s(Fl),s(ue),s(zl),s(Ll),s(he),s(xl),s(be),s(ql),s(ve),s(Ol),s(Dl),s(fe),s(Pl),s(Kl),s(Ce),s(es),s(ls),s(ke),s(ss),s(ts),s(ns),s(Ae),s(as),s(ps),s(is),s(Re),s(Ms),s(Xe),s(os),s(cs),s(Ye)),s(j),m(b,e),m(v,e),m(C,e),m(E,e),m(A,e),m(R,e),m(V,e),m(Q,e),m(Y,e),m(_,e),m(F,e),m(L,e),m(x,e),m(O,e),m(D,e),m(ee,e),m(se,e),m(te,e),m(ae,e),m(ie,e),m(ce),m(re,e),m(me,e),m(we,e),m(Ue,e),m(Ie,e),m(Be,e),m(Ze,e),m(Ee,e),m(Ge,e),m(ge,e),m(We,e),m(Ve,e)}}}const dt='{"title":"Packaging & Deploying","local":"packaging--deploying","sections":[{"title":"Quick Reference Card","local":"quick-reference-card","sections":[{"title":"CLI Quick Reference","local":"cli-quick-reference","sections":[],"depth":3}],"depth":2},{"title":"Overview","local":"overview","sections":[{"title":"Prerequisites","local":"prerequisites","sections":[],"depth":3}],"depth":2},{"title":"Step-by-Step Guide","local":"step-by-step-guide","sections":[{"title":"1. Scaffold with openenv init","local":"1-scaffold-with-openenv-init","sections":[],"depth":3},{"title":"2. Define Models","local":"2-define-models","sections":[],"depth":3},{"title":"3. Implement Environment Logic","local":"3-implement-environment-logic","sections":[],"depth":3},{"title":"4. Create the FastAPI Server","local":"4-create-the-fastapi-server","sections":[],"depth":3},{"title":"5. Implement the Client","local":"5-implement-the-client","sections":[],"depth":3},{"title":"6. Configure Dependencies & Dockerfile","local":"6-configure-dependencies--dockerfile","sections":[],"depth":3},{"title":"7. Build & Validate with the CLI","local":"7-build--validate-with-the-cli","sections":[],"depth":3},{"title":"8. Push & Share with openenv push","local":"8-push--share-with-openenv-push","sections":[{"title":"Declaring public variables in openenv.yaml","local":"declaring-public-variables-in-openenvyaml","sections":[],"depth":4}],"depth":3},{"title":"9. Automate Builds (optional)","local":"9-automate-builds-optional","sections":[],"depth":3},{"title":"Use Your Environment","local":"use-your-environment","sections":[],"depth":3}],"depth":2},{"title":"Nice work! You’ve now built and used your own OpenEnv environment.","local":"nice-work-youve-now-built-and-used-your-own-openenv-environment","sections":[],"depth":2}],"depth":1}';function mt(Js){return pt(()=>{new URLSearchParams(window.location.search).get("fw")}),[]}class Ut extends it{constructor(j){super(),Mt(this,j,mt,rt,nt,{})}}export{Ut as component};

Xet Storage Details

Size:
58.7 kB
·
Xet hash:
474b3a1c84d564381e4abf108fb47adede04f621f768b2ba79dffe3619cba532

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