Skip to content

docs(skills): add Cosmos transfer inference skill - #74

Open
chrisvoncsefalvay wants to merge 10 commits into
NVIDIA:mainfrom
chrisvoncsefalvay:feat/cosmos-transfer-inference-skill
Open

docs(skills): add Cosmos transfer inference skill#74
chrisvoncsefalvay wants to merge 10 commits into
NVIDIA:mainfrom
chrisvoncsefalvay:feat/cosmos-transfer-inference-skill

Conversation

@chrisvoncsefalvay

Copy link
Copy Markdown

Teaches agents how to run Cosmos3 transfer inference with one or more conditioning controls (blur, edge, depth and so on).

@lfengad

lfengad commented Jul 2, 2026

Copy link
Copy Markdown
Collaborator

@trungtpham could have a review and check? THX

@lfengad lfengad left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks a lot for putting this together! 🙏 This is genuinely useful — docs/inference.md has zero transfer coverage today, so this skill basically becomes the only documentation we have for the feature. The structure, frontmatter, and the .agents + .claude duplication all match our existing skills, so that part is spot on.

I went through it line by line against transfer.py / args.py / inference.py, and most of the "Source facts" check out exactly — hint enum ordering, weight normalization, single-hint-only defaults, the output filenames, the no-mixing / no-batching asserts, JSON prompt compaction, and single-frame metadata stripping are all accurate. Nice work on that.

I did bump into a handful of things while reading, left inline below. Two of them (the negative_prompt_file paths and the aspect_ratio rule) I think would actually break or silently mislead someone following the skill, so those are the ones I'd love to see addressed. The rest are smaller / take-them-or-leave-them.

One housekeeping note: I only commented on the .agents/ copy to avoid duplicating everything, but every comment applies to the identical .claude/skills/cosmos3-transfer-inference/SKILL.md too.

Happy to help with any of these if it's easier — just let me know!

## Path convention

All paths below are relative to the Cosmos Framework repo root. Run commands from the directory containing `pyproject.toml`.
Input paths inside JSON/YAML specs are resolved relative to the spec file's directory.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Small but important caveat here, I think — this is true for prompt_path, vision_path, and control_path (they're ResolvedFilePath / ResolvedFilePathOrUrl, absolutized inside contextlib.chdir(path.parent) at cosmos_framework/inference/common/args.py:945), but not for negative_prompt_file.

That one is a plain str (args.py:735) and gets resolved much later, in _build_transfer_data_load_transfer_negative_prompt_file (args.py:53-62), which runs from build_sample at cosmos_framework/scripts/inference.py:56 — i.e. already outside the chdir block. So it resolves against the process CWD, not the spec dir.

Would you mind adding a sentence calling out the exception? Something like: "negative_prompt_file is the exception — it's resolved relative to the process CWD, with a fallback to cosmos_framework/inference/defaults/<basename>." Ties into my comment on the examples below.

"negative_prompt_keep_metadata": false,
"guidance": 3.0,
"control_guidance": 1.5,
"negative_prompt_file": "../assets/negative_prompt.json",

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Following on from the path-convention comment — I believe this one won't resolve. Since negative_prompt_file is resolved against the CWD (which the skill tells the agent is the repo root), this becomes <repo>/../assets/negative_prompt.json. It then falls back to PACKAGE_DIR/defaults/<basename>, and we don't ship a negative_prompt.json there (only neg_prompts.json), so it ends up raising FileNotFoundError.

The field's own docstring says "absolute path or filename under defaults/", so I think an absolute path or just the bare neg_prompts.json would be the safe thing here.

Same line shows up in the WSM (L101), multi-transfer (L130), and single-frame (L161) examples — sorry to make it four edits!


- Any non-empty subset of `edge`, `blur`, `depth`, `seg`, and `wsm` is valid if required paths exist.
- Use precomputed `control_path` for cookbook parity. Use `vision_path` only when intentionally deriving `edge` or `blur` controls from the source media.
- Without `vision_path`, every active hint must provide `control_path`; aspect ratio is auto-detected from the first control when `aspect_ratio` is not set.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this one is stated slightly backwards, and it's a little consequential. Looking at cosmos_framework/inference/transfer.py:409-417: when vision_path is absent, the code calls read_and_resize_media(first_control, aspect_ratio=None) and takes final_aspect_ratio straight from detection — so sample_args.aspect_ratio gets dropped whether or not the user set it. Only the vision_path branch honours it (sample_args.aspect_ratio or detected).

So it's less "auto-detected when aspect_ratio is not set" and more "auto-detected whenever there's no vision_path, overriding any explicit value". Could we reword it that way? It matters because all four cookbook examples are exactly this case.

"name": "transfer_edge",
"model_mode": "video2video",
"resolution": "720",
"aspect_ratio": "16,9",

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tiny follow-on from my comment on the "Conditioning rules" section (L275) — since this sample has control_path and no vision_path, this aspect_ratio is silently ignored by transfer.py:409-417. Not harmful, but it might give readers the wrong mental model about which knobs are live. Maybe drop it from the control-path-only examples, or add a short //-style note in the prose above? Totally your call.

