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 ds,g as c,j as M,k as Ye,l as rs,m as t,n as y,t as d,o as r,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.dbc27f55.js";import{C as T}from"../chunks/CodeBlock.28d01b5a.js";function ot(ms){let j,Se,Ne,$e,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.",Fe,f,Ts="The CLI handles scaffolding, builds, validation, and deployment so you can stay focused on environment logic.",ze,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,C,ws="Already familiar with OpenEnv? Here’s the 8-step process at a glance:",qe,Z,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,G,sl,A,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,R,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,X,Ml,V,Bs="Let’s walk through the process of building a custom environment with OpenEnv.",ol,N,cl,Q,yl,Y,Cs="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>.",dl,S,Zs="Typical layout:",rl,$,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,F,Es="Edit <code>models.py</code> to describe your action and observation using Pydantic:",jl,z,wl,L,ul,x,Gs="Customize <code>server/my_environment.py</code> by extending <code>Environment</code>:",Ul,q,hl,O,bl,D,As="<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,Cl,se,Zl,te,Rs="<code>client.py</code> extends <code>EnvClient</code> so users can interact with your server via WebSocket for persistent sessions:",kl,ne,El,ae,Xs="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,pe,Al,ie,Vs="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,Ns="Keep building from the <code>openenv-base</code> image so shared tooling stays available:",Wl,h,Ve,Qs="Dockerfile",ys,oe,Rl,ce,Ys="If you introduced extra dependencies in the Dockerfile, you should install them in the Dockerfile before removing temp files.",Xl,ye,Vl,de,Ss="From the environment directory:",Nl,re,Ql,me,$s="<code>openenv build</code> understands both standalone environments and in-repo ones. Useful flags:",Yl,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>",Sl,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.",$l,je,_l,we,Fs="Once validation passes, the CLI can deploy directly to Hugging Face Spaces or any registry:",Hl,ue,Fl,Ue,zs="Key options:",zl,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,Ce,Kl,Ze,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,Ge,Ps="Here is a simple example of using your environment:",ts,Ae,ns,ge,as,We,Ks="Your next steps are to:",ps,Re,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,Xe,Ms,Qe,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"}}),G=new J({props:{title:"Overview",local:"overview",headingTag:"h2"}}),W=new J({props:{title:"Prerequisites",local:"prerequisites",headingTag:"h3"}}),X=new J({props:{title:"Step-by-Step Guide",local:"step-by-step-guide",headingTag:"h2"}}),N=new J({props:{title:"1. Scaffold with openenv init",local:"1-scaffold-with-openenv-init",headingTag:"h3"}}),Q=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}}),$=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"}}),z=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}}),ye=new J({props:{title:"7. Build & Validate with the CLI",local:"7-build--validate-with-the-cli",headingTag:"h3"}}),re=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:"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}}),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}}),Ce=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"}}),Ae=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"}}),Xe=new Mt({props:{source:"https://github.com/huggingface/openenv/blob/main/docs/source/getting_started/environment-builder.md"}}),{c(){j=p("meta"),Se=n(),Ne=p("p"),$e=n(),o(b.$$.fragment),_e=n(),o(v.$$.fragment),He=n(),I=p("p"),I.innerHTML=Js,Fe=n(),f=p("p"),f.textContent=Ts,ze=n(),w=p("blockquote"),w.innerHTML=js,Le=n(),o(B.$$.fragment),xe=n(),C=p("p"),C.textContent=ws,qe=n(),Z=p("table"),Z.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(G.$$.fragment),sl=n(),A=p("p"),A.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(),R=p("ul"),R.innerHTML=fs,il=n(),o(X.$$.fragment),Ml=n(),V=p("p"),V.textContent=Bs,ol=n(),o(N.$$.fragment),cl=n(),o(Q.$$.fragment),yl=n(),Y=p("p"),Y.innerHTML=Cs,dl=n(),S=p("p"),S.textContent=Zs,rl=n(),o($.$$.fragment),ml=n(),_=p("p"),_.innerHTML=ks,Jl=n(),o(H.$$.fragment),Tl=n(),F=p("p"),F.innerHTML=Es,jl=n(),o(z.$$.fragment),wl=n(),o(L.$$.fragment),ul=n(),x=p("p"),x.innerHTML=Gs,Ul=n(),o(q.$$.fragment),hl=n(),o(O.$$.fragment),bl=n(),D=p("p"),D.innerHTML=As,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),Cl=n(),o(se.$$.fragment),Zl=n(),te=p("p"),te.innerHTML=Rs,kl=n(),o(ne.$$.fragment),El=n(),ae=p("p"),ae.innerHTML=Xs,Gl=n(),o(pe.$$.fragment),Al=n(),ie=p("p"),ie.innerHTML=Vs,gl=n(),Me=p("p"),Me.innerHTML=Ns,Wl=n(),h=p("details"),Ve=p("summary"),Ve.textContent=Qs,ys=n(),o(oe.$$.fragment),Rl=n(),ce=p("p"),ce.textContent=Ys,Xl=n(),o(ye.$$.fragment),Vl=n(),de=p("p"),de.textContent=Ss,Nl=n(),o(re.$$.fragment),Ql=n(),me=p("p"),me.innerHTML=$s,Yl=n(),Je=p("ul"),Je.innerHTML=_s,Sl=n(),Te=p("p"),Te.innerHTML=Hs,$l=n(),o(je.$$.fragment),_l=n(),we=p("p"),we.textContent=Fs,Hl=n(),o(ue.$$.fragment),Fl=n(),Ue=p("p"),Ue.textContent=zs,zl=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(Ce.$$.fragment),Kl=n(),Ze=p("p"),Ze.innerHTML=Ds,es=n(),o(ke.$$.fragment),ls=n(),o(Ee.$$.fragment),ss=n(),Ge=p("p"),Ge.textContent=Ps,ts=n(),o(Ae.$$.fragment),ns=n(),o(ge.$$.fragment),as=n(),We=p("p"),We.textContent=Ks,ps=n(),Re=p("ul"),Re.innerHTML=et,is=n(),o(Xe.$$.fragment),Ms=n(),Qe=p("p"),this.h()},l(e){const l=pt("svelte-u9bgzb",document.head);j=i(l,"META",{name:!0,content:!0}),l.forEach(s),Se=a(e),Ne=i(e,"P",{}),ds(Ne).forEach(s),$e=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),Fe=a(e),f=i(e,"P",{"data-svelte-h":!0}),M(f)!=="svelte-a8bq9v"&&(f.textContent=Ts),ze=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),C=i(e,"P",{"data-svelte-h":!0}),M(C)!=="svelte-1nsuea4"&&(C.textContent=ws),qe=a(e),Z=i(e,"TABLE",{"data-svelte-h":!0}),M(Z)!=="svelte-1ig457w"&&(Z.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(G.$$.fragment,e),sl=a(e),A=i(e,"P",{"data-svelte-h":!0}),M(A)!=="svelte-1rxjx2x"&&(A.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),R=i(e,"UL",{"data-svelte-h":!0}),M(R)!=="svelte-ghdn1o"&&(R.innerHTML=fs),il=a(e),c(X.$$.fragment,e),Ml=a(e),V=i(e,"P",{"data-svelte-h":!0}),M(V)!=="svelte-u52you"&&(V.textContent=Bs),ol=a(e),c(N.$$.fragment,e),cl=a(e),c(Q.$$.fragment,e),yl=a(e),Y=i(e,"P",{"data-svelte-h":!0}),M(Y)!=="svelte-czocs9"&&(Y.innerHTML=Cs),dl=a(e),S=i(e,"P",{"data-svelte-h":!0}),M(S)!=="svelte-1e70fkc"&&(S.textContent=Zs),rl=a(e),c($.$$.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),F=i(e,"P",{"data-svelte-h":!0}),M(F)!=="svelte-ewzzeg"&&(F.innerHTML=Es),jl=a(e),c(z.$$.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=Gs),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=As),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),Cl=a(e),c(se.$$.fragment,e),Zl=a(e),te=i(e,"P",{"data-svelte-h":!0}),M(te)!=="svelte-hx7m3p"&&(te.innerHTML=Rs),kl=a(e),c(ne.$$.fragment,e),El=a(e),ae=i(e,"P",{"data-svelte-h":!0}),M(ae)!=="svelte-1gtng2a"&&(ae.innerHTML=Xs),Gl=a(e),c(pe.$$.fragment,e),Al=a(e),ie=i(e,"P",{"data-svelte-h":!0}),M(ie)!=="svelte-az7dkj"&&(ie.innerHTML=Vs),gl=a(e),Me=i(e,"P",{"data-svelte-h":!0}),M(Me)!=="svelte-1gnchy7"&&(Me.innerHTML=Ns),Wl=a(e),h=i(e,"DETAILS",{});var cs=ds(h);Ve=i(cs,"SUMMARY",{"data-svelte-h":!0}),M(Ve)!=="svelte-ycltuu"&&(Ve.textContent=Qs),ys=a(cs),c(oe.$$.fragment,cs),cs.forEach(s),Rl=a(e),ce=i(e,"P",{"data-svelte-h":!0}),M(ce)!=="svelte-19ugog0"&&(ce.textContent=Ys),Xl=a(e),c(ye.$$.fragment,e),Vl=a(e),de=i(e,"P",{"data-svelte-h":!0}),M(de)!=="svelte-u4crad"&&(de.textContent=Ss),Nl=a(e),c(re.$$.fragment,e),Ql=a(e),me=i(e,"P",{"data-svelte-h":!0}),M(me)!=="svelte-wir32s"&&(me.innerHTML=$s),Yl=a(e),Je=i(e,"UL",{"data-svelte-h":!0}),M(Je)!=="svelte-1ddboft"&&(Je.innerHTML=_s),Sl=a(e),Te=i(e,"P",{"data-svelte-h":!0}),M(Te)!=="svelte-1i9gylz"&&(Te.innerHTML=Hs),$l=a(e),c(je.$$.fragment,e),_l=a(e),we=i(e,"P",{"data-svelte-h":!0}),M(we)!=="svelte-l2ct19"&&(we.textContent=Fs),Hl=a(e),c(ue.$$.fragment,e),Fl=a(e),Ue=i(e,"P",{"data-svelte-h":!0}),M(Ue)!=="svelte-ctgyqz"&&(Ue.textContent=zs),zl=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(Ce.$$.fragment,e),Kl=a(e),Ze=i(e,"P",{"data-svelte-h":!0}),M(Ze)!=="svelte-tsfsth"&&(Ze.innerHTML=Ds),es=a(e),c(ke.$$.fragment,e),ls=a(e),c(Ee.$$.fragment,e),ss=a(e),Ge=i(e,"P",{"data-svelte-h":!0}),M(Ge)!=="svelte-xtyn70"&&(Ge.textContent=Ps),ts=a(e),c(Ae.$$.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),Re=i(e,"UL",{"data-svelte-h":!0}),M(Re)!=="svelte-1qkff8e"&&(Re.innerHTML=et),is=a(e),c(Xe.$$.fragment,e),Ms=a(e),Qe=i(e,"P",{}),ds(Qe).forEach(s),this.h()},h(){Ye(j,"name","hf:doc:metadata"),Ye(j,"content",ct),Ye(w,"class","note"),Ye(u,"class","tip"),Ye(U,"class","note")},m(e,l){rs(document.head,j),t(e,Se,l),t(e,Ne,l),t(e,$e,l),y(b,e,l),t(e,_e,l),y(v,e,l),t(e,He,l),t(e,I,l),t(e,Fe,l),t(e,f,l),t(e,ze,l),t(e,w,l),t(e,Le,l),y(B,e,l),t(e,xe,l),t(e,C,l),t(e,qe,l),t(e,Z,l),t(e,Oe,l),y(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),y(G,e,l),t(e,sl,l),t(e,A,l),t(e,tl,l),t(e,g,l),t(e,nl,l),t(e,U,l),t(e,al,l),y(W,e,l),t(e,pl,l),t(e,R,l),t(e,il,l),y(X,e,l),t(e,Ml,l),t(e,V,l),t(e,ol,l),y(N,e,l),t(e,cl,l),y(Q,e,l),t(e,yl,l),t(e,Y,l),t(e,dl,l),t(e,S,l),t(e,rl,l),y($,e,l),t(e,ml,l),t(e,_,l),t(e,Jl,l),y(H,e,l),t(e,Tl,l),t(e,F,l),t(e,jl,l),y(z,e,l),t(e,wl,l),y(L,e,l),t(e,ul,l),t(e,x,l),t(e,Ul,l),y(q,e,l),t(e,hl,l),y(O,e,l),t(e,bl,l),t(e,D,l),t(e,vl,l),t(e,P,l),t(e,Il,l),y(K,e,l),t(e,fl,l),t(e,ee,l),t(e,Bl,l),y(le,e,l),t(e,Cl,l),y(se,e,l),t(e,Zl,l),t(e,te,l),t(e,kl,l),y(ne,e,l),t(e,El,l),t(e,ae,l),t(e,Gl,l),y(pe,e,l),t(e,Al,l),t(e,ie,l),t(e,gl,l),t(e,Me,l),t(e,Wl,l),t(e,h,l),rs(h,Ve),rs(h,ys),y(oe,h,null),t(e,Rl,l),t(e,ce,l),t(e,Xl,l),y(ye,e,l),t(e,Vl,l),t(e,de,l),t(e,Nl,l),y(re,e,l),t(e,Ql,l),t(e,me,l),t(e,Yl,l),t(e,Je,l),t(e,Sl,l),t(e,Te,l),t(e,$l,l),y(je,e,l),t(e,_l,l),t(e,we,l),t(e,Hl,l),y(ue,e,l),t(e,Fl,l),t(e,Ue,l),t(e,zl,l),t(e,he,l),t(e,Ll,l),t(e,be,l),t(e,xl,l),y(ve,e,l),t(e,ql,l),t(e,Ie,l),t(e,Ol,l),y(fe,e,l),t(e,Dl,l),t(e,Be,l),t(e,Pl,l),y(Ce,e,l),t(e,Kl,l),t(e,Ze,l),t(e,es,l),y(ke,e,l),t(e,ls,l),y(Ee,e,l),t(e,ss,l),t(e,Ge,l),t(e,ts,l),y(Ae,e,l),t(e,ns,l),y(ge,e,l),t(e,as,l),t(e,We,l),t(e,ps,l),t(e,Re,l),t(e,is,l),y(Xe,e,l),t(e,Ms,l),t(e,Qe,l),os=!0},p:st,i(e){os||(d(b.$$.fragment,e),d(v.$$.fragment,e),d(B.$$.fragment,e),d(k.$$.fragment,e),d(G.$$.fragment,e),d(W.$$.fragment,e),d(X.$$.fragment,e),d(N.$$.fragment,e),d(Q.$$.fragment,e),d($.$$.fragment,e),d(H.$$.fragment,e),d(z.$$.fragment,e),d(L.$$.fragment,e),d(q.$$.fragment,e),d(O.$$.fragment,e),d(K.$$.fragment,e),d(le.$$.fragment,e),d(se.$$.fragment,e),d(ne.$$.fragment,e),d(pe.$$.fragment,e),d(oe.$$.fragment,e),d(ye.$$.fragment,e),d(re.$$.fragment,e),d(je.$$.fragment,e),d(ue.$$.fragment,e),d(ve.$$.fragment,e),d(fe.$$.fragment,e),d(Ce.$$.fragment,e),d(ke.$$.fragment,e),d(Ee.$$.fragment,e),d(Ae.$$.fragment,e),d(ge.$$.fragment,e),d(Xe.$$.fragment,e),os=!0)},o(e){r(b.$$.fragment,e),r(v.$$.fragment,e),r(B.$$.fragment,e),r(k.$$.fragment,e),r(G.$$.fragment,e),r(W.$$.fragment,e),r(X.$$.fragment,e),r(N.$$.fragment,e),r(Q.$$.fragment,e),r($.$$.fragment,e),r(H.$$.fragment,e),r(z.$$.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(ye.$$.fragment,e),r(re.$$.fragment,e),r(je.$$.fragment,e),r(ue.$$.fragment,e),r(ve.$$.fragment,e),r(fe.$$.fragment,e),r(Ce.$$.fragment,e),r(ke.$$.fragment,e),r(Ee.$$.fragment,e),r(Ae.$$.fragment,e),r(ge.$$.fragment,e),r(Xe.$$.fragment,e),os=!1},d(e){e&&(s(Se),s(Ne),s($e),s(_e),s(He),s(I),s(Fe),s(f),s(ze),s(w),s(Le),s(xe),s(C),s(qe),s(Z),s(Oe),s(De),s(E),s(Pe),s(u),s(Ke),s(el),s(ll),s(sl),s(A),s(tl),s(g),s(nl),s(U),s(al),s(pl),s(R),s(il),s(Ml),s(V),s(ol),s(cl),s(yl),s(Y),s(dl),s(S),s(rl),s(ml),s(_),s(Jl),s(Tl),s(F),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(Cl),s(Zl),s(te),s(kl),s(El),s(ae),s(Gl),s(Al),s(ie),s(gl),s(Me),s(Wl),s(h),s(Rl),s(ce),s(Xl),s(Vl),s(de),s(Nl),s(Ql),s(me),s(Yl),s(Je),s(Sl),s(Te),s($l),s(_l),s(we),s(Hl),s(Fl),s(Ue),s(zl),s(he),s(Ll),s(be),s(xl),s(ql),s(Ie),s(Ol),s(Dl),s(Be),s(Pl),s(Kl),s(Ze),s(es),s(ls),s(ss),s(Ge),s(ts),s(ns),s(as),s(We),s(ps),s(Re),s(is),s(Ms),s(Qe)),s(j),m(b,e),m(v,e),m(B,e),m(k,e),m(G,e),m(W,e),m(X,e),m(N,e),m(Q,e),m($,e),m(H,e),m(z,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(ye,e),m(re,e),m(je,e),m(ue,e),m(ve,e),m(fe,e),m(Ce,e),m(ke,e),m(Ee,e),m(Ae,e),m(ge,e),m(Xe,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 yt(ms){return tt(()=>{new URLSearchParams(window.location.search).get("fw")}),[]}class Tt extends nt{constructor(j){super(),at(this,j,yt,ot,lt,{})}}export{Tt as component}; | |
Xet Storage Details
- Size:
- 58.4 kB
- Xet hash:
- caaf563574ddf36e16d623dbaafbfc7b0c329265c4de9a0c1c73f10c4ab430e6
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.