Metadata-Version: 2.4
Name: strands-osmo
Version: 0.1.0
Summary: NVIDIA OSMO workflow orchestration for Strands Agents - submit, monitor, and debug Physical AI pipelines from natural language.
Author-email: Cagatay Cali <cagataycali@icloud.com>
License: Apache-2.0
Project-URL: Homepage, https://github.com/cagataycali/strands-osmo
Project-URL: Repository, https://github.com/cagataycali/strands-osmo
Project-URL: Issues, https://github.com/cagataycali/strands-osmo/issues
Project-URL: Documentation, https://cagataycali.github.io/strands-osmo/
Keywords: strands,agents,osmo,nvidia,kubernetes,workflow,orchestration,physical-ai,robotics,isaac-sim,gr00t,edge,jetson
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: System :: Distributed Computing
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: strands-agents
Requires-Dist: pyyaml>=6.0
Requires-Dist: jinja2>=3.0
Provides-Extra: dev
Requires-Dist: pytest>=7.0; extra == "dev"
Requires-Dist: pytest-asyncio; extra == "dev"
Requires-Dist: ruff; extra == "dev"
Provides-Extra: docs
Requires-Dist: mkdocs-material; extra == "docs"
Requires-Dist: pymdown-extensions; extra == "docs"
Provides-Extra: all
Requires-Dist: strands-agents-tools; extra == "all"
Requires-Dist: pytest>=7.0; extra == "all"
Requires-Dist: ruff; extra == "all"
Requires-Dist: mkdocs-material; extra == "all"
Requires-Dist: pymdown-extensions; extra == "all"
Dynamic: license-file

# strands-osmo

[![PyPI version](https://img.shields.io/pypi/v/strands-osmo?label=PyPI)](https://pypi.org/project/strands-osmo/)
[![Docs](https://img.shields.io/badge/docs-GitHub%20Pages-blue)](https://cagataycali.github.io/strands-osmo/)
[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](LICENSE)

[![Awesome Strands Agents](https://img.shields.io/badge/Awesome-Strands%20Agents-00FF77?style=flat-square)](https://github.com/cagataycali/awesome-strands-agents)

<p align="center">
  <img src="strands-osmo-logo.svg" alt="Strands OSMO" width="180">
</p>

**[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.**

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`](https://github.com/cagataycali/strands-cosmos) (Cosmos VLM provider + 21 generation/edge tools).

---

## Install

```bash
pip install strands-osmo
```

You also need the **OSMO CLI** on `PATH`:

```bash
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:

```python
from strands_osmo import osmo_doctor
osmo_doctor()
# → {"osmo_present": True, "version_ok": True, "logged_in": True, ...}
```

---

## Quick Start

### Discover resources, submit a workflow

```python
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

```python
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).

```python
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**:

1. **CLI is truth.** Tools shell out to `osmo`, never re-implement its client SDK.
2. **Thin wrappers.** Each tool ≈ 50 lines, normalizing JSON into Strands `ToolResult`.
3. **Graceful degradation.** Missing `osmo` binary → `exit 127` ToolResult, not crash.
4. **No upstream forking.** Use OSMO as-is; it's a separate repo on disk.

---

## Workflow YAML 101 (cheat sheet)

```yaml
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:

```bash
osmo workflow submit my-pipeline.yaml --pool h100-prod \
    --set num_gpu=4 --set epochs=10
```

Or:

```python
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](https://nvidia.github.io/OSMO/main/user_guide/).

---

## Development

```bash
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.
