strands-osmo 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. strands_osmo-0.1.0/LICENSE +17 -0
  2. strands_osmo-0.1.0/PKG-INFO +278 -0
  3. strands_osmo-0.1.0/README.md +235 -0
  4. strands_osmo-0.1.0/pyproject.toml +89 -0
  5. strands_osmo-0.1.0/setup.cfg +4 -0
  6. strands_osmo-0.1.0/strands_osmo/__init__.py +102 -0
  7. strands_osmo-0.1.0/strands_osmo/tools/__init__.py +94 -0
  8. strands_osmo-0.1.0/strands_osmo/tools/_common.py +161 -0
  9. strands_osmo-0.1.0/strands_osmo/tools/app_create.py +29 -0
  10. strands_osmo-0.1.0/strands_osmo/tools/app_list.py +23 -0
  11. strands_osmo-0.1.0/strands_osmo/tools/bucket_list.py +16 -0
  12. strands_osmo-0.1.0/strands_osmo/tools/cookbook_fetch.py +80 -0
  13. strands_osmo-0.1.0/strands_osmo/tools/data_download.py +27 -0
  14. strands_osmo-0.1.0/strands_osmo/tools/data_list.py +27 -0
  15. strands_osmo-0.1.0/strands_osmo/tools/data_upload.py +35 -0
  16. strands_osmo-0.1.0/strands_osmo/tools/dataset_describe.py +23 -0
  17. strands_osmo-0.1.0/strands_osmo/tools/dataset_list.py +26 -0
  18. strands_osmo-0.1.0/strands_osmo/tools/doctor.py +57 -0
  19. strands_osmo-0.1.0/strands_osmo/tools/login.py +31 -0
  20. strands_osmo-0.1.0/strands_osmo/tools/pool_list.py +27 -0
  21. strands_osmo-0.1.0/strands_osmo/tools/profile_list.py +16 -0
  22. strands_osmo-0.1.0/strands_osmo/tools/resources_list.py +16 -0
  23. strands_osmo-0.1.0/strands_osmo/tools/task_describe.py +19 -0
  24. strands_osmo-0.1.0/strands_osmo/tools/task_list.py +18 -0
  25. strands_osmo-0.1.0/strands_osmo/tools/version.py +13 -0
  26. strands_osmo-0.1.0/strands_osmo/tools/workflow_cancel.py +23 -0
  27. strands_osmo-0.1.0/strands_osmo/tools/workflow_exec.py +26 -0
  28. strands_osmo-0.1.0/strands_osmo/tools/workflow_list.py +34 -0
  29. strands_osmo-0.1.0/strands_osmo/tools/workflow_logs.py +35 -0
  30. strands_osmo-0.1.0/strands_osmo/tools/workflow_render.py +45 -0
  31. strands_osmo-0.1.0/strands_osmo/tools/workflow_status.py +22 -0
  32. strands_osmo-0.1.0/strands_osmo/tools/workflow_submit.py +57 -0
  33. strands_osmo-0.1.0/strands_osmo/tools/workflow_validate.py +117 -0
  34. strands_osmo-0.1.0/strands_osmo.egg-info/PKG-INFO +278 -0
  35. strands_osmo-0.1.0/strands_osmo.egg-info/SOURCES.txt +39 -0
  36. strands_osmo-0.1.0/strands_osmo.egg-info/dependency_links.txt +1 -0
  37. strands_osmo-0.1.0/strands_osmo.egg-info/requires.txt +19 -0
  38. strands_osmo-0.1.0/strands_osmo.egg-info/top_level.txt +1 -0
  39. strands_osmo-0.1.0/tests/test_doctor.py +17 -0
  40. strands_osmo-0.1.0/tests/test_imports.py +41 -0
  41. strands_osmo-0.1.0/tests/test_validate.py +85 -0
