diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..cc7db8c3 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,163 @@ +# SPDX-License-Identifier: Apache-2.0 AND CC-BY-4.0 +# Copyright (c) 2026 NVIDIA Corporation. All rights reserved. + +name: Agent Skills Sync Check + +on: + schedule: + - cron: "0 8 * * *" # every day at 08:00 UTC + workflow_dispatch: + pull_request: + branches: [main] + +jobs: + check-skills: + name: Verify skill counts match source repos + runs-on: ubuntu-latest + permissions: + contents: read + outputs: + drifted: ${{ steps.sync.outputs.drifted }} + steps: + - uses: actions/checkout@v4 + + - name: Check skill directories in source repos + id: sync + env: + GH_TOKEN: ${{ secrets.PRIVATE_REPO_ACCESS_TOKEN || secrets.GITHUB_TOKEN }} + run: | + set -euo pipefail + + DRIFTED=0 + + # Format: "display_name|owner/repo|ref|skills_path[+extra_path]|expected_count" + REPOS=( + "cuOpt|NVIDIA/cuopt|main|skills|19" + "TensorRT-LLM|NVIDIA/TensorRT-LLM|main|.claude/skills|4" + "Model-Optimizer|NVIDIA/Model-Optimizer|main|.claude/skills|4" + "Megatron-Core|NVIDIA/Megatron-LM|main|.claude/skills|2" + "Megatron-Bridge|NVIDIA-NeMo/Megatron-Bridge|main|skills|8" + "Nemotron Voice Agent|NVIDIA-AI-Blueprints/nemotron-voice-agent|main|.agents/skills|1" + "NeMo Gym|NVIDIA-NeMo/Gym|main|.claude/skills|1" + "NeMo Evaluator|NVIDIA-NeMo/Evaluator|main|packages/nemo-evaluator-launcher/.claude/skills+packages/nemo-evaluator/.claude/skills|4" + ) + + REPORT="## Skill Catalog Sync Report\n\n" + REPORT+="| Product | Expected | Actual | Status |\n" + REPORT+="|---------|----------|--------|--------|\n" + + declare -A UPDATES + + count_skills_in_path() { + local repo="$1" ref="$2" path="$3" + local result + result=$(gh api "repos/${repo}/contents/${path}?ref=${ref}" \ + --jq '[.[] | select(.type == "dir")] | length' 2>&1) + if [ $? -ne 0 ]; then + echo "ERR:${result}" + else + echo "$result" + fi + } + + for entry in "${REPOS[@]}"; do + IFS='|' read -r label owner_repo ref skills_paths expected <<< "$entry" + + # Sum skill counts across all paths (split on +) + actual=0 + error_msg="" + IFS='+' read -ra PATHS <<< "$skills_paths" + for spath in "${PATHS[@]}"; do + count=$(count_skills_in_path "$owner_repo" "$ref" "$spath") + if [[ "$count" == ERR:* ]]; then + error_msg="${count#ERR:}" + break + fi + actual=$((actual + count)) + done + + if [ -n "$error_msg" ]; then + REPORT+="| $label | $expected | ERROR | :x: ${error_msg} |\n" + echo "::error::${label}: ${error_msg}" + DRIFTED=1 + elif [ "$actual" -eq "$expected" ]; then + REPORT+="| $label | $expected | $actual | :white_check_mark: |\n" + else + REPORT+="| $label | $expected | $actual | :warning: DRIFT |\n" + UPDATES["$label"]="$expected:$actual" + DRIFTED=1 + fi + done + + echo -e "$REPORT" + echo -e "$REPORT" > /tmp/sync-report.md + echo "drifted=$DRIFTED" >> "$GITHUB_OUTPUT" + + if [ "$DRIFTED" -ne 0 ]; then + echo "::error::Skill counts have drifted — update README.md to match source repos." + + # Persist updates for the fix job + for label in "${!UPDATES[@]}"; do + echo "${label}=${UPDATES[$label]}" + done > /tmp/updates.txt + fi + + - name: Upload sync artifacts + if: steps.sync.outputs.drifted == '1' + uses: actions/upload-artifact@v4 + with: + name: sync-data + path: | + /tmp/sync-report.md + /tmp/updates.txt + + - name: Fail check on drift + if: steps.sync.outputs.drifted == '1' + run: exit 1 + + fix-drift: + name: Create PR with corrected skill counts + needs: check-skills + if: needs.check-skills.outputs.drifted == '1' && github.event_name != 'pull_request' + runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write + steps: + - uses: actions/checkout@v4 + + - name: Download sync artifacts + uses: actions/download-artifact@v4 + with: + name: sync-data + path: /tmp + + - name: Update README.md with corrected counts + run: | + set -euo pipefail + + while IFS='=' read -r label counts; do + IFS=':' read -r old_count new_count <<< "$counts" + # Escape spaces in label for sed; match bold product name in table row + escaped_label=$(echo "$label" | sed 's/ /[[:space:]]/g') + sed -i -E "s/(\*\*${escaped_label}\*\*[^|]*\|[^|]*\| *)${old_count}( *\|)/\1${new_count}\2/" README.md + done < /tmp/updates.txt + + if git diff --quiet README.md; then + echo "::error::No changes to README.md after update — manual fix may be needed." + exit 1 + fi + + echo "README.md updated:" + git diff README.md + + - name: Create pull request + uses: peter-evans/create-pull-request@v7 + with: + token: ${{ secrets.GITHUB_TOKEN }} + commit-message: "fix: update skill counts to match source repos" + branch: auto/sync-skill-counts + delete-branch: true + title: "fix: sync skill counts with source repos" + body-path: /tmp/sync-report.md + labels: automated diff --git a/README.md b/README.md index c51ae19b..9d728c9f 100644 --- a/README.md +++ b/README.md @@ -47,9 +47,9 @@ That's it — the skill activates automatically the next time your agent encount |---------|-------------|:------:|-----------------| | **cuOpt** | GPU-accelerated optimization — vehicle routing, linear programming, quadratic programming, installation, server deployment, and developer tools. | 19 | [`NVIDIA/cuopt/skills/`](https://github.com/NVIDIA/cuopt/tree/main/skills) | | **TensorRT-LLM** | LLM inference optimization — model onboarding to AutoDeploy, CI pipeline failure analysis, and test failure diagnostics. | 4 | [`NVIDIA/TensorRT-LLM/.claude/skills/`](https://github.com/NVIDIA/TensorRT-LLM/tree/main/.claude/skills) | -| **Model Optimizer** | Model optimization — quantization, sparsity, and distillation for efficient inference. | 4 | [`NVIDIA/Model-Optimizer/.claude/skills/`](https://github.com/NVIDIA/Model-Optimizer/tree/main/.claude/skills) | -| **Megatron Core** | Large-scale distributed training — model parallelism, pipeline parallelism, and mixed precision. | 2 | [`NVIDIA/Megatron-LM/.claude/skills/`](https://github.com/NVIDIA/Megatron-LM/tree/main/.claude/skills) | -| **Megatron Bridge** | Bridge between NeMo and Megatron — data processing, model conversion, and training utilities. | 8 | [`NVIDIA-NeMo/Megatron-Bridge/skills/`](https://github.com/NVIDIA-NeMo/Megatron-Bridge/tree/main/skills) | +| **Model-Optimizer** | Model optimization — quantization, sparsity, and distillation for efficient inference. | 4 | [`NVIDIA/Model-Optimizer/.claude/skills/`](https://github.com/NVIDIA/Model-Optimizer/tree/main/.claude/skills) | +| **Megatron-Core** | Large-scale distributed training — model parallelism, pipeline parallelism, and mixed precision. | 2 | [`NVIDIA/Megatron-LM/.claude/skills/`](https://github.com/NVIDIA/Megatron-LM/tree/main/.claude/skills) | +| **Megatron-Bridge** | Bridge between NeMo and Megatron — data processing, model conversion, and training utilities. | 8 | [`NVIDIA-NeMo/Megatron-Bridge/skills/`](https://github.com/NVIDIA-NeMo/Megatron-Bridge/tree/main/skills) | | **Nemotron Voice Agent** | Real-time conversational AI — deploy speech-to-speech voice agents on Workstation, Jetson Thor, or Cloud NIMs. | 1 | [`nemotron-voice-agent/.agents/skills/`](https://github.com/NVIDIA-AI-Blueprints/nemotron-voice-agent/tree/main/.agents/skills) | | **NeMo Gym** | RL training environments — add benchmarks, resources servers, agent wiring, and reward profiling. | 1 | [`NVIDIA-NeMo/Gym/.claude/skills/`](https://github.com/NVIDIA-NeMo/Gym/tree/main/.claude/skills) | | **NeMo Evaluator** | LLM evaluation — launch evaluations, access MLflow results, NeMo Evaluator Launcher assistant, and bring-your-own benchmarks. | 4 | [`NVIDIA-NeMo/Evaluator/.claude/skills/`](https://github.com/NVIDIA-NeMo/Evaluator/tree/main/packages/nemo-evaluator-launcher/.claude/skills) ([+1](https://github.com/NVIDIA-NeMo/Evaluator/tree/main/packages/nemo-evaluator/.claude/skills)) | @@ -64,9 +64,9 @@ For skill-related issues, feature requests, new skill ideas, discussions, and co |---------|--------|-------------|--------------|----------| | **cuOpt** | [Issues](https://github.com/NVIDIA/cuopt/issues) | [Discussions](https://github.com/NVIDIA/cuopt/discussions) | [Contributing](https://github.com/NVIDIA/cuopt/blob/main/CONTRIBUTING.md) | [Security](https://github.com/NVIDIA/cuopt/blob/main/SECURITY.md) | | **TensorRT-LLM** | [Issues](https://github.com/NVIDIA/TensorRT-LLM/issues) | [Discussions](https://github.com/NVIDIA/TensorRT-LLM/discussions) | [Contributing](https://github.com/NVIDIA/TensorRT-LLM/blob/main/CONTRIBUTING.md) | [Security](https://github.com/NVIDIA/TensorRT-LLM/blob/main/SECURITY.md) | -| **Model Optimizer** | [Issues](https://github.com/NVIDIA/Model-Optimizer/issues) | — | [Contributing](https://github.com/NVIDIA/Model-Optimizer/blob/main/CONTRIBUTING.md) | [Security](https://github.com/NVIDIA/Model-Optimizer/blob/main/SECURITY.md) | -| **Megatron Core** | [Issues](https://github.com/NVIDIA/Megatron-LM/issues) | [Discussions](https://github.com/NVIDIA/Megatron-LM/discussions) | [Contributing](https://github.com/NVIDIA/Megatron-LM/blob/main/CONTRIBUTING.md) | — | -| **Megatron Bridge** | [Issues](https://github.com/NVIDIA-NeMo/Megatron-Bridge/issues) | [Discussions](https://github.com/NVIDIA-NeMo/Megatron-Bridge/discussions) | [Contributing](https://github.com/NVIDIA-NeMo/Megatron-Bridge/blob/main/CONTRIBUTING.md) | — | +| **Model-Optimizer** | [Issues](https://github.com/NVIDIA/Model-Optimizer/issues) | — | [Contributing](https://github.com/NVIDIA/Model-Optimizer/blob/main/CONTRIBUTING.md) | [Security](https://github.com/NVIDIA/Model-Optimizer/blob/main/SECURITY.md) | +| **Megatron-Core** | [Issues](https://github.com/NVIDIA/Megatron-LM/issues) | [Discussions](https://github.com/NVIDIA/Megatron-LM/discussions) | [Contributing](https://github.com/NVIDIA/Megatron-LM/blob/main/CONTRIBUTING.md) | — | +| **Megatron-Bridge** | [Issues](https://github.com/NVIDIA-NeMo/Megatron-Bridge/issues) | [Discussions](https://github.com/NVIDIA-NeMo/Megatron-Bridge/discussions) | [Contributing](https://github.com/NVIDIA-NeMo/Megatron-Bridge/blob/main/CONTRIBUTING.md) | — | | **Nemotron Voice Agent** | [Issues](https://github.com/NVIDIA-AI-Blueprints/nemotron-voice-agent/issues) | [Discussions](https://github.com/NVIDIA-AI-Blueprints/nemotron-voice-agent/discussions) | [Contributing](https://github.com/NVIDIA-AI-Blueprints/nemotron-voice-agent/blob/main/CONTRIBUTING.md) | [Security](https://github.com/NVIDIA-AI-Blueprints/nemotron-voice-agent/blob/main/SECURITY.md) | | **NeMo Gym** | [Issues](https://github.com/NVIDIA-NeMo/Gym/issues) | [Discussions](https://github.com/NVIDIA-NeMo/Gym/discussions) | [Contributing](https://github.com/NVIDIA-NeMo/Gym/blob/main/CONTRIBUTING.md) | [Security](https://github.com/NVIDIA-NeMo/Gym/blob/main/SECURITY.md) | | **NeMo Evaluator** | [Issues](https://github.com/NVIDIA-NeMo/Evaluator/issues) | [Discussions](https://github.com/NVIDIA-NeMo/Evaluator/discussions) | [Contributing](https://github.com/NVIDIA-NeMo/Evaluator/blob/main/CONTRIBUTING.md) | [Security](https://github.com/NVIDIA-NeMo/Evaluator/blob/main/SECURITY.md) |