strands-osmo
NVIDIA OSMO workflow orchestration for Strands Agents - submit, monitor, and debug Physical AI pipelines from natural language.
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.
This package wraps the production osmo CLI as 22 Strands tools so an agent can drive the entire workflow lifecycle in plain English.
Sister project:
strands-cosmos(Cosmos VLM provider + 21 generation/edge tools).
🔌 Use as an MCP server
Use strands-osmo from Claude Code, Claude Desktop, Cursor, Kiro, or any MCP client — all 25 OSMO tools (workflows, tasks, data, datasets, apps, pools) become MCP tools.
claude mcp add osmo -- uvx strands-osmo
Claude Desktop config:
{
"mcpServers": {
"osmo": {
"command": "uvx",
"args": ["strands-osmo"]
}
}
}
Options:
strands-osmo --tools osmo_workflow_submit,osmo_workflow_status # subset
strands-osmo --http --port 8000 # HTTP mode
Install
pip install strands-osmo
You also need the OSMO CLI on PATH:
curl -fsSL https://raw.githubusercontent.com/NVIDIA/OSMO/main/install.sh | bash
osmo login # one-time OAuth
osmo version # confirm
Verify everything from your agent:
from strands_osmo import osmo_doctor
osmo_doctor()
# → {"osmo_present": True, "version_ok": True, "logged_in": True, ...}
Quick Start
Discover resources, submit a workflow
from strands import Agent
from strands_osmo import (
osmo_doctor, osmo_pool_list, osmo_resources_list,
osmo_workflow_validate, osmo_workflow_submit, osmo_workflow_status,
osmo_workflow_logs, osmo_workflow_cancel,
osmo_cookbook_fetch,
)
agent = Agent(tools=[
osmo_doctor, osmo_pool_list, osmo_resources_list,
osmo_workflow_validate, osmo_workflow_submit, osmo_workflow_status,
osmo_workflow_logs, osmo_workflow_cancel,
osmo_cookbook_fetch,
])
agent("""
Find me an idle H100 pool with at least 4 GPUs free,
fetch the GR00T fine-tune recipe from the cookbook,
validate it, then submit it. Report the workflow ID.
""")
One-shot pipeline
from strands_osmo import osmo_workflow_submit
osmo_workflow_submit(
workflow_yaml="train.yaml",
pool="h100-prod",
set_vars={"num_gpu": 4, "epochs": 10},
priority="LOW", # bypass quota, run on idle capacity
)
Tools
| Category | Tools | Wraps |
|---|---|---|
| Auth | osmo_doctor, osmo_login, osmo_version |
env / osmo login / osmo version |
| Resources | osmo_pool_list, osmo_resources_list, osmo_profile_list, osmo_bucket_list |
osmo pool/resources/profile/bucket list |
| Workflow | osmo_workflow_submit, osmo_workflow_list, osmo_workflow_status, osmo_workflow_cancel, osmo_workflow_logs, osmo_workflow_exec |
osmo workflow ... |
| Task | osmo_task_list, osmo_task_describe |
osmo task ... |
| Data | osmo_data_upload, osmo_data_download, osmo_data_list |
osmo data ... |
| Dataset | osmo_dataset_list, osmo_dataset_describe |
osmo dataset ... |
| App | osmo_app_list, osmo_app_create |
osmo app ... |
| Cookbook | osmo_cookbook_fetch |
GitHub raw / local clone |
| Spec | osmo_workflow_validate, osmo_workflow_render |
local YAML + Jinja |
Total: 25 tools (22 OSMO-CLI-backed + 3 local helpers).
from strands_osmo import osmo_pool_list, osmo_workflow_submit
osmo_pool_list(mode="free")
# → JSON: pools, free GPUs, quota state
osmo_workflow_submit("train.yaml", pool="h100-prod", set_vars={"epochs": 10})
# → workflow ID(s)
Why use it inside an agent?
OSMO already has a great CLI. The point of strands-osmo is letting an
agent chain OSMO ops with reasoning:
| Without an agent | With an agent |
|---|---|
osmo pool list → eyeball |
"Find me an idle H100" |
| Edit YAML by hand to fit quota | "Cap memory to fit the smallest A100 node, then submit" |
osmo workflow logs <id> → grep for stack trace |
"Why did workflow X fail and how do I fix it?" |
osmo workflow submit && watch status |
"Submit, wait until done, summarize results, retrain on failure" |
Architecture
strands_osmo/
├── __init__.py # exports 25 tools
└── tools/
├── _common.py # osmo CLI runner + ToolResult helpers
├── doctor.py # env probe (osmo binary, login, profile)
├── login.py # osmo login
├── version.py # osmo version
├── pool_list.py # osmo pool list [--mode free]
├── resources_list.py # osmo resources list
├── profile_list.py # osmo profile list
├── bucket_list.py # osmo bucket list
├── workflow_submit.py # osmo workflow submit
├── workflow_list.py # osmo workflow list
├── workflow_status.py # osmo workflow describe
├── workflow_cancel.py # osmo workflow cancel
├── workflow_logs.py # osmo workflow logs
├── workflow_exec.py # osmo workflow exec
├── task_list.py # osmo task list
├── task_describe.py # osmo task describe
├── data_upload.py # osmo data upload
├── data_download.py # osmo data download
├── data_list.py # osmo data list
├── dataset_list.py # osmo dataset list
├── dataset_describe.py # osmo dataset describe
├── app_list.py # osmo app list
├── app_create.py # osmo app create
├── cookbook_fetch.py # OSMO cookbook fetcher
├── workflow_validate.py# local YAML lint
└── workflow_render.py # local Jinja render
Design tenets:
- CLI is truth. Tools shell out to
osmo, never re-implement its client SDK. - Thin wrappers. Each tool ≈ 50 lines, normalizing JSON into Strands
ToolResult. - Graceful degradation. Missing
osmobinary →exit 127ToolResult, not crash. - No upstream forking. Use OSMO as-is; it's a separate repo on disk.
Workflow YAML 101 (cheat sheet)
workflow:
name: my-pipeline
resources:
default: { cpu: 4, memory: 16Gi, storage: 40Gi, gpu: 1 }
tasks:
- name: train
image: pytorch/pytorch:2.6.0-cuda12.4-cudnn9-devel
command: ["python", "train.py"]
args: ["--epochs", "{{epochs}}", "--num-gpu", "{{num_gpu}}"]
resources: { gpu: "{{num_gpu}}" }
Submit with:
osmo workflow submit my-pipeline.yaml --pool h100-prod \
--set num_gpu=4 --set epochs=10
Or:
osmo_workflow_submit("my-pipeline.yaml", pool="h100-prod",
set_vars={"num_gpu": 4, "epochs": 10})
For the full reference (including groups, inputs, outputs.dataset,
checkpointing, and platform constraints) see the OSMO User Guide.
Development
git clone https://github.com/cagataycali/strands-osmo && cd strands-osmo
pip install -e ".[dev]"
pytest tests/ # smoke tests
ruff check . # lint
ruff format . # format
See Also
- OSMO - https://github.com/NVIDIA/OSMO
- OSMO docs - https://nvidia.github.io/OSMO/main/
- Strands Agents - https://strandsagents.com
- strands-cosmos - https://github.com/cagataycali/strands-cosmos
License
Apache 2.0 - same license as upstream OSMO.
OSMO is © NVIDIA Corporation. strands-osmo is an independent
community project.
Metadata
Release files for strands-osmo 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| strands_osmo-0.2.0.tar.gz | 23.9 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| strands_osmo-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 53.9 kB
Release files / strands_osmo-0.2.0.tar.gz
| Download URL | strands_osmo-0.2.0.tar.gz |
|---|---|
| Size | 23.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
a1d0fb6257ac0be423f277d832d0e39f8fa6b3a3e326fb243a7ea96b70ff424a
|
|
BLAKE2b-256 checksum How to use checksums |
6194b17b2d8e7bfbca45d265e0a181453b3d0297f2a4fed35b0d5957d2d8de15
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.13
|
Release files / strands_osmo-0.2.0-py3-none-any.whl
| Download URL | strands_osmo-0.2.0-py3-none-any.whl |
|---|---|
| Size | 30.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
86842996a18e512ac9f893279106d711a5597acc81f43dfaa5f69cf4ad3ecd2a
|
|
BLAKE2b-256 checksum How to use checksums |
20613ab0e2c8adc9af44b1219c5c358464cb473f99865b11654f4f3d1454b61a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.13
|
Security for strands-osmo 0.2.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.