Buckets:
| import{s as lt,n as st,o as tt}from"../chunks/scheduler.2b22cead.js";import{S as nt,i as at,e as p,s as n,c as o,h as pt,a as i,d as s,b as a,f as rs,g as c,j as M,k as Qe,l as ys,m as t,n as d,t as r,o as y,p as m}from"../chunks/index.1a0e8013.js";import{C as it,H as J,E as Mt}from"../chunks/MermaidChart.svelte_svelte_type_style_lang.4c120efc.js";import{C as T}from"../chunks/CodeBlock.5fc6cbc6.js";function ot(ms){let j,$e,Ve,Se,b,_e,v,He,I,Js="This guide walks you through creating a custom environment using the <code>OpenEnv</code> framework and the <code>openenv</code> CLI.",ze,f,Ts="The CLI handles scaffolding, builds, validation, and deployment so you can stay focused on environment logic.",Fe,w,js='<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>',Le,B,xe,Z,ws="Already familiar with OpenEnv? Here’s the 8-step process at a glance:",qe,C,us="<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 & 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("you/my-env")</code></td></tr></tbody>",Oe,k,De,E,Us="<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>",Pe,u,hs='<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>',Ke,el,ll,A,sl,G,bs="A typical workflow looks like:",tl,g,vs="<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>",nl,U,Is="<p>These integrations are handled automatically by the <code>openenv</code> CLI when you run <code>openenv init</code>.</p>",al,W,pl,X,fs='<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>',il,R,Ml,N,Bs="Let’s walk through the process of building a custom environment with OpenEnv.",ol,V,cl,Y,dl,Q,Zs="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>.",rl,$,Cs="Typical layout:",yl,S,ml,_,ks="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,H,Tl,z,Es="Edit <code>models.py</code> to describe your action and observation using Pydantic:",jl,F,wl,L,ul,x,As="Customize <code>server/my_environment.py</code> by extending <code>Environment</code>:",Ul,q,hl,O,bl,D,Gs="<code>server/app.py</code> should expose the environment through <code>create_app</code>.",vl,P,gs="<strong>Important:</strong> You must pass a class or factory function (not an instance) to enable WebSocket-based concurrent sessions:",Il,K,fl,ee,Ws="For environments with constructor arguments, create a factory function:",Bl,le,Zl,se,Cl,te,Xs="<code>client.py</code> extends <code>EnvClient</code> so users can interact with your server via WebSocket for persistent sessions:",kl,ne,El,ae,Rs="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.",Al,pe,Gl,ie,Ns="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.",gl,Me,Vs="Keep building from the <code>openenv-base</code> image so shared tooling stays available:",Wl,h,Ne,Ys="Dockerfile",ds,oe,Xl,ce,Qs="If you introduced extra dependencies in the Dockerfile, you should install them in the Dockerfile before removing temp files.",Rl,de,Nl,re,$s="From the environment directory:",Vl,ye,Yl,me,Ss="<code>openenv build</code> understands both standalone environments and in-repo ones. Useful flags:",Ql,Je,_s="<li><code>--tag/-t</code>: override the default <code>openenv-<env_name></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,Te,Hs="<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.",Sl,je,_l,we,zs="Once validation passes, the CLI can deploy directly to Hugging Face Spaces or any registry:",Hl,ue,zl,Ue,Fs="Key options:",Fl,he,Ls="<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>",Ll,be,xs=`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>.`,xl,ve,ql,Ie,qs=`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:`,Ol,fe,Dl,Be,Os=`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.`,Pl,Ze,Kl,Ce,Ds="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>:",es,ke,ls,Ee,ss,Ae,Ps="Here is a simple example of using your environment:",ts,Ge,ns,ge,as,We,Ks="Your next steps are to:",ps,Xe,et='<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>',is,Re,Ms,Ye,os;return b=new it({props:{containerStyle:"float: right; margin-left: 10px; display: inline-flex; position: relative; z-index: 10;"}}),v=new J({props:{title:"Packaging & Deploying",local:"packaging--deploying",headingTag:"h1"}}),B=new J({props:{title:"Quick Reference Card",local:"quick-reference-card",headingTag:"h2"}}),k=new J({props:{title:"CLI Quick Reference",local:"cli-quick-reference",headingTag:"h3"}}),A=new J({props:{title:"Overview",local:"overview",headingTag:"h2"}}),W=new J({props:{title:"Prerequisites",local:"prerequisites",headingTag:"h3"}}),R=new J({props:{title:"Step-by-Step Guide",local:"step-by-step-guide",headingTag:"h2"}}),V=new J({props:{title:"1. Scaffold with openenv init",local:"1-scaffold-with-openenv-init",headingTag:"h3"}}),Y=new T({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}}),S=new T({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}}),H=new J({props:{title:"2. Define Models",local:"2-define-models",headingTag:"h3"}}),F=new T({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">"""Your custom action."""</span> | |
| command: <span class="hljs-built_in">str</span> = Field(..., description=<span class="hljs-string">"Command to execute"</span>) | |
| parameters: <span class="hljs-built_in">dict</span> = Field(default_factory=<span class="hljs-built_in">dict</span>, description=<span class="hljs-string">"Command parameters"</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">"""Your custom observation."""</span> | |
| result: <span class="hljs-built_in">str</span> = Field(..., description=<span class="hljs-string">"Result of the action"</span>) | |
| success: <span class="hljs-built_in">bool</span> = Field(..., description=<span class="hljs-string">"Whether the action succeeded"</span>)`,lang:"python",wrap:!1}}),L=new J({props:{title:"3. Implement Environment Logic",local:"3-implement-environment-logic",headingTag:"h3"}}),q=new T({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>) -> 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">"Ready"</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>) -> 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>) -> State: | |
| <span class="hljs-keyword">return</span> self._state`,lang:"python",wrap:!1}}),O=new J({props:{title:"4. Create the FastAPI Server",local:"4-create-the-fastapi-server",headingTag:"h3"}}),K=new T({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">"my_env"</span>)`,lang:"python",wrap:!1}}),le=new T({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">"MY_API_KEY"</span>) | |
| timeout = <span class="hljs-built_in">int</span>(os.getenv(<span class="hljs-string">"MY_TIMEOUT"</span>, <span class="hljs-string">"30"</span>)) | |
| <span class="hljs-keyword">def</span> <span class="hljs-title function_">create_my_environment</span>(): | |
| <span class="hljs-string">"""Factory function that creates MyEnvironment with config."""</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">"my_env"</span>)`,lang:"python",wrap:!1}}),se=new J({props:{title:"5. Implement the Client",local:"5-implement-the-client",headingTag:"h3"}}),ne=new T({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>) -> <span class="hljs-built_in">dict</span>: | |
| <span class="hljs-keyword">return</span> {<span class="hljs-string">"command"</span>: action.command, <span class="hljs-string">"parameters"</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>) -> StepResult[MyObservation]: | |
| obs_data = payload.get(<span class="hljs-string">"observation"</span>, {}) | |
| obs = MyObservation( | |
| result=obs_data.get(<span class="hljs-string">"result"</span>, <span class="hljs-string">""</span>), | |
| success=obs_data.get(<span class="hljs-string">"success"</span>, <span class="hljs-literal">False</span>), | |
| done=payload.get(<span class="hljs-string">"done"</span>, <span class="hljs-literal">False</span>), | |
| reward=payload.get(<span class="hljs-string">"reward"</span>), | |
| ) | |
| <span class="hljs-keyword">return</span> StepResult( | |
| observation=obs, | |
| reward=payload.get(<span class="hljs-string">"reward"</span>), | |
| done=payload.get(<span class="hljs-string">"done"</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>) -> State: | |
| <span class="hljs-keyword">return</span> State( | |
| episode_id=payload.get(<span class="hljs-string">"episode_id"</span>), | |
| step_count=payload.get(<span class="hljs-string">"step_count"</span>, <span class="hljs-number">0</span>), | |
| )`,lang:"python",wrap:!1}}),pe=new J({props:{title:"6. Configure Dependencies & Dockerfile",local:"6-configure-dependencies--dockerfile",headingTag:"h3"}}),oe=new T({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'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">"/app/.venv/bin:$PATH"</span> | |
| <span class="hljs-comment"># Set PYTHONPATH so imports work correctly</span> | |
| <span class="hljs-keyword">ENV</span> PYTHONPATH=<span class="hljs-string">"/app/env:$PYTHONPATH"</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">"sh"</span>, <span class="hljs-string">"-c"</span>, <span class="hljs-string">"cd /app/env && uvicorn server.app:app --host 0.0.0.0 --port 8000"</span>]</span> | |
| `,lang:"dockerfile",wrap:!1}}),de=new J({props:{title:"7. Build & Validate with the CLI",local:"7-build--validate-with-the-cli",headingTag:"h3"}}),ye=new T({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}}),je=new J({props:{title:"8. Push & Share with openenv push",local:"8-push--share-with-openenv-push",headingTag:"h3"}}),ue=new T({props:{code:"JTIzJTIwUHVzaCUyMHRvJTIwSEYlMjBTcGFjZXMlMjAoYXV0byUyMGVuYWJsZXMlMjB3ZWIlMjBVSSUyMGFuZCUyMHByb21wdHMlMjBmb3IlMjBsb2dpbiUyMGlmJTIwbmVlZGVkKSUwQW9wZW5lbnYlMjBwdXNoJTBBJTBBJTIzJTIwUHVzaCUyMHRvJTIwYSUyMHNwZWNpZmljJTIwcmVwbyUyMG9yJTIwbmFtZXNwYWNlJTBBb3BlbmVudiUyMHB1c2glMjAtLXJlcG8taWQlMjBteS1vcmclMkZteS1lbnYlMEElMEElMjMlMjBQdXNoJTIwdG8lMjBEb2NrZXIlMkZnaGNyJTIwKGludGVyZmFjZSUyMGRpc2FibGVkJTIwYnklMjBkZWZhdWx0KSUwQW9wZW5lbnYlMjBwdXNoJTIwLS1yZWdpc3RyeSUyMGdoY3IuaW8lMkZteS1vcmclMjAtLXRhZyUyMG15LWVudiUzQWxhdGVzdCUwQSUwQSUyMyUyMEN1c3RvbWl6ZSUyMGltYWdlJTIwYmFzZSUyMG9yJTIwdmlzaWJpbGl0eSUwQW9wZW5lbnYlMjBwdXNoJTIwLS1iYXNlLWltYWdlJTIwZ2hjci5pbyUyRmh1Z2dpbmdmYWNlJTJGb3BlbmVudi1iYXNlJTNBbGF0ZXN0JTIwLS1wcml2YXRlJTBBJTBBJTIzJTIwQ29uZmlndXJlJTIwU3BhY2UlMjB2YXJpYWJsZXMlMjBhbmQlMjBzZWNyZXRzJTIwYXQlMjBwdXNoJTIwdGltZSUwQW9wZW5lbnYlMjBwdXNoJTIwLWUlMjBPUEVOU1BJRUxfR0FNRSUzRHRpY190YWNfdG9lJTIwLS1zZWNyZXQlMjBPUEVOQUlfQVBJX0tFWSUzRHNrLS4uLg==",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/huggingface/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}}),ve=new J({props:{title:"Declaring public variables in openenv.yaml",local:"declaring-public-variables-in-openenvyaml",headingTag:"h4"}}),fe=new T({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 J({props:{title:"9. Automate Builds (optional)",local:"9-automate-builds-optional",headingTag:"h3"}}),ke=new T({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}}),Ee=new J({props:{title:"Use Your Environment",local:"use-your-environment",headingTag:"h3"}}),Ge=new T({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">"my-env:latest"</span>) | |
| <span class="hljs-comment"># Or, connect to the remote space on Hugging Face</span> | |
| client = MyEnv.from_hub(<span class="hljs-string">"my-org/my-env"</span>) | |
| <span class="hljs-comment"># Or, connect to the local server</span> | |
| client = MyEnv(base_url=<span class="hljs-string">"http://localhost:8000"</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"># "Ready"</span> | |
| <span class="hljs-comment"># Execute actions</span> | |
| result = client.step(MyAction(command=<span class="hljs-string">"test"</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">"http://localhost:8000"</span>) | |
| result = client.reset() | |
| result = client.step(MyAction(command=<span class="hljs-string">"test"</span>, parameters={})) | |
| <span class="hljs-keyword">finally</span>: | |
| client.close()`,lang:"python",wrap:!1}}),ge=new J({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"}}),Re=new Mt({props:{source:"https://github.com/huggingface/openenv/blob/main/docs/source/getting_started/environment-builder.md"}}),{c(){j=p("meta"),$e=n(),Ve=p("p"),Se=n(),o(b.$$.fragment),_e=n(),o(v.$$.fragment),He=n(),I=p("p"),I.innerHTML=Js,ze=n(),f=p("p"),f.textContent=Ts,Fe=n(),w=p("blockquote"),w.innerHTML=js,Le=n(),o(B.$$.fragment),xe=n(),Z=p("p"),Z.textContent=ws,qe=n(),C=p("table"),C.innerHTML=us,Oe=n(),o(k.$$.fragment),De=n(),E=p("table"),E.innerHTML=Us,Pe=n(),u=p("blockquote"),u.innerHTML=hs,Ke=n(),el=p("hr"),ll=n(),o(A.$$.fragment),sl=n(),G=p("p"),G.textContent=bs,tl=n(),g=p("ol"),g.innerHTML=vs,nl=n(),U=p("blockquote"),U.innerHTML=Is,al=n(),o(W.$$.fragment),pl=n(),X=p("ul"),X.innerHTML=fs,il=n(),o(R.$$.fragment),Ml=n(),N=p("p"),N.textContent=Bs,ol=n(),o(V.$$.fragment),cl=n(),o(Y.$$.fragment),dl=n(),Q=p("p"),Q.innerHTML=Zs,rl=n(),$=p("p"),$.textContent=Cs,yl=n(),o(S.$$.fragment),ml=n(),_=p("p"),_.innerHTML=ks,Jl=n(),o(H.$$.fragment),Tl=n(),z=p("p"),z.innerHTML=Es,jl=n(),o(F.$$.fragment),wl=n(),o(L.$$.fragment),ul=n(),x=p("p"),x.innerHTML=As,Ul=n(),o(q.$$.fragment),hl=n(),o(O.$$.fragment),bl=n(),D=p("p"),D.innerHTML=Gs,vl=n(),P=p("p"),P.innerHTML=gs,Il=n(),o(K.$$.fragment),fl=n(),ee=p("p"),ee.textContent=Ws,Bl=n(),o(le.$$.fragment),Zl=n(),o(se.$$.fragment),Cl=n(),te=p("p"),te.innerHTML=Xs,kl=n(),o(ne.$$.fragment),El=n(),ae=p("p"),ae.innerHTML=Rs,Al=n(),o(pe.$$.fragment),Gl=n(),ie=p("p"),ie.innerHTML=Ns,gl=n(),Me=p("p"),Me.innerHTML=Vs,Wl=n(),h=p("details"),Ne=p("summary"),Ne.textContent=Ys,ds=n(),o(oe.$$.fragment),Xl=n(),ce=p("p"),ce.textContent=Qs,Rl=n(),o(de.$$.fragment),Nl=n(),re=p("p"),re.textContent=$s,Vl=n(),o(ye.$$.fragment),Yl=n(),me=p("p"),me.innerHTML=Ss,Ql=n(),Je=p("ul"),Je.innerHTML=_s,$l=n(),Te=p("p"),Te.innerHTML=Hs,Sl=n(),o(je.$$.fragment),_l=n(),we=p("p"),we.textContent=zs,Hl=n(),o(ue.$$.fragment),zl=n(),Ue=p("p"),Ue.textContent=Fs,Fl=n(),he=p("ul"),he.innerHTML=Ls,Ll=n(),be=p("p"),be.innerHTML=xs,xl=n(),o(ve.$$.fragment),ql=n(),Ie=p("p"),Ie.innerHTML=qs,Ol=n(),o(fe.$$.fragment),Dl=n(),Be=p("p"),Be.innerHTML=Os,Pl=n(),o(Ze.$$.fragment),Kl=n(),Ce=p("p"),Ce.innerHTML=Ds,es=n(),o(ke.$$.fragment),ls=n(),o(Ee.$$.fragment),ss=n(),Ae=p("p"),Ae.textContent=Ps,ts=n(),o(Ge.$$.fragment),ns=n(),o(ge.$$.fragment),as=n(),We=p("p"),We.textContent=Ks,ps=n(),Xe=p("ul"),Xe.innerHTML=et,is=n(),o(Re.$$.fragment),Ms=n(),Ye=p("p"),this.h()},l(e){const l=pt("svelte-u9bgzb",document.head);j=i(l,"META",{name:!0,content:!0}),l.forEach(s),$e=a(e),Ve=i(e,"P",{}),rs(Ve).forEach(s),Se=a(e),c(b.$$.fragment,e),_e=a(e),c(v.$$.fragment,e),He=a(e),I=i(e,"P",{"data-svelte-h":!0}),M(I)!=="svelte-ctnfvd"&&(I.innerHTML=Js),ze=a(e),f=i(e,"P",{"data-svelte-h":!0}),M(f)!=="svelte-a8bq9v"&&(f.textContent=Ts),Fe=a(e),w=i(e,"BLOCKQUOTE",{class:!0,"data-svelte-h":!0}),M(w)!=="svelte-r906iz"&&(w.innerHTML=js),Le=a(e),c(B.$$.fragment,e),xe=a(e),Z=i(e,"P",{"data-svelte-h":!0}),M(Z)!=="svelte-1nsuea4"&&(Z.textContent=ws),qe=a(e),C=i(e,"TABLE",{"data-svelte-h":!0}),M(C)!=="svelte-1ig457w"&&(C.innerHTML=us),Oe=a(e),c(k.$$.fragment,e),De=a(e),E=i(e,"TABLE",{"data-svelte-h":!0}),M(E)!=="svelte-1gg898p"&&(E.innerHTML=Us),Pe=a(e),u=i(e,"BLOCKQUOTE",{class:!0,"data-svelte-h":!0}),M(u)!=="svelte-1c5nyvq"&&(u.innerHTML=hs),Ke=a(e),el=i(e,"HR",{}),ll=a(e),c(A.$$.fragment,e),sl=a(e),G=i(e,"P",{"data-svelte-h":!0}),M(G)!=="svelte-1rxjx2x"&&(G.textContent=bs),tl=a(e),g=i(e,"OL",{"data-svelte-h":!0}),M(g)!=="svelte-18h6ho"&&(g.innerHTML=vs),nl=a(e),U=i(e,"BLOCKQUOTE",{class:!0,"data-svelte-h":!0}),M(U)!=="svelte-id12cf"&&(U.innerHTML=Is),al=a(e),c(W.$$.fragment,e),pl=a(e),X=i(e,"UL",{"data-svelte-h":!0}),M(X)!=="svelte-ghdn1o"&&(X.innerHTML=fs),il=a(e),c(R.$$.fragment,e),Ml=a(e),N=i(e,"P",{"data-svelte-h":!0}),M(N)!=="svelte-u52you"&&(N.textContent=Bs),ol=a(e),c(V.$$.fragment,e),cl=a(e),c(Y.$$.fragment,e),dl=a(e),Q=i(e,"P",{"data-svelte-h":!0}),M(Q)!=="svelte-czocs9"&&(Q.innerHTML=Zs),rl=a(e),$=i(e,"P",{"data-svelte-h":!0}),M($)!=="svelte-1e70fkc"&&($.textContent=Cs),yl=a(e),c(S.$$.fragment,e),ml=a(e),_=i(e,"P",{"data-svelte-h":!0}),M(_)!=="svelte-1csvp49"&&(_.innerHTML=ks),Jl=a(e),c(H.$$.fragment,e),Tl=a(e),z=i(e,"P",{"data-svelte-h":!0}),M(z)!=="svelte-ewzzeg"&&(z.innerHTML=Es),jl=a(e),c(F.$$.fragment,e),wl=a(e),c(L.$$.fragment,e),ul=a(e),x=i(e,"P",{"data-svelte-h":!0}),M(x)!=="svelte-1kzvzkk"&&(x.innerHTML=As),Ul=a(e),c(q.$$.fragment,e),hl=a(e),c(O.$$.fragment,e),bl=a(e),D=i(e,"P",{"data-svelte-h":!0}),M(D)!=="svelte-yy593y"&&(D.innerHTML=Gs),vl=a(e),P=i(e,"P",{"data-svelte-h":!0}),M(P)!=="svelte-1bx2epd"&&(P.innerHTML=gs),Il=a(e),c(K.$$.fragment,e),fl=a(e),ee=i(e,"P",{"data-svelte-h":!0}),M(ee)!=="svelte-pom1de"&&(ee.textContent=Ws),Bl=a(e),c(le.$$.fragment,e),Zl=a(e),c(se.$$.fragment,e),Cl=a(e),te=i(e,"P",{"data-svelte-h":!0}),M(te)!=="svelte-hx7m3p"&&(te.innerHTML=Xs),kl=a(e),c(ne.$$.fragment,e),El=a(e),ae=i(e,"P",{"data-svelte-h":!0}),M(ae)!=="svelte-1gtng2a"&&(ae.innerHTML=Rs),Al=a(e),c(pe.$$.fragment,e),Gl=a(e),ie=i(e,"P",{"data-svelte-h":!0}),M(ie)!=="svelte-az7dkj"&&(ie.innerHTML=Ns),gl=a(e),Me=i(e,"P",{"data-svelte-h":!0}),M(Me)!=="svelte-1gnchy7"&&(Me.innerHTML=Vs),Wl=a(e),h=i(e,"DETAILS",{});var cs=rs(h);Ne=i(cs,"SUMMARY",{"data-svelte-h":!0}),M(Ne)!=="svelte-ycltuu"&&(Ne.textContent=Ys),ds=a(cs),c(oe.$$.fragment,cs),cs.forEach(s),Xl=a(e),ce=i(e,"P",{"data-svelte-h":!0}),M(ce)!=="svelte-19ugog0"&&(ce.textContent=Qs),Rl=a(e),c(de.$$.fragment,e),Nl=a(e),re=i(e,"P",{"data-svelte-h":!0}),M(re)!=="svelte-u4crad"&&(re.textContent=$s),Vl=a(e),c(ye.$$.fragment,e),Yl=a(e),me=i(e,"P",{"data-svelte-h":!0}),M(me)!=="svelte-wir32s"&&(me.innerHTML=Ss),Ql=a(e),Je=i(e,"UL",{"data-svelte-h":!0}),M(Je)!=="svelte-1ddboft"&&(Je.innerHTML=_s),$l=a(e),Te=i(e,"P",{"data-svelte-h":!0}),M(Te)!=="svelte-1i9gylz"&&(Te.innerHTML=Hs),Sl=a(e),c(je.$$.fragment,e),_l=a(e),we=i(e,"P",{"data-svelte-h":!0}),M(we)!=="svelte-l2ct19"&&(we.textContent=zs),Hl=a(e),c(ue.$$.fragment,e),zl=a(e),Ue=i(e,"P",{"data-svelte-h":!0}),M(Ue)!=="svelte-ctgyqz"&&(Ue.textContent=Fs),Fl=a(e),he=i(e,"UL",{"data-svelte-h":!0}),M(he)!=="svelte-nchqxm"&&(he.innerHTML=Ls),Ll=a(e),be=i(e,"P",{"data-svelte-h":!0}),M(be)!=="svelte-1bgmmlj"&&(be.innerHTML=xs),xl=a(e),c(ve.$$.fragment,e),ql=a(e),Ie=i(e,"P",{"data-svelte-h":!0}),M(Ie)!=="svelte-x39e7s"&&(Ie.innerHTML=qs),Ol=a(e),c(fe.$$.fragment,e),Dl=a(e),Be=i(e,"P",{"data-svelte-h":!0}),M(Be)!=="svelte-12uu88k"&&(Be.innerHTML=Os),Pl=a(e),c(Ze.$$.fragment,e),Kl=a(e),Ce=i(e,"P",{"data-svelte-h":!0}),M(Ce)!=="svelte-tsfsth"&&(Ce.innerHTML=Ds),es=a(e),c(ke.$$.fragment,e),ls=a(e),c(Ee.$$.fragment,e),ss=a(e),Ae=i(e,"P",{"data-svelte-h":!0}),M(Ae)!=="svelte-xtyn70"&&(Ae.textContent=Ps),ts=a(e),c(Ge.$$.fragment,e),ns=a(e),c(ge.$$.fragment,e),as=a(e),We=i(e,"P",{"data-svelte-h":!0}),M(We)!=="svelte-15prqjs"&&(We.textContent=Ks),ps=a(e),Xe=i(e,"UL",{"data-svelte-h":!0}),M(Xe)!=="svelte-1qkff8e"&&(Xe.innerHTML=et),is=a(e),c(Re.$$.fragment,e),Ms=a(e),Ye=i(e,"P",{}),rs(Ye).forEach(s),this.h()},h(){Qe(j,"name","hf:doc:metadata"),Qe(j,"content",ct),Qe(w,"class","note"),Qe(u,"class","tip"),Qe(U,"class","note")},m(e,l){ys(document.head,j),t(e,$e,l),t(e,Ve,l),t(e,Se,l),d(b,e,l),t(e,_e,l),d(v,e,l),t(e,He,l),t(e,I,l),t(e,ze,l),t(e,f,l),t(e,Fe,l),t(e,w,l),t(e,Le,l),d(B,e,l),t(e,xe,l),t(e,Z,l),t(e,qe,l),t(e,C,l),t(e,Oe,l),d(k,e,l),t(e,De,l),t(e,E,l),t(e,Pe,l),t(e,u,l),t(e,Ke,l),t(e,el,l),t(e,ll,l),d(A,e,l),t(e,sl,l),t(e,G,l),t(e,tl,l),t(e,g,l),t(e,nl,l),t(e,U,l),t(e,al,l),d(W,e,l),t(e,pl,l),t(e,X,l),t(e,il,l),d(R,e,l),t(e,Ml,l),t(e,N,l),t(e,ol,l),d(V,e,l),t(e,cl,l),d(Y,e,l),t(e,dl,l),t(e,Q,l),t(e,rl,l),t(e,$,l),t(e,yl,l),d(S,e,l),t(e,ml,l),t(e,_,l),t(e,Jl,l),d(H,e,l),t(e,Tl,l),t(e,z,l),t(e,jl,l),d(F,e,l),t(e,wl,l),d(L,e,l),t(e,ul,l),t(e,x,l),t(e,Ul,l),d(q,e,l),t(e,hl,l),d(O,e,l),t(e,bl,l),t(e,D,l),t(e,vl,l),t(e,P,l),t(e,Il,l),d(K,e,l),t(e,fl,l),t(e,ee,l),t(e,Bl,l),d(le,e,l),t(e,Zl,l),d(se,e,l),t(e,Cl,l),t(e,te,l),t(e,kl,l),d(ne,e,l),t(e,El,l),t(e,ae,l),t(e,Al,l),d(pe,e,l),t(e,Gl,l),t(e,ie,l),t(e,gl,l),t(e,Me,l),t(e,Wl,l),t(e,h,l),ys(h,Ne),ys(h,ds),d(oe,h,null),t(e,Xl,l),t(e,ce,l),t(e,Rl,l),d(de,e,l),t(e,Nl,l),t(e,re,l),t(e,Vl,l),d(ye,e,l),t(e,Yl,l),t(e,me,l),t(e,Ql,l),t(e,Je,l),t(e,$l,l),t(e,Te,l),t(e,Sl,l),d(je,e,l),t(e,_l,l),t(e,we,l),t(e,Hl,l),d(ue,e,l),t(e,zl,l),t(e,Ue,l),t(e,Fl,l),t(e,he,l),t(e,Ll,l),t(e,be,l),t(e,xl,l),d(ve,e,l),t(e,ql,l),t(e,Ie,l),t(e,Ol,l),d(fe,e,l),t(e,Dl,l),t(e,Be,l),t(e,Pl,l),d(Ze,e,l),t(e,Kl,l),t(e,Ce,l),t(e,es,l),d(ke,e,l),t(e,ls,l),d(Ee,e,l),t(e,ss,l),t(e,Ae,l),t(e,ts,l),d(Ge,e,l),t(e,ns,l),d(ge,e,l),t(e,as,l),t(e,We,l),t(e,ps,l),t(e,Xe,l),t(e,is,l),d(Re,e,l),t(e,Ms,l),t(e,Ye,l),os=!0},p:st,i(e){os||(r(b.$$.fragment,e),r(v.$$.fragment,e),r(B.$$.fragment,e),r(k.$$.fragment,e),r(A.$$.fragment,e),r(W.$$.fragment,e),r(R.$$.fragment,e),r(V.$$.fragment,e),r(Y.$$.fragment,e),r(S.$$.fragment,e),r(H.$$.fragment,e),r(F.$$.fragment,e),r(L.$$.fragment,e),r(q.$$.fragment,e),r(O.$$.fragment,e),r(K.$$.fragment,e),r(le.$$.fragment,e),r(se.$$.fragment,e),r(ne.$$.fragment,e),r(pe.$$.fragment,e),r(oe.$$.fragment,e),r(de.$$.fragment,e),r(ye.$$.fragment,e),r(je.$$.fragment,e),r(ue.$$.fragment,e),r(ve.$$.fragment,e),r(fe.$$.fragment,e),r(Ze.$$.fragment,e),r(ke.$$.fragment,e),r(Ee.$$.fragment,e),r(Ge.$$.fragment,e),r(ge.$$.fragment,e),r(Re.$$.fragment,e),os=!0)},o(e){y(b.$$.fragment,e),y(v.$$.fragment,e),y(B.$$.fragment,e),y(k.$$.fragment,e),y(A.$$.fragment,e),y(W.$$.fragment,e),y(R.$$.fragment,e),y(V.$$.fragment,e),y(Y.$$.fragment,e),y(S.$$.fragment,e),y(H.$$.fragment,e),y(F.$$.fragment,e),y(L.$$.fragment,e),y(q.$$.fragment,e),y(O.$$.fragment,e),y(K.$$.fragment,e),y(le.$$.fragment,e),y(se.$$.fragment,e),y(ne.$$.fragment,e),y(pe.$$.fragment,e),y(oe.$$.fragment,e),y(de.$$.fragment,e),y(ye.$$.fragment,e),y(je.$$.fragment,e),y(ue.$$.fragment,e),y(ve.$$.fragment,e),y(fe.$$.fragment,e),y(Ze.$$.fragment,e),y(ke.$$.fragment,e),y(Ee.$$.fragment,e),y(Ge.$$.fragment,e),y(ge.$$.fragment,e),y(Re.$$.fragment,e),os=!1},d(e){e&&(s($e),s(Ve),s(Se),s(_e),s(He),s(I),s(ze),s(f),s(Fe),s(w),s(Le),s(xe),s(Z),s(qe),s(C),s(Oe),s(De),s(E),s(Pe),s(u),s(Ke),s(el),s(ll),s(sl),s(G),s(tl),s(g),s(nl),s(U),s(al),s(pl),s(X),s(il),s(Ml),s(N),s(ol),s(cl),s(dl),s(Q),s(rl),s($),s(yl),s(ml),s(_),s(Jl),s(Tl),s(z),s(jl),s(wl),s(ul),s(x),s(Ul),s(hl),s(bl),s(D),s(vl),s(P),s(Il),s(fl),s(ee),s(Bl),s(Zl),s(Cl),s(te),s(kl),s(El),s(ae),s(Al),s(Gl),s(ie),s(gl),s(Me),s(Wl),s(h),s(Xl),s(ce),s(Rl),s(Nl),s(re),s(Vl),s(Yl),s(me),s(Ql),s(Je),s($l),s(Te),s(Sl),s(_l),s(we),s(Hl),s(zl),s(Ue),s(Fl),s(he),s(Ll),s(be),s(xl),s(ql),s(Ie),s(Ol),s(Dl),s(Be),s(Pl),s(Kl),s(Ce),s(es),s(ls),s(ss),s(Ae),s(ts),s(ns),s(as),s(We),s(ps),s(Xe),s(is),s(Ms),s(Ye)),s(j),m(b,e),m(v,e),m(B,e),m(k,e),m(A,e),m(W,e),m(R,e),m(V,e),m(Y,e),m(S,e),m(H,e),m(F,e),m(L,e),m(q,e),m(O,e),m(K,e),m(le,e),m(se,e),m(ne,e),m(pe,e),m(oe),m(de,e),m(ye,e),m(je,e),m(ue,e),m(ve,e),m(fe,e),m(Ze,e),m(ke,e),m(Ee,e),m(Ge,e),m(ge,e),m(Re,e)}}}const ct='{"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 dt(ms){return tt(()=>{new URLSearchParams(window.location.search).get("fw")}),[]}class Tt extends nt{constructor(j){super(),at(this,j,dt,ot,lt,{})}}export{Tt as component}; | |
Xet Storage Details
- Size:
- 58.4 kB
- Xet hash:
- 8d57820e8eca29a3032781eed243da34fd19494825ed72e683ed8c78ebb39ac4
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.