```

- If multiple control videos are active, their duration, frame count, and fps should match or be intentionally trimmed to the same range. If they differ, stop and report the mismatch before generation.
- If a control image/video has a different aspect ratio from the requested spec, state that the framework will resize/crop to the requested `resolution` and `aspect_ratio`; do not hide that transformation in the report.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same root cause as the aspect_ratio comment on L275 — for the "precomputed control_path, no vision_path" case (which is what all the cookbook examples do), the framework resizes to the requested resolution but uses the detected aspect ratio, not the requested one. So an agent following this bullet would report the transformation slightly wrong. Would be great to split the two cases here.


Use a local checkpoint directory in `--checkpoint-path` when the model is already downloaded.

To mirror the public cookbook exactly, set `SPEC` to a checked-in `specs/<control>.json` file and set the output directory to either `Cosmos3-Nano` or `Cosmos3-Super`; change only the launcher and `--checkpoint-path`.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A couple of small clarity things on this line:

  • SPEC doesn't appear in either launch template above — they both use -i transfer.json. Was a SPEC=... variable meant to be in the templates?
  • "set the output directory to either Cosmos3-Nano or Cosmos3-Super" reads to me like the checkpoint names are being used as the output dir — is that intentional?
  • Also, specs/ and ../assets/ don't exist in this repo (they're cosmos-cookbook paths). The skill leans on that layout in a lot of places without ever naming it — could we link the cookbook repo once, up in the "Path convention" section? That'd make the whole doc much easier to follow for someone who only has this repo checked out.

"vision_path": "inputs/source.mp4",
"resolution": "256",
"aspect_ratio": "16,9",
"num_frames": 17,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: MIN_NUM_FRAMES = 24 (args.py:144), so 17 will log a "Number of frames 17 is outside the recommended range… Quality may be degraded" warning, and then get rounded up by the temporal compression factor anyway (args.py:531-534). Since the Validation checklist asks the agent to report warnings, bumping this to 25 would avoid a scary-looking log line in the happy path. Very minor!

- Keep controls aligned in time and content. The loader resizes controls to the requested resolution/aspect ratio, but it does not fix semantic mismatches.
- `weight` must be non-negative and the total weight must be positive. Equal weights are implied when omitted.
- Hint order is deterministic by enum order: `edge`, `blur`, `depth`, `seg`, `wsm`, not JSON insertion order.
- For multi-transfer, explicitly set `guidance`, `control_guidance`, and `shift`; the code applies task-tuned defaults only for single-hint transfer.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is accurate, and it'd be even more useful with the actual table inlined (args.py:834-847), since the examples only cover edge and wsm:

hint guidance control_guidance shift also defaults
edge / blur / depth 3.0 1.5 10.0
seg 3.0 2.0 10.0
wsm 1.0 3.0 10.0 num_frames=101, fps=10, num_video_frames_per_chunk=101

The seg case in particular is 2.0, not 1.5, so an agent extrapolating from the edge example would guess wrong. Just a nice-to-have.

Nano:

```shell
LD_LIBRARY_PATH= uv run --all-extras --group=cu130-train \

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very minor / feel free to ignore: LD_LIBRARY_PATH= is prefixed unconditionally on both templates, but AGENTS.md:104 documents it as an NGC-container-specific workaround for the torch._C import error. Harmless outside a container, but a short # NGC container: avoid torch._C import error trailing comment (like we do in docs/action_policy_libero_posttrain.md:69) would save readers a "wait, why?" moment.

- `edge` and `blur` can also be computed on the fly from `vision_path`; use that as a local convenience smoke-test path, not as the default cookbook-parity transfer spec. `depth`, `seg`, and `wsm` require a precomputed `control_path`.
- Multi-transfer is not a separate command. Put multiple hint objects in one sample. The model packs `[ctrl_1, ..., ctrl_N, target]`, normalises non-negative per-hint `weight` values, and uses weighted multi-control attention.
- Single-hint transfer defaults for `guidance`, `control_guidance`, and `shift` are applied only when exactly one hint is present. For multi-transfer, set those fields explicitly.
- Transfer samples are generated one sample at a time. Do not mix transfer and non-transfer samples in one batch. You may pass multiple transfer input files to one command so the model loads once.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"You may pass multiple transfer input files to one command" is true today, but only because max_num_seqs defaults to 1 (common/args.py:820). If someone passes --max-num-seqs=2 or --max-model-len, the greedy packer (inference.py:1406) can put two transfer samples in one batch and trip the bare assert len(sample_args_list) == 1, "Batching is not supported for transfer inference" (inference.py:1495).

Probably worth a half-sentence like "(don't override --max-num-seqs / --max-model-len for transfer)" so nobody hits a raw AssertionError. Low priority.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants