Adding a New Feature#
At a glance#
Create requirement markdown + validation rule under an existing
capabilities/folder.Create a feature JSON under
features/that lists the requirement codes.Document the feature and add it to
features/features.md.Add the feature to
Prop-Robotics-Neutralinprofiles/profiles.toml.pip install simready-validate, then runsimready-validateto verify.
This guide walks through adding a new feature to the SimReady Foundation spec end-to-end. The example adds a dummy “Has Foo Prim” feature (FET_099) with one requirement (FOO.001) to the existing hierarchy capability.
Core concepts#
What is a feature?#
A feature describes a runtime behavior that an asset either supports or doesn’t (e.g. “has physics”, “can drive”, “is grasp-ready”). Features are defined as JSON files in features/ and each one bundles one or more requirements together. A feature passes only when all of its requirements pass.
Feature dependencies#
A feature can depend on other features. When specified, the validation system:
Automatically includes all requirements from dependent features.
Recursively resolves nested dependencies.
Validates against the complete set of requirements from all dependencies.
This lets you build on existing features without duplicating their requirement lists.
1. Add the new requirement#
1a. Create the requirement documentation#
Add a new .md file in the existing capability’s requirements/ folder. For this example, create capabilities/hierarchy/requirements/has-foo-prim.md:
# has-foo-prim
| Code | FOO.001 |
|----------|---------|
| Validator| {oav-validator-latest-link}`foo-001` |
| Compatibility | {compatibility}`open-usd` |
| Tags | {tag}`essential` |
## Summary
The stage must contain a prim named "Foo".
## Description
The stage's default prim hierarchy must include at least one prim named
"Foo". This is a structural requirement that downstream tools depend on
to locate the primary content root.
### Valid USDA
```usda
#usda 1.0
(
defaultPrim = "Root"
)
def Xform "Root"
{
def Xform "Foo"
{
}
}
```
### Invalid USDA
```usda
#usda 1.0
(
defaultPrim = "Root"
)
def Xform "Root"
{
def Xform "Bar"
{
}
}
```
## How to comply
- Add an Xform prim named "Foo" under the default prim hierarchy.
1b. Register the requirement#
Add the requirement filename to capabilities/hierarchy/requirements.md in the toctree:
```{toctree}
:maxdepth: 1
:hidden:
requirements/hierarchy-has-root
requirements/exclusive-xform-parent-for-usdgeom
requirements/root-is-xformable
requirements/stage-has-default-prim
requirements/logical-geometry-grouping
requirements/xform-common-api-usage
requirements/placeable-posable-are-xformable
requirements/has-foo-prim <-- add this line
1c. Implement the rule#
Add the checker class to capabilities/hierarchy/validation.py:
@omni.asset_validator.register_rule("Hierarchy")
@omni.asset_validator.register_requirements(cap.HierarchyRequirements.FOO_001)
class HasFooPrimChecker(omni.asset_validator.BaseRuleChecker):
"""Stage must contain a prim named 'Foo'."""
def CheckStage(self, stage: Usd.Stage) -> None:
default_prim = stage.GetDefaultPrim()
if not default_prim:
return
for child in default_prim.GetAllChildren():
if child.GetName() == "Foo":
return
self._AddFailedCheck(
requirement=cap.HierarchyRequirements.FOO_001,
message="No prim named 'Foo' found under the default prim.",
)
2. Define the feature#
Create features/FET_099_base_neutral-0.1.0-has_foo_prim.json:
{
"id": "FET099_BASE_NEUTRAL",
"version": "0.1.0",
"display_name": "Has Foo Prim",
"path": "features/FET_099-has_foo_prim.html",
"requirements": [
"FOO.001"
]
}
If your feature builds on an existing feature, you can declare a dependency to inherit its requirements and only list additional ones:
{
"id": "FET099_BASE_NEUTRAL",
"version": "0.1.0",
"display_name": "Has Foo Prim",
"path": "features/FET_099-has_foo_prim.html",
"dependencies": [
{"FET003_BASE_NEUTRAL": {"version": "0.1.0"}}
],
"requirements": [
"FOO.001"
]
}
The validation system merges all requirement sets (from dependencies and the feature itself) into a single set that gets validated.
Feature ID conventions#
Feature IDs follow the pattern FET<NNN>_<VARIANT>:
Variant suffix |
Meaning |
|---|---|
|
Core OpenUSD only |
|
Uses PhysX extensions |
|
Uses MDL materials |
|
Robot domain with PhysX |
|
Robot core for Isaac Sim |
Pick the next available number for a new logical feature. If your feature is a runtime-specific variant of an existing feature, reuse the same number with a different suffix.
3. Add feature documentation#
3a. Create a feature markdown#
Create features/FET_099-has_foo_prim.md:
# Feature: `ID:099 - Has Foo Prim`
## Neutral Format
### Version 0.1.0
<details>
<summary><strong>Details</strong></summary>
#### Requirements
* Capability: [Hierarchy](../capabilities/hierarchy/capability-hierarchy.md)
* FOO.001
</details>
3b. Update the features index#
Add the feature to features/features.md in the toctree:
```{toctree}
:maxdepth: 1
ID:099 - Has Foo Prim - Base <FET_099-has_foo_prim>
4. Wire profiles#
Add your feature to the Prop-Robotics-Neutral profile in profiles/profiles.toml:
[Prop-Robotics-Neutral]
"1.0.0" = {features = [
{"FET000_CORE" = {version = "0.1.0"}}, # "Core"
{"FET001_BASE_NEUTRAL" = {version = "0.1.0"}}, # "Minimal"
{"FET003_BASE_NEUTRAL" = {version = "0.1.0"}}, # "RBD Physics"
{"FET004_BASE_NEUTRAL" = {version = "0.1.0"}}, # "Simulate Multi-Body Physics"
{"FET005_BASE_NEUTRAL" = {version = "0.1.0"}}, # "Simulate Grasp Physics"
{"FET006_BASE_MDL" = {version = "0.1.0"}}, # "Materials"
{"FET099_BASE_NEUTRAL" = {version = "0.1.0"}}, # "Has Foo Prim" <-- add this line
]}
5. Install and verify#
5a. Install simready-validate#
Requires Python >=3.10,<3.13 (Python 3.12 recommended).
pip install simready-validate
5b. Confirm it fails on a non-conforming asset#
From the root of this repository (simready_foundations/), run the following. The sample asset sm_apple_a01_01.usd has no prim named “Foo”, so it should fail FOO.001:
simready-validate \
--rules-path nv_core/sr_specs/docs/capabilities \
--features-path nv_core/sr_specs/docs/features \
--profiles-path nv_core/sr_specs/docs/profiles/profiles.toml \
--profile Prop-Robotics-Neutral --version 1.0.0 \
sample_content/common_assets/props_general/apple_a01/simready_usd/sm_apple_a01_01.usd
Expected output:
Asset: sample_content/.../sm_apple_a01_01.usd
[FAILED] Prop-Robotics-Neutral v1.0.0
FET099_BASE_NEUTRAL: failing requirements: ['FOO.001']
5c. Fix the asset#
Add a “Foo” prim to the stage using the USD Python API and export the result:
from pxr import Usd, UsdGeom
stage = Usd.Stage.Open(
"sample_content/common_assets/props_general/apple_a01/simready_usd/sm_apple_a01_01.usd"
)
default_prim = stage.GetDefaultPrim()
UsdGeom.Xform.Define(stage, default_prim.GetPath().AppendChild("Foo"))
stage.Export("fixed_asset.usd")
The exported fixed_asset.usd now contains the required prim:
def Xform "Root"
{
def Xform "Foo"
{
}
# ... existing geometry ...
}
5d. Confirm it passes#
Re-run validation against the fixed asset:
simready-validate \
--rules-path nv_core/sr_specs/docs/capabilities \
--features-path nv_core/sr_specs/docs/features \
--profiles-path nv_core/sr_specs/docs/profiles/profiles.toml \
--profile Prop-Robotics-Neutral --version 1.0.0 \
fixed_asset.usd
Expected output:
Asset: fixed_asset.usd
[PASSED] Prop-Robotics-Neutral v1.0.0
Checklist#
Requirement markdown: Create under the existing capability’s
requirements/folder. Add to therequirements.mdtoctree.Validation rule: Implement the checker class in the capability’s
validation.py.Feature JSON: Create under
features/.Feature documentation: Create the feature markdown under
features/. Add tofeatures/features.md.Profile wiring: Add the feature to
Prop-Robotics-Neutralinprofiles/profiles.toml.Install:
pip install simready-validateVerify: Run
simready-validateagainst a sample asset and confirm pass/fail behavior.
Tips#
Version from 0.1.0. Start at
0.1.0and bump the version when the requirement set changes.One feature per logical concept. Don’t pack unrelated checks into the same feature.
Document clearly. In the feature markdown, list every requirement and link back to the capability docs.
Test with sample assets. Use the reference assets in
sample_content/to validate against the target profile before merging.
Note
For the full acceptance lifecycle (domain identification, gap analysis, prototyping, QA, delivery), see the SimReady Acceptance Workflow.
Appendix A: Creating a new capability#
If your requirement doesn’t fit any existing capability, create a new capability folder under capabilities/:
capabilities/
└── foo_prims/
├── capability-foo_prims.md
├── requirements.md
├── requirements/
│ └── has-foo-prim.md
└── validation.py
Then register it by adding the validation import to capabilities/__init__.py. Once the capability exists, the steps in this guide apply the same way – add requirements, wire features, and validate.
Appendix B: Validating with the Python API#
The simready-validate CLI is backed by the simready.validate Python library, which you can use directly for scripted or programmatic validation:
from pathlib import Path
import simready.validate as sv
FOUNDATIONS_DOCS_DIR = Path("nv_core/sr_specs/docs")
sv.initialize(
rules_and_requirements_paths=[FOUNDATIONS_DOCS_DIR / "capabilities"],
features_paths=[FOUNDATIONS_DOCS_DIR / "features"],
profiles_paths=[FOUNDATIONS_DOCS_DIR / "profiles"],
)
result = sv.validate_asset(sv.AssetValidationConfig(
asset_path="fixed_asset.usd",
profile_id="Prop-Robotics-Neutral",
profile_version="1.0.0",
))
assert result is not None
assert result.passed