@@ -0,0 +1,17 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ Copyright 2026 Cagatay Cali
6
+
7
+ Licensed under the Apache License, Version 2.0 (the "License");
8
+ you may not use this file except in compliance with the License.
9
+ You may obtain a copy of the License at
10
+
11
+ http://www.apache.org/licenses/LICENSE-2.0
12
+
13
+ Unless required by applicable law or agreed to in writing, software
14
+ distributed under the License is distributed on an "AS IS" BASIS,
15
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ See the License for the specific language governing permissions and
17
+ limitations under the License.
@@ -0,0 +1,278 @@
1
+ Metadata-Version: 2.4
2
+ Name: strands-osmo
3
+ Version: 0.1.0
4
+ Summary: NVIDIA OSMO workflow orchestration for Strands Agents - submit, monitor, and debug Physical AI pipelines from natural language.
5
+ Author-email: Cagatay Cali <cagataycali@icloud.com>
6
+ License: Apache-2.0
7
+ Project-URL: Homepage, https://github.com/cagataycali/strands-osmo
8
+ Project-URL: Repository, https://github.com/cagataycali/strands-osmo
9
+ Project-URL: Issues, https://github.com/cagataycali/strands-osmo/issues
10
+ Project-URL: Documentation, https://cagataycali.github.io/strands-osmo/
11
+ Keywords: strands,agents,osmo,nvidia,kubernetes,workflow,orchestration,physical-ai,robotics,isaac-sim,gr00t,edge,jetson
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: Apache Software License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
21
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
22
+ Classifier: Topic :: System :: Distributed Computing
23
+ Requires-Python: >=3.10
24
+ Description-Content-Type: text/markdown
25
+ License-File: LICENSE
26
+ Requires-Dist: strands-agents
27
+ Requires-Dist: pyyaml>=6.0
28
+ Requires-Dist: jinja2>=3.0
29
+ Provides-Extra: dev
30
+ Requires-Dist: pytest>=7.0; extra == "dev"
31
+ Requires-Dist: pytest-asyncio; extra == "dev"
32
+ Requires-Dist: ruff; extra == "dev"
33
+ Provides-Extra: docs
34
+ Requires-Dist: mkdocs-material; extra == "docs"
35
+ Requires-Dist: pymdown-extensions; extra == "docs"
36
+ Provides-Extra: all
37
+ Requires-Dist: strands-agents-tools; extra == "all"
38
+ Requires-Dist: pytest>=7.0; extra == "all"
39
+ Requires-Dist: ruff; extra == "all"
40
+ Requires-Dist: mkdocs-material; extra == "all"
41
+ Requires-Dist: pymdown-extensions; extra == "all"
42
+ Dynamic: license-file
43
+
44
+ # strands-osmo
45
+
46
+ [![PyPI version](https://img.shields.io/pypi/v/strands-osmo?label=PyPI)](https://pypi.org/project/strands-osmo/)
47
+ [![Docs](https://img.shields.io/badge/docs-GitHub%20Pages-blue)](https://cagataycali.github.io/strands-osmo/)
48
+ [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](LICENSE)
49
+
50
+ [![Awesome Strands Agents](https://img.shields.io/badge/Awesome-Strands%20Agents-00FF77?style=flat-square)](https://github.com/cagataycali/awesome-strands-agents)
51
+
52
+ <p align="center">
53
+ <img src="strands-osmo-logo.svg" alt="Strands OSMO" width="180">
54
+ </p>
55
+
56
+ **[NVIDIA OSMO](https://github.com/NVIDIA/OSMO) workflow orchestration for [Strands Agents](https://strandsagents.com) - submit, monitor, and debug Physical AI pipelines from natural language.**
57
+
58
+ OSMO is NVIDIA's open-source Kubernetes-native control plane for Physical AI. It runs heterogeneous compute (training GPUs, simulation GPUs, edge devices) from a single YAML spec - used in production for **GR00T**, **Isaac Lab**, **Isaac Dexterity**, **Isaac Sim**, **Isaac ROS**.
59
+
60
+ This package wraps the production `osmo` CLI as **22 Strands tools** so an agent can drive the entire workflow lifecycle in plain English.
61
+
62
+ > Sister project: [`strands-cosmos`](https://github.com/cagataycali/strands-cosmos) (Cosmos VLM provider + 21 generation/edge tools).
63
+
64
+ ---
65
+
66
+ ## Install
67
+
68
+ ```bash
69
+ pip install strands-osmo
70
+ ```
71
+
72
+ You also need the **OSMO CLI** on `PATH`:
73
+
74
+ ```bash
75
+ curl -fsSL https://raw.githubusercontent.com/NVIDIA/OSMO/main/install.sh | bash
76
+ osmo login # one-time OAuth
77
+ osmo version # confirm
78
+ ```
79
+
80
+ Verify everything from your agent:
81
+
82
+ ```python
83
+ from strands_osmo import osmo_doctor
84
+ osmo_doctor()
85
+ # → {"osmo_present": True, "version_ok": True, "logged_in": True, ...}
86
+ ```
87
+
88
+ ---
89
+
90
+ ## Quick Start
91
+
92
+ ### Discover resources, submit a workflow
93
+
94
+ ```python
95
+ from strands import Agent
96
+ from strands_osmo import (
97
+ osmo_doctor, osmo_pool_list, osmo_resources_list,
98
+ osmo_workflow_validate, osmo_workflow_submit, osmo_workflow_status,
99
+ osmo_workflow_logs, osmo_workflow_cancel,
100
+ osmo_cookbook_fetch,
101
+ )
102
+
103
+ agent = Agent(tools=[
104
+ osmo_doctor, osmo_pool_list, osmo_resources_list,
105
+ osmo_workflow_validate, osmo_workflow_submit, osmo_workflow_status,
106
+ osmo_workflow_logs, osmo_workflow_cancel,
107
+ osmo_cookbook_fetch,
108
+ ])
109
+
110
+ agent("""
111
+ Find me an idle H100 pool with at least 4 GPUs free,
112
+ fetch the GR00T fine-tune recipe from the cookbook,
113
+ validate it, then submit it. Report the workflow ID.
114
+ """)
115
+ ```
116
+
117
+ ### One-shot pipeline
118
+
119
+ ```python
120
+ from strands_osmo import osmo_workflow_submit
121
+
122
+ osmo_workflow_submit(
123
+ workflow_yaml="train.yaml",
124
+ pool="h100-prod",
125
+ set_vars={"num_gpu": 4, "epochs": 10},
126
+ priority="LOW", # bypass quota, run on idle capacity
127
+ )
128
+ ```
129
+
130
+ ---
131
+
132
+ ## Tools
133
+
134
+ | Category | Tools | Wraps |
135
+ |-------------|----------------------------------------------------------------------------------------------------------|-------|
136
+ | **Auth** | `osmo_doctor`, `osmo_login`, `osmo_version` | env / `osmo login` / `osmo version` |
137
+ | **Resources** | `osmo_pool_list`, `osmo_resources_list`, `osmo_profile_list`, `osmo_bucket_list` | `osmo pool/resources/profile/bucket list` |
138
+ | **Workflow** | `osmo_workflow_submit`, `osmo_workflow_list`, `osmo_workflow_status`, `osmo_workflow_cancel`, `osmo_workflow_logs`, `osmo_workflow_exec` | `osmo workflow ...` |
139
+ | **Task** | `osmo_task_list`, `osmo_task_describe` | `osmo task ...` |
140
+ | **Data** | `osmo_data_upload`, `osmo_data_download`, `osmo_data_list` | `osmo data ...` |
141
+ | **Dataset** | `osmo_dataset_list`, `osmo_dataset_describe` | `osmo dataset ...` |
142
+ | **App** | `osmo_app_list`, `osmo_app_create` | `osmo app ...` |
143
+ | **Cookbook** | `osmo_cookbook_fetch` | GitHub raw / local clone |
144
+ | **Spec** | `osmo_workflow_validate`, `osmo_workflow_render` | local YAML + Jinja |
145
+
146
+ **Total: 25 tools** (22 OSMO-CLI-backed + 3 local helpers).
147
+
148
+ ```python
149
+ from strands_osmo import osmo_pool_list, osmo_workflow_submit
150
+
151
+ osmo_pool_list(mode="free")
152
+ # → JSON: pools, free GPUs, quota state
153
+
154
+ osmo_workflow_submit("train.yaml", pool="h100-prod", set_vars={"epochs": 10})
155
+ # → workflow ID(s)
156
+ ```
157
+
158
+ ---
159
+
160
+ ## Why use it inside an agent?
161
+
162
+ OSMO already has a great CLI. The point of `strands-osmo` is letting an
163
+ agent **chain** OSMO ops with reasoning:
164
+
165
+ | Without an agent | With an agent |
166
+ |-----------------------------------------------------|---------------------------------------------------------|
167
+ | `osmo pool list` → eyeball | "Find me an idle H100" |
168
+ | Edit YAML by hand to fit quota | "Cap memory to fit the smallest A100 node, then submit" |
169
+ | `osmo workflow logs <id>` → grep for stack trace | "Why did workflow X fail and how do I fix it?" |
170
+ | `osmo workflow submit && watch status` | "Submit, wait until done, summarize results, retrain on failure" |
171
+
172
+ ---
173
+
174
+ ## Architecture
175
+
176
+ ```
177
+ strands_osmo/
178
+ ├── __init__.py # exports 25 tools
179
+ └── tools/
180
+ ├── _common.py # osmo CLI runner + ToolResult helpers
181
+ ├── doctor.py # env probe (osmo binary, login, profile)
182
+ ├── login.py # osmo login
183
+ ├── version.py # osmo version
184
+ ├── pool_list.py # osmo pool list [--mode free]
185
+ ├── resources_list.py # osmo resources list
186
+ ├── profile_list.py # osmo profile list
187
+ ├── bucket_list.py # osmo bucket list
188
+ ├── workflow_submit.py # osmo workflow submit
189
+ ├── workflow_list.py # osmo workflow list
190
+ ├── workflow_status.py # osmo workflow describe
191
+ ├── workflow_cancel.py # osmo workflow cancel
192
+ ├── workflow_logs.py # osmo workflow logs
193
+ ├── workflow_exec.py # osmo workflow exec
194
+ ├── task_list.py # osmo task list
195
+ ├── task_describe.py # osmo task describe
196
+ ├── data_upload.py # osmo data upload
197
+ ├── data_download.py # osmo data download
198
+ ├── data_list.py # osmo data list
199
+ ├── dataset_list.py # osmo dataset list
200
+ ├── dataset_describe.py # osmo dataset describe
201
+ ├── app_list.py # osmo app list
202
+ ├── app_create.py # osmo app create
203
+ ├── cookbook_fetch.py # OSMO cookbook fetcher
204
+ ├── workflow_validate.py# local YAML lint
205
+ └── workflow_render.py # local Jinja render
206
+ ```
207
+
208
+ **Design tenets**:
209
+
210
+ 1. **CLI is truth.** Tools shell out to `osmo`, never re-implement its client SDK.
211
+ 2. **Thin wrappers.** Each tool ≈ 50 lines, normalizing JSON into Strands `ToolResult`.
212
+ 3. **Graceful degradation.** Missing `osmo` binary → `exit 127` ToolResult, not crash.
213
+ 4. **No upstream forking.** Use OSMO as-is; it's a separate repo on disk.
214
+
215
+ ---
216
+
217
+ ## Workflow YAML 101 (cheat sheet)
218
+
219
+ ```yaml
220
+ workflow:
221
+ name: my-pipeline
222
+ resources:
223
+ default: { cpu: 4, memory: 16Gi, storage: 40Gi, gpu: 1 }
224
+
225
+ tasks:
226
+ - name: train
227
+ image: pytorch/pytorch:2.6.0-cuda12.4-cudnn9-devel
228
+ command: ["python", "train.py"]
229
+ args: ["--epochs", "{{epochs}}", "--num-gpu", "{{num_gpu}}"]
230
+ resources: { gpu: "{{num_gpu}}" }
231
+ ```
232
+
233
+ Submit with:
234
+
235
+ ```bash
236
+ osmo workflow submit my-pipeline.yaml --pool h100-prod \
237
+ --set num_gpu=4 --set epochs=10
238
+ ```
239
+
240
+ Or:
241
+
242
+ ```python
243
+ osmo_workflow_submit("my-pipeline.yaml", pool="h100-prod",
244
+ set_vars={"num_gpu": 4, "epochs": 10})
245
+ ```
246
+
247
+ For the full reference (including `groups`, `inputs`, `outputs.dataset`,
248
+ checkpointing, and platform constraints) see the [OSMO User Guide](https://nvidia.github.io/OSMO/main/user_guide/).
249
+
250
+ ---
251
+
252
+ ## Development
253
+
254
+ ```bash
255
+ git clone https://github.com/cagataycali/strands-osmo && cd strands-osmo
256
+ pip install -e ".[dev]"
257
+ pytest tests/ # smoke tests
258
+ ruff check . # lint
259
+ ruff format . # format
260
+ ```
261
+
262
+ ---
263
+
264
+ ## See Also
265
+
266
+ - **OSMO** - <https://github.com/NVIDIA/OSMO>
267
+ - **OSMO docs** - <https://nvidia.github.io/OSMO/main/>
268
+ - **Strands Agents** - <https://strandsagents.com>
269
+ - **strands-cosmos** - <https://github.com/cagataycali/strands-cosmos>
270
+
271
+ ---
272
+
273
+ ## License
274
+
275
+ Apache 2.0 - same license as upstream OSMO.
276
+
277
+ OSMO is © NVIDIA Corporation. `strands-osmo` is an independent
278
+ community project.
@@ -0,0 +1,235 @@
1
+ # strands-osmo
2
+
3
+ [![PyPI version](https://img.shields.io/pypi/v/strands-osmo?label=PyPI)](https://pypi.org/project/strands-osmo/)
4
+ [![Docs](https://img.shields.io/badge/docs-GitHub%20Pages-blue)](https://cagataycali.github.io/strands-osmo/)
5
+ [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](LICENSE)
6
+
7
+ [![Awesome Strands Agents](https://img.shields.io/badge/Awesome-Strands%20Agents-00FF77?style=flat-square)](https://github.com/cagataycali/awesome-strands-agents)
8
+
9
+ <p align="center">
10
+ <img src="strands-osmo-logo.svg" alt="Strands OSMO" width="180">
11
+ </p>
12
+
13
+ **[NVIDIA OSMO](https://github.com/NVIDIA/OSMO) workflow orchestration for [Strands Agents](https://strandsagents.com) - submit, monitor, and debug Physical AI pipelines from natural language.**
14
+
15
+ OSMO is NVIDIA's open-source Kubernetes-native control plane for Physical AI. It runs heterogeneous compute (training GPUs, simulation GPUs, edge devices) from a single YAML spec - used in production for **GR00T**, **Isaac Lab**, **Isaac Dexterity**, **Isaac Sim**, **Isaac ROS**.
16
+
17
+ This package wraps the production `osmo` CLI as **22 Strands tools** so an agent can drive the entire workflow lifecycle in plain English.
18
+
19
+ > Sister project: [`strands-cosmos`](https://github.com/cagataycali/strands-cosmos) (Cosmos VLM provider + 21 generation/edge tools).
20
+
21
+ ---
22
+
23
+ ## Install
24
+
25
+ ```bash
26
+ pip install strands-osmo
27
+ ```
28
+
29
+ You also need the **OSMO CLI** on `PATH`:
30
+
31
+ ```bash
32
+ curl -fsSL https://raw.githubusercontent.com/NVIDIA/OSMO/main/install.sh | bash
33
+ osmo login # one-time OAuth
34
+ osmo version # confirm
35
+ ```
36
+
37
+ Verify everything from your agent:
38
+
39
+ ```python
40
+ from strands_osmo import osmo_doctor
41
+ osmo_doctor()
42
+ # → {"osmo_present": True, "version_ok": True, "logged_in": True, ...}
43
+ ```
44
+
45
+ ---
46
+
47
+ ## Quick Start
48
+
49
+ ### Discover resources, submit a workflow
50
+
51
+ ```python
52
+ from strands import Agent
53
+ from strands_osmo import (
54
+ osmo_doctor, osmo_pool_list, osmo_resources_list,
55
+ osmo_workflow_validate, osmo_workflow_submit, osmo_workflow_status,
56
+ osmo_workflow_logs, osmo_workflow_cancel,
57
+ osmo_cookbook_fetch,
58
+ )
59
+
60
+ agent = Agent(tools=[
61
+ osmo_doctor, osmo_pool_list, osmo_resources_list,
62
+ osmo_workflow_validate, osmo_workflow_submit, osmo_workflow_status,
63
+ osmo_workflow_logs, osmo_workflow_cancel,
64
+ osmo_cookbook_fetch,
65
+ ])
66
+
67
+ agent("""
68
+ Find me an idle H100 pool with at least 4 GPUs free,
69
+ fetch the GR00T fine-tune recipe from the cookbook,
70
+ validate it, then submit it. Report the workflow ID.
71
+ """)
72
+ ```
73
+
74
+ ### One-shot pipeline
75
+
76
+ ```python
77
+ from strands_osmo import osmo_workflow_submit
78
+
79
+ osmo_workflow_submit(
80
+ workflow_yaml="train.yaml",
81
+ pool="h100-prod",
82
+ set_vars={"num_gpu": 4, "epochs": 10},
83
+ priority="LOW", # bypass quota, run on idle capacity
84
+ )
85
+ ```
86
+
87
+ ---
88
+
89
+ ## Tools
90
+
91
+ | Category | Tools | Wraps |
92
+ |-------------|----------------------------------------------------------------------------------------------------------|-------|
93
+ | **Auth** | `osmo_doctor`, `osmo_login`, `osmo_version` | env / `osmo login` / `osmo version` |
94
+ | **Resources** | `osmo_pool_list`, `osmo_resources_list`, `osmo_profile_list`, `osmo_bucket_list` | `osmo pool/resources/profile/bucket list` |
95
+ | **Workflow** | `osmo_workflow_submit`, `osmo_workflow_list`, `osmo_workflow_status`, `osmo_workflow_cancel`, `osmo_workflow_logs`, `osmo_workflow_exec` | `osmo workflow ...` |
96
+ | **Task** | `osmo_task_list`, `osmo_task_describe` | `osmo task ...` |
97
+ | **Data** | `osmo_data_upload`, `osmo_data_download`, `osmo_data_list` | `osmo data ...` |
98
+ | **Dataset** | `osmo_dataset_list`, `osmo_dataset_describe` | `osmo dataset ...` |
99
+ | **App** | `osmo_app_list`, `osmo_app_create` | `osmo app ...` |
100
+ | **Cookbook** | `osmo_cookbook_fetch` | GitHub raw / local clone |
101
+ | **Spec** | `osmo_workflow_validate`, `osmo_workflow_render` | local YAML + Jinja |
102
+
103
+ **Total: 25 tools** (22 OSMO-CLI-backed + 3 local helpers).
104
+
105
+ ```python
106
+ from strands_osmo import osmo_pool_list, osmo_workflow_submit
107
+
108
+ osmo_pool_list(mode="free")
109
+ # → JSON: pools, free GPUs, quota state
110
+
111
+ osmo_workflow_submit("train.yaml", pool="h100-prod", set_vars={"epochs": 10})
112
+ # → workflow ID(s)
113
+ ```
114
+
115
+ ---
116
+
117
+ ## Why use it inside an agent?
118
+
119
+ OSMO already has a great CLI. The point of `strands-osmo` is letting an
120
+ agent **chain** OSMO ops with reasoning:
121
+
122
+ | Without an agent | With an agent |
123
+ |-----------------------------------------------------|---------------------------------------------------------|
124
+ | `osmo pool list` → eyeball | "Find me an idle H100" |
125
+ | Edit YAML by hand to fit quota | "Cap memory to fit the smallest A100 node, then submit" |
126
+ | `osmo workflow logs <id>` → grep for stack trace | "Why did workflow X fail and how do I fix it?" |
127
+ | `osmo workflow submit && watch status` | "Submit, wait until done, summarize results, retrain on failure" |
128
+
129
+ ---
130
+
131
+ ## Architecture
132
+
133
+ ```
134
+ strands_osmo/
135
+ ├── __init__.py # exports 25 tools
136
+ └── tools/
137
+ ├── _common.py # osmo CLI runner + ToolResult helpers
138
+ ├── doctor.py # env probe (osmo binary, login, profile)
139
+ ├── login.py # osmo login
140
+ ├── version.py # osmo version
141
+ ├── pool_list.py # osmo pool list [--mode free]
142
+ ├── resources_list.py # osmo resources list
143
+ ├── profile_list.py # osmo profile list
144
+ ├── bucket_list.py # osmo bucket list
145
+ ├── workflow_submit.py # osmo workflow submit
146
+ ├── workflow_list.py # osmo workflow list
147
+ ├── workflow_status.py # osmo workflow describe
148
+ ├── workflow_cancel.py # osmo workflow cancel
149
+ ├── workflow_logs.py # osmo workflow logs
150
+ ├── workflow_exec.py # osmo workflow exec
151
+ ├── task_list.py # osmo task list
152
+ ├── task_describe.py # osmo task describe
153
+ ├── data_upload.py # osmo data upload
154
+ ├── data_download.py # osmo data download
155
+ ├── data_list.py # osmo data list
156
+ ├── dataset_list.py # osmo dataset list
157
+ ├── dataset_describe.py # osmo dataset describe
158
+ ├── app_list.py # osmo app list
159
+ ├── app_create.py # osmo app create
160
+ ├── cookbook_fetch.py # OSMO cookbook fetcher
161
+ ├── workflow_validate.py# local YAML lint
162
+ └── workflow_render.py # local Jinja render
163
+ ```
164
+
165
+ **Design tenets**:
166
+
167
+ 1. **CLI is truth.** Tools shell out to `osmo`, never re-implement its client SDK.
168
+ 2. **Thin wrappers.** Each tool ≈ 50 lines, normalizing JSON into Strands `ToolResult`.
169
+ 3. **Graceful degradation.** Missing `osmo` binary → `exit 127` ToolResult, not crash.
170
+ 4. **No upstream forking.** Use OSMO as-is; it's a separate repo on disk.
171
+
172
+ ---
173
+
174
+ ## Workflow YAML 101 (cheat sheet)
175
+
176
+ ```yaml
177
+ workflow:
178
+ name: my-pipeline
179
+ resources:
180
+ default: { cpu: 4, memory: 16Gi, storage: 40Gi, gpu: 1 }
181
+
182
+ tasks:
183
+ - name: train
184
+ image: pytorch/pytorch:2.6.0-cuda12.4-cudnn9-devel
185
+ command: ["python", "train.py"]
186
+ args: ["--epochs", "{{epochs}}", "--num-gpu", "{{num_gpu}}"]
187
+ resources: { gpu: "{{num_gpu}}" }
188
+ ```
189
+
190
+ Submit with:
191
+
192
+ ```bash
193
+ osmo workflow submit my-pipeline.yaml --pool h100-prod \
194
+ --set num_gpu=4 --set epochs=10
195
+ ```
196
+
197
+ Or:
198
+
199
+ ```python
200
+ osmo_workflow_submit("my-pipeline.yaml", pool="h100-prod",
201
+ set_vars={"num_gpu": 4, "epochs": 10})
202
+ ```
203
+
204
+ For the full reference (including `groups`, `inputs`, `outputs.dataset`,
205
+ checkpointing, and platform constraints) see the [OSMO User Guide](https://nvidia.github.io/OSMO/main/user_guide/).
206
+
207
+ ---
208
+
209
+ ## Development
210
+
211
+ ```bash
212
+ git clone https://github.com/cagataycali/strands-osmo && cd strands-osmo
213
+ pip install -e ".[dev]"
214
+ pytest tests/ # smoke tests
215
+ ruff check . # lint
216
+ ruff format . # format
217
+ ```
218
+
219
+ ---
220
+
221
+ ## See Also
222
+
223
+ - **OSMO** - <https://github.com/NVIDIA/OSMO>
224
+ - **OSMO docs** - <https://nvidia.github.io/OSMO/main/>
225
+ - **Strands Agents** - <https://strandsagents.com>
226
+ - **strands-cosmos** - <https://github.com/cagataycali/strands-cosmos>
227
+
228
+ ---
229
+
230
+ ## License
231
+
232
+ Apache 2.0 - same license as upstream OSMO.
233
+
234
+ OSMO is © NVIDIA Corporation. `strands-osmo` is an independent
235
+ community project.
@@ -0,0 +1,89 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "strands-osmo"
7
+ version = "0.1.0"
8
+ description = "NVIDIA OSMO workflow orchestration for Strands Agents - submit, monitor, and debug Physical AI pipelines from natural language."
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ license = {text = "Apache-2.0"}
12
+ authors = [
13
+ {name = "Cagatay Cali", email = "cagataycali@icloud.com"}
14
+ ]
15
+ keywords = [
16
+ "strands",
17
+ "agents",
18
+ "osmo",
19
+ "nvidia",
20
+ "kubernetes",
21
+ "workflow",
22
+ "orchestration",
23
+ "physical-ai",
24
+ "robotics",
25
+ "isaac-sim",
26
+ "gr00t",
27
+ "edge",
28
+ "jetson",
29
+ ]
30
+ classifiers = [
31
+ "Development Status :: 3 - Alpha",
32
+ "Intended Audience :: Developers",
33
+ "License :: OSI Approved :: Apache Software License",
34
+ "Programming Language :: Python :: 3",
35
+ "Programming Language :: Python :: 3.10",
36
+ "Programming Language :: Python :: 3.11",
37
+ "Programming Language :: Python :: 3.12",
38
+ "Programming Language :: Python :: 3.13",
39
+ "Topic :: Scientific/Engineering :: Artificial Intelligence",
40
+ "Topic :: Software Development :: Libraries :: Python Modules",
41
+ "Topic :: System :: Distributed Computing",
42
+ ]
43
+
44
+ dependencies = [
45
+ "strands-agents",
46
+ "pyyaml>=6.0",
47
+ "jinja2>=3.0",
48
+ ]
49
+
50
+ [project.optional-dependencies]
51
+ dev = [
52
+ "pytest>=7.0",
53
+ "pytest-asyncio",
54
+ "ruff",
55
+ ]
56
+ docs = [
57
+ "mkdocs-material",
58
+ "pymdown-extensions",
59
+ ]
60
+ all = [
61
+ "strands-agents-tools",
62
+ "pytest>=7.0",
63
+ "ruff",
64
+ "mkdocs-material",
65
+ "pymdown-extensions",
66
+ ]
67
+
68
+ [project.urls]
69
+ Homepage = "https://github.com/cagataycali/strands-osmo"
70
+ Repository = "https://github.com/cagataycali/strands-osmo"
71
+ Issues = "https://github.com/cagataycali/strands-osmo/issues"
72
+ Documentation = "https://cagataycali.github.io/strands-osmo/"
73
+
74
+ [tool.setuptools.packages.find]
75
+ where = ["."]
76
+ include = ["strands_osmo*"]
77
+ exclude = ["tests*"]
78
+
79
+ [tool.ruff]
80
+ line-length = 100
81
+ target-version = "py310"
82
+
83
+ [tool.ruff.lint]
84
+ select = ["E", "F", "I", "N", "W"]
85
+ ignore = ["E501"]
86
+
87
+ [tool.pytest.ini_options]
88
+ testpaths = ["tests"]
89
+ python_files = ["test_*.py"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+