Switchyard lets LLM applications route traffic across models and providers while preserving native OpenAI and Anthropic API compatibility - enabling flexible model selection, benchmarking, and cost/performance optimization.
Research preview: skills that help your coding assistant build evaluations for custom agents, assess the quality of existing suites, and find behavior-coverage gaps. Works today with NeMo Gym and Harbor.
Developer Asset Hub for NVIDIA Nemotron โ A one-stop resource for training recipes, usage cookbooks, datasets, and full end-to-end reference examples to build with Nemotron models
+
+
+
diff --git a/profile/README.template.md b/profile/README.template.md
new file mode 100644
index 0000000..6f09105
--- /dev/null
+++ b/profile/README.template.md
@@ -0,0 +1,3 @@
+### Featured repositories ยท {{month_year}}
+
+{{featured_cards_html}}
diff --git a/profile/assets/categories/nemo-agents.svg b/profile/assets/categories/nemo-agents.svg
new file mode 100644
index 0000000..d515307
--- /dev/null
+++ b/profile/assets/categories/nemo-agents.svg
@@ -0,0 +1 @@
+
diff --git a/profile/assets/categories/nemo-data.svg b/profile/assets/categories/nemo-data.svg
new file mode 100644
index 0000000..c7c31de
--- /dev/null
+++ b/profile/assets/categories/nemo-data.svg
@@ -0,0 +1 @@
+
diff --git a/profile/assets/categories/nemo-evaluation.svg b/profile/assets/categories/nemo-evaluation.svg
new file mode 100644
index 0000000..4a99938
--- /dev/null
+++ b/profile/assets/categories/nemo-evaluation.svg
@@ -0,0 +1 @@
+
diff --git a/profile/assets/categories/nemo-safety.svg b/profile/assets/categories/nemo-safety.svg
new file mode 100644
index 0000000..8257dad
--- /dev/null
+++ b/profile/assets/categories/nemo-safety.svg
@@ -0,0 +1 @@
+
diff --git a/profile/assets/categories/nemo-training.svg b/profile/assets/categories/nemo-training.svg
new file mode 100644
index 0000000..d3d5480
--- /dev/null
+++ b/profile/assets/categories/nemo-training.svg
@@ -0,0 +1 @@
+
diff --git a/profile/assets/nemo-header-tm.png b/profile/assets/nemo-header-tm.png
new file mode 100644
index 0000000..478cd19
Binary files /dev/null and b/profile/assets/nemo-header-tm.png differ
diff --git a/profile/repositories.json b/profile/repositories.json
new file mode 100644
index 0000000..7524c3a
--- /dev/null
+++ b/profile/repositories.json
@@ -0,0 +1,887 @@
+{
+ "schema_version": 1,
+ "organization": "NVIDIA-NeMo",
+ "generated_at": "2026-11-07T01:31:30.722820+00:00",
+ "source_url": "https://api.github.com/orgs/NVIDIA-NeMo/repos",
+ "scope": "All public repositories, including archived repos and repos excluded from promotion.",
+ "field_notes": {
+ "categories": "Derived only from the five documented nemo category topics. Empty means unclassified.",
+ "research_preview": "True means the nemo-research-preview topic is present. Null means unspecified, not stable or production-ready.",
+ "homepage_url": "Repository owner supplied homepage; it is not necessarily documentation.",
+ "license": "GitHub-reported license metadata, not a review of repository terms. Null or NOASSERTION means no specific license was identified by GitHub. A license with source 'manual override' was set from rotation/config.json where GitHub could not match the repo's license file.",
+ "excluded_from_featured": "True if the repo has the nemo-exclude-featured topic or is excluded in rotation/config.json. Promotion exclusion only. Does not remove the repo from this catalog."
+ },
+ "category_topics": {
+ "nemo-data": "NeMo Data",
+ "nemo-training": "NeMo Training",
+ "nemo-evaluation": "NeMo Evaluation",
+ "nemo-agents": "NeMo Agents",
+ "nemo-safety": "NeMo Safety"
+ },
+ "repositories": [
+ {
+ "name": ".github",
+ "full_name": "NVIDIA-NeMo/.github",
+ "description": null,
+ "repository_url": "https://github.com/NVIDIA-NeMo/.github",
+ "readme_api_url": "https://api.github.com/repos/NVIDIA-NeMo/.github/readme",
+ "homepage_url": null,
+ "license": null,
+ "default_branch": "main",
+ "topics": [],
+ "categories": [],
+ "research_preview": null,
+ "archived": false,
+ "disabled": false,
+ "fork": false,
+ "excluded_from_featured": true
+ },
+ {
+ "name": "agent-hardener",
+ "full_name": "NVIDIA-NeMo/agent-hardener",
+ "description": null,
+ "repository_url": "https://github.com/NVIDIA-NeMo/agent-hardener",
+ "readme_api_url": "https://api.github.com/repos/NVIDIA-NeMo/agent-hardener/readme",
+ "homepage_url": null,
+ "license": {
+ "key": "apache-2.0",
+ "name": "Apache License 2.0",
+ "spdx_id": "Apache-2.0",
+ "url": "https://api.github.com/licenses/apache-2.0",
+ "node_id": "MDc6TGljZW5zZTI="
+ },
+ "default_branch": "main",
+ "topics": [],
+ "categories": [],
+ "research_preview": null,
+ "archived": false,
+ "disabled": false,
+ "fork": false,
+ "excluded_from_featured": true
+ },
+ {
+ "name": "Anonymizer",
+ "full_name": "NVIDIA-NeMo/Anonymizer",
+ "description": "๐ต๏ธ NeMo Anonymizer: Detect and protect PII through context-aware replacement and rewriting",
+ "repository_url": "https://github.com/NVIDIA-NeMo/Anonymizer",
+ "readme_api_url": "https://api.github.com/repos/NVIDIA-NeMo/Anonymizer/readme",
+ "homepage_url": "https://nvidia-nemo.github.io/Anonymizer/latest/",
+ "license": {
+ "key": "apache-2.0",
+ "name": "Apache License 2.0",
+ "spdx_id": "Apache-2.0",
+ "url": "https://api.github.com/licenses/apache-2.0",
+ "node_id": "MDc6TGljZW5zZTI="
+ },
+ "default_branch": "main",
+ "topics": [
+ "anonymization-pipeline",
+ "contextual-privacy",
+ "llm",
+ "nvidia",
+ "nvidia-nemo",
+ "pii-anonymization",
+ "sdg"
+ ],
+ "categories": [],
+ "research_preview": null,
+ "archived": false,
+ "disabled": false,
+ "fork": false,
+ "excluded_from_featured": false
+ },
+ {
+ "name": "Automodel",
+ "full_name": "NVIDIA-NeMo/Automodel",
+ "description": "๐ Pytorch Distributed native training library for LLMs/VLMs with OOTB Hugging Face support",
+ "repository_url": "https://github.com/NVIDIA-NeMo/Automodel",
+ "readme_api_url": "https://api.github.com/repos/NVIDIA-NeMo/Automodel/readme",
+ "homepage_url": "https://docs.nvidia.com/nemo/automodel/nightly",
+ "license": {
+ "key": "apache-2.0",
+ "name": "Apache License 2.0",
+ "spdx_id": "Apache-2.0",
+ "url": "https://api.github.com/licenses/apache-2.0",
+ "node_id": "MDc6TGljZW5zZTI="
+ },
+ "default_branch": "main",
+ "topics": [
+ "agent",
+ "deepseek-v4",
+ "deepseek-v4-flash",
+ "finetuning",
+ "gemma3",
+ "gemma4",
+ "glm",
+ "gpt-oss",
+ "kimi-k3",
+ "llama",
+ "llama3",
+ "llm",
+ "minimax-m2",
+ "mistral",
+ "openai",
+ "qwen-38-27b",
+ "qwen3",
+ "qwen3-next",
+ "vlm"
+ ],
+ "categories": [],
+ "research_preview": null,
+ "archived": false,
+ "disabled": false,
+ "fork": false,
+ "excluded_from_featured": false
+ },
+ {
+ "name": "Curator",
+ "full_name": "NVIDIA-NeMo/Curator",
+ "description": "Scalable data pre processing and curation toolkit for LLMs",
+ "repository_url": "https://github.com/NVIDIA-NeMo/Curator",
+ "readme_api_url": "https://api.github.com/repos/NVIDIA-NeMo/Curator/readme",
+ "homepage_url": null,
+ "license": {
+ "key": "apache-2.0",
+ "name": "Apache License 2.0",
+ "spdx_id": "Apache-2.0",
+ "url": "https://api.github.com/licenses/apache-2.0",
+ "node_id": "MDc6TGljZW5zZTI="
+ },
+ "default_branch": "main",
+ "topics": [
+ "data",
+ "data-curation",
+ "data-prep",
+ "data-preparation",
+ "data-processing",
+ "data-processing-pipelines",
+ "data-quality",
+ "datacuration",
+ "datarecipes",
+ "deduplication",
+ "fast-data-processing",
+ "fine-tuning",
+ "large-language-models",
+ "large-scale-data-processing",
+ "llm",
+ "llm-data-quality",
+ "llmapps",
+ "python",
+ "semantic-deduplication"
+ ],
+ "categories": [],
+ "research_preview": null,
+ "archived": false,
+ "disabled": false,
+ "fork": false,
+ "excluded_from_featured": false
+ },
+ {
+ "name": "DataDesigner",
+ "full_name": "NVIDIA-NeMo/DataDesigner",
+ "description": "๐จ NeMo Data Designer: Generate high-quality synthetic data from scratch or from seed data.",
+ "repository_url": "https://github.com/NVIDIA-NeMo/DataDesigner",
+ "readme_api_url": "https://api.github.com/repos/NVIDIA-NeMo/DataDesigner/readme",
+ "homepage_url": "https://docs.nvidia.com/nemo/datadesigner",
+ "license": {
+ "key": "apache-2.0",
+ "name": "Apache License 2.0",
+ "spdx_id": "Apache-2.0",
+ "url": "https://api.github.com/licenses/apache-2.0",
+ "node_id": "MDc6TGljZW5zZTI="
+ },
+ "default_branch": "main",
+ "topics": [
+ "agentic-ai",
+ "data-augmentation",
+ "data-generation",
+ "llm",
+ "mcp",
+ "multimodal",
+ "nemo",
+ "nvidia",
+ "sdg",
+ "synthetic-data",
+ "tool-use"
+ ],
+ "categories": [],
+ "research_preview": null,
+ "archived": false,
+ "disabled": false,
+ "fork": false,
+ "excluded_from_featured": false
+ },
+ {
+ "name": "DataDesignerPlugins",
+ "full_name": "NVIDIA-NeMo/DataDesignerPlugins",
+ "description": "๐ ๐จ NeMo Data Designer Plugins",
+ "repository_url": "https://github.com/NVIDIA-NeMo/DataDesignerPlugins",
+ "readme_api_url": "https://api.github.com/repos/NVIDIA-NeMo/DataDesignerPlugins/readme",
+ "homepage_url": null,
+ "license": {
+ "key": "apache-2.0",
+ "name": "Apache License 2.0",
+ "spdx_id": "Apache-2.0",
+ "url": "https://api.github.com/licenses/apache-2.0",
+ "node_id": "MDc6TGljZW5zZTI="
+ },
+ "default_branch": "main",
+ "topics": [],
+ "categories": [],
+ "research_preview": null,
+ "archived": false,
+ "disabled": false,
+ "fork": false,
+ "excluded_from_featured": true
+ },
+ {
+ "name": "DFM",
+ "full_name": "NVIDIA-NeMo/DFM",
+ "description": "State-of-the-art framework for fast, large-scale training and inference of diffusion models",
+ "repository_url": "https://github.com/NVIDIA-NeMo/DFM",
+ "readme_api_url": "https://api.github.com/repos/NVIDIA-NeMo/DFM/readme",
+ "homepage_url": null,
+ "license": {
+ "key": "apache-2.0",
+ "name": "Apache License 2.0",
+ "spdx_id": "Apache-2.0",
+ "url": "https://api.github.com/licenses/apache-2.0",
+ "node_id": "MDc6TGljZW5zZTI="
+ },
+ "default_branch": "main",
+ "topics": [],
+ "categories": [],
+ "research_preview": null,
+ "archived": true,
+ "disabled": false,
+ "fork": false,
+ "excluded_from_featured": true
+ },
+ {
+ "name": "Emerging-Optimizers",
+ "full_name": "NVIDIA-NeMo/Emerging-Optimizers",
+ "description": null,
+ "repository_url": "https://github.com/NVIDIA-NeMo/Emerging-Optimizers",
+ "readme_api_url": "https://api.github.com/repos/NVIDIA-NeMo/Emerging-Optimizers/readme",
+ "homepage_url": "https://docs.nvidia.com/nemo/emerging-optimizers/latest/index.html",
+ "license": {
+ "key": "apache-2.0",
+ "name": "Apache License 2.0",
+ "spdx_id": "Apache-2.0",
+ "url": "https://api.github.com/licenses/apache-2.0",
+ "node_id": "MDc6TGljZW5zZTI="
+ },
+ "default_branch": "main",
+ "topics": [],
+ "categories": [],
+ "research_preview": null,
+ "archived": false,
+ "disabled": false,
+ "fork": false,
+ "excluded_from_featured": false
+ },
+ {
+ "name": "eval-author",
+ "full_name": "NVIDIA-NeMo/eval-author",
+ "description": "Research preview: skills that help your coding assistant build evaluations for custom agents, assess the quality of existing suites, and find behavior-coverage gaps. Works today with NeMo Gym and Harbor.",
+ "repository_url": "https://github.com/NVIDIA-NeMo/eval-author",
+ "readme_api_url": "https://api.github.com/repos/NVIDIA-NeMo/eval-author/readme",
+ "homepage_url": null,
+ "license": {
+ "key": "apache-2.0",
+ "name": "Apache License 2.0",
+ "spdx_id": "Apache-2.0",
+ "url": "https://api.github.com/licenses/apache-2.0",
+ "node_id": "MDc6TGljZW5zZTI="
+ },
+ "default_branch": "main",
+ "topics": [],
+ "categories": [],
+ "research_preview": null,
+ "archived": false,
+ "disabled": false,
+ "fork": false,
+ "excluded_from_featured": false
+ },
+ {
+ "name": "Evaluator",
+ "full_name": "NVIDIA-NeMo/Evaluator",
+ "description": "Open-source library for scalable, reproducible evaluation of AI models and benchmarks.",
+ "repository_url": "https://github.com/NVIDIA-NeMo/Evaluator",
+ "readme_api_url": "https://api.github.com/repos/NVIDIA-NeMo/Evaluator/readme",
+ "homepage_url": "https://docs.nvidia.com/nemo/evaluator/latest/",
+ "license": {
+ "key": "apache-2.0",
+ "name": "Apache License 2.0",
+ "spdx_id": "Apache-2.0",
+ "url": "https://api.github.com/licenses/apache-2.0",
+ "node_id": "MDc6TGljZW5zZTI="
+ },
+ "default_branch": "main",
+ "topics": [],
+ "categories": [],
+ "research_preview": null,
+ "archived": false,
+ "disabled": false,
+ "fork": false,
+ "excluded_from_featured": true
+ },
+ {
+ "name": "Export-Deploy",
+ "full_name": "NVIDIA-NeMo/Export-Deploy",
+ "description": "A library for exporting models including NeMo and Hugging Face to optimized inference backends, and deploying them for efficient querying",
+ "repository_url": "https://github.com/NVIDIA-NeMo/Export-Deploy",
+ "readme_api_url": "https://api.github.com/repos/NVIDIA-NeMo/Export-Deploy/readme",
+ "homepage_url": null,
+ "license": {
+ "key": "apache-2.0",
+ "name": "Apache License 2.0",
+ "spdx_id": "Apache-2.0",
+ "url": "https://api.github.com/licenses/apache-2.0",
+ "node_id": "MDc6TGljZW5zZTI="
+ },
+ "default_branch": "main",
+ "topics": [],
+ "categories": [],
+ "research_preview": null,
+ "archived": false,
+ "disabled": false,
+ "fork": false,
+ "excluded_from_featured": true
+ },
+ {
+ "name": "FW-CI-templates",
+ "full_name": "NVIDIA-NeMo/FW-CI-templates",
+ "description": "CI/CD templates for NeMo-FW libraries",
+ "repository_url": "https://github.com/NVIDIA-NeMo/FW-CI-templates",
+ "readme_api_url": "https://api.github.com/repos/NVIDIA-NeMo/FW-CI-templates/readme",
+ "homepage_url": null,
+ "license": {
+ "key": "apache-2.0",
+ "name": "Apache License 2.0",
+ "spdx_id": "Apache-2.0",
+ "url": "https://api.github.com/licenses/apache-2.0",
+ "node_id": "MDc6TGljZW5zZTI="
+ },
+ "default_branch": "main",
+ "topics": [],
+ "categories": [],
+ "research_preview": null,
+ "archived": false,
+ "disabled": false,
+ "fork": false,
+ "excluded_from_featured": true
+ },
+ {
+ "name": "Guardrails",
+ "full_name": "NVIDIA-NeMo/Guardrails",
+ "description": "NeMo Guardrails is an open-source toolkit for easily adding programmable guardrails to LLM-based conversational systems.",
+ "repository_url": "https://github.com/NVIDIA-NeMo/Guardrails",
+ "readme_api_url": "https://api.github.com/repos/NVIDIA-NeMo/Guardrails/readme",
+ "homepage_url": "https://docs.nvidia.com/nemo/guardrails/latest/index.html",
+ "license": {
+ "key": "apache-2.0",
+ "name": "Apache License 2.0",
+ "spdx_id": "Apache-2.0",
+ "url": "https://api.github.com/licenses/apache-2.0",
+ "source": "manual override",
+ "note": "LICENSE.md declares Apache-2.0 (SPDX-License-Identifier header and the standard short notice); GitHub reports NOASSERTION because it cannot match the file to a standard license."
+ },
+ "default_branch": "develop",
+ "topics": [
+ "agents",
+ "generative-ai",
+ "guardrails",
+ "llm-safety",
+ "llm-security",
+ "llms",
+ "nvidia",
+ "python",
+ "safety"
+ ],
+ "categories": [],
+ "research_preview": null,
+ "archived": false,
+ "disabled": false,
+ "fork": false,
+ "excluded_from_featured": false
+ },
+ {
+ "name": "Gym",
+ "full_name": "NVIDIA-NeMo/Gym",
+ "description": "Evaluate and improve models and agents using environments",
+ "repository_url": "https://github.com/NVIDIA-NeMo/Gym",
+ "readme_api_url": "https://api.github.com/repos/NVIDIA-NeMo/Gym/readme",
+ "homepage_url": "https://docs.nvidia.com/nemo/gym/main/about/",
+ "license": {
+ "key": "apache-2.0",
+ "name": "Apache License 2.0",
+ "spdx_id": "Apache-2.0",
+ "url": "https://api.github.com/licenses/apache-2.0",
+ "node_id": "MDc6TGljZW5zZTI="
+ },
+ "default_branch": "main",
+ "topics": [
+ "agents",
+ "benchmarks",
+ "environments",
+ "evaluation",
+ "gym",
+ "llm",
+ "reinforcement-learning",
+ "reinforcement-learning-environments",
+ "rl-environment",
+ "rl-training"
+ ],
+ "categories": [],
+ "research_preview": null,
+ "archived": false,
+ "disabled": false,
+ "fork": false,
+ "excluded_from_featured": false
+ },
+ {
+ "name": "labs-molt",
+ "full_name": "NVIDIA-NeMo/labs-molt",
+ "description": "A scalable, agentic-first, and HuggingFace-native RL framework for research (9k lines).",
+ "repository_url": "https://github.com/NVIDIA-NeMo/labs-molt",
+ "readme_api_url": "https://api.github.com/repos/NVIDIA-NeMo/labs-molt/readme",
+ "homepage_url": null,
+ "license": {
+ "key": "apache-2.0",
+ "name": "Apache License 2.0",
+ "spdx_id": "Apache-2.0",
+ "url": "https://api.github.com/licenses/apache-2.0",
+ "node_id": "MDc6TGljZW5zZTI="
+ },
+ "default_branch": "main",
+ "topics": [
+ "agentic-rl",
+ "context-parallelism",
+ "expert-parallelism",
+ "fsdp",
+ "huggingface",
+ "llm",
+ "rl-framework",
+ "rlhf",
+ "rlvr",
+ "tensor-parallelism"
+ ],
+ "categories": [],
+ "research_preview": null,
+ "archived": false,
+ "disabled": false,
+ "fork": false,
+ "excluded_from_featured": false
+ },
+ {
+ "name": "labs-OO-Agents",
+ "full_name": "NVIDIA-NeMo/labs-OO-Agents",
+ "description": "NVIDIA Object Oriented Agents: the Pythonic way to build AI Agents.",
+ "repository_url": "https://github.com/NVIDIA-NeMo/labs-OO-Agents",
+ "readme_api_url": "https://api.github.com/repos/NVIDIA-NeMo/labs-OO-Agents/readme",
+ "homepage_url": null,
+ "license": {
+ "key": "apache-2.0",
+ "name": "Apache License 2.0",
+ "spdx_id": "Apache-2.0",
+ "url": "https://api.github.com/licenses/apache-2.0",
+ "source": "manual override",
+ "note": "LICENSE declares Apache-2.0 (full Apache License 2.0 text plus an appended copyright notice); GitHub reports NOASSERTION because it cannot match the file to a standard license."
+ },
+ "default_branch": "main",
+ "topics": [],
+ "categories": [],
+ "research_preview": null,
+ "archived": false,
+ "disabled": false,
+ "fork": false,
+ "excluded_from_featured": false
+ },
+ {
+ "name": "labs-Voice-Agent",
+ "full_name": "NVIDIA-NeMo/labs-Voice-Agent",
+ "description": "A fully opensource framework for building and evaluating voice agents with open models. ",
+ "repository_url": "https://github.com/NVIDIA-NeMo/labs-Voice-Agent",
+ "readme_api_url": "https://api.github.com/repos/NVIDIA-NeMo/labs-Voice-Agent/readme",
+ "homepage_url": "https://docs.nvidia.com/nemo/labs-voice-agent/about/overview/",
+ "license": {
+ "key": "apache-2.0",
+ "name": "Apache License 2.0",
+ "spdx_id": "Apache-2.0",
+ "url": "https://api.github.com/licenses/apache-2.0",
+ "node_id": "MDc6TGljZW5zZTI="
+ },
+ "default_branch": "main",
+ "topics": [],
+ "categories": [],
+ "research_preview": null,
+ "archived": false,
+ "disabled": false,
+ "fork": false,
+ "excluded_from_featured": false
+ },
+ {
+ "name": "Lens",
+ "full_name": "NVIDIA-NeMo/Lens",
+ "description": null,
+ "repository_url": "https://github.com/NVIDIA-NeMo/Lens",
+ "readme_api_url": "https://api.github.com/repos/NVIDIA-NeMo/Lens/readme",
+ "homepage_url": null,
+ "license": {
+ "key": "apache-2.0",
+ "name": "Apache License 2.0",
+ "spdx_id": "Apache-2.0",
+ "url": "https://api.github.com/licenses/apache-2.0",
+ "node_id": "MDc6TGljZW5zZTI="
+ },
+ "default_branch": "main",
+ "topics": [],
+ "categories": [],
+ "research_preview": null,
+ "archived": false,
+ "disabled": false,
+ "fork": false,
+ "excluded_from_featured": false
+ },
+ {
+ "name": "Megatron-Bridge",
+ "full_name": "NVIDIA-NeMo/Megatron-Bridge",
+ "description": "Training library for Megatron-based models with bidirectional Hugging Face conversion capability",
+ "repository_url": "https://github.com/NVIDIA-NeMo/Megatron-Bridge",
+ "readme_api_url": "https://api.github.com/repos/NVIDIA-NeMo/Megatron-Bridge/readme",
+ "homepage_url": "https://docs.nvidia.com/nemo/megatron-bridge/latest/",
+ "license": {
+ "key": "apache-2.0",
+ "name": "Apache License 2.0",
+ "spdx_id": "Apache-2.0",
+ "url": "https://api.github.com/licenses/apache-2.0",
+ "node_id": "MDc6TGljZW5zZTI="
+ },
+ "default_branch": "main",
+ "topics": [],
+ "categories": [],
+ "research_preview": null,
+ "archived": false,
+ "disabled": false,
+ "fork": false,
+ "excluded_from_featured": false
+ },
+ {
+ "name": "nemo-compass",
+ "full_name": "NVIDIA-NeMo/nemo-compass",
+ "description": "Research preview: Tools to efficiently find signals in large sets of agent traces and inform agent improvements.",
+ "repository_url": "https://github.com/NVIDIA-NeMo/nemo-compass",
+ "readme_api_url": "https://api.github.com/repos/NVIDIA-NeMo/nemo-compass/readme",
+ "homepage_url": null,
+ "license": {
+ "key": "apache-2.0",
+ "name": "Apache License 2.0",
+ "spdx_id": "Apache-2.0",
+ "url": "https://api.github.com/licenses/apache-2.0",
+ "node_id": "MDc6TGljZW5zZTI="
+ },
+ "default_branch": "main",
+ "topics": [],
+ "categories": [],
+ "research_preview": null,
+ "archived": false,
+ "disabled": false,
+ "fork": false,
+ "excluded_from_featured": false
+ },
+ {
+ "name": "nemo-helix",
+ "full_name": "NVIDIA-NeMo/nemo-helix",
+ "description": "NeMo Helix: Make the agents you ship faster, more accurate, and safer.",
+ "repository_url": "https://github.com/NVIDIA-NeMo/nemo-helix",
+ "readme_api_url": "https://api.github.com/repos/NVIDIA-NeMo/nemo-helix/readme",
+ "homepage_url": "https://docs.nvidia.com/nemo-helix",
+ "license": {
+ "key": "apache-2.0",
+ "name": "Apache License 2.0",
+ "spdx_id": "Apache-2.0",
+ "url": "https://api.github.com/licenses/apache-2.0",
+ "node_id": "MDc6TGljZW5zZTI="
+ },
+ "default_branch": "main",
+ "topics": [
+ "agent-evaluation",
+ "ai-agents",
+ "guardrails",
+ "kubernetes",
+ "llm",
+ "llmops",
+ "nemo",
+ "nvidia",
+ "python",
+ "red-teaming"
+ ],
+ "categories": [],
+ "research_preview": null,
+ "archived": false,
+ "disabled": false,
+ "fork": false,
+ "excluded_from_featured": false
+ },
+ {
+ "name": "Nemotron",
+ "full_name": "NVIDIA-NeMo/Nemotron",
+ "description": "Developer Asset Hub for NVIDIA Nemotron โ A one-stop resource for training recipes, usage cookbooks, datasets, and full end-to-end reference examples to build with Nemotron models",
+ "repository_url": "https://github.com/NVIDIA-NeMo/Nemotron",
+ "readme_api_url": "https://api.github.com/repos/NVIDIA-NeMo/Nemotron/readme",
+ "homepage_url": "https://docs.nvidia.com/nemotron/latest/index.html",
+ "license": {
+ "key": "apache-2.0",
+ "name": "Apache License 2.0",
+ "spdx_id": "Apache-2.0",
+ "url": "https://api.github.com/licenses/apache-2.0",
+ "node_id": "MDc6TGljZW5zZTI="
+ },
+ "default_branch": "main",
+ "topics": [
+ "ai",
+ "fine-tuning",
+ "model-training",
+ "nemotron",
+ "nvidia",
+ "reinforcement-learning"
+ ],
+ "categories": [],
+ "research_preview": null,
+ "archived": false,
+ "disabled": false,
+ "fork": false,
+ "excluded_from_featured": false
+ },
+ {
+ "name": "ProRL-Agent-Server",
+ "full_name": "NVIDIA-NeMo/ProRL-Agent-Server",
+ "description": "Agentic RL on Any Harness at Scale",
+ "repository_url": "https://github.com/NVIDIA-NeMo/ProRL-Agent-Server",
+ "readme_api_url": "https://api.github.com/repos/NVIDIA-NeMo/ProRL-Agent-Server/readme",
+ "homepage_url": null,
+ "license": {
+ "key": "apache-2.0",
+ "name": "Apache License 2.0",
+ "spdx_id": "Apache-2.0",
+ "url": "https://api.github.com/licenses/apache-2.0",
+ "node_id": "MDc6TGljZW5zZTI="
+ },
+ "default_branch": "stable",
+ "topics": [],
+ "categories": [],
+ "research_preview": null,
+ "archived": false,
+ "disabled": false,
+ "fork": false,
+ "excluded_from_featured": false
+ },
+ {
+ "name": "RL",
+ "full_name": "NVIDIA-NeMo/RL",
+ "description": "Scalable toolkit for efficient model reinforcement",
+ "repository_url": "https://github.com/NVIDIA-NeMo/RL",
+ "readme_api_url": "https://api.github.com/repos/NVIDIA-NeMo/RL/readme",
+ "homepage_url": "https://docs.nvidia.com/nemo/rl/latest/index.html",
+ "license": {
+ "key": "apache-2.0",
+ "name": "Apache License 2.0",
+ "spdx_id": "Apache-2.0",
+ "url": "https://api.github.com/licenses/apache-2.0",
+ "node_id": "MDc6TGljZW5zZTI="
+ },
+ "default_branch": "main",
+ "topics": [],
+ "categories": [],
+ "research_preview": null,
+ "archived": false,
+ "disabled": false,
+ "fork": false,
+ "excluded_from_featured": false
+ },
+ {
+ "name": "Run",
+ "full_name": "NVIDIA-NeMo/Run",
+ "description": "A tool to configure, launch and manage your machine learning experiments.",
+ "repository_url": "https://github.com/NVIDIA-NeMo/Run",
+ "readme_api_url": "https://api.github.com/repos/NVIDIA-NeMo/Run/readme",
+ "homepage_url": "https://docs.nvidia.com/nemo/run/latest/",
+ "license": {
+ "key": "apache-2.0",
+ "name": "Apache License 2.0",
+ "spdx_id": "Apache-2.0",
+ "url": "https://api.github.com/licenses/apache-2.0",
+ "node_id": "MDc6TGljZW5zZTI="
+ },
+ "default_branch": "main",
+ "topics": [],
+ "categories": [],
+ "research_preview": null,
+ "archived": false,
+ "disabled": false,
+ "fork": false,
+ "excluded_from_featured": false
+ },
+ {
+ "name": "Safe-Synthesizer",
+ "full_name": "NVIDIA-NeMo/Safe-Synthesizer",
+ "description": "๐ก๏ธ NeMo Safe Synthesizer: Create private, safe versions of sensitive tabular datasets.",
+ "repository_url": "https://github.com/NVIDIA-NeMo/Safe-Synthesizer",
+ "readme_api_url": "https://api.github.com/repos/NVIDIA-NeMo/Safe-Synthesizer/readme",
+ "homepage_url": "https://nvidia-nemo.github.io/Safe-Synthesizer/",
+ "license": {
+ "key": "apache-2.0",
+ "name": "Apache License 2.0",
+ "spdx_id": "Apache-2.0",
+ "url": "https://api.github.com/licenses/apache-2.0",
+ "node_id": "MDc6TGljZW5zZTI="
+ },
+ "default_branch": "main",
+ "topics": [],
+ "categories": [],
+ "research_preview": null,
+ "archived": false,
+ "disabled": false,
+ "fork": false,
+ "excluded_from_featured": false
+ },
+ {
+ "name": "SDG-PGMs",
+ "full_name": "NVIDIA-NeMo/SDG-PGMs",
+ "description": "NeMo SDG-PGMs is a user-friendly Python library for building probabilistic graphical models (PGMs) to generate synthetic data",
+ "repository_url": "https://github.com/NVIDIA-NeMo/SDG-PGMs",
+ "readme_api_url": "https://api.github.com/repos/NVIDIA-NeMo/SDG-PGMs/readme",
+ "homepage_url": null,
+ "license": {
+ "key": "apache-2.0",
+ "name": "Apache License 2.0",
+ "spdx_id": "Apache-2.0",
+ "url": "https://api.github.com/licenses/apache-2.0",
+ "node_id": "MDc6TGljZW5zZTI="
+ },
+ "default_branch": "main",
+ "topics": [],
+ "categories": [],
+ "research_preview": null,
+ "archived": false,
+ "disabled": false,
+ "fork": false,
+ "excluded_from_featured": true
+ },
+ {
+ "name": "Skills",
+ "full_name": "NVIDIA-NeMo/Skills",
+ "description": "A project to improve skills of large language models",
+ "repository_url": "https://github.com/NVIDIA-NeMo/Skills",
+ "readme_api_url": "https://api.github.com/repos/NVIDIA-NeMo/Skills/readme",
+ "homepage_url": "https://nvidia-nemo.github.io/Skills/",
+ "license": {
+ "key": "apache-2.0",
+ "name": "Apache License 2.0",
+ "spdx_id": "Apache-2.0",
+ "url": "https://api.github.com/licenses/apache-2.0",
+ "node_id": "MDc6TGljZW5zZTI="
+ },
+ "default_branch": "main",
+ "topics": [],
+ "categories": [],
+ "research_preview": null,
+ "archived": false,
+ "disabled": false,
+ "fork": false,
+ "excluded_from_featured": false
+ },
+ {
+ "name": "Speech",
+ "full_name": "NVIDIA-NeMo/Speech",
+ "description": "A scalable generative AI framework built for researchers and developers working on Large Language Models, Multimodal, and Speech AI (Automatic Speech Recognition and Text-to-Speech)",
+ "repository_url": "https://github.com/NVIDIA-NeMo/Speech",
+ "readme_api_url": "https://api.github.com/repos/NVIDIA-NeMo/Speech/readme",
+ "homepage_url": "https://docs.nvidia.com/nemo/speech/nightly/index.html",
+ "license": {
+ "key": "apache-2.0",
+ "name": "Apache License 2.0",
+ "spdx_id": "Apache-2.0",
+ "url": "https://api.github.com/licenses/apache-2.0",
+ "node_id": "MDc6TGljZW5zZTI="
+ },
+ "default_branch": "main",
+ "topics": [
+ "asr",
+ "deeplearning",
+ "generative-ai",
+ "machine-translation",
+ "neural-networks",
+ "speaker-diariazation",
+ "speaker-recognition",
+ "speech-synthesis",
+ "speech-translation",
+ "tts"
+ ],
+ "categories": [],
+ "research_preview": null,
+ "archived": false,
+ "disabled": false,
+ "fork": false,
+ "excluded_from_featured": false
+ },
+ {
+ "name": "Switchyard",
+ "full_name": "NVIDIA-NeMo/Switchyard",
+ "description": "Switchyard lets LLM applications route traffic across models and providers while preserving native OpenAI and Anthropic API compatibility - enabling flexible model selection, benchmarking, and cost/performance optimization.",
+ "repository_url": "https://github.com/NVIDIA-NeMo/Switchyard",
+ "readme_api_url": "https://api.github.com/repos/NVIDIA-NeMo/Switchyard/readme",
+ "homepage_url": null,
+ "license": {
+ "key": "apache-2.0",
+ "name": "Apache License 2.0",
+ "spdx_id": "Apache-2.0",
+ "url": "https://api.github.com/licenses/apache-2.0",
+ "node_id": "MDc6TGljZW5zZTI="
+ },
+ "default_branch": "main",
+ "topics": [],
+ "categories": [],
+ "research_preview": null,
+ "archived": false,
+ "disabled": false,
+ "fork": false,
+ "excluded_from_featured": false
+ },
+ {
+ "name": "UserSim",
+ "full_name": "NVIDIA-NeMo/UserSim",
+ "description": "๐ญ NeMo User Sim: Improve models and agents with population-grounded simulated users, even before production traffic exists.",
+ "repository_url": "https://github.com/NVIDIA-NeMo/UserSim",
+ "readme_api_url": "https://api.github.com/repos/NVIDIA-NeMo/UserSim/readme",
+ "homepage_url": null,
+ "license": {
+ "key": "apache-2.0",
+ "name": "Apache License 2.0",
+ "spdx_id": "Apache-2.0",
+ "url": "https://api.github.com/licenses/apache-2.0",
+ "node_id": "MDc6TGljZW5zZTI="
+ },
+ "default_branch": "main",
+ "topics": [
+ "dynamic-evaluation",
+ "multilingual-ai",
+ "nemo",
+ "nvidia",
+ "personas",
+ "sdg",
+ "simulation",
+ "sovereign-ai",
+ "synthetic-data",
+ "user-simulator"
+ ],
+ "categories": [],
+ "research_preview": null,
+ "archived": false,
+ "disabled": false,
+ "fork": false,
+ "excluded_from_featured": false
+ }
+ ]
+}
diff --git a/rotation/config.json b/rotation/config.json
new file mode 100644
index 0000000..800e578
--- /dev/null
+++ b/rotation/config.json
@@ -0,0 +1,31 @@
+{
+ "cards_per_month": 6,
+ "excluded": {
+ ".github": "Org infrastructure",
+ "FW-CI-templates": "Org infrastructure",
+ "DFM": "Archived",
+ "agent-hardener": "Excluded by request, 2026-10-29",
+ "DataDesignerPlugins": "Excluded by request, 2026-10-29",
+ "Export-Deploy": "Excluded by request, 2026-10-29",
+ "Evaluator": "Excluded by request, 2026-10-29",
+ "SDG-PGMs": "No pushes since 2026-09-28"
+ },
+ "display_names": {
+ "Automodel": "NeMo AutoModel",
+ "Nemotron": "Nemotron"
+ },
+ "license_overrides": {
+ "Guardrails": {
+ "key": "apache-2.0",
+ "name": "Apache License 2.0",
+ "spdx_id": "Apache-2.0",
+ "note": "LICENSE.md declares Apache-2.0 (SPDX-License-Identifier header and the standard short notice); GitHub reports NOASSERTION because it cannot match the file to a standard license."
+ },
+ "labs-OO-Agents": {
+ "key": "apache-2.0",
+ "name": "Apache License 2.0",
+ "spdx_id": "Apache-2.0",
+ "note": "LICENSE declares Apache-2.0 (full Apache License 2.0 text plus an appended copyright notice); GitHub reports NOASSERTION because it cannot match the file to a standard license."
+ }
+ }
+}
diff --git a/rotation/state.json b/rotation/state.json
new file mode 100644
index 0000000..c524a61
--- /dev/null
+++ b/rotation/state.json
@@ -0,0 +1,47 @@
+{
+ "order": [
+ "Curator",
+ "RL",
+ "Automodel",
+ "Megatron-Bridge",
+ "Guardrails",
+ "Gym",
+ "Safe-Synthesizer",
+ "Switchyard",
+ "eval-author",
+ "labs-molt",
+ "Lens",
+ "Nemotron",
+ "labs-Voice-Agent",
+ "nemo-helix",
+ "nemo-compass",
+ "Skills",
+ "UserSim",
+ "DataDesigner",
+ "Anonymizer",
+ "Emerging-Optimizers",
+ "Speech",
+ "Run",
+ "labs-OO-Agents",
+ "ProRL-Agent-Server"
+ ],
+ "cursor": 12,
+ "history": {
+ "2026-10": [
+ "Curator",
+ "RL",
+ "Automodel",
+ "Megatron-Bridge",
+ "Guardrails",
+ "Gym"
+ ],
+ "2026-11": [
+ "Safe-Synthesizer",
+ "Switchyard",
+ "eval-author",
+ "labs-molt",
+ "Lens",
+ "Nemotron"
+ ]
+ }
+}
diff --git a/scripts/rotate_readme.py b/scripts/rotate_readme.py
new file mode 100644
index 0000000..3131500
--- /dev/null
+++ b/scripts/rotate_readme.py
@@ -0,0 +1,264 @@
+# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+# SPDX-License-Identifier: Apache-2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""Refresh the org repository catalog and render the monthly profile README.
+
+Reads rotation/config.json (hand-edited) and rotation/state.json (machine-edited),
+fetches public repo metadata, picks this month's featured repos and writes
+profile/README.md and profile/repositories.json. Standard library only.
+"""
+
+import argparse
+import datetime
+import html
+import json
+import os
+from pathlib import Path
+import re
+import sys
+import urllib.request
+
+
+ORG = "NVIDIA-NeMo"
+CATEGORIES = {
+ "nemo-data": "NeMo Data",
+ "nemo-training": "NeMo Training",
+ "nemo-evaluation": "NeMo Evaluation",
+ "nemo-agents": "NeMo Agents",
+ "nemo-safety": "NeMo Safety",
+}
+EXCLUDE_TOPIC = "nemo-exclude-featured"
+SEARCH = "https://github.com/search?q=org%3A{org}+topic%3A{topic}+is%3Apublic+archived%3Afalse&type=repositories"
+
+
+def fetch_repos(token):
+ repos, page = [], 1
+ while True:
+ url = f"https://api.github.com/orgs/{ORG}/repos?type=public&per_page=100&page={page}"
+ headers = {"Accept": "application/vnd.github+json", "User-Agent": "nemo-org-profile-rotation"}
+ if token:
+ headers["Authorization"] = f"Bearer {token}"
+ with urllib.request.urlopen(urllib.request.Request(url, headers=headers), timeout=30) as response:
+ batch = json.load(response)
+ repos.extend(batch)
+ if len(batch) < 100:
+ return repos
+ page += 1
+
+
+def to_entry(repo):
+ topics = sorted(repo.get("topics", []))
+ return {
+ "name": repo["name"],
+ "full_name": repo["full_name"],
+ "description": repo["description"],
+ "repository_url": repo["html_url"],
+ "readme_api_url": f'https://api.github.com/repos/{repo["full_name"]}/readme',
+ "homepage_url": repo.get("homepage") or None,
+ "license": repo.get("license"),
+ "default_branch": repo["default_branch"],
+ "topics": topics,
+ "categories": [label for topic, label in CATEGORIES.items() if topic in topics],
+ "research_preview": True if "nemo-research-preview" in topics else None,
+ "archived": repo["archived"],
+ "disabled": repo["disabled"],
+ "fork": repo["fork"],
+ "excluded_from_featured": EXCLUDE_TOPIC in topics,
+ }
+
+
+def build_catalog(entries, previous):
+ catalog = {
+ "schema_version": 1,
+ "organization": ORG,
+ "generated_at": datetime.datetime.now(datetime.timezone.utc).isoformat(),
+ "source_url": f"https://api.github.com/orgs/{ORG}/repos",
+ "scope": "All public repositories, including archived repos and repos excluded from promotion.",
+ "field_notes": previous["field_notes"],
+ "category_topics": CATEGORIES,
+ "repositories": sorted(entries, key=lambda item: item["full_name"].lower()),
+ }
+ # Keep the old timestamp when nothing else changed, so unchanged runs make no commit.
+ if {k: v for k, v in catalog.items() if k != "generated_at"} == {k: v for k, v in previous.items() if k != "generated_at"}:
+ catalog["generated_at"] = previous["generated_at"]
+ return catalog
+
+
+def is_eligible(entry, config):
+ return not (
+ entry["archived"] or entry["disabled"] or entry["fork"]
+ or entry["excluded_from_featured"] or entry["name"] in config["excluded"]
+ )
+
+
+def select(period, state, by_name, config):
+ """Return this period's featured names, updating state in place.
+
+ A new period takes the eligible repos in the next `cards_per_month` positions of
+ the order and always advances the cursor by that many, so later batches never
+ shift. Any shortfall, from ineligible repos or a mid-month replacement, is filled
+ from the positions after the window without moving the cursor. Such a repo is
+ featured again in its own slot. A period already in history is reused.
+ """
+ count = config["cards_per_month"]
+ eligible = {name for name, entry in by_name.items() if is_eligible(entry, config)}
+ order = state["order"]
+ order.extend(sorted(eligible - set(order), key=str.lower))
+ if not order:
+ raise ValueError("no eligible repositories to feature")
+
+ if period in state["history"]:
+ chosen = [n for n in state["history"][period] if n in eligible]
+ else:
+ start = state["cursor"] % len(order)
+ window = [order[(start + step) % len(order)] for step in range(count)]
+ chosen = list(dict.fromkeys(n for n in window if n in eligible))
+ state["cursor"] = (start + count) % len(order)
+
+ cursor = state["cursor"] % len(order)
+ for step in range(len(order)):
+ if len(chosen) >= count:
+ break
+ name = order[(cursor + step) % len(order)]
+ if name in eligible and name not in chosen:
+ chosen.append(name)
+ state["history"][period] = chosen
+ return chosen
+
+
+def display_name(name, config):
+ if name in config["display_names"]:
+ return config["display_names"][name]
+ words = [w if w != w.lower() else w.capitalize() for w in re.split(r"[-_]", name)]
+ if words[0].lower() == "nemo":
+ words[0] = "NeMo"
+ return " ".join(words)
+ return "NeMo " + " ".join(words)
+
+
+def render_card(entry, config):
+ url = html.escape(entry["repository_url"], quote=True)
+ lines = [
+ '
',
+ ]
+ if entry["description"]:
+ lines.append(f'
{html.escape(entry["description"])}
')
+ chips = [
+ f''
+ f''
+ for topic, label in CATEGORIES.items() if label in entry["categories"]
+ ]
+ if chips:
+ lines.append(f'
{" ".join(chips)}
')
+ lines.append("
")
+ return "\n".join(lines)
+
+
+def render_cards(names, by_name, config):
+ cells = [render_card(by_name[n], config) for n in names]
+ if len(cells) % 2:
+ cells.append('
')
+ rows = [f"
\n{cells[i]}\n{cells[i + 1]}\n
" for i in range(0, len(cells), 2)]
+ return "
\n" + "\n".join(rows) + "\n
"
+
+
+def placeholder(values, key):
+ if key not in values:
+ raise ValueError(f"unknown template placeholder {{{{{key}}}}}")
+ return values[key]
+
+
+def validate(readme, names, config, root):
+ for ref in re.findall(r'src="(assets/[^"]+)"', readme):
+ if not (root / "profile" / ref).is_file():
+ raise ValueError(f"missing asset {ref}")
+ for name in config["excluded"]:
+ if f"/{ORG}/{name}\"" in readme:
+ raise ValueError(f"excluded repo {name} is featured")
+ if readme.count("
") != len(names):
+ raise ValueError("card count does not match selection")
+
+
+def main():
+ parser = argparse.ArgumentParser(description=__doc__)
+ parser.add_argument("--root", type=Path, default=Path(__file__).resolve().parent.parent)
+ parser.add_argument("--date", type=datetime.date.fromisoformat, default=datetime.datetime.now(datetime.timezone.utc).date())
+ parser.add_argument("--offline", action="store_true", help="use profile/repositories.json instead of the API")
+ parser.add_argument("--dry-run", action="store_true", help="print the selection without writing files")
+ args = parser.parse_args()
+ root = args.root
+
+ today = datetime.datetime.now(datetime.timezone.utc).date()
+ if not args.dry_run and (args.date.year, args.date.month) != (today.year, today.month):
+ raise ValueError(f"--date {args.date} is not in the current UTC month; use --dry-run to preview other months")
+
+ config = json.loads((root / "rotation/config.json").read_text())
+ state = json.loads((root / "rotation/state.json").read_text())
+ previous = json.loads((root / "profile/repositories.json").read_text())
+
+ if args.offline:
+ entries = previous["repositories"]
+ else:
+ entries = [to_entry(r) for r in fetch_repos(os.environ.get("GITHUB_TOKEN"))]
+ for entry in entries:
+ entry["excluded_from_featured"] = EXCLUDE_TOPIC in entry["topics"] or entry["name"] in config["excluded"]
+ override = config.get("license_overrides", {}).get(entry["name"])
+ current = entry["license"]
+ # Only fill gaps: never replace a license GitHub identified.
+ if override and (not current or current["spdx_id"] == "NOASSERTION"):
+ entry["license"] = {
+ "key": override["key"],
+ "name": override["name"],
+ "spdx_id": override["spdx_id"],
+ "url": f"https://api.github.com/licenses/{override['key']}",
+ "source": "manual override",
+ "note": override["note"],
+ }
+ by_name = {e["name"]: e for e in entries}
+ catalog = build_catalog(entries, previous)
+
+ period = args.date.strftime("%Y-%m")
+ names = select(period, state, by_name, config)
+ if not names:
+ raise ValueError("selection is empty; refusing to publish an empty README")
+ month_year = args.date.strftime("%B %Y")
+ cards = render_cards(names, by_name, config)
+ template = (root / "profile/README.template.md").read_text()
+ values = {"month_year": month_year, "featured_cards_html": cards}
+ # One pass, so braces inside repo descriptions are never treated as placeholders.
+ readme = re.sub(r"\{\{(\w+)\}\}", lambda m: placeholder(values, m.group(1)), template)
+ validate(readme, names, config, root)
+
+ print(f"{month_year}: {', '.join(names)}")
+ if args.dry_run:
+ return
+ outputs = {
+ "profile/README.md": readme,
+ "profile/repositories.json": json.dumps(catalog, ensure_ascii=False, indent=2) + "\n",
+ "rotation/state.json": json.dumps(state, indent=2) + "\n",
+ }
+ for relative, text in outputs.items():
+ destination = root / relative
+ staging = destination.with_suffix(destination.suffix + ".tmp")
+ staging.write_text(text)
+ staging.replace(destination)
+
+
+if __name__ == "__main__":
+ try:
+ main()
+ except Exception as error:
+ print(f"error: {error}", file=sys.stderr)
+ sys.exit(1)