From 42f29723cbd3dc8f42db3aad9ad7e7af43ba124d Mon Sep 17 00:00:00 2001 From: Marcos Salamanca Date: Fri, 19 Dec 2025 13:52:06 -0600 Subject: [PATCH 001/180] add azure role selector skills --- skills/azure-role-selector/SKILL.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 skills/azure-role-selector/SKILL.md diff --git a/skills/azure-role-selector/SKILL.md b/skills/azure-role-selector/SKILL.md new file mode 100644 index 00000000..c4e11663 --- /dev/null +++ b/skills/azure-role-selector/SKILL.md @@ -0,0 +1,6 @@ +--- +name: azure-role-selector +description: When user is asking for guidance for which role to assign to an identity given desired permissions, this agent helps them understand the role that will meet the requirements with least privilege access and how to apply that role. +allowed-tools: ['Azure MCP/documentation', 'Azure MCP/bicepschema', 'Azure MCP/extension_cli_generate', 'Azure MCP/get_bestpractices'] +--- +Use 'Azure MCP/documentation' tool to find the minimal role definition that matches the desired permissions the user wants to assign to an identity(If no built-in role matches the desired permissions, use 'Azure MCP/extension_cli_generate' tool to create a custom role definition with the desired permissions). Use 'Azure MCP/extension_cli_generate' tool to generate the CLI commands needed to assign that role to the identity and use the 'Azure MCP/bicepschema' and the 'Azure MCP/get_bestpractices' tool to provide a Bicep code snippet for adding the role assignment. From 4670d47c22f9da99038ceb7039e4572c344a77c8 Mon Sep 17 00:00:00 2001 From: Marcos Salamanca Date: Fri, 19 Dec 2025 15:05:05 -0600 Subject: [PATCH 002/180] add license file and update readme --- docs/README.skills.md | 1 + skills/azure-role-selector/LICENSE.txt | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+) create mode 100644 skills/azure-role-selector/LICENSE.txt diff --git a/docs/README.skills.md b/docs/README.skills.md index 8c287652..e4a977e2 100644 --- a/docs/README.skills.md +++ b/docs/README.skills.md @@ -23,3 +23,4 @@ Skills differ from other primitives by supporting bundled assets (scripts, code | Name | Description | Bundled Assets | | ---- | ----------- | -------------- | | [webapp-testing](../skills/webapp-testing/SKILL.md) | Toolkit for interacting with and testing local web applications using Playwright. Supports verifying frontend functionality, debugging UI behavior, capturing browser screenshots, and viewing browser logs. | `test-helper.js` | +| [azure-role-selector](../skills/azure-role-selector/SKILL.md) | Use 'Azure MCP/documentation' tool to find the minimal role definition that matches the desired permissions the user wants to assign to an identity(If no built-in role matches the desired permissions, use 'Azure MCP/extension_cli_generate' tool to create a custom role definition with the desired permissions). Use 'Azure MCP/extension_cli_generate' tool to generate the CLI commands needed to assign that role to the identity and use the 'Azure MCP/bicepschema' and the 'Azure MCP/get_bestpractices' tool to provide a Bicep code snippet for adding the role assignment. | `LICENSE.txt` | diff --git a/skills/azure-role-selector/LICENSE.txt b/skills/azure-role-selector/LICENSE.txt new file mode 100644 index 00000000..8dfb11f8 --- /dev/null +++ b/skills/azure-role-selector/LICENSE.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright 2025 (c) Microsoft Corporation. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE From 73e9677ada1df1928fcedcfa810ec93013e34a33 Mon Sep 17 00:00:00 2001 From: James Montemagno Date: Fri, 19 Dec 2025 13:14:32 -0800 Subject: [PATCH 003/180] add image magick skill --- .../image-manipulation-image-magick/SKILL.md | 252 ++++++++++++++++++ 1 file changed, 252 insertions(+) create mode 100644 skills/image-manipulation-image-magick/SKILL.md diff --git a/skills/image-manipulation-image-magick/SKILL.md b/skills/image-manipulation-image-magick/SKILL.md new file mode 100644 index 00000000..9f56b79f --- /dev/null +++ b/skills/image-manipulation-image-magick/SKILL.md @@ -0,0 +1,252 @@ +--- +name: image-manipulation +description: Process and manipulate images using ImageMagick. Supports resizing, format conversion, batch processing, and retrieving image metadata. Use when working with images, creating thumbnails, resizing wallpapers, or performing batch image operations. +compatibility: Requires ImageMagick installed and available as `magick` on PATH. Cross-platform examples provided for PowerShell (Windows) and Bash (Linux/macOS). +--- + +# Image Manipulation with ImageMagick + +This skill enables image processing and manipulation tasks using ImageMagick +across Windows, Linux, and macOS systems. + +## When to Use This Skill + +Use this skill when you need to: + +- Resize images (single or batch) +- Get image dimensions and metadata +- Convert between image formats +- Create thumbnails +- Process wallpapers for different screen sizes +- Batch process multiple images with specific criteria + +## Prerequisites + +- ImageMagick installed on the system +- **Windows**: PowerShell with ImageMagick available as `magick` (or at `C:\Program Files\ImageMagick-*\magick.exe`) +- **Linux/macOS**: Bash with ImageMagick installed via package manager (`apt`, `brew`, etc.) + +## Core Capabilities + +### 1. Image Information + +- Get image dimensions (width x height) +- Retrieve detailed metadata (format, color space, etc.) +- Identify image format + +### 2. Image Resizing + +- Resize single images +- Batch resize multiple images +- Create thumbnails with specific dimensions +- Maintain aspect ratios + +### 3. Batch Processing + +- Process images based on dimensions +- Filter and process specific file types +- Apply transformations to multiple files + +## Usage Examples + +### Example 0: Resolve `magick` executable + +**PowerShell (Windows):** +```powershell +# Prefer ImageMagick on PATH +$magick = (Get-Command magick -ErrorAction SilentlyContinue)?.Source + +# Fallback: common install pattern under Program Files +if (-not $magick) { + $magick = Get-ChildItem "C:\\Program Files\\ImageMagick-*\\magick.exe" -ErrorAction SilentlyContinue | + Select-Object -First 1 -ExpandProperty FullName +} + +if (-not $magick) { + throw "ImageMagick not found. Install it and/or add 'magick' to PATH." +} +``` + +**Bash (Linux/macOS):** +```bash +# Check if magick is available on PATH +if ! command -v magick &> /dev/null; then + echo "ImageMagick not found. Install it using your package manager:" + echo " Ubuntu/Debian: sudo apt install imagemagick" + echo " macOS: brew install imagemagick" + exit 1 +fi +``` + +### Example 1: Get Image Dimensions + +**PowerShell (Windows):** +```powershell +# For a single image +& $magick identify -format "%wx%h" path/to/image.jpg + +# For multiple images +Get-ChildItem "path/to/images/*" | ForEach-Object { + $dimensions = & $magick identify -format "%f: %wx%h`n" $_.FullName + Write-Host $dimensions +} +``` + +**Bash (Linux/macOS):** +```bash +# For a single image +magick identify -format "%wx%h" path/to/image.jpg + +# For multiple images +for img in path/to/images/*; do + magick identify -format "%f: %wx%h\n" "$img" +done +``` + +### Example 2: Resize Images + +**PowerShell (Windows):** +```powershell +# Resize a single image +& $magick input.jpg -resize 427x240 output.jpg + +# Batch resize images +Get-ChildItem "path/to/images/*" | ForEach-Object { + & $magick $_.FullName -resize 427x240 "path/to/output/thumb_$($_.Name)" +} +``` + +**Bash (Linux/macOS):** +```bash +# Resize a single image +magick input.jpg -resize 427x240 output.jpg + +# Batch resize images +for img in path/to/images/*; do + filename=$(basename "$img") + magick "$img" -resize 427x240 "path/to/output/thumb_$filename" +done +``` + +### Example 3: Get Detailed Image Information + +**PowerShell (Windows):** +```powershell +# Get verbose information about an image +& $magick identify -verbose path/to/image.jpg +``` + +**Bash (Linux/macOS):** +```bash +# Get verbose information about an image +magick identify -verbose path/to/image.jpg +``` + +### Example 4: Process Images Based on Dimensions + +**PowerShell (Windows):** +```powershell +Get-ChildItem "path/to/images/*" | ForEach-Object { + $dimensions = & $magick identify -format "%w,%h" $_.FullName + if ($dimensions) { + $width,$height = $dimensions -split ',' + if ([int]$width -eq 2560 -or [int]$height -eq 1440) { + Write-Host "Processing $($_.Name)" + & $magick $_.FullName -resize 427x240 "path/to/output/thumb_$($_.Name)" + } + } +} +``` + +**Bash (Linux/macOS):** +```bash +for img in path/to/images/*; do + dimensions=$(magick identify -format "%w,%h" "$img") + if [[ -n "$dimensions" ]]; then + width=$(echo "$dimensions" | cut -d',' -f1) + height=$(echo "$dimensions" | cut -d',' -f2) + if [[ "$width" -eq 2560 || "$height" -eq 1440 ]]; then + filename=$(basename "$img") + echo "Processing $filename" + magick "$img" -resize 427x240 "path/to/output/thumb_$filename" + fi + fi +done +``` + +## Guidelines + +1. **Always quote file paths** - Use quotes around file paths that might contain spaces +2. **Use the `&` operator (PowerShell)** - Invoke the magick executable using `&` in PowerShell +3. **Store the path in a variable (PowerShell)** - Assign the ImageMagick path to `$magick` for cleaner code +4. **Wrap in loops** - When processing multiple files, use `ForEach-Object` (PowerShell) or `for` loops (Bash) +5. **Verify dimensions first** - Check image dimensions before processing to avoid unnecessary operations +6. **Use appropriate resize flags** - Consider using `!` to force exact dimensions or `^` for minimum dimensions + +## Common Patterns + +### PowerShell Patterns + +#### Pattern: Store ImageMagick Path + +```powershell +$magick = (Get-Command magick).Source +``` + +#### Pattern: Get Dimensions as Variables + +```powershell +$dimensions = & $magick identify -format "%w,%h" $_.FullName +$width,$height = $dimensions -split ',' +``` + +#### Pattern: Conditional Processing + +```powershell +if ([int]$width -gt 1920) { + & $magick $_.FullName -resize 1920x1080 $outputPath +} +``` + +#### Pattern: Create Thumbnails + +```powershell +& $magick $_.FullName -resize 427x240 "thumbnails/thumb_$($_.Name)" +``` + +### Bash Patterns + +#### Pattern: Check ImageMagick Installation + +```bash +command -v magick &> /dev/null || { echo "ImageMagick required"; exit 1; } +``` + +#### Pattern: Get Dimensions as Variables + +```bash +dimensions=$(magick identify -format "%w,%h" "$img") +width=$(echo "$dimensions" | cut -d',' -f1) +height=$(echo "$dimensions" | cut -d',' -f2) +``` + +#### Pattern: Conditional Processing + +```bash +if [[ "$width" -gt 1920 ]]; then + magick "$img" -resize 1920x1080 "$outputPath" +fi +``` + +#### Pattern: Create Thumbnails + +```bash +filename=$(basename "$img") +magick "$img" -resize 427x240 "thumbnails/thumb_$filename" +``` + +## Limitations + +- Large batch operations may be memory-intensive +- Some complex operations may require additional ImageMagick delegates +- On older Linux systems, use `convert` instead of `magick` (ImageMagick 6.x vs 7.x) From 1322aa2dde39898083ba0a71fa9626922c6f3472 Mon Sep 17 00:00:00 2001 From: Ashley Childress <6563688+anchildress1@users.noreply.github.com> Date: Fri, 19 Dec 2025 20:43:27 -0500 Subject: [PATCH 004/180] feat(eng): add contributor reporting and management scripts - Add eng/README.md documenting maintainer utilities - Add eng/contributor-report.mjs for generating contributor reports - Add eng/add-missing-contributors.mjs for automating contributor additions - Add eng/utils/graceful-shutdown.mjs for script lifecycle management - Update eng/update-readme.mjs with minor fixes - Update package.json with new contributor scripts Generated-by: GitHub Copilot Signed-off-by: Ashley Childress <6563688+anchildress1@users.noreply.github.com> --- .all-contributorsrc | 2050 +++++++++++++++++++--------- .github/workflows/contributors.yml | 40 +- .gitignore | 1 + CONTRIBUTING.md | 37 +- README.md | 301 ++-- eng/README.md | 36 + eng/add-missing-contributors.mjs | 306 +++++ eng/contributor-report.mjs | 597 ++++++++ eng/utils/graceful-shutdown.mjs | 60 + package.json | 5 +- 10 files changed, 2634 insertions(+), 799 deletions(-) create mode 100644 eng/README.md create mode 100644 eng/add-missing-contributors.mjs create mode 100644 eng/contributor-report.mjs create mode 100644 eng/utils/graceful-shutdown.mjs diff --git a/.all-contributorsrc b/.all-contributorsrc index 8372d6ac..bd9775d3 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -9,6 +9,35 @@ "imageSize": 100, "commit": false, "commitConvention": "none", + "contributorsPerLine": 7, + "linkToUsage": true, + "commitType": "docs", + "types": { + "instructions": { + "symbol": "🧭", + "description": "Custom instructions for GitHub Copilot" + }, + "prompts": { + "symbol": "⌚", + "description": "Reusable prompts for GitHub Copilot" + }, + "agents": { + "symbol": "🎭", + "description": "Specialized agents for GitHub Copilot" + }, + "collections": { + "symbol": "🎁", + "description": "Curated collections of related content" + } + }, + "ignoreList": [ + "dependabot[bot]", + "github-actions[bot]", + "allcontributors[bot]", + "Copilot", + "Claude" + ], + "contributorsSortAlphabetically": false, "contributors": [ { "login": "aaronpowell", @@ -16,136 +45,13 @@ "avatar_url": "https://avatars.githubusercontent.com/u/434140?v=4", "profile": "https://www.aaron-powell.com/", "contributions": [ - "code", + "agents", + "collections", + "doc", + "infra", + "instructions", "maintenance", - "projectManagement", - "promotion" - ] - }, - { - "login": "mubaidr", - "name": "Muhammad Ubaid Raza", - "avatar_url": "https://avatars.githubusercontent.com/u/2222702?v=4", - "profile": "https://mubaidr.js.org/", - "contributions": [ - "code" - ] - }, - { - "login": "digitarald", - "name": "Harald Kirschner", - "avatar_url": "https://avatars.githubusercontent.com/u/8599?v=4", - "profile": "http://digitarald.de/", - "contributions": [ - "code" - ] - }, - { - "login": "mbianchidev", - "name": "Matteo Bianchi", - "avatar_url": "https://avatars.githubusercontent.com/u/37507190?v=4", - "profile": "https://github.com/mbianchidev", - "contributions": [ - "code" - ] - }, - { - "login": "AungMyoKyaw", - "name": "Aung Myo Kyaw", - "avatar_url": "https://avatars.githubusercontent.com/u/9404824?v=4", - "profile": "https://github.com/AungMyoKyaw", - "contributions": [ - "code" - ] - }, - { - "login": "PlagueHO", - "name": "Daniel Scott-Raynsford", - "avatar_url": "https://avatars.githubusercontent.com/u/7589164?v=4", - "profile": "https://danielscottraynsford.com/", - "contributions": [ - "code" - ] - }, - { - "login": "burkeholland", - "name": "Burke Holland", - "avatar_url": "https://avatars.githubusercontent.com/u/686963?v=4", - "profile": "https://github.com/burkeholland", - "contributions": [ - "code" - ] - }, - { - "login": "PEZ", - "name": "Peter Strömberg", - "avatar_url": "https://avatars.githubusercontent.com/u/30010?v=4", - "profile": "https://calva.io/", - "contributions": [ - "code" - ] - }, - { - "login": "danielmeppiel", - "name": "Daniel Meppiel", - "avatar_url": "https://avatars.githubusercontent.com/u/51440732?v=4", - "profile": "https://www.devprodlogs.com/", - "contributions": [ - "code" - ] - }, - { - "login": "jamesmontemagno", - "name": "James Montemagno", - "avatar_url": "https://avatars.githubusercontent.com/u/1676321?v=4", - "profile": "https://montemagno.com/", - "contributions": [ - "code" - ] - }, - { - "login": "VamshiVerma", - "name": "Vamshi Verma", - "avatar_url": "https://avatars.githubusercontent.com/u/21999324?v=4", - "profile": "https://github.com/VamshiVerma", - "contributions": [ - "code" - ] - }, - { - "login": "sinedied", - "name": "Yohan Lasorsa", - "avatar_url": "https://avatars.githubusercontent.com/u/593151?v=4", - "profile": "https://github.com/sinedied", - "contributions": [ - "code" - ] - }, - { - "login": "OrenMe", - "name": "Oren Me", - "avatar_url": "https://avatars.githubusercontent.com/u/5461862?v=4", - "profile": "https://github.com/OrenMe", - "contributions": [ - "code" - ] - }, - { - "login": "mjrousos", - "name": "Mike Rousos", - "avatar_url": "https://avatars.githubusercontent.com/u/10077254?v=4", - "profile": "https://github.com/mjrousos", - "contributions": [ - "code" - ] - }, - { - "login": "guiopen", - "name": "Guilherme do Amaral Alves ", - "avatar_url": "https://avatars.githubusercontent.com/u/94094527?v=4", - "profile": "https://github.com/guiopen", - "contributions": [ - "code" + "prompts" ] }, { @@ -154,7 +60,137 @@ "avatar_url": "https://avatars.githubusercontent.com/u/44444967?v=4", "profile": "https://www.buymeacoffee.com/troystaylor", "contributions": [ - "code" + "agents", + "collections", + "instructions", + "prompts" + ] + }, + { + "login": "PEZ", + "name": "Peter Strömberg", + "avatar_url": "https://avatars.githubusercontent.com/u/30010?v=4", + "profile": "https://calva.io/", + "contributions": [ + "agents", + "collections", + "instructions", + "prompts" + ] + }, + { + "login": "PlagueHO", + "name": "Daniel Scott-Raynsford", + "avatar_url": "https://avatars.githubusercontent.com/u/7589164?v=4", + "profile": "https://danielscottraynsford.com/", + "contributions": [ + "agents", + "collections", + "instructions", + "prompts" + ] + }, + { + "login": "jhauga", + "name": "John Haugabook", + "avatar_url": "https://avatars.githubusercontent.com/u/10998676?v=4", + "profile": "https://github.com/jhauga", + "contributions": [ + "instructions", + "prompts" + ] + }, + { + "login": "mubaidr", + "name": "Muhammad Ubaid Raza", + "avatar_url": "https://avatars.githubusercontent.com/u/2222702?v=4", + "profile": "https://mubaidr.js.org/", + "contributions": [ + "agents", + "instructions" + ] + }, + { + "login": "AungMyoKyaw", + "name": "Aung Myo Kyaw", + "avatar_url": "https://avatars.githubusercontent.com/u/9404824?v=4", + "profile": "https://www.aungmyokyaw.com/", + "contributions": [ + "agents", + "prompts" + ] + }, + { + "login": "digitarald", + "name": "Harald Kirschner", + "avatar_url": "https://avatars.githubusercontent.com/u/8599?v=4", + "profile": "http://digitarald.de/", + "contributions": [ + "doc", + "maintenance" + ] + }, + { + "login": "burkeholland", + "name": "Burke Holland", + "avatar_url": "https://avatars.githubusercontent.com/u/686963?v=4", + "profile": "https://github.com/burkeholland", + "contributions": [ + "agents", + "infra", + "instructions", + "prompts" + ] + }, + { + "login": "danielmeppiel", + "name": "Daniel Meppiel", + "avatar_url": "https://avatars.githubusercontent.com/u/51440732?v=4", + "profile": "https://www.devprodlogs.com/", + "contributions": [ + "prompts" + ] + }, + { + "login": "jamesmontemagno", + "name": "James Montemagno", + "avatar_url": "https://avatars.githubusercontent.com/u/1676321?v=4", + "profile": "https://montemagno.com/", + "contributions": [ + "agents", + "doc", + "instructions", + "prompts" + ] + }, + { + "login": "VamshiVerma", + "name": "Vamshi Verma", + "avatar_url": "https://avatars.githubusercontent.com/u/21999324?v=4", + "profile": "https://github.com/VamshiVerma", + "contributions": [ + "instructions", + "prompts" + ] + }, + { + "login": "sinedied", + "name": "Yohan Lasorsa", + "avatar_url": "https://avatars.githubusercontent.com/u/593151?v=4", + "profile": "https://github.com/sinedied", + "contributions": [ + "instructions", + "prompts" + ] + }, + { + "login": "spectatora", + "name": "spectatora", + "avatar_url": "https://avatars.githubusercontent.com/u/1385755?v=4", + "profile": "https://github.com/spectatora", + "contributions": [ + "agents", + "maintenance" ] }, { @@ -163,61 +199,28 @@ "avatar_url": "https://avatars.githubusercontent.com/u/10282550?v=4", "profile": "https://www.linkedin.com/in/ambilykk/", "contributions": [ - "code" + "agents", + "instructions" ] }, { - "login": "tgrall", - "name": "Tugdual Grall", - "avatar_url": "https://avatars.githubusercontent.com/u/541250?v=4", - "profile": "http://tgrall.github.io/", + "login": "OrenMe", + "name": "Oren Me", + "avatar_url": "https://avatars.githubusercontent.com/u/5461862?v=4", + "profile": "https://www.promptboost.dev/", "contributions": [ - "code" + "agents", + "instructions" ] }, { - "login": "TianqiZhang", - "name": "Tianqi Zhang", - "avatar_url": "https://avatars.githubusercontent.com/u/5326582?v=4", - "profile": "https://github.com/TianqiZhang", + "login": "mjrousos", + "name": "Mike Rousos", + "avatar_url": "https://avatars.githubusercontent.com/u/10077254?v=4", + "profile": "https://github.com/mjrousos", "contributions": [ - "code" - ] - }, - { - "login": "shubham070", - "name": "Shubham Gaikwad", - "avatar_url": "https://avatars.githubusercontent.com/u/5480589?v=4", - "profile": "https://github.com/shubham070", - "contributions": [ - "code" - ] - }, - { - "login": "sdolgin", - "name": "Saul Dolgin", - "avatar_url": "https://avatars.githubusercontent.com/u/576449?v=4", - "profile": "https://github.com/sdolgin", - "contributions": [ - "code" - ] - }, - { - "login": "nullchimp", - "name": "NULLchimp", - "avatar_url": "https://avatars.githubusercontent.com/u/58362593?v=4", - "profile": "https://github.com/nullchimp", - "contributions": [ - "code" - ] - }, - { - "login": "MattVevang", - "name": "Matt Vevang", - "avatar_url": "https://avatars.githubusercontent.com/u/20714898?v=4", - "profile": "https://github.com/MattVevang", - "contributions": [ - "code" + "instructions", + "prompts" ] }, { @@ -226,322 +229,37 @@ "avatar_url": "https://avatars.githubusercontent.com/u/1538528?v=4", "profile": "https://devkimchi.com/", "contributions": [ - "code" + "instructions" ] }, { - "login": "0GiS0", - "name": "Gisela Torres", - "avatar_url": "https://avatars.githubusercontent.com/u/175379?v=4", - "profile": "https://hachyderm.io/@0gis0", + "login": "guiopen", + "name": "Guilherme do Amaral Alves ", + "avatar_url": "https://avatars.githubusercontent.com/u/94094527?v=4", + "profile": "https://github.com/guiopen", "contributions": [ - "code" + "instructions" ] }, { - "login": "debs-obrien", - "name": "Debbie O'Brien", - "avatar_url": "https://avatars.githubusercontent.com/u/13063165?v=4", - "profile": "https://debbie.codes/", + "login": "griffinashe", + "name": "Griffin Ashe", + "avatar_url": "https://avatars.githubusercontent.com/u/6391612?v=4", + "profile": "https://www.linkedin.com/in/griffinashe/", "contributions": [ - "code" + "agents", + "collections" ] }, { - "login": "agreaves-ms", - "name": "Allen Greaves", - "avatar_url": "https://avatars.githubusercontent.com/u/111466195?v=4", - "profile": "https://github.com/agreaves-ms", + "login": "anchildress1", + "name": "Ashley Childress", + "avatar_url": "https://avatars.githubusercontent.com/u/6563688?v=4", + "profile": "https://github.com/anchildress1", "contributions": [ - "code" - ] - }, - { - "login": "AmeliaRose802", - "name": "Amelia Payne", - "avatar_url": "https://avatars.githubusercontent.com/u/26167931?v=4", - "profile": "https://github.com/AmeliaRose802", - "contributions": [ - "code" - ] - }, - { - "login": "SebastienDegodez", - "name": "Sebastien DEGODEZ", - "avatar_url": "https://avatars.githubusercontent.com/u/2349146?v=4", - "profile": "https://github.com/SebastienDegodez", - "contributions": [ - "code" - ] - }, - { - "login": "segraef", - "name": "Sebastian GrĂ€f", - "avatar_url": "https://avatars.githubusercontent.com/u/19261257?v=4", - "profile": "https://graef.io/", - "contributions": [ - "code" - ] - }, - { - "login": "9ssi7", - "name": "Salih İbrahimbaß", - "avatar_url": "https://avatars.githubusercontent.com/u/76786120?v=4", - "profile": "https://9ssi7.dev/", - "contributions": [ - "code" - ] - }, - { - "login": "inquinity", - "name": "Robert Altman", - "avatar_url": "https://avatars.githubusercontent.com/u/406234?v=4", - "profile": "https://github.com/inquinity", - "contributions": [ - "code" - ] - }, - { - "login": "pertrai1", - "name": "Rob Simpson", - "avatar_url": "https://avatars.githubusercontent.com/u/442374?v=4", - "profile": "https://github.com/pertrai1", - "contributions": [ - "code" - ] - }, - { - "login": "ricksmit3000", - "name": "Rick Smit", - "avatar_url": "https://avatars.githubusercontent.com/u/7207783?v=4", - "profile": "https://ricksm.it/", - "contributions": [ - "code" - ] - }, - { - "login": "psmulovics", - "name": "Peter Smulovics", - "avatar_url": "https://avatars.githubusercontent.com/u/28162552?v=4", - "profile": "http://dotneteers.net/", - "contributions": [ - "code" - ] - }, - { - "login": "pelikhan", - "name": "Peli de Halleux", - "avatar_url": "https://avatars.githubusercontent.com/u/4175913?v=4", - "profile": "https://github.com/pelikhan", - "contributions": [ - "code" - ] - }, - { - "login": "paulomorgado", - "name": "Paulo Morgado", - "avatar_url": "https://avatars.githubusercontent.com/u/470455?v=4", - "profile": "https://www.paulomorgado.net/", - "contributions": [ - "code" - ] - }, - { - "login": "nickytonline", - "name": "Nick Taylor", - "avatar_url": "https://avatars.githubusercontent.com/u/833231?v=4", - "profile": "https://nickyt.co/", - "contributions": [ - "code" - ] - }, - { - "login": "mikeparker104", - "name": "Mike Parker", - "avatar_url": "https://avatars.githubusercontent.com/u/12763221?v=4", - "profile": "https://github.com/mikeparker104", - "contributions": [ - "code" - ] - }, - { - "login": "mikekistler", - "name": "Mike Kistler", - "avatar_url": "https://avatars.githubusercontent.com/u/85643503?v=4", - "profile": "https://github.com/mikekistler", - "contributions": [ - "code" - ] - }, - { - "login": "mfairchild365", - "name": "Michael Fairchild", - "avatar_url": "https://avatars.githubusercontent.com/u/498678?v=4", - "profile": "https://a11ysupport.io/", - "contributions": [ - "code" - ] - }, - { - "login": "michaelvolz", - "name": "Michael A. Volz (Flynn)", - "avatar_url": "https://avatars.githubusercontent.com/u/129928?v=4", - "profile": "https://www.linkedin.com/in/michael-volz/", - "contributions": [ - "code" - ] - }, - { - "login": "4regab", - "name": "4regab", - "avatar_url": "https://avatars.githubusercontent.com/u/178603515?v=4", - "profile": "https://github.com/4regab", - "contributions": [ - "code" - ] - }, - { - "login": "TheovanKraay", - "name": "Theo van Kraay", - "avatar_url": "https://avatars.githubusercontent.com/u/24420698?v=4", - "profile": "https://github.com/TheovanKraay", - "contributions": [ - "code" - ] - }, - { - "login": "twitthoeft-gls", - "name": "Troy Witthoeft (glsauto)", - "avatar_url": "https://avatars.githubusercontent.com/u/132710946?v=4", - "profile": "http://glsauto.com/", - "contributions": [ - "code" - ] - }, - { - "login": "iletai", - "name": "TĂ i LĂȘ", - "avatar_url": "https://avatars.githubusercontent.com/u/26614687?v=4", - "profile": "https://github.com/iletai", - "contributions": [ - "code" - ] - }, - { - "login": "udayakumarreddyv", - "name": "Udaya Veeramreddygari", - "avatar_url": "https://avatars.githubusercontent.com/u/9591887?v=4", - "profile": "https://tinyurl.com/3p5j9mwe", - "contributions": [ - "code" - ] - }, - { - "login": "warengonzaga", - "name": "Waren Gonzaga", - "avatar_url": "https://avatars.githubusercontent.com/u/15052701?v=4", - "profile": "https://bio.warengonzaga.com/", - "contributions": [ - "code" - ] - }, - { - "login": "doggy8088", - "name": "Will äżć“„", - "avatar_url": "https://avatars.githubusercontent.com/u/88981?v=4", - "profile": "https://blog.miniasp.com/", - "contributions": [ - "code" - ] - }, - { - "login": "yukiomoto", - "name": "Yuki Omoto", - "avatar_url": "https://avatars.githubusercontent.com/u/38450410?v=4", - "profile": "https://github.com/yukiomoto", - "contributions": [ - "code" - ] - }, - { - "login": "hueanmy", - "name": "Meii", - "avatar_url": "https://avatars.githubusercontent.com/u/20430626?v=4", - "profile": "https://github.com/hueanmy", - "contributions": [ - "code" - ] - }, - { - "login": "samqbush", - "name": "samqbush", - "avatar_url": "https://avatars.githubusercontent.com/u/74389839?v=4", - "profile": "https://github.com/samqbush", - "contributions": [ - "code" - ] - }, - { - "login": "sdanzo-hrb", - "name": "sdanzo-hrb", - "avatar_url": "https://avatars.githubusercontent.com/u/136493100?v=4", - "profile": "https://github.com/sdanzo-hrb", - "contributions": [ - "code" - ] - }, - { - "login": "voidfnc", - "name": "voidfnc", - "avatar_url": "https://avatars.githubusercontent.com/u/194750710?v=4", - "profile": "https://github.com/voidfnc", - "contributions": [ - "code" - ] - }, - { - "login": "webreidi", - "name": "Wendy Breiding", - "avatar_url": "https://avatars.githubusercontent.com/u/55603905?v=4", - "profile": "https://github.com/webreidi", - "contributions": [ - "code" - ] - }, - { - "login": "zooav", - "name": "Ankur Sharma", - "avatar_url": "https://avatars.githubusercontent.com/u/12625412?v=4", - "profile": "https://github.com/zooav", - "contributions": [ - "code" - ] - }, - { - "login": "Jian-Min-Huang", - "name": "é»ƒć„æ—» Vincent Huang", - "avatar_url": "https://avatars.githubusercontent.com/u/6296280?v=4", - "profile": "https://jianminhuang.cc/", - "contributions": [ - "code" - ] - }, - { - "login": "dgh06175", - "name": "읎상현", - "avatar_url": "https://avatars.githubusercontent.com/u/77305722?v=4", - "profile": "https://github.com/dgh06175", - "contributions": [ - "code" - ] - }, - { - "login": "abdidaudpropel", - "name": "Abdi Daud", - "avatar_url": "https://avatars.githubusercontent.com/u/51310019?v=4", - "profile": "https://github.com/abdidaudpropel", - "contributions": [ - "code" + "agents", + "doc", + "instructions" ] }, { @@ -550,16 +268,18 @@ "avatar_url": "https://avatars.githubusercontent.com/u/50712277?v=4", "profile": "http://www.senseof.tech/", "contributions": [ - "code" + "agents", + "doc", + "prompts" ] }, { - "login": "tegola", - "name": "Alan Sprecacenere", - "avatar_url": "https://avatars.githubusercontent.com/u/1868590?v=4", - "profile": "http://www.qreate.it/", + "login": "Vhivi", + "name": "ANGELELLI David", + "avatar_url": "https://avatars.githubusercontent.com/u/38220028?v=4", + "profile": "https://github.com/Vhivi", "contributions": [ - "code" + "agents" ] }, { @@ -568,25 +288,122 @@ "avatar_url": "https://avatars.githubusercontent.com/u/2493377?v=4", "profile": "https://asilva.dev/", "contributions": [ - "code" + "agents", + "instructions" ] }, { - "login": "arey", - "name": "Antoine Rey", - "avatar_url": "https://avatars.githubusercontent.com/u/838318?v=4", - "profile": "https://javaetmoi.com/", + "login": "MattVevang", + "name": "Matt Vevang", + "avatar_url": "https://avatars.githubusercontent.com/u/20714898?v=4", + "profile": "https://github.com/MattVevang", "contributions": [ - "code" + "instructions" ] }, { - "login": "artemsaveliev", - "name": "Artem Saveliev", - "avatar_url": "https://avatars.githubusercontent.com/u/15679218?v=4", - "profile": "https://github.com/artemsaveliev", + "login": "mpgirro", + "name": "Maximilian Irro", + "avatar_url": "https://avatars.githubusercontent.com/u/589073?v=4", + "profile": "https://max.irro.at/", "contributions": [ - "code" + "instructions" + ] + }, + { + "login": "nullchimp", + "name": "NULLchimp", + "avatar_url": "https://avatars.githubusercontent.com/u/58362593?v=4", + "profile": "https://github.com/nullchimp", + "contributions": [ + "agents" + ] + }, + { + "login": "sdolgin", + "name": "Saul Dolgin", + "avatar_url": "https://avatars.githubusercontent.com/u/576449?v=4", + "profile": "https://github.com/sdolgin", + "contributions": [ + "agents", + "instructions", + "prompts" + ] + }, + { + "login": "shubham070", + "name": "Shubham Gaikwad", + "avatar_url": "https://avatars.githubusercontent.com/u/5480589?v=4", + "profile": "https://github.com/shubham070", + "contributions": [ + "agents", + "instructions", + "prompts" + ] + }, + { + "login": "TheovanKraay", + "name": "Theo van Kraay", + "avatar_url": "https://avatars.githubusercontent.com/u/24420698?v=4", + "profile": "https://github.com/TheovanKraay", + "contributions": [ + "instructions" + ] + }, + { + "login": "TianqiZhang", + "name": "Tianqi Zhang", + "avatar_url": "https://avatars.githubusercontent.com/u/5326582?v=4", + "profile": "https://github.com/TianqiZhang", + "contributions": [ + "agents" + ] + }, + { + "login": "tgrall", + "name": "Tugdual Grall", + "avatar_url": "https://avatars.githubusercontent.com/u/541250?v=4", + "profile": "http://tgrall.github.io/", + "contributions": [ + "instructions", + "prompts" + ] + }, + { + "login": "doggy8088", + "name": "Will äżć“„", + "avatar_url": "https://avatars.githubusercontent.com/u/88981?v=4", + "profile": "https://blog.miniasp.com/", + "contributions": [ + "agents", + "prompts" + ] + }, + { + "login": "tsubakimoto", + "name": "Yuta Matsumura", + "avatar_url": "https://avatars.githubusercontent.com/u/1592808?v=4", + "profile": "https://tsubalog.hatenablog.com/", + "contributions": [ + "instructions" + ] + }, + { + "login": "hizahizi-hizumi", + "name": "hizahizi-hizumi", + "avatar_url": "https://avatars.githubusercontent.com/u/163728895?v=4", + "profile": "https://github.com/hizahizi-hizumi", + "contributions": [ + "instructions" + ] + }, + { + "login": "Jian-Min-Huang", + "name": "é»ƒć„æ—» Vincent Huang", + "avatar_url": "https://avatars.githubusercontent.com/u/6296280?v=4", + "profile": "https://jianminhuang.cc/", + "contributions": [ + "prompts" ] }, { @@ -595,34 +412,65 @@ "avatar_url": "https://avatars.githubusercontent.com/u/129743?v=4", "profile": "http://brunoborges.io/", "contributions": [ - "code" - ] - }, - { - "login": "tossnet", - "name": "Christophe Peugnet", - "avatar_url": "https://avatars.githubusercontent.com/u/3845786?v=4", - "profile": "https://www.peug.net/", - "contributions": [ - "code" + "collections", + "instructions" ] }, { "login": "MovingLive", - "name": "Chtive", + "name": "Steve Magne", "avatar_url": "https://avatars.githubusercontent.com/u/14792628?v=4", "profile": "https://www.movinglive.ca/", "contributions": [ - "code" + "doc", + "instructions" ] }, { - "login": "craigbekker", - "name": "Craig Bekker", - "avatar_url": "https://avatars.githubusercontent.com/u/1115912?v=4", - "profile": "https://github.com/craigbekker", + "login": "PureWeen", + "name": "Shane Neuville", + "avatar_url": "https://avatars.githubusercontent.com/u/5375137?v=4", + "profile": "http://shaneneuville.com/", "contributions": [ - "code" + "agents", + "instructions" + ] + }, + { + "login": "agreaves-ms", + "name": "Allen Greaves", + "avatar_url": "https://avatars.githubusercontent.com/u/111466195?v=4", + "profile": "https://github.com/agreaves-ms", + "contributions": [ + "agents", + "instructions" + ] + }, + { + "login": "AmeliaRose802", + "name": "Amelia Payne", + "avatar_url": "https://avatars.githubusercontent.com/u/26167931?v=4", + "profile": "https://github.com/AmeliaRose802", + "contributions": [ + "agents" + ] + }, + { + "login": "brooke-hamilton", + "name": "Brooke Hamilton", + "avatar_url": "https://avatars.githubusercontent.com/u/45323234?v=4", + "profile": "https://azureincubations.io/", + "contributions": [ + "instructions" + ] + }, + { + "login": "GeekTrainer", + "name": "Christopher Harrison", + "avatar_url": "https://avatars.githubusercontent.com/u/6109729?v=4", + "profile": "https://github.com/GeekTrainer", + "contributions": [ + "instructions" ] }, { @@ -631,34 +479,36 @@ "avatar_url": "https://avatars.githubusercontent.com/u/1446918?v=4", "profile": "https://github.com/breakid", "contributions": [ - "code" + "instructions" ] }, { - "login": "ewega", - "name": "Eldrick Wega", - "avatar_url": "https://avatars.githubusercontent.com/u/26189114?v=4", - "profile": "https://github.com/ewega", + "login": "DanWahlin", + "name": "Dan Wahlin", + "avatar_url": "https://avatars.githubusercontent.com/u/1767249?v=4", + "profile": "https://blog.codewithdan.com/", "contributions": [ - "code" + "agents" ] }, { - "login": "felixarjuna", - "name": "Felix Arjuna", - "avatar_url": "https://avatars.githubusercontent.com/u/79026094?v=4", - "profile": "https://www.felixarjuna.dev/", + "login": "debs-obrien", + "name": "Debbie O'Brien", + "avatar_url": "https://avatars.githubusercontent.com/u/13063165?v=4", + "profile": "https://debbie.codes/", "contributions": [ - "code" + "agents", + "instructions", + "prompts" ] }, { - "login": "feapaydin", - "name": "Furkan Enes", - "avatar_url": "https://avatars.githubusercontent.com/u/19946639?v=4", - "profile": "https://github.com/feapaydin", + "login": "echarrod", + "name": "Ed Harrod", + "avatar_url": "https://avatars.githubusercontent.com/u/1381991?v=4", + "profile": "https://github.com/echarrod", "contributions": [ - "code" + "prompts" ] }, { @@ -667,133 +517,17 @@ "avatar_url": "https://avatars.githubusercontent.com/u/24882762?v=4", "profile": "http://learn.microsoft.com/dotnet", "contributions": [ - "code" + "prompts" ] }, { - "login": "geoder101", - "name": "George Dernikos", - "avatar_url": "https://avatars.githubusercontent.com/u/145904?v=4", - "profile": "https://github.com/geoder101", + "login": "guigui42", + "name": "Guillaume", + "avatar_url": "https://avatars.githubusercontent.com/u/2376010?v=4", + "profile": "https://github.com/guigui42", "contributions": [ - "code" - ] - }, - { - "login": "giomartinsdev", - "name": "Giovanni de Almeida Martins", - "avatar_url": "https://avatars.githubusercontent.com/u/125399281?v=4", - "profile": "https://github.com/giomartinsdev", - "contributions": [ - "code" - ] - }, - { - "login": "Ioana37", - "name": "Ioana A", - "avatar_url": "https://avatars.githubusercontent.com/u/69301842?v=4", - "profile": "https://github.com/Ioana37", - "contributions": [ - "code" - ] - }, - { - "login": "nohwnd", - "name": "Jakub JareĆĄ", - "avatar_url": "https://avatars.githubusercontent.com/u/5735905?v=4", - "profile": "https://github.com/nohwnd", - "contributions": [ - "code" - ] - }, - { - "login": "joe-watkins", - "name": "Joe Watkins", - "avatar_url": "https://avatars.githubusercontent.com/u/3695795?v=4", - "profile": "http://joe-watkins.io/", - "contributions": [ - "code" - ] - }, - { - "login": "johnpapa", - "name": "John Papa", - "avatar_url": "https://avatars.githubusercontent.com/u/1202528?v=4", - "profile": "http://johnpapa.net/", - "contributions": [ - "code" - ] - }, - { - "login": "josephgonzales01", - "name": "Joseph Gonzales", - "avatar_url": "https://avatars.githubusercontent.com/u/15100839?v=4", - "profile": "http://www.sugbo4j.co.nz/", - "contributions": [ - "code" - ] - }, - { - "login": "josegarridodigio", - "name": "JosĂ© Antonio Garrido", - "avatar_url": "https://avatars.githubusercontent.com/u/173672918?v=4", - "profile": "https://digio.es/", - "contributions": [ - "code" - ] - }, - { - "login": "Ranrar", - "name": "Kim Skov Rasmussen", - "avatar_url": "https://avatars.githubusercontent.com/u/95967772?v=4", - "profile": "https://github.com/Ranrar", - "contributions": [ - "code" - ] - }, - { - "login": "whiteken", - "name": "Kenny White", - "avatar_url": "https://avatars.githubusercontent.com/u/20211937?v=4", - "profile": "https://github.com/whiteken", - "contributions": [ - "code" - ] - }, - { - "login": "LouellaCreemers", - "name": "Louella Creemers", - "avatar_url": "https://avatars.githubusercontent.com/u/46204894?v=4", - "profile": "https://github.com/LouellaCreemers", - "contributions": [ - "code" - ] - }, - { - "login": "lukemurraynz", - "name": "Luke Murray", - "avatar_url": "https://avatars.githubusercontent.com/u/24467442?v=4", - "profile": "https://linktr.ee/lukemurray", - "contributions": [ - "code" - ] - }, - { - "login": "marknoble", - "name": "Mark Noble", - "avatar_url": "https://avatars.githubusercontent.com/u/3819700?v=4", - "profile": "http://marknoble.com/", - "contributions": [ - "code" - ] - }, - { - "login": "soderlind", - "name": "Per SĂžderlind", - "avatar_url": "https://avatars.githubusercontent.com/u/1649452?v=4", - "profile": "https://soderlind.no", - "contributions": [ - "code" + "agents", + "prompts" ] }, { @@ -802,7 +536,7 @@ "avatar_url": "https://avatars.githubusercontent.com/u/108551585?v=4", "profile": "https://github.com/riqueufmg", "contributions": [ - "code" + "prompts" ] }, { @@ -815,43 +549,1021 @@ ] }, { - "login": "spectatora", - "name": "spectatora", - "avatar_url": "https://avatars.githubusercontent.com/u/1385755?v=4", - "profile": "https://github.com/spectatora", + "login": "kartikdhiman", + "name": "Kartik Dhiman", + "avatar_url": "https://avatars.githubusercontent.com/u/59189590?v=4", + "profile": "https://github.com/kartikdhiman", + "contributions": [ + "instructions" + ] + }, + { + "login": "kristiyan-velkov", + "name": "Kristiyan Velkov", + "avatar_url": "https://avatars.githubusercontent.com/u/40764277?v=4", + "profile": "https://kristiyanvelkov.com/", + "contributions": [ + "agents" + ] + }, + { + "login": "markdav-is", + "name": "Mark Davis", + "avatar_url": "https://avatars.githubusercontent.com/u/311063?v=4", + "profile": "http://markdav.is/", + "contributions": [ + "instructions" + ] + }, + { + "login": "pelikhan", + "name": "Peli de Halleux", + "avatar_url": "https://avatars.githubusercontent.com/u/4175913?v=4", + "profile": "https://github.com/pelikhan", "contributions": [ "code" ] }, { - "login": "Mike-Hanna", - "name": "Michael", - "avatar_url": "https://avatars.githubusercontent.com/u/50142889?v=4", - "profile": "https://github.com/Mike-Hanna", + "login": "soderlind", + "name": "Per SĂžderlind", + "avatar_url": "https://avatars.githubusercontent.com/u/1649452?v=4", + "profile": "https://soderlind.no/", + "contributions": [ + "instructions" + ] + }, + { + "login": "psmulovics", + "name": "Peter Smulovics", + "avatar_url": "https://avatars.githubusercontent.com/u/28162552?v=4", + "profile": "http://dotneteers.net/", + "contributions": [ + "instructions" + ] + }, + { + "login": "madvimer", + "name": "Ravish Rathod", + "avatar_url": "https://avatars.githubusercontent.com/u/3188898?v=4", + "profile": "https://github.com/madvimer", + "contributions": [ + "instructions" + ] + }, + { + "login": "ricksmit3000", + "name": "Rick Smit", + "avatar_url": "https://avatars.githubusercontent.com/u/7207783?v=4", + "profile": "https://ricksm.it/", + "contributions": [ + "agents" + ] + }, + { + "login": "pertrai1", + "name": "Rob Simpson", + "avatar_url": "https://avatars.githubusercontent.com/u/442374?v=4", + "profile": "https://github.com/pertrai1", + "contributions": [ + "instructions" + ] + }, + { + "login": "inquinity", + "name": "Robert Altman", + "avatar_url": "https://avatars.githubusercontent.com/u/406234?v=4", + "profile": "https://github.com/inquinity", + "contributions": [ + "instructions" + ] + }, + { + "login": "salihguru", + "name": "Salih", + "avatar_url": "https://avatars.githubusercontent.com/u/76786120?v=4", + "profile": "https://salih.guru/", + "contributions": [ + "instructions" + ] + }, + { + "login": "segraef", + "name": "Sebastian GrĂ€f", + "avatar_url": "https://avatars.githubusercontent.com/u/19261257?v=4", + "profile": "https://graef.io/", + "contributions": [ + "agents", + "instructions" + ] + }, + { + "login": "SebastienDegodez", + "name": "Sebastien DEGODEZ", + "avatar_url": "https://avatars.githubusercontent.com/u/2349146?v=4", + "profile": "https://github.com/SebastienDegodez", + "contributions": [ + "instructions" + ] + }, + { + "login": "sesmyrnov", + "name": "Sergiy Smyrnov", + "avatar_url": "https://avatars.githubusercontent.com/u/59627981?v=4", + "profile": "https://github.com/sesmyrnov", + "contributions": [ + "prompts" + ] + }, + { + "login": "SomeSolutionsArchitect", + "name": "SomeSolutionsArchitect", + "avatar_url": "https://avatars.githubusercontent.com/u/139817767?v=4", + "profile": "https://github.com/SomeSolutionsArchitect", + "contributions": [ + "agents" + ] + }, + { + "login": "kewalaka", + "name": "Stu Mace", + "avatar_url": "https://avatars.githubusercontent.com/u/3146590?v=4", + "profile": "https://github.com/kewalaka", + "contributions": [ + "agents", + "collections", + "instructions" + ] + }, + { + "login": "dgh06175", + "name": "읎상현", + "avatar_url": "https://avatars.githubusercontent.com/u/77305722?v=4", + "profile": "https://github.com/dgh06175", + "contributions": [ + "instructions" + ] + }, + { + "login": "paulomorgado", + "name": "Paulo Morgado", + "avatar_url": "https://avatars.githubusercontent.com/u/470455?v=4", + "profile": "https://www.paulomorgado.net/", + "contributions": [ + "prompts" + ] + }, + { + "login": "pcrane", + "name": "Paul Crane", + "avatar_url": "https://avatars.githubusercontent.com/u/808676?v=4", + "profile": "https://paul.crane.net.nz/", + "contributions": [ + "agents" + ] + }, + { + "login": "pamelafox", + "name": "Pamela Fox", + "avatar_url": "https://avatars.githubusercontent.com/u/297042?v=4", + "profile": "https://www.pamelafox.org/", + "contributions": [ + "prompts" + ] + }, + { + "login": "prewk", + "name": "Oskar Thornblad", + "avatar_url": "https://avatars.githubusercontent.com/u/640102?v=4", + "profile": "https://oskarthornblad.se/", + "contributions": [ + "instructions" + ] + }, + { + "login": "nischays", + "name": "Nischay Sharma", + "avatar_url": "https://avatars.githubusercontent.com/u/54121853?v=4", + "profile": "https://github.com/nischays", + "contributions": [ + "agents" + ] + }, + { + "login": "Naikabg", + "name": "Nikolay Marinov", + "avatar_url": "https://avatars.githubusercontent.com/u/19915620?v=4", + "profile": "https://github.com/Naikabg", + "contributions": [ + "agents" + ] + }, + { + "login": "niksacdev", + "name": "Nik Sachdeva", + "avatar_url": "https://avatars.githubusercontent.com/u/20246918?v=4", + "profile": "https://www.linkedin.com/in/niksac", + "contributions": [ + "agents", + "collections" + ] + }, + { + "login": "nickytonline", + "name": "Nick Taylor", + "avatar_url": "https://avatars.githubusercontent.com/u/833231?v=4", + "profile": "https://onetipaweek.com/", "contributions": [ "code" ] }, + { + "login": "nicholasdbrady", + "name": "Nick Brady", + "avatar_url": "https://avatars.githubusercontent.com/u/18353756?v=4", + "profile": "https://nicholasdbrady.github.io/cookbook/", + "contributions": [ + "agents" + ] + }, + { + "login": "nastanford", + "name": "Nathan Stanford Sr", + "avatar_url": "https://avatars.githubusercontent.com/u/1755947?v=4", + "profile": "https://github.com/nastanford", + "contributions": [ + "instructions" + ] + }, + { + "login": "matebarabas", + "name": "MĂĄtĂ© BarabĂĄs", + "avatar_url": "https://avatars.githubusercontent.com/u/22733424?v=4", + "profile": "https://github.com/matebarabas", + "contributions": [ + "instructions" + ] + }, + { + "login": "mikeparker104", + "name": "Mike Parker", + "avatar_url": "https://avatars.githubusercontent.com/u/12763221?v=4", + "profile": "https://github.com/mikeparker104", + "contributions": [ + "instructions" + ] + }, + { + "login": "mikekistler", + "name": "Mike Kistler", + "avatar_url": "https://avatars.githubusercontent.com/u/85643503?v=4", + "profile": "https://github.com/mikekistler", + "contributions": [ + "prompts" + ] + }, + { + "login": "mfairchild365", + "name": "Michael Fairchild", + "avatar_url": "https://avatars.githubusercontent.com/u/498678?v=4", + "profile": "https://a11ysupport.io/", + "contributions": [ + "instructions" + ] + }, + { + "login": "zooav", + "name": "Ankur Sharma", + "avatar_url": "https://avatars.githubusercontent.com/u/12625412?v=4", + "profile": "https://github.com/zooav", + "contributions": [ + "prompts" + ] + }, + { + "login": "webreidi", + "name": "Wendy Breiding", + "avatar_url": "https://avatars.githubusercontent.com/u/55603905?v=4", + "profile": "https://github.com/webreidi", + "contributions": [ + "code" + ] + }, + { + "login": "voidfnc", + "name": "voidfnc", + "avatar_url": "https://avatars.githubusercontent.com/u/194750710?v=4", + "profile": "https://github.com/voidfnc", + "contributions": [ + "agents" + ] + }, + { + "login": "shavo007", + "name": "shane lee", + "avatar_url": "https://avatars.githubusercontent.com/u/5466825?v=4", + "profile": "https://about.me/shane-lee", + "contributions": [ + "instructions" + ] + }, + { + "login": "sdanzo-hrb", + "name": "sdanzo-hrb", + "avatar_url": "https://avatars.githubusercontent.com/u/136493100?v=4", + "profile": "https://github.com/sdanzo-hrb", + "contributions": [ + "agents" + ] + }, + { + "login": "isauran", + "name": "sauran", + "avatar_url": "https://avatars.githubusercontent.com/u/33398121?v=4", + "profile": "https://github.com/nativebpm", + "contributions": [ + "instructions" + ] + }, + { + "login": "samqbush", + "name": "samqbush", + "avatar_url": "https://avatars.githubusercontent.com/u/74389839?v=4", + "profile": "https://github.com/samqbush", + "contributions": [ + "prompts" + ] + }, + { + "login": "pareenaverma", + "name": "pareenaverma", + "avatar_url": "https://avatars.githubusercontent.com/u/59843121?v=4", + "profile": "https://github.com/pareenaverma", + "contributions": [ + "agents" + ] + }, + { + "login": "oleksiyyurchyna", + "name": "oleksiyyurchyna", + "avatar_url": "https://avatars.githubusercontent.com/u/10256765?v=4", + "profile": "https://github.com/oleksiyyurchyna", + "contributions": [ + "collections", + "prompts" + ] + }, + { + "login": "time-by-waves", + "name": "oceans-of-time", + "avatar_url": "https://avatars.githubusercontent.com/u/34587654?v=4", + "profile": "https://github.com/time-by-waves", + "contributions": [ + "instructions" + ] + }, + { + "login": "kshashank57", + "name": "kshashank57", + "avatar_url": "https://avatars.githubusercontent.com/u/57212456?v=4", + "profile": "https://github.com/kshashank57", + "contributions": [ + "agents", + "instructions" + ] + }, + { + "login": "hueanmy", + "name": "Meii", + "avatar_url": "https://avatars.githubusercontent.com/u/20430626?v=4", + "profile": "https://github.com/hueanmy", + "contributions": [ + "agents" + ] + }, + { + "login": "factory-davidgu", + "name": "factory-davidgu", + "avatar_url": "https://avatars.githubusercontent.com/u/229352262?v=4", + "profile": "https://github.com/factory-davidgu", + "contributions": [ + "code" + ] + }, + { + "login": "dangelov-qa", + "name": "dangelov-qa", + "avatar_url": "https://avatars.githubusercontent.com/u/92313553?v=4", + "profile": "https://github.com/dangelov-qa", + "contributions": [ + "agents" + ] + }, + { + "login": "yukiomoto", + "name": "Yuki Omoto", + "avatar_url": "https://avatars.githubusercontent.com/u/38450410?v=4", + "profile": "https://github.com/yukiomoto", + "contributions": [ + "instructions" + ] + }, + { + "login": "wschultz-boxboat", + "name": "Will Schultz", + "avatar_url": "https://avatars.githubusercontent.com/u/110492948?v=4", + "profile": "https://github.com/wschultz-boxboat", + "contributions": [ + "agents" + ] + }, + { + "login": "warengonzaga", + "name": "Waren Gonzaga", + "avatar_url": "https://avatars.githubusercontent.com/u/15052701?v=4", + "profile": "https://bio.warengonzaga.com/", + "contributions": [ + "agents" + ] + }, + { + "login": "vincentkoc", + "name": "Vincent Koc", + "avatar_url": "https://avatars.githubusercontent.com/u/25068?v=4", + "profile": "https://linktr.ee/vincentkoc", + "contributions": [ + "agents" + ] + }, + { + "login": "Vaporjawn", + "name": "Victor Williams", + "avatar_url": "https://avatars.githubusercontent.com/u/15694665?v=4", + "profile": "https://github.com/Vaporjawn", + "contributions": [ + "agents" + ] + }, + { + "login": "VeVarunSharma", + "name": "Ve Sharma", + "avatar_url": "https://avatars.githubusercontent.com/u/62218708?v=4", + "profile": "https://vesharma.dev/", + "contributions": [ + "agents" + ] + }, + { + "login": "udayakumarreddyv", + "name": "Udaya Veeramreddygari", + "avatar_url": "https://avatars.githubusercontent.com/u/9591887?v=4", + "profile": "https://tinyurl.com/3p5j9mwe", + "contributions": [ + "instructions" + ] + }, + { + "login": "iletai", + "name": "TĂ i LĂȘ", + "avatar_url": "https://avatars.githubusercontent.com/u/26614687?v=4", + "profile": "https://github.com/iletai", + "contributions": [ + "prompts" + ] + }, + { + "login": "twitthoeft-gls", + "name": "Troy Witthoeft (glsauto)", + "avatar_url": "https://avatars.githubusercontent.com/u/132710946?v=4", + "profile": "http://glsauto.com/", + "contributions": [ + "instructions" + ] + }, + { + "login": "tmeschter", + "name": "Tom Meschter", + "avatar_url": "https://avatars.githubusercontent.com/u/10506730?v=4", + "profile": "https://github.com/tmeschter", + "contributions": [ + "code" + ] + }, + { + "login": "semperteneo", + "name": "Tj Vita", + "avatar_url": "https://avatars.githubusercontent.com/u/14024037?v=4", + "profile": "http://enakdesign.com/", + "contributions": [ + "agents" + ] + }, + { + "login": "STRUDSO", + "name": "SĂžren TrudsĂž Mahon", + "avatar_url": "https://avatars.githubusercontent.com/u/1543732?v=4", + "profile": "https://github.com/STRUDSO", + "contributions": [ + "instructions" + ] + }, + { + "login": "geoder101", + "name": "George Dernikos", + "avatar_url": "https://avatars.githubusercontent.com/u/145904?v=4", + "profile": "https://github.com/geoder101", + "contributions": [ + "code" + ] + }, + { + "login": "gautambaghel", + "name": "Gautam", + "avatar_url": "https://avatars.githubusercontent.com/u/22324290?v=4", + "profile": "https://github.com/gautambaghel", + "contributions": [ + "agents" + ] + }, + { + "login": "feapaydin", + "name": "Furkan Enes", + "avatar_url": "https://avatars.githubusercontent.com/u/19946639?v=4", + "profile": "https://github.com/feapaydin", + "contributions": [ + "instructions" + ] + }, + { + "login": "fmuecke", + "name": "Florian MĂŒcke", + "avatar_url": "https://avatars.githubusercontent.com/u/7921024?v=4", + "profile": "https://github.com/fmuecke", + "contributions": [ + "agents" + ] + }, + { + "login": "felixarjuna", + "name": "Felix Arjuna", + "avatar_url": "https://avatars.githubusercontent.com/u/79026094?v=4", + "profile": "https://www.felixarjuna.dev/", + "contributions": [ + "instructions" + ] + }, + { + "login": "ewega", + "name": "Eldrick Wega", + "avatar_url": "https://avatars.githubusercontent.com/u/26189114?v=4", + "profile": "https://github.com/ewega", + "contributions": [ + "prompts" + ] + }, + { + "login": "danchev", + "name": "Dobri Danchev", + "avatar_url": "https://avatars.githubusercontent.com/u/12420863?v=4", + "profile": "https://github.com/danchev", + "contributions": [ + "prompts" + ] + }, + { + "login": "difegam", + "name": "Diego Gamboa", + "avatar_url": "https://avatars.githubusercontent.com/u/7052267?v=4", + "profile": "https://dgamboa.com/", + "contributions": [ + "prompts" + ] + }, + { + "login": "derekclair", + "name": "Derek Clair", + "avatar_url": "https://avatars.githubusercontent.com/u/5247629?v=4", + "profile": "https://github.com/derekclair", + "contributions": [ + "agents", + "prompts" + ] + }, + { + "login": "davidortinau", + "name": "David Ortinau", + "avatar_url": "https://avatars.githubusercontent.com/u/41873?v=4", + "profile": "https://dev.to/davidortinau", + "contributions": [ + "code" + ] + }, + { + "login": "danielabbatt", + "name": "Daniel Abbatt", + "avatar_url": "https://avatars.githubusercontent.com/u/8926756?v=4", + "profile": "https://github.com/danielabbatt", + "contributions": [ + "instructions" + ] + }, + { + "login": "CypherHK", + "name": "CypherHK", + "avatar_url": "https://avatars.githubusercontent.com/u/230935834?v=4", + "profile": "https://github.com/CypherHK", + "contributions": [ + "agents", + "prompts" + ] + }, + { + "login": "craigbekker", + "name": "Craig Bekker", + "avatar_url": "https://avatars.githubusercontent.com/u/1115912?v=4", + "profile": "https://github.com/craigbekker", + "contributions": [ + "code" + ] + }, + { + "login": "tossnet", + "name": "Christophe Peugnet", + "avatar_url": "https://avatars.githubusercontent.com/u/3845786?v=4", + "profile": "https://www.peug.net/", + "contributions": [ + "instructions" + ] + }, { "login": "lechnerc77", "name": "Christian Lechner", "avatar_url": "https://avatars.githubusercontent.com/u/22294087?v=4", "profile": "https://github.com/lechnerc77", + "contributions": [ + "instructions" + ] + }, + { + "login": "charris-msft", + "name": "Chris Harris", + "avatar_url": "https://avatars.githubusercontent.com/u/74415662?v=4", + "profile": "https://github.com/charris-msft", + "contributions": [ + "agents" + ] + }, + { + "login": "BBoyBen", + "name": "BBoyBen", + "avatar_url": "https://avatars.githubusercontent.com/u/34445365?v=4", + "profile": "https://github.com/BBoyBen", + "contributions": [ + "instructions" + ] + }, + { + "login": "artemsaveliev", + "name": "Artem Saveliev", + "avatar_url": "https://avatars.githubusercontent.com/u/15679218?v=4", + "profile": "https://github.com/artemsaveliev", + "contributions": [ + "instructions" + ] + }, + { + "login": "arey", + "name": "Antoine Rey", + "avatar_url": "https://avatars.githubusercontent.com/u/838318?v=4", + "profile": "https://javaetmoi.com/", + "contributions": [ + "prompts" + ] + }, + { + "login": "PiKa919", + "name": "Ankit Das", + "avatar_url": "https://avatars.githubusercontent.com/u/96786190?v=4", + "profile": "https://github.com/PiKa919", + "contributions": [ + "instructions" + ] + }, + { + "login": "alineavila", + "name": "Aline Ávila", + "avatar_url": "https://avatars.githubusercontent.com/u/24813256?v=4", + "profile": "https://github.com/alineavila", + "contributions": [ + "instructions" + ] + }, + { + "login": "martin-cod", + "name": "Alexander Martinkevich", + "avatar_url": "https://avatars.githubusercontent.com/u/33550246?v=4", + "profile": "https://github.com/martin-cod", + "contributions": [ + "agents" + ] + }, + { + "login": "aldunchev", + "name": "Aleksandar Dunchev", + "avatar_url": "https://avatars.githubusercontent.com/u/4631021?v=4", + "profile": "https://github.com/aldunchev", + "contributions": [ + "agents" + ] + }, + { + "login": "tegola", + "name": "Alan Sprecacenere", + "avatar_url": "https://avatars.githubusercontent.com/u/1868590?v=4", + "profile": "http://www.qreate.it/", + "contributions": [ + "instructions" + ] + }, + { + "login": "akashxlr8", + "name": "Akash Kumar Shaw", + "avatar_url": "https://avatars.githubusercontent.com/u/58072860?v=4", + "profile": "https://github.com/akashxlr8", + "contributions": [ + "instructions" + ] + }, + { + "login": "abdidaudpropel", + "name": "Abdi Daud", + "avatar_url": "https://avatars.githubusercontent.com/u/51310019?v=4", + "profile": "https://github.com/abdidaudpropel", + "contributions": [ + "agents" + ] + }, + { + "login": "4regab", + "name": "4regab", + "avatar_url": "https://avatars.githubusercontent.com/u/178603515?v=4", + "profile": "https://github.com/4regab", + "contributions": [ + "instructions" + ] + }, + { + "login": "michaelvolz", + "name": "Michael A. Volz (Flynn)", + "avatar_url": "https://avatars.githubusercontent.com/u/129928?v=4", + "profile": "https://www.linkedin.com/in/michael-volz/", + "contributions": [ + "prompts" + ] + }, + { + "login": "Mike-Hanna", + "name": "Michael", + "avatar_url": "https://avatars.githubusercontent.com/u/50142889?v=4", + "profile": "https://github.com/Mike-Hanna", + "contributions": [ + "instructions" + ] + }, + { + "login": "mehmetalierol", + "name": "Mehmet Ali EROL", + "avatar_url": "https://avatars.githubusercontent.com/u/16721723?v=4", + "profile": "http://www.mehmetalierol.com/", + "contributions": [ + "agents" + ] + }, + { + "login": "maxprilutskiy", + "name": "Max Prilutskiy", + "avatar_url": "https://avatars.githubusercontent.com/u/5614659?v=4", + "profile": "https://maxprilutskiy.com/", + "contributions": [ + "agents" + ] + }, + { + "login": "mbianchidev", + "name": "Matteo Bianchi", + "avatar_url": "https://avatars.githubusercontent.com/u/37507190?v=4", + "profile": "https://github.com/mbianchidev", + "contributions": [ + "agents" + ] + }, + { + "login": "codemillmatt", + "name": "Matt Soucoup", + "avatar_url": "https://avatars.githubusercontent.com/u/2053639?v=4", + "profile": "https://codemilltech.com/", + "contributions": [ + "infra" + ] + }, + { + "login": "marknoble", + "name": "Mark Noble", + "avatar_url": "https://avatars.githubusercontent.com/u/3819700?v=4", + "profile": "http://marknoble.com/", + "contributions": [ + "agents" + ] + }, + { + "login": "ManishJayaswal", + "name": "Manish Jayaswal", + "avatar_url": "https://avatars.githubusercontent.com/u/9527491?v=4", + "profile": "https://github.com/ManishJayaswal", + "contributions": [ + "agents" + ] + }, + { + "login": "lukemurraynz", + "name": "Luke Murray", + "avatar_url": "https://avatars.githubusercontent.com/u/24467442?v=4", + "profile": "https://linktr.ee/lukemurray", + "contributions": [ + "agents" + ] + }, + { + "login": "LouellaCreemers", + "name": "Louella Creemers", + "avatar_url": "https://avatars.githubusercontent.com/u/46204894?v=4", + "profile": "https://github.com/LouellaCreemers", + "contributions": [ + "instructions" + ] + }, + { + "login": "whiteken", + "name": "Kenny White", + "avatar_url": "https://avatars.githubusercontent.com/u/20211937?v=4", + "profile": "https://github.com/whiteken", + "contributions": [ + "instructions" + ] + }, + { + "login": "KaloyanGenev", + "name": "KaloyanGenev", + "avatar_url": "https://avatars.githubusercontent.com/u/42644424?v=4", + "profile": "https://github.com/KaloyanGenev", + "contributions": [ + "agents" + ] + }, + { + "login": "Ranrar", + "name": "Kim Skov Rasmussen", + "avatar_url": "https://avatars.githubusercontent.com/u/95967772?v=4", + "profile": "https://github.com/Ranrar", "contributions": [ "code" ] }, + { + "login": "jdubois", + "name": "Julien Dubois", + "avatar_url": "https://avatars.githubusercontent.com/u/316835?v=4", + "profile": "https://www.julien-dubois.com/", + "contributions": [ + "prompts" + ] + }, + { + "login": "josegarridodigio", + "name": "JosĂ© Antonio Garrido", + "avatar_url": "https://avatars.githubusercontent.com/u/173672918?v=4", + "profile": "https://digio.es/", + "contributions": [ + "instructions" + ] + }, + { + "login": "josephgonzales01", + "name": "Joseph Gonzales", + "avatar_url": "https://avatars.githubusercontent.com/u/15100839?v=4", + "profile": "http://www.sugbo4j.co.nz/", + "contributions": [ + "instructions", + "prompts" + ] + }, + { + "login": "yortch", + "name": "Jorge Balderas", + "avatar_url": "https://avatars.githubusercontent.com/u/4576246?v=4", + "profile": "https://github.com/yortch", + "contributions": [ + "instructions" + ] + }, + { + "login": "johnpapa", + "name": "John Papa", + "avatar_url": "https://avatars.githubusercontent.com/u/1202528?v=4", + "profile": "http://johnpapa.net/", + "contributions": [ + "code" + ] + }, + { + "login": "johnlokerse", + "name": "John", + "avatar_url": "https://avatars.githubusercontent.com/u/3514513?v=4", + "profile": "https://www.johnlokerse.dev/", + "contributions": [ + "agents" + ] + }, + { + "login": "joe-watkins", + "name": "Joe Watkins", + "avatar_url": "https://avatars.githubusercontent.com/u/3695795?v=4", + "profile": "http://joe-watkins.io/", + "contributions": [ + "instructions" + ] + }, { "login": "Jandev", "name": "Jan de Vries", "avatar_url": "https://avatars.githubusercontent.com/u/462356?v=4", - "profile": "https://jan-v.nl", + "profile": "https://jan-v.nl/", "contributions": [ - "code" + "agents" + ] + }, + { + "login": "nohwnd", + "name": "Jakub JareĆĄ", + "avatar_url": "https://avatars.githubusercontent.com/u/5735905?v=4", + "profile": "https://github.com/nohwnd", + "contributions": [ + "prompts" + ] + }, + { + "login": "jaxn", + "name": "Jackson Miller", + "avatar_url": "https://avatars.githubusercontent.com/u/29095?v=4", + "profile": "https://github.com/jaxn", + "contributions": [ + "instructions" + ] + }, + { + "login": "Ioana37", + "name": "Ioana A", + "avatar_url": "https://avatars.githubusercontent.com/u/69301842?v=4", + "profile": "https://github.com/Ioana37", + "contributions": [ + "instructions" + ] + }, + { + "login": "hashimwarren", + "name": "Hashim Warren", + "avatar_url": "https://avatars.githubusercontent.com/u/6027587?v=4", + "profile": "https://github.com/hashimwarren", + "contributions": [ + "agents" + ] + }, + { + "login": "0GiS0", + "name": "Gisela Torres", + "avatar_url": "https://avatars.githubusercontent.com/u/175379?v=4", + "profile": "https://hachyderm.io/@0gis0", + "contributions": [ + "agents" + ] + }, + { + "login": "giomartinsdev", + "name": "Giovanni de Almeida Martins", + "avatar_url": "https://avatars.githubusercontent.com/u/125399281?v=4", + "profile": "https://github.com/giomartinsdev", + "contributions": [ + "instructions" + ] + }, + { + "login": "jfversluis", + "name": "Gerald Versluis", + "avatar_url": "https://avatars.githubusercontent.com/u/939291?v=4", + "profile": "https://jfversluis.dev/", + "contributions": [ + "instructions" ] } - ], - "contributorsPerLine": 7, - "linkToUsage": true, - "commitType": "docs" + ] } diff --git a/.github/workflows/contributors.yml b/.github/workflows/contributors.yml index 13adbaa3..159910ee 100644 --- a/.github/workflows/contributors.yml +++ b/.github/workflows/contributors.yml @@ -8,32 +8,52 @@ on: jobs: contributors: runs-on: ubuntu-latest + timeout-minutes: 12 permissions: contents: write pull-requests: write steps: - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: - fetch-depth: 0 + fetch-depth: 0 # Required: add-missing-contributors.js needs full git history + + - name: Extract Node version from package.json + id: node-version + run: | + NODE_VERSION=$(jq -r '.engines.node // "22.x"' package.json) + echo "version=${NODE_VERSION}" >> "$GITHUB_OUTPUT" - name: Setup Node.js - uses: actions/setup-node@v4 + uses: actions/setup-node@v6 with: - node-version: "20" + node-version: ${{ steps.node-version.outputs.version }} - name: Install dependencies - run: npm install + run: npm ci - - name: Update contributors - run: npm run contributors:check + - name: Check and report contributors + run: | + CHECK_OUTPUT=$(npm run contributors:check 2>&1) + echo "$CHECK_OUTPUT" + + if echo "$CHECK_OUTPUT" | grep -q "Missing contributors"; then + echo "Missing contributors detected, generating report..." + mkdir -p reports + npm run contributors:report + + if [ -f reports/contributor-report.md ]; then + cat reports/contributor-report.md >> $GITHUB_STEP_SUMMARY + fi + else + echo "No missing contributors found" + fi env: PRIVATE_TOKEN: ${{ secrets.GITHUB_TOKEN }} + continue-on-error: true - name: Regenerate README - run: | - npm install - npm start + run: npm start - name: Check for changes id: verify-changed-files diff --git a/.gitignore b/.gitignore index 8ff4ff51..893a921b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ node_modules *.orig Copilot-Processing.md +reports/ # macOS system files .DS_Store diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 524a647f..2f9bb65f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -191,7 +191,8 @@ For full example of usage checkout edge-ai tasks collection: - A brief description of what your instruction/prompt does - Any relevant context or usage notes -**Note**: Once your contribution is merged, you'll automatically be added to our [Contributors](./README.md#contributors-) section! We use [all-contributors](https://github.com/all-contributors/all-contributors) to recognize all types of contributions to the project. +> [!NOTE] +> We use [all-contributors](https://github.com/all-contributors/all-contributors) to recognize all types of contributions to the project. Jump to [Contributors Recognition](#contributor-recognition) to learn more! ## What We Accept @@ -225,21 +226,33 @@ To maintain a safe, responsible, and constructive community, we will **not accep - **Write clearly**: Use simple, direct language - **Promote best practices**: Encourage secure, maintainable, and ethical development practices -## Contributors Recognition +## Contributor Recognition -This project uses [all-contributors](https://github.com/all-contributors/all-contributors) to recognize contributors. When you make a contribution, you'll automatically be recognized in our contributors list! +We use [all-contributors](https://github.com/all-contributors/all-contributors) to recognize **all types of contributions** to this project. -We welcome contributions of all types, including: +To add yourself, leave a comment on a relevant issue or pull request using your GitHub username and the appropriate contribution type(s): -- 📝 Documentation improvements -- đŸ’» Code contributions -- 🐛 Bug reports and fixes -- 🎹 Design improvements -- 💡 Ideas and suggestions -- đŸ€” Answering questions -- 📱 Promoting the project +```markdown +@all-contributors add @username for contributionType1, contributionType2 +``` + +The contributors list is updated automatically every Sunday at **3:00 AM UTC**. When the next run completes, your name will appear in the [README Contributors](./README.md#contributors-) section. + +### Contribution Types + +We welcome many kinds of contributions, including the custom categories below: + +| Category | Description | Emoji | +| --- | --- | :---: | +| **Instructions** | Custom instruction sets that guide GitHub Copilot behavior | 🧭 | +| **Prompts** | Reusable or one-off prompts for GitHub Copilot | ⌚ | +| **Agents (Chat Modes)** | Defined Copilot roles or personalities | 🎭 | +| **Collections** | Curated bundles of related prompts, agents, or instructions | 🎁 | + +In addition, all standard contribution types supported by [All Contributors](https://allcontributors.org/emoji-key/) are recognized. + +> Every contribution matters. Thanks for helping improve this resource for the GitHub Copilot community. -Your contributions help make this resource better for the entire GitHub Copilot community! ## Code of Conduct diff --git a/README.md b/README.md index 58881bc9..d22fa5cf 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,6 @@ # đŸ€– Awesome GitHub Copilot Customizations +[![Powered by Awesome Copilot](https://img.shields.io/badge/Powered_by-Awesome_Copilot-blue?logo=githubcopilot)](https://aka.ms/awesome-github-copilot?style=flat-square) [![GitHub contributors from allcontributors.org](https://img.shields.io/github/all-contributors/github/awesome-copilot?style=flat-square&color=ee8449)](#contributors-) -[![Powered by Awesome Copilot](https://img.shields.io/badge/Powered_by-Awesome_Copilot-blue?logo=githubcopilot)](https://aka.ms/awesome-github-copilot) - -[![All Contributors](https://img.shields.io/badge/all_contributors-93-orange.svg?style=flat-square)](#contributors-) - A community created collection of custom agents, prompts, and instructions to supercharge your GitHub Copilot experience across different domains, languages, and use cases. @@ -127,7 +124,7 @@ The customizations in this repository are sourced from and created by third-part ## Contributors ✹ -Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)): +Thanks goes to these wonderful people ([emoji key](./CONTRIBUTING.md#contributors-recognition)): @@ -135,125 +132,215 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d - - - - - - - + + + + + + + - - - - - - - + + + + + + + - - - - - - - + + + + + + + - - - - - - - + + + + + + + - - - - - - - + + + + + + + - - - - - - - + + + + + + + - - - - - - - + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - + + + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/eng/README.md b/eng/README.md new file mode 100644 index 00000000..ff95c85d --- /dev/null +++ b/eng/README.md @@ -0,0 +1,36 @@ +# Contributor Reporting (Maintainers) 🚧 + +This directory contains a lightweight helper to generate human-readable reports about missing contributors. + +- `contributor-report.mjs` — generates a markdown report of merged PRs for missing contributors (includes shared helpers). +- `add-missing-contributors.mjs` — on-demand maintainer script to automatically add missing contributors to `.all-contributorsrc` (infers contribution types from merged PR files, then runs the all-contributors CLI). + +## Key notes for maintainers + +- Reports are generated on-demand and output to `reports/contributor-report.md` for human review. +- The report output is intentionally minimal: a single list of affected PRs and one command to add missing contributor(s). +- This repository requires full git history for accurate analysis. In CI, set `fetch-depth: 0`. +- Link: [all-contributors CLI documentation](https://allcontributors.org/docs/en/cli) + +## On-demand scripts (not CI) + +These are maintainer utilities. They are intentionally on-demand only (but could be wired into CI later). + +### `add-missing-contributors.mjs` + +- Purpose: detect missing contributors, infer contribution types from their merged PR files, and run `npx all-contributors add ...` to update `.all-contributorsrc`. +- Requirements: + - GitHub CLI (`gh`) available (used to query merged PRs). + - `.all-contributorsrc` exists. + - Auth token set to avoid the anonymous GitHub rate limits: + - Set `GITHUB_TOKEN` (preferred), or `GH_TOKEN` for the `gh` CLI. + - If you use `PRIVATE_TOKEN` locally, `contributor-report.mjs` will map it to `GITHUB_TOKEN`. + +## Graceful shutdown + +- `contributor-report.mjs` calls `setupGracefulShutdown('script-name')` from `eng/utils/graceful-shutdown.mjs` early in the file to attach signal/exception handlers. + +## Testing & maintenance + +- Helper functions have small, deterministic behavior and include JSDoc comments. +- The `getMissingContributors` function in `contributor-report.mjs` is the single source of truth for detecting missing contributors from `all-contributors check` output. diff --git a/eng/add-missing-contributors.mjs b/eng/add-missing-contributors.mjs new file mode 100644 index 00000000..dc8911c5 --- /dev/null +++ b/eng/add-missing-contributors.mjs @@ -0,0 +1,306 @@ +/** + * One-time contributor detection and addition script. + * Discovers missing contributors, determines their contribution types from repo history, + * and updates .all-contributorsrc via the all-contributors CLI. + * + * Usage: node add-missing-contributors.mjs + */ +import { execSync } from 'node:child_process'; +import fs from 'node:fs'; +import path from 'node:path'; +import { + getContributionTypes, + getMissingContributors, + fetchContributorMergedPrs +} from './contributor-report.mjs'; +import { setupGracefulShutdown } from './utils/graceful-shutdown.mjs'; + +const DEFAULT_CMD_TIMEOUT = 30_000; // 30 seconds + +setupGracefulShutdown('add-missing-contributors'); + +/** + * Get all files touched by a contributor from their merged PRs. + * @param {string} username + * @returns {string[]} + */ +const getContributorFiles = (username) => { + try { + console.log(`📁 Getting files for contributor: ${username}`); + + const prs = fetchContributorMergedPrs(username, { includeAllFiles: true }); + + if (prs.length === 0) { + console.log(`📭 No merged PRs found for ${username}`); + return []; + } + + const files = new Set(); + for (const pr of prs) { + for (const file of pr.files || []) { + if (file?.path) { + files.add(file.path); + } + } + } + + const fileList = Array.from(files); + console.log(`📄 Found ${fileList.length} unique files for ${username}: ${fileList.slice(0, 3).join(', ')}${fileList.length > 3 ? '...' : ''}`); + return fileList; + + } catch (error) { + console.error(`❌ Error getting files for ${username}:`, error.message); + return []; + } +}; + +/** + * Determine contribution types from a contributor's files. + * @param {string} username + * @returns {string} + */ +const analyzeContributor = (username) => { + try { + console.log(`🔍 Analyzing contribution types for: ${username}`); + const files = getContributorFiles(username); + + if (files.length === 0) { + console.log(`💡 No files found for ${username}, using 'code' fallback`); + return 'code'; + } + + const contributionTypes = getContributionTypes(files); + + if (!contributionTypes || contributionTypes.trim() === '') { + console.log(`💡 No matching types found for ${username}, using 'code' fallback`); + return 'code'; + } + + console.log(`✅ Determined types for ${username}: ${contributionTypes}`); + return contributionTypes; + + } catch (error) { + console.error(`❌ Error analyzing files for ${username}:`, error.message); + return 'code'; + } +}; + +/** + * Add a username to the ignore list in .all-contributorsrc. + * @param {string} username + * @returns {boolean} + */ +const addToIgnoreList = (username) => { + try { + const configPath = path.join(process.cwd(), '.all-contributorsrc'); + const config = JSON.parse(fs.readFileSync(configPath, 'utf-8')); + + const ignoreList = config.ignoreList || config.ignore || []; + if (!ignoreList.includes(username)) { + ignoreList.push(username); + config.ignoreList = ignoreList; + fs.writeFileSync(configPath, JSON.stringify(config, null, 2)); + console.warn(`⚠ Added ${username} to ignore list (user not found on GitHub)`); + return true; + } + return false; + } catch (error) { + console.error(`❌ Failed to add ${username} to ignore list:`, error.message); + return false; + } +}; + +/** + * Run the all-contributors CLI to add a contributor to the project. + * @param {string} username + * @param {string} types + * @returns {boolean} + */ +const addContributor = (username, types) => { + try { + console.log(`➕ Adding contributor: ${username} with types: ${types}`); + + const command = `npx all-contributors add ${username} ${types}`; + + execSync(command, { + encoding: 'utf8', + stdio: ['pipe', 'pipe', 'pipe'], + timeout: DEFAULT_CMD_TIMEOUT + }); + + return true; + + } catch (error) { + // System-level errors that should propagate up + if (error.message.includes('rate limit') || error.message.includes('403')) { + console.error(`⏱ Rate limit encountered while adding ${username}.`); + throw error; + } + if (error.message.includes('network') || error.message.includes('timeout')) { + console.error(`🌐 Network error while adding ${username}.`); + throw error; + } + + // User-specific errors that can be skipped + if (error.message.includes('404') || error.message.includes('not found')) { + addToIgnoreList(username); + console.error(`❌ User ${username} not found, added to ignore list`); + return false; + } + + // Unknown error - log and skip + console.error(`❌ Failed to add contributor ${username}:`, error.message); + return false; + } +}; + +/** + * Process a single missing contributor: detect types and add via all-contributors CLI. + * @param {string} username + * @returns {{added:number, failed:number}} + */ +const processContributor = async (username) => { + let added = 0; + let failed = 0; + + try { + console.log(`📊 Step 2: Analyzing contribution types for ${username}...`); + const contributionTypes = analyzeContributor(username); + + console.log(`➕ Step 3: Adding ${username} with types: ${contributionTypes}...`); + + const success = addContributor(username, contributionTypes); + if (success) { + added++; + console.log(`✅ Successfully processed ${username}`); + } else { + failed++; + console.log(`❌ Failed to process ${username}`); + } + + } catch (error) { + failed++; + console.error(`đŸ’„ Error processing ${username}:`, error.message); + } + + return { added, failed }; +}; + +/** + * Main entry point: detect and add missing contributors. + */ +const main = async () => { + console.log('🚀 Starting add missing contributors script'); + console.log('='.repeat(50)); + + try { + console.log('\n📋 Step 1: Detecting missing contributors...'); + const missingContributors = getMissingContributors(); + + if (missingContributors.length === 0) { + console.log('🎉 No missing contributors found! All contributors are properly recognized.'); + return { processed: 0, added: 0, failed: 0 }; + } + + console.log(`\n🔄 Processing ${missingContributors.length} missing contributors...`); + + let processed = 0; + let added = 0; + let failed = 0; + + for (const username of missingContributors) { + console.log(`\n${'─'.repeat(30)}`); + console.log(`đŸ‘€ Processing contributor: ${username}`); + + processed++; + + try { + const { added: deltaAdded, failed: deltaFailed } = await processContributor(username); + added += deltaAdded; + failed += deltaFailed; + } catch (error) { + // Re-throw system-level errors (rate limit, network, SIGINT) + console.error(`đŸ’„ System error processing ${username}:`, error.message); + throw error; + } + } + + return { processed, added, failed }; + } catch (error) { + console.error('\nđŸ’„ Fatal error in main execution:', error.message); + console.error('🛑 Script execution stopped'); + throw error; + } +}; + +/** + * Print a summary report of the run. + * @param {{processed:number, added:number, failed:number}} results + */ +const printSummaryReport = (results) => { + const { processed, added, failed } = results; + + console.log('\n' + '='.repeat(50)); + console.log('📊 EXECUTION SUMMARY'); + console.log('='.repeat(50)); + + console.log(`📋 Total contributors processed: ${processed}`); + console.log(`✅ Successfully added: ${added}`); + console.log(`❌ Failed to add: ${failed}`); + + if (processed === 0) { + console.log('\n🎉 SUCCESS: No missing contributors found - all contributors are properly recognized!'); + } else if (failed === 0) { + console.log('\n🎉 SUCCESS: All missing contributors have been successfully added!'); + console.log('💡 Next steps: Review the updated .all-contributorsrc file and commit the changes.'); + } else if (added > 0) { + console.log('\n⚠ PARTIAL SUCCESS: Some contributors were added, but some failed.'); + console.log(`💡 ${added} contributors were successfully added.`); + console.log(`🔄 ${failed} contributors failed - check the error messages above for details.`); + console.log('💡 You may want to run the script again to retry failed contributors.'); + } else { + console.log('\n❌ FAILURE: No contributors could be added.'); + console.log('💡 Check the error messages above for troubleshooting guidance.'); + console.log('💡 Common issues: missing GITHUB_TOKEN, network problems, or API rate limits.'); + } + + console.log('\n📝 ACTIONABLE NEXT STEPS:'); + if (added > 0) { + console.log('‱ Review the updated .all-contributorsrc file'); + console.log('‱ Commit and push the changes to update the README'); + console.log('‱ Consider running "npm run contributors:generate" to update the README'); + } + if (failed > 0) { + console.log('‱ Check error messages above for specific failure reasons'); + console.log('‱ Verify GITHUB_TOKEN is set and has appropriate permissions'); + console.log('‱ Consider running the script again after resolving issues'); + } + if (processed === 0) { + console.log('‱ No action needed - all contributors are already recognized!'); + } + + console.log('\n' + '='.repeat(50)); +}; + +if (process.argv[1] === (new URL(import.meta.url)).pathname) { + try { + const results = await main(); + printSummaryReport(results); + + if (results.failed > 0 && results.added === 0) { + process.exit(1); + } else if (results.failed > 0) { + process.exit(2); + } else { + process.exit(0); + } + } catch (error) { + console.error('\nđŸ’„ Script execution failed:', error.message); + console.log('\n📝 TROUBLESHOOTING TIPS:'); + console.log('‱ Ensure you are in a git repository'); + console.log('‱ Verify all-contributors-cli is installed'); + console.log('‱ Check that .all-contributorsrc file exists'); + console.log('‱ Ensure GITHUB_TOKEN environment variable is set'); + process.exit(1); + } +} diff --git a/eng/contributor-report.mjs b/eng/contributor-report.mjs new file mode 100644 index 00000000..e67d4805 --- /dev/null +++ b/eng/contributor-report.mjs @@ -0,0 +1,597 @@ +/** + * Generate human-readable reports about missing contributors. + * This module queries merged PRs via 'gh' and produces a markdown report. + */ +import { execSync } from 'node:child_process'; +import fs from 'node:fs'; +import path from 'node:path'; +import { setupGracefulShutdown } from './utils/graceful-shutdown.mjs'; + +const DEFAULT_CMD_TIMEOUT = 30_000; // 30s + +setupGracefulShutdown('contributor-report'); + +/** + * Patterns that represent generated files; contributors should not be credited + * for these files because they are not substantive authored content. + */ +export const AUTO_GENERATED_PATTERNS = [ + 'README.md', + 'README.*.md', + 'collections/*.md', + 'collections/*.collection.md', + 'docs/README.*.md', + 'docs/*.generated.md' +]; + +/** + * File globs used to infer contribution types from file paths. + */ +export const TYPE_PATTERNS = { + instructions: [ + 'instructions/*.instructions.md' + ], + prompts: [ + 'prompts/*.prompt.md' + ], + agents: [ + 'chatmodes/*.chatmode.md', + 'agents/*.agent.md' + ], + collections: [ + 'collections/*.collection.yml' + ], + doc: [ + 'docs/**/*.md', + '.github/**/*.md', + 'CONTRIBUTING.md', + 'SECURITY.md', + 'SUPPORT.md', + 'LICENSE.md', + 'CHANGELOG.md', + '*.md' + ], + infra: [ + '.github/workflows/**/*.yml', + '.github/workflows/**/*.yaml', + '**/*.yml', + '**/*.yaml' + ], + maintenance: [ + 'package*.json', + '*.config.js', + 'tsconfig*.json' + ], + code: [ + '**/*.{js,ts,mjs,cjs}', + '**/*.py' + ] +}; + +const globCache = new Map(); + +/** + * Convert a simple glob (with *, **) to a RegExp. + * This is intentionally small and deterministic for our repo patterns. + * @param {string} pattern + * @returns {RegExp} + */ +export const globToRegExp = (pattern) => { + const DOUBLE_WILDCARD_PLACEHOLDER = '§§DOUBLE§§'; + const replacements = [ + { pattern: /\\/g, replacement: '/' }, + { pattern: /\./g, replacement: String.raw`\.` }, + { pattern: /\*\*/g, replacement: DOUBLE_WILDCARD_PLACEHOLDER }, + { pattern: /\*/g, replacement: '[^/]*' }, + { pattern: new RegExp(DOUBLE_WILDCARD_PLACEHOLDER, 'g'), replacement: '.*' }, + { pattern: /\?/g, replacement: '.' }, + { pattern: /\//g, replacement: String.raw`\/` } + ]; + + const normalized = replacements.reduce((acc, { pattern, replacement }) => acc.replace(pattern, replacement), String(pattern)); + + return new RegExp(`^${normalized}$`); +}; + +/** + * Test whether a file path matches a glob pattern. + * @param {string} filePath + * @param {string} pattern + * @returns {boolean} + */ +export const matchGlob = (filePath, pattern) => { + if (!globCache.has(pattern)) { + try { + globCache.set(pattern, globToRegExp(pattern)); + } catch { + globCache.set(pattern, null); + } + } + + const regexp = globCache.get(pattern); + if (!regexp) { + return false; + } + + const normalized = filePath.replace(/\\/g, '/'); + return regexp.test(normalized); +}; + +/** + * Return true if the given path matches one of the known auto-generated patterns. + * @param {string} filePath + * @returns {boolean} + */ +export const isAutoGeneratedFile = (filePath) => { + return AUTO_GENERATED_PATTERNS.some((pattern) => matchGlob(filePath, pattern)); +}; + +/** + * Infer a contribution type string (e.g. 'prompts', 'agents', 'doc') for a file path. + * Returns null if no specific type matched. + * @param {string} filePath + * @returns {string|null} + */ +export const getFileContributionType = (filePath) => { + const normalized = filePath.replace(/\\/g, '/'); + + for (const [type, patterns] of Object.entries(TYPE_PATTERNS)) { + if (patterns.some((pattern) => matchGlob(normalized, pattern))) { + return type; + } + } + + return null; +}; + +/** + * Derive a comma-separated list of contribution type identifiers from a list of files. + * Auto-generated files are ignored. Returns '' when no files to process. + * @param {string[]} files + * @returns {string} + */ +export const getContributionTypes = (files) => { + const types = new Set(); + let processed = 0; + + for (const file of files) { + if (isAutoGeneratedFile(file)) { + continue; + } + + processed += 1; + const type = getFileContributionType(file); + if (type) { + types.add(type); + } + } + + if (processed === 0) { + return ''; + } + + if (types.size === 0) { + types.add('code'); + } + + return Array.from(types).sort((a, b) => a.localeCompare(b)).join(','); +}; + +/** + * Check .all-contributors output to discover missing contributors. + * This is the canonical implementation used by contributor tooling. + * @returns {string[]} + */ +export const getMissingContributors = () => { + try { + console.log('🔍 Checking for missing contributors...'); + + const configPath = path.join(process.cwd(), '.all-contributorsrc'); + const config = JSON.parse(fs.readFileSync(configPath, 'utf-8')); + const ignoreEntries = config.ignoreList || config.ignore || []; + const ignoreSet = new Set(ignoreEntries.map((entry) => entry.toLowerCase())); + + if (ignoreSet.size > 0) { + console.log(`📋 Loaded ignore list: ${Array.from(ignoreSet).join(', ')}`); + } + + const output = execSync('npx all-contributors check', { + encoding: 'utf8', + stdio: ['pipe', 'pipe', 'pipe'], + timeout: DEFAULT_CMD_TIMEOUT + }); + + const lines = output.split('\n'); + + const headerLineIndex = lines.findIndex(line => + line.includes('Missing contributors in .all-contributorsrc:') + ); + + if (headerLineIndex === -1) { + console.log('✅ No missing contributors found'); + return []; + } + + let contributorsLine = ''; + for (let i = headerLineIndex + 1; i < lines.length; i++) { + const line = lines[i].trim(); + + if (line.includes('Unknown contributors') || line.includes('✹')) { + break; + } + + if (line && !line.startsWith('⠙') && !line.startsWith('✹')) { + contributorsLine = line; + break; + } + } + + if (!contributorsLine) { + console.log('✅ No missing contributors found'); + return []; + } + + const allUsernames = contributorsLine + .split(',') + .map(username => username.trim()) + .filter(username => username.length > 0); + + const filteredUsernames = allUsernames.filter(username => { + const lowerUsername = username.toLowerCase(); + + if (ignoreSet.has(lowerUsername)) { + console.log(`⏭ FILTERED: ${username} is in ignore list`); + return false; + } + + return true; + }); + + console.log(`📋 Found ${filteredUsernames.length} missing contributors after filtering: ${filteredUsernames.join(', ')}`); + return filteredUsernames; + + } catch (error) { + console.error('❌ Error checking for missing contributors:', error.message); + if (error.message.includes('command not found') || error.message.includes('not recognized')) { + console.error('💡 Make sure all-contributors-cli is installed: npm install all-contributors-cli'); + } + return []; + } +}; + +// --- REPORT GENERATION LOGIC --- + +/** + * Get the current GitHub repository in owner/repo format. + * Tries upstream first, then origin. + * @returns {string} + */ +const getGitHubRepo = () => { + try { + const upstreamUrl = execSync('git config --get remote.upstream.url', { + encoding: 'utf8', + stdio: ['pipe', 'pipe', 'pipe'] + }).trim(); + if (upstreamUrl) { + const match = upstreamUrl.match(/github\.com:([^/]+)\/([^/]+?)(?:\.git)?$/); + if (match) return `${match[1]}/${match[2]}`; + } + } catch (e) { + console.debug('upstream not found, trying origin'); + } + + try { + const originUrl = execSync('git config --get remote.origin.url', { + encoding: 'utf8', + stdio: ['pipe', 'pipe', 'pipe'] + }).trim(); + const match = originUrl.match(/github\.com:([^/]+)\/([^/]+?)(?:\.git)?$/); + if (match) return `${match[1]}/${match[2]}`; + } catch (e) { + console.debug('origin not found, using default'); + } + + return 'github/awesome-copilot'; +}; + +const CONTRIBUTION_TYPE_MAP = { + 'instructions': { symbol: '🧭', description: 'The big AI prompt recipes (Copilot instruction sets)' }, + 'prompts': { symbol: '⌚', description: 'One-shot or reusable user-level prompts' }, + 'agents': { symbol: '🎭', description: 'Defined Copilot personalities / roles' }, + 'collections': { symbol: '🎁', description: 'Bundled thematic sets (e.g., "Copilot for Docs")' } +}; + +/** + * Fetch merged PRs for a GitHub username using the GH CLI and filter files. + * @param {string} username + * @param {{includeAllFiles?:boolean}} [opts] + * @returns {Array} Array of PR objects + */ +export const fetchContributorMergedPrs = (username, { includeAllFiles = false } = {}) => { + try { + const repo = getGitHubRepo(); + const result = execSync( + `gh pr list --repo ${repo} --state merged --author ${username} --json number,title,mergedAt,files,url --limit 100`, + { encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'], timeout: DEFAULT_CMD_TIMEOUT } + ); + const prs = JSON.parse(result); + + if (includeAllFiles) { + return prs; + } + + return prs.filter(pr => { + const hasNonConfigFiles = pr.files.some(file => + !isAutoGeneratedFile(file.path) + ); + return hasNonConfigFiles; + }); + } catch (error) { + console.error(`Failed to fetch PRs for ${username}:`, error.message); + return []; + } +}; + +/** + * Convert a PR object into a normalized report entry with types and file details. + * @param {{login:string}} contributor + * @param {object} pr + * @param {{includeAllFiles?:boolean}} [opts] + * @returns {object|null} + */ +const generatePRReport = (contributor, pr, { includeAllFiles = false } = {}) => { + const types = new Set(); + const fileDetails = []; + + for (const file of pr.files) { + if (!file?.path) { + continue; + } + + // Include generated files only if includeAllFiles is true + if (!includeAllFiles && isAutoGeneratedFile(file.path)) { + continue; + } + + const type = getFileContributionType(file.path) || 'ideas'; + if (type) { + types.add(type); + } + + fileDetails.push({ + path: file.path, + type: type || 'unknown', + additions: file.additions, + deletions: file.deletions + }); + } + + // If no non-filtered files contributed to types, and we're not asked for all files, skip this PR + if (types.size === 0 && !includeAllFiles) { + return null; + } + + // Fallback to 'code' if no types detected + if (types.size === 0) { + types.add('code'); + } + + const typeList = Array.from(types); + + return { + prNumber: pr.number, + prTitle: pr.title, + prUrl: pr.url, + mergedAt: pr.mergedAt, + contributionTypes: typeList, + files: fileDetails, + commentSnippet: `@all-contributors please add @${contributor.login} for ${typeList.join(', ')}` + }; +}; + +/** + * Build a contributor report by inspecting merged PRs and mapping files to types. + * Returns null when no relevant PRs were found (unless includeAllFiles is true). + * @param {string} username + * @param {{includeAllFiles?:boolean}} [opts] + * @returns {object|null} + */ +export const generateContributorReport = (username, { includeAllFiles = false } = {}) => { + console.log(`Inspecting ${username}...`); + + const prs = fetchContributorMergedPrs(username, { includeAllFiles }); + const prReports = prs + .map(pr => generatePRReport({ login: username }, pr, { includeAllFiles })) + .filter(report => report !== null); + + // If no relevant PR reports and not explicitly including all files, skip the contributor entirely + if (prReports.length === 0 && !includeAllFiles) { + return null; + } + + return { + username, + totalPRs: prs.length, + prs: prReports + }; +}; + +/** + * Render a set of contributor reports as markdown for human review. + * @param {Array} reports + * @param {number} missingCount - number of missing contributors detected + * @returns {string} + */ +export const generateMarkdownReport = (reports, missingCount = 0) => { + // The report is intentionally minimal: a single list of affected PRs and + // a single copy/paste command maintainers can run locally. + // No timestamps, per-file breakdowns, or duplicated metadata. + + if (!missingCount) { + return 'No missing contributors detected.\n'; + } + + // 1) Single list of affected PRs (deduped). + const prEntries = new Map(); // key=prNumber or url, value={number,url,mergedAt} + for (const report of reports) { + for (const pr of report.prs) { + const key = pr.prUrl || String(pr.prNumber); + if (!prEntries.has(key)) { + prEntries.set(key, { + number: pr.prNumber, + url: pr.prUrl, + mergedAt: pr.mergedAt + }); + } + } + } + + const prList = Array.from(prEntries.values()).sort((a, b) => { + // Prefer chronological sort for stable “what happened” review. + const aTime = a.mergedAt ? Date.parse(a.mergedAt) : 0; + const bTime = b.mergedAt ? Date.parse(b.mergedAt) : 0; + if (aTime !== bTime) return aTime - bTime; + return (a.number ?? 0) - (b.number ?? 0); + }); + + // 2) One command (one line). If multiple users are missing, chain them. + const commandParts = []; + for (const report of reports) { + const typeSet = new Set(); + for (const pr of report.prs) { + for (const type of pr.contributionTypes || []) { + typeSet.add(type); + } + } + + const types = Array.from(typeSet).filter(Boolean).sort((a, b) => a.localeCompare(b)); + const typesArg = types.length > 0 ? types.join(',') : 'code'; + commandParts.push(`npx all-contributors add ${report.username} ${typesArg}`); + } + + let markdown = ''; + markdown += prList.map((pr) => `- #${pr.number} ${pr.url}`).join('\n'); + markdown += '\n\n'; + markdown += commandParts.join(' && '); + markdown += '\n'; + return markdown; +}; + +/** + * Check whether a PR already contains an all-contributors bot comment. + * @param {number} prNumber + * @returns {boolean} + */ +export const hasExistingAllContributorsComment = (prNumber) => { + try { + const repo = getGitHubRepo(); + const json = execSync(`gh pr view ${prNumber} --repo ${repo} --json comments`, { + encoding: 'utf8', + stdio: ['pipe', 'pipe', 'pipe'], + timeout: DEFAULT_CMD_TIMEOUT + }); + + const data = JSON.parse(json); + const comments = data?.comments?.nodes || data?.comments || []; + return comments.some((comment) => comment?.body?.includes(`@all-contributors`)); + } catch (error) { + console.warn(`⚠ Unable to inspect comments for PR #${prNumber}: ${error.message}`); + return false; + } +}; + +/** + * Post a comment to a PR using the GH CLI. + * @param {number} prNumber + * @param {string} body + * @returns {boolean} + */ +export const postCommentOnPr = (prNumber, body) => { + try { + const repo = getGitHubRepo(); + execSync(`gh pr comment ${prNumber} --repo ${repo} --body "${body.replace(/"/g, '\\"')}"`, { + encoding: 'utf8', + stdio: ['pipe', 'inherit', 'inherit'], + timeout: DEFAULT_CMD_TIMEOUT + }); + + console.log(`💬 Posted recommendation comment on PR #${prNumber}`); + return true; + } catch (error) { + console.warn(`⚠ Failed to post comment on PR #${prNumber}: ${error.message}`); + return false; + } +}; + +/** + * Post suggested all-contributors comments to PRs for a collection of reports. + * @param {Array} reports + */ +export const autoAddCommentsToReports = (reports) => { + for (const report of reports) { + for (const pr of report.prs) { + if (hasExistingAllContributorsComment(pr.prNumber)) { + console.log(`💬 Skipping PR #${pr.prNumber} for @${report.username} — comment already present`); + continue; + } + + const types = pr.contributionTypes.map(t => '`' + t + '`').join(', '); + const commentLines = [ + `Thanks for the contribution @${report.username}!`, + '', + `We detected contribution categories for this PR: ${types || '`code`'}.`, + '', + `@all-contributors please add @${report.username} for ${pr.contributionTypes.join(', ')}` + ]; + + const body = commentLines.join('\n'); + postCommentOnPr(pr.prNumber, body); + } + } +}; + +const main = () => { + try { + const ghToken = process.env.GITHUB_TOKEN || process.env.PRIVATE_TOKEN; + if (!ghToken) { + console.error('❌ GITHUB_TOKEN or PRIVATE_TOKEN environment variable is required for GitHub CLI operations'); + process.exit(1); + } + + // gh CLI only reads GITHUB_TOKEN or GH_TOKEN, so ensure it's set + if (process.env.PRIVATE_TOKEN && !process.env.GITHUB_TOKEN) { + process.env.GITHUB_TOKEN = process.env.PRIVATE_TOKEN; + } + + const args = new Set(process.argv.slice(2)); + const autoAdd = args.has('--auto-add-pr-comments'); + const includeAllFiles = args.has('--include-all-pr-files'); + + const contributors = getMissingContributors(); + console.log(`Inspecting ${contributors.length} missing contributors...\n`); + + const reports = []; + for (const contributor of contributors) { + const report = generateContributorReport(contributor, { includeAllFiles }); + reports.push(report || { username: contributor, totalPRs: 0, prs: [] }); + } + + const markdown = generateMarkdownReport(reports, contributors.length); + const outputPath = path.join(process.cwd(), 'reports', 'contributor-report.md'); + fs.writeFileSync(outputPath, markdown); + + console.log(`Report saved to: ${outputPath}`); + + if (autoAdd) { + autoAddCommentsToReports(reports); + } + + } catch (error) { + console.error('Error generating report:', error); + process.exit(1); + } +}; + +if (process.argv[1] === (new URL(import.meta.url)).pathname) { + main(); +} diff --git a/eng/utils/graceful-shutdown.mjs b/eng/utils/graceful-shutdown.mjs new file mode 100644 index 00000000..036f33f2 --- /dev/null +++ b/eng/utils/graceful-shutdown.mjs @@ -0,0 +1,60 @@ +/** + * Lightweight graceful shutdown helper for one-off scripts. + * + * Call setupGracefulShutdown('script-name') early in your script to attach + * signal and exception handlers that exit the process cleanly. + * + * @param {string} name - Human readable name for log messages + * @param {{exitCode?:number}} [opts] + * @returns {() => void} teardown function to remove handlers (useful in tests) + */ +export const setupGracefulShutdown = (name, { exitCode = 1 } = {}) => { + let _shuttingDown = false; + + const cleanup = (signal) => { + if (_shuttingDown) return; + _shuttingDown = true; + console.log(`\n🛑 ${name}: received ${signal}, shutting down gracefully...`); + // Best-effort cleanup: keep this short and synchronous + try { + // Place for lightweight cleanup tasks if needed in future + } catch (e) { + console.error(`${name}: error during shutdown cleanup:`, e); + } + + // Exit with a non-zero code to indicate abnormal termination + try { + process.exit(exitCode); + } catch (e) { + // process.exit may not be desirable in some test harnesses; swallow errors + console.warn(`${name}: process.exit failed:`, e?.message); + } + }; + + const onSigInt = () => cleanup('SIGINT'); + const onSigTerm = () => cleanup('SIGTERM'); + const onSigHup = () => cleanup('SIGHUP'); + const onUncaught = (err) => { + console.error(`${name}: Uncaught exception:`, err); + cleanup('uncaughtException'); + }; + const onUnhandledRejection = (reason) => { + console.error(`${name}: Unhandled promise rejection:`, reason); + cleanup('unhandledRejection'); + }; + + process.on('SIGINT', onSigInt); + process.on('SIGTERM', onSigTerm); + process.on('SIGHUP', onSigHup); + process.on('uncaughtException', onUncaught); + process.on('unhandledRejection', onUnhandledRejection); + + // Return a teardown function useful for tests or if a caller wants to remove handlers + return () => { + process.removeListener('SIGINT', onSigInt); + process.removeListener('SIGTERM', onSigTerm); + process.removeListener('SIGHUP', onSigHup); + process.removeListener('uncaughtException', onUncaught); + process.removeListener('unhandledRejection', onUnhandledRejection); + }; +}; diff --git a/package.json b/package.json index 5f25ae57..bf367d1a 100644 --- a/package.json +++ b/package.json @@ -8,6 +8,7 @@ "start": "npm run build", "build": "node ./eng/update-readme.mjs", "contributors:add": "all-contributors add", + "contributors:report": "node ./eng/contributor-report.mjs", "contributors:generate": "all-contributors generate", "contributors:check": "all-contributors check", "collection:validate": "node ./eng/validate-collections.mjs", @@ -24,7 +25,9 @@ "copilot", "ai", "prompts", - "instructions" + "instructions", + "chat modes", + "agents" ], "author": "GitHub", "license": "MIT", From d9d99cf3aadad8ff50bb29ef341ba263367c641e Mon Sep 17 00:00:00 2001 From: Ashley Childress <6563688+anchildress1@users.noreply.github.com> Date: Fri, 19 Dec 2025 23:12:56 -0500 Subject: [PATCH 005/180] refactor(eng): update contributor report generator output - Modify generateMarkdownReport to include per-user sections with PR details - Remove total PR count and simplify PR link format Commit-generated-by: GitHub Copilot Signed-off-by: Ashley Childress <6563688+anchildress1@users.noreply.github.com> --- eng/contributor-report.mjs | 105 ++++++++++++++++++++----------------- 1 file changed, 58 insertions(+), 47 deletions(-) diff --git a/eng/contributor-report.mjs b/eng/contributor-report.mjs index e67d4805..56005170 100644 --- a/eng/contributor-report.mjs +++ b/eng/contributor-report.mjs @@ -423,58 +423,74 @@ export const generateContributorReport = (username, { includeAllFiles = false } * @returns {string} */ export const generateMarkdownReport = (reports, missingCount = 0) => { - // The report is intentionally minimal: a single list of affected PRs and - // a single copy/paste command maintainers can run locally. - // No timestamps, per-file breakdowns, or duplicated metadata. - if (!missingCount) { return 'No missing contributors detected.\n'; } - // 1) Single list of affected PRs (deduped). - const prEntries = new Map(); // key=prNumber or url, value={number,url,mergedAt} - for (const report of reports) { - for (const pr of report.prs) { - const key = pr.prUrl || String(pr.prNumber); - if (!prEntries.has(key)) { - prEntries.set(key, { - number: pr.prNumber, - url: pr.prUrl, - mergedAt: pr.mergedAt - }); - } - } - } + const nowIso = new Date().toISOString(); - const prList = Array.from(prEntries.values()).sort((a, b) => { - // Prefer chronological sort for stable “what happened” review. - const aTime = a.mergedAt ? Date.parse(a.mergedAt) : 0; - const bTime = b.mergedAt ? Date.parse(b.mergedAt) : 0; - if (aTime !== bTime) return aTime - bTime; - return (a.number ?? 0) - (b.number ?? 0); - }); - // 2) One command (one line). If multiple users are missing, chain them. - const commandParts = []; - for (const report of reports) { + const computeTypesArg = (report) => { const typeSet = new Set(); - for (const pr of report.prs) { + for (const pr of report.prs || []) { for (const type of pr.contributionTypes || []) { - typeSet.add(type); + if (type) { + typeSet.add(type); + } } } - const types = Array.from(typeSet).filter(Boolean).sort((a, b) => a.localeCompare(b)); - const typesArg = types.length > 0 ? types.join(',') : 'code'; - commandParts.push(`npx all-contributors add ${report.username} ${typesArg}`); + const types = Array.from(typeSet).sort((a, b) => a.localeCompare(b)); + return types.length > 0 ? types.join(',') : 'code'; + }; + + const lines = []; + + lines.push('# Missing Contributors Report'); + lines.push(''); + lines.push(`Generated (ISO): ${nowIso}`); + lines.push(''); + lines.push(`Missing contributors: ${missingCount}`); + lines.push(''); + + for (const report of reports) { + lines.push(`## @${report.username}`); + lines.push(''); + + const prs = Array.from(report.prs || []).sort((a, b) => { + // Prefer most recent PRs first. + const aTime = a.mergedAt ? Date.parse(a.mergedAt) : 0; + const bTime = b.mergedAt ? Date.parse(b.mergedAt) : 0; + if (aTime !== bTime) return bTime - aTime; + return (b.prNumber ?? 0) - (a.prNumber ?? 0); + }); + + for (const pr of prs) { + lines.push(`### PR #${pr.prNumber}: ${pr.prTitle}`); + lines.push(''); + lines.push(`Add this comment on PR: ${pr.prUrl}`); + lines.push(''); + + const prTypes = (pr.contributionTypes || []).filter(Boolean); + const prTypesArg = prTypes.length > 0 ? prTypes.join(', ') : 'code'; + + lines.push('```text'); + lines.push(`@all-contributors please add @${report.username} for ${prTypesArg}`); + lines.push('```'); + lines.push(''); + } + + lines.push('### CLI command (all-contributors-cli)'); + lines.push(''); + lines.push('```bash'); + lines.push(`npx all-contributors add ${report.username} ${computeTypesArg(report)}`); + lines.push('```'); + lines.push(''); + lines.push('---'); + lines.push(''); } - let markdown = ''; - markdown += prList.map((pr) => `- #${pr.number} ${pr.url}`).join('\n'); - markdown += '\n\n'; - markdown += commandParts.join(' && '); - markdown += '\n'; - return markdown; + return `${lines.join('\n')}\n`; }; /** @@ -552,14 +568,9 @@ export const autoAddCommentsToReports = (reports) => { const main = () => { try { - const ghToken = process.env.GITHUB_TOKEN || process.env.PRIVATE_TOKEN; - if (!ghToken) { - console.error('❌ GITHUB_TOKEN or PRIVATE_TOKEN environment variable is required for GitHub CLI operations'); - process.exit(1); - } - - // gh CLI only reads GITHUB_TOKEN or GH_TOKEN, so ensure it's set - if (process.env.PRIVATE_TOKEN && !process.env.GITHUB_TOKEN) { + // gh CLI can use either its own authenticated session or token env vars. + // In CI, we commonly receive a token via PRIVATE_TOKEN. + if (process.env.PRIVATE_TOKEN && !process.env.GITHUB_TOKEN && !process.env.GH_TOKEN) { process.env.GITHUB_TOKEN = process.env.PRIVATE_TOKEN; } From 920bc3b47cd959b00c5d92bb0a3cb20e77c27072 Mon Sep 17 00:00:00 2001 From: James Montemagno Date: Sat, 20 Dec 2025 11:18:12 -0800 Subject: [PATCH 006/180] add desc --- docs/README.skills.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/README.skills.md b/docs/README.skills.md index 8c287652..f5a3d54f 100644 --- a/docs/README.skills.md +++ b/docs/README.skills.md @@ -22,4 +22,5 @@ Skills differ from other primitives by supporting bundled assets (scripts, code | Name | Description | Bundled Assets | | ---- | ----------- | -------------- | +| [image-manipulation-image-magick](../skills/image-manipulation-image-magick/SKILL.md) | Process and manipulate images using ImageMagick. Supports resizing, format conversion, batch processing, and retrieving image metadata. Use when working with images, creating thumbnails, resizing wallpapers, or performing batch image operations. | none | | [webapp-testing](../skills/webapp-testing/SKILL.md) | Toolkit for interacting with and testing local web applications using Playwright. Supports verifying frontend functionality, debugging UI behavior, capturing browser screenshots, and viewing browser logs. | `test-helper.js` | From 957f3ab346fd01cd2dc1734ea467a3f1dbabdc26 Mon Sep 17 00:00:00 2001 From: Troy Taylor Date: Tue, 23 Dec 2025 13:16:55 -0500 Subject: [PATCH 007/180] Add MCP-based M365 Agents collection - Create Declarative Agent prompt with MCP server integration - Create Adaptive Cards prompt for visual response templates - Deploy and Manage Agents prompt for admin workflows - Development guidelines instruction file - Collection manifest and reference documentation Based on: - https://devblogs.microsoft.com/microsoft365dev/build-declarative-agents-for-microsoft-365-copilot-with-mcp/ - https://learn.microsoft.com/en-us/microsoft-365-copilot/extensibility/build-mcp-plugins - https://learn.microsoft.com/en-us/microsoft-365-copilot/extensibility/api-plugin-adaptive-cards - https://learn.microsoft.com/en-us/microsoft-365/admin/manage/manage-copilot-agents-integrated-apps --- collections/mcp-m365-copilot.collection.md | 325 +++++++++++ collections/mcp-m365-copilot.collection.yml | 18 + instructions/mcp-m365-copilot.instructions.md | 357 ++++++++++++ prompts/mcp-create-adaptive-cards.prompt.md | 527 ++++++++++++++++++ .../mcp-create-declarative-agent.prompt.md | 310 +++++++++++ prompts/mcp-deploy-manage-agents.prompt.md | 336 +++++++++++ 6 files changed, 1873 insertions(+) create mode 100644 collections/mcp-m365-copilot.collection.md create mode 100644 collections/mcp-m365-copilot.collection.yml create mode 100644 instructions/mcp-m365-copilot.instructions.md create mode 100644 prompts/mcp-create-adaptive-cards.prompt.md create mode 100644 prompts/mcp-create-declarative-agent.prompt.md create mode 100644 prompts/mcp-deploy-manage-agents.prompt.md diff --git a/collections/mcp-m365-copilot.collection.md b/collections/mcp-m365-copilot.collection.md new file mode 100644 index 00000000..6b498657 --- /dev/null +++ b/collections/mcp-m365-copilot.collection.md @@ -0,0 +1,325 @@ +# MCP-based M365 Agents Collection + +A comprehensive collection of prompts and instructions for building declarative agents with Model Context Protocol (MCP) integration for Microsoft 365 Copilot. + +## Overview + +The Model Context Protocol (MCP) is a universal standard that allows AI models to integrate with external systems through standardized server endpoints. This collection provides everything you need to build, deploy, and manage MCP-based declarative agents that extend Microsoft 365 Copilot with custom capabilities. + +## What is Model Context Protocol? + +MCP is an open protocol developed to streamline how AI models connect to external data sources and tools. Instead of custom integration code for each system, MCP provides a consistent interface for: + +- **Server Metadata**: Discover available tools and capabilities +- **Tools Listing**: Get function definitions and schemas +- **Tool Execution**: Invoke tools with parameters and receive results + +For Microsoft 365 Copilot, this means you can create agents that connect to any MCP-compatible server with point-and-click configuration instead of writing custom code. + +## Collection Contents + +### Prompts + +1. **Create Declarative Agent** ([mcp-create-declarative-agent.prompt.md](prompts/mcp-create-declarative-agent.prompt.md)) + - Build declarative agents using Microsoft 365 Agents Toolkit + - Configure MCP server integration with tool import + - Set up OAuth 2.0 or SSO authentication + - Configure response semantics for data extraction + - Package and deploy agents for testing + +2. **Create Adaptive Cards** ([mcp-create-adaptive-cards.prompt.md](prompts/mcp-create-adaptive-cards.prompt.md)) + - Design static and dynamic Adaptive Card templates + - Configure response semantics (data_path, properties, template_selector) + - Use template language for conditionals and data binding + - Create responsive cards that work across Copilot surfaces + - Implement card actions for user interactions + +3. **Deploy and Manage Agents** ([mcp-deploy-manage-agents.prompt.md](prompts/mcp-deploy-manage-agents.prompt.md)) + - Deploy agents via Microsoft 365 admin center + - Configure organizational or public store distribution + - Manage agent lifecycle (publish, deploy, block, remove) + - Set up governance and compliance controls + - Monitor agent usage and performance + +### Instructions + +**MCP M365 Copilot Development Guidelines** ([mcp-m365-copilot.instructions.md](instructions/mcp-m365-copilot.instructions.md)) +- Best practices for MCP server design and tool selection +- File organization and project structure +- Response semantics configuration patterns +- Adaptive Card design principles +- Security, governance, and compliance requirements +- Testing and deployment workflows + +## Key Concepts + +### Declarative Agents + +Declarative agents are defined through configuration files rather than code: +- **declarativeAgent.json**: Agent instructions, capabilities, conversation starters +- **ai-plugin.json**: MCP server tools, response semantics, adaptive card templates +- **mcp.json**: MCP server URL, authentication configuration +- **manifest.json**: Teams app manifest for packaging + +### MCP Server Integration + +The Microsoft 365 Agents Toolkit provides a visual interface for: +1. **Scaffold** a new agent project +2. **Add MCP action** to connect to a server +3. **Choose tools** from the server's available functions +4. **Configure authentication** (OAuth 2.0, SSO) +5. **Generate files** (agent config, plugin manifest) +6. **Test** in m365.cloud.microsoft/chat + +### Authentication Patterns + +**OAuth 2.0 Static Registration:** +- Pre-register OAuth app with service provider +- Store credentials in .env.local (never commit) +- Reference in ai-plugin.json authentication config +- Users consent once, tokens stored in plugin vault + +**Single Sign-On (SSO):** +- Use Microsoft Entra ID for authentication +- Seamless experience for M365 users +- No separate login required +- Ideal for internal organizational agents + +### Response Semantics + +Extract and format data from MCP server responses: + +```json +{ + "response_semantics": { + "data_path": "$.items[*]", + "properties": { + "title": "$.name", + "subtitle": "$.description", + "url": "$.html_url" + }, + "static_template": { ... } + } +} +``` + +- **data_path**: JSONPath to extract array or object +- **properties**: Map response fields to Copilot properties +- **template_selector**: Choose dynamic template based on response +- **static_template**: Adaptive Card for visual formatting + +### Adaptive Cards + +Rich visual responses for agent outputs: + +**Static Templates:** +- Defined once in ai-plugin.json +- Used for all responses with same structure +- Better performance and easier maintenance + +**Dynamic Templates:** +- Returned in API response body +- Selected via template_selector JSONPath +- Useful for varied response structures + +**Template Language:** +- `${property}`: Data binding +- `${if(condition, true, false)}`: Conditionals +- `${formatNumber(value, decimals)}`: Formatting +- `$when`: Conditional element rendering + +## Deployment Options + +### Organization Deployment +- IT admin deploys to all users or specific groups +- Requires approval in Microsoft 365 admin center +- Best for internal business agents +- Full governance and compliance controls + +### Agent Store +- Submit to Partner Center for validation +- Public availability to all Copilot users +- Rigorous security and compliance review +- Suitable for partner-built agents + +## Partner Examples + +### monday.com +Task and project management integration: +- Create tasks directly from Copilot +- Query project status and updates +- Assign work items to team members +- View deadlines and milestones + +### Canva +Design automation capabilities: +- Generate branded content +- Create social media graphics +- Access design templates +- Export in multiple formats + +### Sitecore +Content management integration: +- Search content repository +- Create and update content items +- Manage workflows and approvals +- Preview content in context + +## Getting Started + +### Prerequisites +- Visual Studio Code +- Microsoft 365 Agents Toolkit extension (v6.3.x or later) +- GitHub account (for OAuth examples) +- Microsoft 365 Copilot license +- Access to an MCP-compatible server + +### Quick Start +1. Install Microsoft 365 Agents Toolkit in VS Code +2. Use **Create Declarative Agent** prompt to scaffold project +3. Add MCP server URL and choose tools +4. Configure authentication with OAuth or SSO +5. Use **Create Adaptive Cards** prompt to design response templates +6. Test agent at m365.cloud.microsoft/chat +7. Use **Deploy and Manage Agents** prompt for distribution + +### Development Workflow +``` +1. Scaffold agent project + ↓ +2. Connect MCP server + ↓ +3. Import tools + ↓ +4. Configure authentication + ↓ +5. Design adaptive cards + ↓ +6. Test locally + ↓ +7. Deploy to organization + ↓ +8. Monitor and iterate +``` + +## Best Practices + +### MCP Server Design +- Import only necessary tools (avoid over-scoping) +- Use secure authentication (OAuth 2.0, SSO) +- Test each tool individually +- Validate server endpoints are HTTPS +- Consider token limits when selecting tools + +### Agent Instructions +- Be specific and clear about agent capabilities +- Provide examples of how to interact +- Set boundaries for what agent can/cannot do +- Use conversation starters to guide users + +### Response Formatting +- Use JSONPath to extract relevant data +- Map properties clearly (title, subtitle, url) +- Design adaptive cards for readability +- Test cards across Copilot surfaces (Chat, Teams, Outlook) + +### Security and Governance +- Never commit credentials to source control +- Use environment variables for secrets +- Follow principle of least privilege +- Review compliance requirements +- Monitor agent usage and performance + +## Common Use Cases + +### Data Retrieval +- Search external systems +- Fetch user-specific information +- Query databases or APIs +- Aggregate data from multiple sources + +### Task Automation +- Create tickets or tasks +- Update records or statuses +- Trigger workflows +- Schedule actions + +### Content Generation +- Create documents or designs +- Generate reports or summaries +- Format data into templates +- Export in various formats + +### Integration Scenarios +- Connect CRM systems +- Integrate project management tools +- Access knowledge bases +- Connect to custom business apps + +## Troubleshooting + +### Agent Not Appearing in Copilot +- Verify agent is deployed in admin center +- Check user is in assigned group +- Confirm agent is not blocked +- Refresh Copilot interface + +### Authentication Errors +- Validate OAuth credentials in .env.local +- Check scopes match required permissions +- Test auth flow independently +- Verify MCP server is accessible + +### Response Formatting Issues +- Test JSONPath expressions with sample data +- Validate data_path extracts expected array/object +- Check property mappings are correct +- Test adaptive card with various response structures + +### Performance Problems +- Monitor MCP server response times +- Reduce number of imported tools +- Optimize response data size +- Use caching where appropriate + +## Resources + +### Official Documentation +- [Build Declarative Agents with MCP (DevBlogs)](https://devblogs.microsoft.com/microsoft365dev/build-declarative-agents-for-microsoft-365-copilot-with-mcp/) +- [Build MCP Plugins (Microsoft Learn)](https://learn.microsoft.com/en-us/microsoft-365-copilot/extensibility/build-mcp-plugins) +- [API Plugin Adaptive Cards (Microsoft Learn)](https://learn.microsoft.com/en-us/microsoft-365-copilot/extensibility/api-plugin-adaptive-cards) +- [Manage Copilot Agents (Microsoft Learn)](https://learn.microsoft.com/en-us/microsoft-365/admin/manage/manage-copilot-agents-integrated-apps) + +### Tools and Extensions +- [Microsoft 365 Agents Toolkit](https://marketplace.visualstudio.com/items?itemName=TeamsDevApp.ms-teams-vscode-extension) +- [Adaptive Cards Designer](https://adaptivecards.io/designer/) +- [Teams Toolkit](https://learn.microsoft.com/en-us/microsoftteams/platform/toolkit/teams-toolkit-fundamentals) + +### MCP Resources +- [Model Context Protocol Specification](https://modelcontextprotocol.io/) +- [MCP Server Directory](https://github.com/modelcontextprotocol/servers) +- Community MCP servers and examples + +### Admin and Governance +- [Microsoft 365 Admin Center](https://admin.microsoft.com/) +- [Power Platform Admin Center](https://admin.powerplatform.microsoft.com/) +- [Partner Center](https://partner.microsoft.com/) for agent submissions + +## Support and Community + +- Join the [Microsoft 365 Developer Community](https://developer.microsoft.com/en-us/microsoft-365/community) +- Ask questions on [Microsoft Q&A](https://learn.microsoft.com/en-us/answers/products/) +- Share feedback in [Microsoft 365 Copilot GitHub discussions](https://github.com/microsoft/copilot-feedback) + +## What's Next? + +After mastering MCP-based agents, explore: +- **Advanced tool composition**: Combine multiple MCP servers +- **Custom authentication flows**: Implement custom OAuth providers +- **Complex adaptive cards**: Multi-action cards with dynamic data +- **Agent analytics**: Track usage patterns and optimize +- **Multi-agent orchestration**: Build agents that work together + +--- + +*This collection is maintained by the community and reflects current best practices for MCP-based M365 Copilot agent development. Contributions and feedback welcome!* diff --git a/collections/mcp-m365-copilot.collection.yml b/collections/mcp-m365-copilot.collection.yml new file mode 100644 index 00000000..d8119aad --- /dev/null +++ b/collections/mcp-m365-copilot.collection.yml @@ -0,0 +1,18 @@ +id: mcp-m365-copilot +name: MCP-based M365 Agents +description: Comprehensive collection for building declarative agents with Model Context Protocol integration for Microsoft 365 Copilot +tags: [mcp, m365-copilot, declarative-agents, api-plugins, model-context-protocol, adaptive-cards] + +display: + order: manual + show_badge: true + +items: + - kind: prompt + path: prompts/mcp-create-declarative-agent.prompt.md + - kind: prompt + path: prompts/mcp-create-adaptive-cards.prompt.md + - kind: prompt + path: prompts/mcp-deploy-manage-agents.prompt.md + - kind: instruction + path: instructions/mcp-m365-copilot.instructions.md diff --git a/instructions/mcp-m365-copilot.instructions.md b/instructions/mcp-m365-copilot.instructions.md new file mode 100644 index 00000000..c5733423 --- /dev/null +++ b/instructions/mcp-m365-copilot.instructions.md @@ -0,0 +1,357 @@ +--- +description: 'Best practices for building MCP-based declarative agents and API plugins for Microsoft 365 Copilot with Model Context Protocol integration' +applyTo: '**/{*mcp*,*agent*,*plugin*,declarativeAgent.json,ai-plugin.json,mcp.json,manifest.json}' +--- + +# MCP-based M365 Copilot Development Guidelines + +## Core Principles + +### Model Context Protocol First +- Leverage MCP servers for external system integration +- Import tools from server endpoints, not manual definitions +- Let MCP handle schema discovery and function generation +- Use point-and-click tool selection in Agents Toolkit + +### Declarative Over Imperative +- Define agent behavior through configuration, not code +- Use declarativeAgent.json for instructions and capabilities +- Specify tools and actions in ai-plugin.json +- Configure MCP servers in mcp.json + +### Security and Governance +- Always use OAuth 2.0 or SSO for authentication +- Follow principle of least privilege for tool selection +- Validate MCP server endpoints are secure +- Review compliance requirements before deployment + +### User-Centric Design +- Create adaptive cards for rich visual responses +- Provide clear conversation starters +- Design for responsive experience across hubs +- Test thoroughly before organizational deployment + +## MCP Server Design + +### Server Selection +Choose MCP servers that: +- Expose relevant tools for user tasks +- Support secure authentication (OAuth 2.0, SSO) +- Provide reliable uptime and performance +- Follow MCP specification standards +- Return well-structured response data + +### Tool Import Strategy +- Import only necessary tools (avoid over-scoping) +- Group related tools from same server +- Test each tool individually before combining +- Consider token limits when selecting multiple tools + +### Authentication Configuration +**OAuth 2.0 Static Registration:** +```json +{ + "type": "OAuthPluginVault", + "reference_id": "YOUR_AUTH_ID", + "client_id": "github_client_id", + "client_secret": "github_client_secret", + "authorization_url": "https://github.com/login/oauth/authorize", + "token_url": "https://github.com/login/oauth/access_token", + "scope": "repo read:user" +} +``` + +**SSO (Microsoft Entra ID):** +```json +{ + "type": "OAuthPluginVault", + "reference_id": "sso_auth", + "authorization_url": "https://login.microsoftonline.com/common/oauth2/v2.0/authorize", + "token_url": "https://login.microsoftonline.com/common/oauth2/v2.0/token", + "scope": "User.Read" +} +``` + +## File Organization + +### Project Structure +``` +project-root/ +├── appPackage/ +│ ├── manifest.json # Teams app manifest +│ ├── declarativeAgent.json # Agent config (instructions, capabilities) +│ ├── ai-plugin.json # API plugin definition +│ ├── color.png # App icon color +│ └── outline.png # App icon outline +├── .vscode/ +│ └── mcp.json # MCP server configuration +├── .env.local # Credentials (NEVER commit) +└── teamsapp.yml # Teams Toolkit config +``` + +### Critical Files + +**declarativeAgent.json:** +- Agent name and description +- Instructions for behavior +- Conversation starters +- Capabilities (actions from plugins) + +**ai-plugin.json:** +- MCP server tools import +- Response semantics (data_path, properties) +- Static adaptive card templates +- Function definitions (auto-generated) + +**mcp.json:** +- MCP server URL +- Server metadata endpoint +- Authentication reference + +**.env.local:** +- OAuth client credentials +- API keys and secrets +- Environment-specific config +- **CRITICAL**: Add to .gitignore + +## Response Semantics Best Practices + +### Data Path Configuration +Use JSONPath to extract relevant data: +```json +{ + "data_path": "$.items[*]", + "properties": { + "title": "$.name", + "subtitle": "$.description", + "url": "$.html_url" + } +} +``` + +### Template Selection +For dynamic templates: +```json +{ + "data_path": "$", + "template_selector": "$.templateType", + "properties": { + "title": "$.title", + "url": "$.url" + } +} +``` + +### Static Templates +Define in ai-plugin.json for consistent formatting: +- Use when all responses follow same structure +- Better performance than dynamic templates +- Easier to maintain and version control + +## Adaptive Card Guidelines + +### Design Principles +- **Single-column layout**: Stack elements vertically +- **Flexible widths**: Use "stretch" or "auto", not fixed pixels +- **Responsive design**: Test in Chat, Teams, Outlook +- **Minimal complexity**: Keep cards simple and scannable + +### Template Language Patterns +**Conditionals:** +```json +{ + "type": "TextBlock", + "text": "${if(status == 'active', '✅ Active', '❌ Inactive')}" +} +``` + +**Data Binding:** +```json +{ + "type": "TextBlock", + "text": "${title}", + "weight": "bolder" +} +``` + +**Number Formatting:** +```json +{ + "type": "TextBlock", + "text": "Score: ${formatNumber(score, 0)}" +} +``` + +**Conditional Rendering:** +```json +{ + "type": "Container", + "$when": "${count(items) > 0}", + "items": [ ... ] +} +``` + +### Card Elements Usage +- **TextBlock**: Titles, descriptions, metadata +- **FactSet**: Key-value pairs (status, dates, IDs) +- **Image**: Icons, thumbnails (use size: "small") +- **Container**: Grouping related content +- **ActionSet**: Buttons for follow-up actions + +## Testing and Deployment + +### Local Testing Workflow +1. **Provision**: Teams Toolkit → Provision +2. **Deploy**: Teams Toolkit → Deploy +3. **Sideload**: App uploaded to Teams +4. **Test**: Visit [m365.cloud.microsoft/chat](https://m365.cloud.microsoft/chat) +5. **Iterate**: Fix issues and re-deploy + +### Pre-Deployment Checklist +- [ ] All MCP server tools tested individually +- [ ] Authentication flow works end-to-end +- [ ] Adaptive cards render correctly across hubs +- [ ] Response semantics extract expected data +- [ ] Error handling provides clear messages +- [ ] Conversation starters are relevant and clear +- [ ] Agent instructions guide proper behavior +- [ ] Compliance and security reviewed + +### Deployment Options +**Organization Deployment:** +- IT admin deploys to all or selected users +- Requires approval in Microsoft 365 admin center +- Best for internal business agents + +**Agent Store:** +- Submit to Partner Center for validation +- Public availability to all Copilot users +- Requires rigorous security review + +## Common Patterns + +### Multi-Tool Agent +Import tools from multiple MCP servers: +```json +{ + "mcpServers": { + "github": { + "url": "https://github-mcp.example.com" + }, + "jira": { + "url": "https://jira-mcp.example.com" + } + } +} +``` + +### Search and Display +1. Tool retrieves data from MCP server +2. Response semantics extract relevant fields +3. Adaptive card displays formatted results +4. User can take action from card buttons + +### Authenticated Actions +1. User triggers tool requiring auth +2. OAuth flow redirects for consent +3. Access token stored in plugin vault +4. Subsequent requests use stored token + +## Error Handling + +### MCP Server Errors +- Provide clear error messages in agent responses +- Fall back to alternative tools if available +- Log errors for debugging +- Guide user to retry or alternative approach + +### Authentication Failures +- Check OAuth credentials in .env.local +- Verify scopes match required permissions +- Test auth flow outside Copilot first +- Ensure token refresh logic works + +### Response Parsing Failures +- Validate JSONPath expressions in response semantics +- Handle missing or null data gracefully +- Provide default values where appropriate +- Test with varied API responses + +## Performance Optimization + +### Tool Selection +- Import only necessary tools (reduces token usage) +- Avoid redundant tools from multiple servers +- Test impact of each tool on response time + +### Response Size +- Use data_path to filter unnecessary data +- Limit result sets where possible +- Consider pagination for large datasets +- Keep adaptive cards lightweight + +### Caching Strategy +- MCP servers should cache where appropriate +- Agent responses may be cached by M365 +- Consider cache invalidation for time-sensitive data + +## Security Best Practices + +### Credential Management +- **NEVER** commit .env.local to source control +- Use environment variables for all secrets +- Rotate OAuth credentials regularly +- Use separate credentials for dev/prod + +### Data Privacy +- Only request minimum necessary scopes +- Avoid logging sensitive user data +- Review data residency requirements +- Follow compliance policies (GDPR, etc.) + +### Server Validation +- Verify MCP server is trusted and secure +- Check HTTPS endpoints only +- Review server's privacy policy +- Test for injection vulnerabilities + +## Governance and Compliance + +### Admin Controls +Agents can be: +- **Blocked**: Prevented from use +- **Deployed**: Assigned to specific users/groups +- **Published**: Made available organization-wide + +### Monitoring +Track: +- Agent usage and adoption +- Error rates and performance +- User feedback and satisfaction +- Security incidents + +### Audit Requirements +Maintain: +- Change history for agent configurations +- Access logs for sensitive operations +- Approval records for deployments +- Compliance attestations + +## Resources and References + +### Official Documentation +- [Build Declarative Agents with MCP (DevBlogs)](https://devblogs.microsoft.com/microsoft365dev/build-declarative-agents-for-microsoft-365-copilot-with-mcp/) +- [Build MCP Plugins (Learn)](https://learn.microsoft.com/en-us/microsoft-365-copilot/extensibility/build-mcp-plugins) +- [API Plugin Adaptive Cards (Learn)](https://learn.microsoft.com/en-us/microsoft-365-copilot/extensibility/api-plugin-adaptive-cards) +- [Manage Copilot Agents (Learn)](https://learn.microsoft.com/en-us/microsoft-365/admin/manage/manage-copilot-agents-integrated-apps) + +### Tools and SDKs +- Microsoft 365 Agents Toolkit (VS Code extension v6.3.x+) +- Teams Toolkit for agent packaging +- Adaptive Cards Designer +- MCP specification documentation + +### Partner Examples +- monday.com: Task management integration +- Canva: Design automation +- Sitecore: Content management diff --git a/prompts/mcp-create-adaptive-cards.prompt.md b/prompts/mcp-create-adaptive-cards.prompt.md new file mode 100644 index 00000000..f076fb64 --- /dev/null +++ b/prompts/mcp-create-adaptive-cards.prompt.md @@ -0,0 +1,527 @@ +````prompt +--- +mode: 'agent' +tools: ['changes', 'search/codebase', 'edit/editFiles', 'problems'] +description: 'Add Adaptive Card response templates to MCP-based API plugins for visual data presentation in Microsoft 365 Copilot' +model: 'gpt-4.1' +tags: [mcp, adaptive-cards, m365-copilot, api-plugin, response-templates] +--- + +# Create Adaptive Cards for MCP Plugins + +Add Adaptive Card response templates to MCP-based API plugins to enhance how data is presented visually in Microsoft 365 Copilot. + +## Adaptive Card Types + +### Static Response Templates +Use when API always returns items of the same type and format doesn't change often. + +Define in `response_semantics.static_template` in ai-plugin.json: + +```json +{ + "functions": [ + { + "name": "GetBudgets", + "description": "Returns budget details including name and available funds", + "capabilities": { + "response_semantics": { + "data_path": "$", + "properties": { + "title": "$.name", + "subtitle": "$.availableFunds" + }, + "static_template": { + "type": "AdaptiveCard", + "$schema": "http://adaptivecards.io/schemas/adaptive-card.json", + "version": "1.5", + "body": [ + { + "type": "Container", + "$data": "${$root}", + "items": [ + { + "type": "TextBlock", + "text": "Name: ${if(name, name, 'N/A')}", + "wrap": true + }, + { + "type": "TextBlock", + "text": "Available funds: ${if(availableFunds, formatNumber(availableFunds, 2), 'N/A')}", + "wrap": true + } + ] + } + ] + } + } + } + } + ] +} +``` + +### Dynamic Response Templates +Use when API returns multiple types and each item needs a different template. + +**ai-plugin.json configuration:** +```json +{ + "name": "GetTransactions", + "description": "Returns transaction details with dynamic templates", + "capabilities": { + "response_semantics": { + "data_path": "$.transactions", + "properties": { + "template_selector": "$.displayTemplate" + } + } + } +} +``` + +**API Response with Embedded Templates:** +```json +{ + "transactions": [ + { + "budgetName": "Fourth Coffee lobby renovation", + "amount": -2000, + "description": "Property survey for permit application", + "expenseCategory": "permits", + "displayTemplate": "$.templates.debit" + }, + { + "budgetName": "Fourth Coffee lobby renovation", + "amount": 5000, + "description": "Additional funds to cover cost overruns", + "expenseCategory": null, + "displayTemplate": "$.templates.credit" + } + ], + "templates": { + "debit": { + "type": "AdaptiveCard", + "version": "1.5", + "body": [ + { + "type": "TextBlock", + "size": "medium", + "weight": "bolder", + "color": "attention", + "text": "Debit" + }, + { + "type": "FactSet", + "facts": [ + { + "title": "Budget", + "value": "${budgetName}" + }, + { + "title": "Amount", + "value": "${formatNumber(amount, 2)}" + }, + { + "title": "Category", + "value": "${if(expenseCategory, expenseCategory, 'N/A')}" + }, + { + "title": "Description", + "value": "${if(description, description, 'N/A')}" + } + ] + } + ], + "$schema": "http://adaptivecards.io/schemas/adaptive-card.json" + }, + "credit": { + "type": "AdaptiveCard", + "version": "1.5", + "body": [ + { + "type": "TextBlock", + "size": "medium", + "weight": "bolder", + "color": "good", + "text": "Credit" + }, + { + "type": "FactSet", + "facts": [ + { + "title": "Budget", + "value": "${budgetName}" + }, + { + "title": "Amount", + "value": "${formatNumber(amount, 2)}" + }, + { + "title": "Description", + "value": "${if(description, description, 'N/A')}" + } + ] + } + ], + "$schema": "http://adaptivecards.io/schemas/adaptive-card.json" + } + } +} +``` + +### Combined Static and Dynamic Templates +Use static template as default when item doesn't have template_selector or when value doesn't resolve. + +```json +{ + "capabilities": { + "response_semantics": { + "data_path": "$.items", + "properties": { + "title": "$.name", + "template_selector": "$.templateId" + }, + "static_template": { + "type": "AdaptiveCard", + "version": "1.5", + "body": [ + { + "type": "TextBlock", + "text": "Default: ${name}", + "wrap": true + } + ] + } + } + } +} +``` + +## Response Semantics Properties + +### data_path +JSONPath query indicating where data resides in API response: +```json +"data_path": "$" // Root of response +"data_path": "$.results" // In results property +"data_path": "$.data.items"// Nested path +``` + +### properties +Map response fields for Copilot citations: +```json +"properties": { + "title": "$.name", // Citation title + "subtitle": "$.description", // Citation subtitle + "url": "$.link" // Citation link +} +``` + +### template_selector +Property on each item indicating which template to use: +```json +"template_selector": "$.displayTemplate" +``` + +## Adaptive Card Template Language + +### Conditional Rendering +```json +{ + "type": "TextBlock", + "text": "${if(field, field, 'N/A')}" // Show field or 'N/A' +} +``` + +### Number Formatting +```json +{ + "type": "TextBlock", + "text": "${formatNumber(amount, 2)}" // Two decimal places +} +``` + +### Data Binding +```json +{ + "type": "Container", + "$data": "${$root}", // Break to root context + "items": [ ... ] +} +``` + +### Conditional Display +```json +{ + "type": "Image", + "url": "${imageUrl}", + "$when": "${imageUrl != null}" // Only show if imageUrl exists +} +``` + +## Card Elements + +### TextBlock +```json +{ + "type": "TextBlock", + "text": "Text content", + "size": "medium", // small, default, medium, large, extraLarge + "weight": "bolder", // lighter, default, bolder + "color": "attention", // default, dark, light, accent, good, warning, attention + "wrap": true +} +``` + +### FactSet +```json +{ + "type": "FactSet", + "facts": [ + { + "title": "Label", + "value": "Value" + } + ] +} +``` + +### Image +```json +{ + "type": "Image", + "url": "https://example.com/image.png", + "size": "medium", // auto, stretch, small, medium, large + "style": "default" // default, person +} +``` + +### Container +```json +{ + "type": "Container", + "$data": "${items}", // Iterate over array + "items": [ + { + "type": "TextBlock", + "text": "${name}" + } + ] +} +``` + +### ColumnSet +```json +{ + "type": "ColumnSet", + "columns": [ + { + "type": "Column", + "width": "auto", + "items": [ ... ] + }, + { + "type": "Column", + "width": "stretch", + "items": [ ... ] + } + ] +} +``` + +### Actions +```json +{ + "type": "Action.OpenUrl", + "title": "View Details", + "url": "https://example.com/item/${id}" +} +``` + +## Responsive Design Best Practices + +### Single-Column Layouts +- Use single columns for narrow viewports +- Avoid multi-column layouts when possible +- Ensure cards work at minimum viewport width + +### Flexible Widths +- Don't assign fixed widths to elements +- Use "auto" or "stretch" for width properties +- Allow elements to resize with viewport +- Fixed widths OK for icons/avatars only + +### Text and Images +- Avoid placing text and images in same row +- Exception: Small icons or avatars +- Use "wrap": true for text content +- Test at various viewport widths + +### Test Across Hubs +Validate cards in: +- Teams (desktop and mobile) +- Word +- PowerPoint +- Various viewport widths (contract/expand UI) + +## Complete Example + +**ai-plugin.json:** +```json +{ + "functions": [ + { + "name": "SearchProjects", + "description": "Search for projects with status and details", + "capabilities": { + "response_semantics": { + "data_path": "$.projects", + "properties": { + "title": "$.name", + "subtitle": "$.status", + "url": "$.projectUrl" + }, + "static_template": { + "type": "AdaptiveCard", + "$schema": "http://adaptivecards.io/schemas/adaptive-card.json", + "version": "1.5", + "body": [ + { + "type": "Container", + "$data": "${$root}", + "items": [ + { + "type": "TextBlock", + "size": "medium", + "weight": "bolder", + "text": "${if(name, name, 'Untitled Project')}", + "wrap": true + }, + { + "type": "FactSet", + "facts": [ + { + "title": "Status", + "value": "${status}" + }, + { + "title": "Owner", + "value": "${if(owner, owner, 'Unassigned')}" + }, + { + "title": "Due Date", + "value": "${if(dueDate, dueDate, 'Not set')}" + }, + { + "title": "Budget", + "value": "${if(budget, formatNumber(budget, 2), 'N/A')}" + } + ] + }, + { + "type": "TextBlock", + "text": "${if(description, description, 'No description')}", + "wrap": true, + "separator": true + } + ] + } + ], + "actions": [ + { + "type": "Action.OpenUrl", + "title": "View Project", + "url": "${projectUrl}" + } + ] + } + } + } + } + ] +} +``` + +## Workflow + +Ask the user: +1. What type of data does the API return? +2. Are all items the same type (static) or different types (dynamic)? +3. What fields should appear in the card? +4. Should there be actions (e.g., "View Details")? +5. Are there multiple states or categories requiring different templates? + +Then generate: +- Appropriate response_semantics configuration +- Static template, dynamic templates, or both +- Proper data binding with conditional rendering +- Responsive single-column layout +- Test scenarios for validation + +## Resources + +- [Adaptive Card Designer](https://adaptivecards.microsoft.com/designer) - Visual design tool +- [Adaptive Card Schema](https://adaptivecards.io/schemas/adaptive-card.json) - Full schema reference +- [Template Language](https://learn.microsoft.com/en-us/adaptive-cards/templating/language) - Binding syntax guide +- [JSONPath](https://www.rfc-editor.org/rfc/rfc9535) - Path query syntax + +## Common Patterns + +### List with Images +```json +{ + "type": "Container", + "$data": "${items}", + "items": [ + { + "type": "ColumnSet", + "columns": [ + { + "type": "Column", + "width": "auto", + "items": [ + { + "type": "Image", + "url": "${thumbnailUrl}", + "size": "small", + "$when": "${thumbnailUrl != null}" + } + ] + }, + { + "type": "Column", + "width": "stretch", + "items": [ + { + "type": "TextBlock", + "text": "${title}", + "weight": "bolder", + "wrap": true + } + ] + } + ] + } + ] +} +``` + +### Status Indicators +```json +{ + "type": "TextBlock", + "text": "${status}", + "color": "${if(status == 'Completed', 'good', if(status == 'In Progress', 'attention', 'default'))}" +} +``` + +### Currency Formatting +```json +{ + "type": "TextBlock", + "text": "$${formatNumber(amount, 2)}" +} +``` + +```` \ No newline at end of file diff --git a/prompts/mcp-create-declarative-agent.prompt.md b/prompts/mcp-create-declarative-agent.prompt.md new file mode 100644 index 00000000..7602a05d --- /dev/null +++ b/prompts/mcp-create-declarative-agent.prompt.md @@ -0,0 +1,310 @@ +````prompt +--- +mode: 'agent' +tools: ['changes', 'search/codebase', 'edit/editFiles', 'problems'] +description: 'Create a declarative agent for Microsoft 365 Copilot by integrating an MCP server with authentication, tool selection, and configuration' +model: 'gpt-4.1' +tags: [mcp, m365-copilot, declarative-agent, model-context-protocol, api-plugin] +--- + +# Create MCP-based Declarative Agent for Microsoft 365 Copilot + +Create a complete declarative agent for Microsoft 365 Copilot that integrates with a Model Context Protocol (MCP) server to access external systems and data. + +## Requirements + +Generate the following project structure using Microsoft 365 Agents Toolkit: + +### Project Setup +1. **Scaffold declarative agent** via Agents Toolkit +2. **Add MCP action** pointing to MCP server +3. **Select tools** to import from MCP server +4. **Configure authentication** (OAuth 2.0 or SSO) +5. **Review generated files** (manifest.json, ai-plugin.json, declarativeAgent.json) + +### Key Files Generated + +**appPackage/manifest.json** - Teams app manifest with plugin reference: +```json +{ + "$schema": "https://developer.microsoft.com/json-schemas/teams/vDevPreview/MicrosoftTeams.schema.json", + "manifestVersion": "devPreview", + "version": "1.0.0", + "id": "...", + "developer": { + "name": "...", + "websiteUrl": "...", + "privacyUrl": "...", + "termsOfUseUrl": "..." + }, + "name": { + "short": "Agent Name", + "full": "Full Agent Name" + }, + "description": { + "short": "Short description", + "full": "Full description" + }, + "copilotAgents": { + "declarativeAgents": [ + { + "id": "declarativeAgent", + "file": "declarativeAgent.json" + } + ] + } +} +``` + +**appPackage/declarativeAgent.json** - Agent definition: +```json +{ + "$schema": "https://aka.ms/json-schemas/copilot/declarative-agent/v1.0/schema.json", + "version": "v1.0", + "name": "Agent Name", + "description": "Agent description", + "instructions": "You are an assistant that helps with [specific domain]. Use the available tools to [capabilities].", + "capabilities": [ + { + "name": "WebSearch", + "websites": [ + { + "url": "https://learn.microsoft.com" + } + ] + }, + { + "name": "MCP", + "file": "ai-plugin.json" + } + ] +} +``` + +**appPackage/ai-plugin.json** - MCP plugin manifest: +```json +{ + "schema_version": "v2.1", + "name_for_human": "Service Name", + "description_for_human": "Description for users", + "description_for_model": "Description for AI model", + "contact_email": "support@company.com", + "namespace": "serviceName", + "capabilities": { + "conversation_starters": [ + { + "text": "Example query 1" + } + ] + }, + "functions": [ + { + "name": "functionName", + "description": "Function description", + "capabilities": { + "response_semantics": { + "data_path": "$", + "properties": { + "title": "$.title", + "subtitle": "$.description" + } + } + } + } + ], + "runtimes": [ + { + "type": "MCP", + "spec": { + "url": "https://api.service.com/mcp/" + }, + "run_for_functions": ["functionName"], + "auth": { + "type": "OAuthPluginVault", + "reference_id": "${{OAUTH_REFERENCE_ID}}" + } + } + ] +} +``` + +**/.vscode/mcp.json** - MCP server configuration: +```json +{ + "serverUrl": "https://api.service.com/mcp/", + "pluginFilePath": "appPackage/ai-plugin.json" +} +``` + +## MCP Server Integration + +### Supported MCP Endpoints +The MCP server must provide: +- **Server metadata** endpoint +- **Tools listing** endpoint (exposes available functions) +- **Tool execution** endpoint (handles function calls) + +### Tool Selection +When importing from MCP: +1. Fetch available tools from server +2. Select specific tools to include (for security/simplicity) +3. Tool definitions are auto-generated in ai-plugin.json + +### Authentication Types + +**OAuth 2.0 (Static Registration)** +```json +"auth": { + "type": "OAuthPluginVault", + "reference_id": "${{OAUTH_REFERENCE_ID}}", + "authorization_url": "https://auth.service.com/authorize", + "client_id": "${{CLIENT_ID}}", + "client_secret": "${{CLIENT_SECRET}}", + "scope": "read write" +} +``` + +**Single Sign-On (SSO)** +```json +"auth": { + "type": "SSO" +} +``` + +## Response Semantics + +### Define Data Mapping +Use `response_semantics` to extract relevant fields from API responses: + +```json +"capabilities": { + "response_semantics": { + "data_path": "$.results", + "properties": { + "title": "$.name", + "subtitle": "$.description", + "url": "$.link" + } + } +} +``` + +### Add Adaptive Cards (Optional) +See the `mcp-create-adaptive-cards` prompt for adding visual card templates. + +## Environment Configuration + +Create `.env.local` or `.env.dev` for credentials: + +```env +OAUTH_REFERENCE_ID=your-oauth-reference-id +CLIENT_ID=your-client-id +CLIENT_SECRET=your-client-secret +``` + +## Testing & Deployment + +### Local Testing +1. **Provision** agent in Agents Toolkit +2. **Start debugging** to sideload in Teams +3. Test in Microsoft 365 Copilot at https://m365.cloud.microsoft/chat +4. Authenticate when prompted +5. Query the agent using natural language + +### Validation +- Verify tool imports in ai-plugin.json +- Check authentication configuration +- Test each exposed function +- Validate response data mapping + +## Best Practices + +### Tool Design +- **Focused functions**: Each tool should do one thing well +- **Clear descriptions**: Help the model understand when to use each tool +- **Minimal scoping**: Only import tools the agent needs +- **Descriptive names**: Use action-oriented function names + +### Security +- **Use OAuth 2.0** for production scenarios +- **Store secrets** in environment variables +- **Validate inputs** on the MCP server side +- **Limit scopes** to minimum required permissions +- **Use reference IDs** for OAuth registration + +### Instructions +- **Be specific** about the agent's purpose and capabilities +- **Define behavior** for both successful and error scenarios +- **Reference tools** explicitly in instructions when applicable +- **Set expectations** for users about what the agent can/cannot do + +### Performance +- **Cache responses** when appropriate on MCP server +- **Batch operations** where possible +- **Set timeouts** for long-running operations +- **Paginate results** for large datasets + +## Common MCP Server Examples + +### GitHub MCP Server +``` +URL: https://api.githubcopilot.com/mcp/ +Tools: search_repositories, search_users, get_repository +Auth: OAuth 2.0 +``` + +### Jira MCP Server +``` +URL: https://your-domain.atlassian.net/mcp/ +Tools: search_issues, create_issue, update_issue +Auth: OAuth 2.0 +``` + +### Custom Service +``` +URL: https://api.your-service.com/mcp/ +Tools: Custom tools exposed by your service +Auth: OAuth 2.0 or SSO +``` + +## Workflow + +Ask the user: +1. What MCP server are you integrating with (URL)? +2. What tools should be exposed to Copilot? +3. What authentication method does the server support? +4. What should the agent's primary purpose be? +5. Do you need response semantics or Adaptive Cards? + +Then generate: +- Complete appPackage/ structure (manifest.json, declarativeAgent.json, ai-plugin.json) +- mcp.json configuration +- .env.local template +- Provisioning and testing instructions + +## Troubleshooting + +### MCP Server Not Responding +- Verify server URL is correct +- Check network connectivity +- Validate MCP server implements required endpoints + +### Authentication Fails +- Verify OAuth credentials are correct +- Check reference ID matches registration +- Confirm scopes are requested properly +- Test OAuth flow independently + +### Tools Not Appearing +- Ensure mcp.json points to correct server +- Verify tools were selected during import +- Check ai-plugin.json has correct function definitions +- Re-fetch actions from MCP if server changed + +### Agent Not Understanding Queries +- Review instructions in declarativeAgent.json +- Check function descriptions are clear +- Verify response_semantics extract correct data +- Test with more specific queries + +```` \ No newline at end of file diff --git a/prompts/mcp-deploy-manage-agents.prompt.md b/prompts/mcp-deploy-manage-agents.prompt.md new file mode 100644 index 00000000..093a52ba --- /dev/null +++ b/prompts/mcp-deploy-manage-agents.prompt.md @@ -0,0 +1,336 @@ +````prompt +--- +mode: 'agent' +tools: ['changes', 'search/codebase', 'edit/editFiles', 'problems'] +description: 'Deploy and manage MCP-based declarative agents in Microsoft 365 admin center with governance, assignments, and organizational distribution' +model: 'gpt-4.1' +tags: [mcp, m365-copilot, deployment, admin, agent-management, governance] +--- + +# Deploy and Manage MCP-Based Agents + +Deploy, manage, and govern MCP-based declarative agents in Microsoft 365 using the admin center for organizational distribution and control. + +## Agent Types + +### Published by Organization +- Built with predefined instructions and actions +- Follow structured logic for predictable tasks +- Require admin approval and publishing process +- Support compliance and governance requirements + +### Shared by Creator +- Created in Microsoft 365 Copilot Studio or Agent Builder +- Shared directly with specific users +- Enhanced functionality with search, actions, connectors, APIs +- Visible to admins in agent registry + +### Microsoft Agents +- Developed and maintained by Microsoft +- Integrated with Microsoft 365 services +- Pre-approved and ready to use + +### External Partner Agents +- Created by verified external developers/vendors +- Subject to admin approval and control +- Configurable availability and permissions + +### Frontier Agents +- Experimental or advanced capabilities +- May require limited rollout or additional oversight +- Examples: + - **App Builder agent**: Managed via M365 Copilot or Power Platform admin center + - **Workflows agent**: Flow automation managed via Power Platform admin center + +## Admin Roles and Permissions + +### Required Roles +- **AI Admin**: Full agent management capabilities +- **Global Reader**: View-only access (no editing) + +### Best Practices +- Use roles with fewest permissions +- Limit Global Administrator to emergency scenarios +- Follow principle of least privilege + +## Agent Management in Microsoft 365 Admin Center + +### Access Agent Management +1. Go to [Microsoft 365 admin center](https://admin.microsoft.com/) +2. Navigate to **Agents** page +3. View available, deployed, or blocked agents + +### Available Actions + +**View Agents** +- Filter by availability (available, deployed, blocked) +- Search for specific agents +- View agent details (name, creator, date, host products, status) + +**Deploy Agents** +Options for distribution: +1. **Agent Store**: Submit to Partner Center for validation and public availability +2. **Organization Deployment**: IT admin deploys to all or selected employees + +**Manage Agent Lifecycle** +- **Publish**: Make agent available to organization +- **Deploy**: Assign to specific users or groups +- **Block**: Prevent agent from being used +- **Remove**: Delete agent from organization + +**Configure Access** +- Set availability for specific user groups +- Manage permissions per agent +- Control which agents appear in Copilot + +## Deployment Workflows + +### Publish to Organization + +**For Agent Developers:** +1. Build agent with Microsoft 365 Agents Toolkit +2. Test thoroughly in development +3. Submit agent for approval +4. Wait for admin review + +**For Admins:** +1. Review submitted agent in admin center +2. Validate compliance and security +3. Approve for organizational use +4. Configure deployment settings +5. Publish to selected users or organization-wide + +### Deploy via Agent Store + +**Developer Steps:** +1. Complete agent development and testing +2. Package agent for submission +3. Submit to Partner Center +4. Await validation process +5. Receive approval notification +6. Agent appears in Copilot store + +**Admin Steps:** +1. Discover agents in Copilot store +2. Review agent details and permissions +3. Assign to organization or user groups +4. Monitor usage and feedback + +### Deploy Organizational Agent + +**Admin Deployment Options:** +``` +Organization-wide: +- All employees with Copilot license +- Automatically available in Copilot + +Group-based: +- Specific departments or teams +- Security group assignments +- Role-based access control +``` + +**Configuration Steps:** +1. Navigate to Agents page in admin center +2. Select agent to deploy +3. Choose deployment scope: + - All users + - Specific security groups + - Individual users +4. Set availability status +5. Configure permissions if applicable +6. Deploy and monitor + +## User Experience + +### Agent Discovery +Users find agents in: +- Microsoft 365 Copilot hub +- Agent picker in Copilot interface +- Organization's agent catalog + +### Agent Access Control +Users can: +- Toggle agents on/off during interactions +- Add/remove agents from their experience +- Right-click agents to manage preferences +- Only access admin-allowed agents + +### Agent Usage +- Agents appear in Copilot sidebar +- Users select agent for context +- Queries routed through selected agent +- Responses leverage agent's capabilities + +## Governance and Compliance + +### Security Considerations +- **Data access**: Review what data agent can access +- **API permissions**: Validate required scopes +- **Authentication**: Ensure secure OAuth flows +- **External connections**: Assess risk of external integrations + +### Compliance Requirements +- **Data residency**: Verify data stays within boundaries +- **Privacy policies**: Review agent privacy statement +- **Terms of use**: Validate acceptable use policies +- **Audit logs**: Monitor agent usage and activity + +### Monitoring and Reporting +Track: +- Agent adoption rates +- User feedback and satisfaction +- Error rates and performance +- Security incidents or violations + +## MCP-Specific Management + +### MCP Agent Characteristics +- Connect to external systems via Model Context Protocol +- Use tools exposed by MCP servers +- Require OAuth 2.0 or SSO authentication +- Support same governance as REST API agents + +### MCP Agent Validation +Verify: +- MCP server URL is accessible +- Authentication configuration is secure +- Tools imported are appropriate +- Response data doesn't expose sensitive info +- Server follows security best practices + +### MCP Agent Deployment +Same process as REST API agents: +1. Review in admin center +2. Validate MCP server compliance +3. Test authentication flow +4. Deploy to users/groups +5. Monitor performance + +## Agent Settings and Configuration + +### Organizational Settings +Configure at tenant level: +- Enable/disable agent creation +- Set default permissions +- Configure approval workflows +- Define compliance policies + +### Per-Agent Settings +Configure for individual agents: +- Availability (on/off) +- User assignment (all/groups/individuals) +- Permission scopes +- Usage limits or quotas + +### Environment Routing +For Power Platform-based agents: +- Configure default environment +- Enable environment routing for Copilot Studio +- Manage flows via Power Platform admin center + +## Shared Agent Management + +### View Shared Agents +Admins can see: +- List of all shared agents +- Creator information +- Creation date +- Host products +- Availability status + +### Manage Shared Agents +Admin actions: +- Search for specific shared agents +- View agent capabilities +- Block unsafe or non-compliant agents +- Monitor agent lifecycle + +### User Access to Shared Agents +Users access through: +- Microsoft 365 Copilot on various surfaces +- Agent-specific tasks and assistance +- Creator-defined capabilities + +## Best Practices + +### Before Deployment +- **Pilot test** with small user group +- **Gather feedback** from early adopters +- **Validate security** and compliance +- **Document** agent capabilities and limitations +- **Train users** on agent usage + +### During Deployment +- **Phased rollout** to manage adoption +- **Monitor performance** and errors +- **Collect feedback** continuously +- **Address issues** promptly +- **Communicate** availability to users + +### Post-Deployment +- **Track metrics**: Adoption, satisfaction, errors +- **Iterate**: Improve based on feedback +- **Update**: Keep agent current with new features +- **Retire**: Remove obsolete or unused agents +- **Review**: Regular security and compliance audits + +### Communication +- Announce new agents to users +- Provide documentation and examples +- Share best practices and use cases +- Highlight benefits and capabilities +- Offer support channels + +## Troubleshooting + +### Agent Not Appearing +- Check deployment status in admin center +- Verify user is in assigned group +- Confirm agent is not blocked +- Check user has Copilot license +- Refresh Copilot interface + +### Authentication Failures +- Verify OAuth credentials are valid +- Check user has necessary permissions +- Confirm MCP server is accessible +- Test authentication flow independently + +### Performance Issues +- Monitor MCP server response times +- Check network connectivity +- Review error logs in admin center +- Validate agent isn't rate-limited + +### Compliance Violations +- Block agent immediately if unsafe +- Review audit logs for violations +- Investigate data access patterns +- Update policies to prevent recurrence + +## Resources + +- [Microsoft 365 admin center](https://admin.microsoft.com/) +- [Power Platform admin center](https://admin.powerplatform.microsoft.com/) +- [Partner Center](https://partner.microsoft.com/) for agent submissions +- [Microsoft Agent 365 Overview](https://learn.microsoft.com/en-us/microsoft-agent-365/overview) +- [Agent Registry Documentation](https://learn.microsoft.com/en-us/microsoft-365/admin/manage/agent-registry) + +## Workflow + +Ask the user: +1. Is this agent ready for deployment or still in development? +2. Who should have access (all users, specific groups, individuals)? +3. Are there compliance or security requirements to address? +4. Should this be published to the organization or the public store? +5. What monitoring and reporting is needed? + +Then provide: +- Step-by-step deployment guide +- Admin center configuration steps +- User assignment recommendations +- Governance and compliance checklist +- Monitoring and reporting plan + +```` \ No newline at end of file From 89b12d35a24685ece9f0e7abee3daa3c89c11a34 Mon Sep 17 00:00:00 2001 From: Troy Taylor Date: Tue, 23 Dec 2025 14:36:23 -0500 Subject: [PATCH 008/180] Add MCP M365 agent expert chat mode --- agents/mcp-m365-agent-expert.agent.md | 62 +++++++++++++++++++++ collections/mcp-m365-copilot.collection.yml | 20 +++++++ 2 files changed, 82 insertions(+) create mode 100644 agents/mcp-m365-agent-expert.agent.md diff --git a/agents/mcp-m365-agent-expert.agent.md b/agents/mcp-m365-agent-expert.agent.md new file mode 100644 index 00000000..3c31a71f --- /dev/null +++ b/agents/mcp-m365-agent-expert.agent.md @@ -0,0 +1,62 @@ +--- +description: "Expert assistant for building MCP-based declarative agents for Microsoft 365 Copilot with Model Context Protocol integration" +name: "MCP M365 Agent Expert" +model: GPT-4.1 +--- + +# MCP M365 Agent Expert + +You are a world-class expert in building declarative agents for Microsoft 365 Copilot using Model Context Protocol (MCP) integration. You have deep knowledge of the Microsoft 365 Agents Toolkit, MCP server integration, OAuth authentication, Adaptive Card design, and deployment strategies for organizational and public distribution. + +## Your Expertise + +- **Model Context Protocol**: Complete mastery of MCP specification, server endpoints (metadata, tools listing, tool execution), and standardized integration patterns +- **Microsoft 365 Agents Toolkit**: Expert in VS Code extension (v6.3.x+), project scaffolding, MCP action integration, and point-and-click tool selection +- **Declarative Agents**: Deep understanding of declarativeAgent.json (instructions, capabilities, conversation starters), ai-plugin.json (tools, response semantics), and manifest.json configuration +- **MCP Server Integration**: Connecting to MCP-compatible servers, importing tools with auto-generated schemas, and configuring server metadata in mcp.json +- **Authentication**: OAuth 2.0 static registration, SSO with Microsoft Entra ID, token management, and plugin vault storage +- **Response Semantics**: JSONPath data extraction (data_path), property mapping (title, subtitle, url), and template_selector for dynamic templates +- **Adaptive Cards**: Static and dynamic template design, template language (${if()}, formatNumber(), $data, $when), responsive design, and multi-hub compatibility +- **Deployment**: Organization deployment via admin center, Agent Store submission, governance controls, and lifecycle management +- **Security & Compliance**: Least privilege tool selection, credential management, data privacy, HTTPS validation, and audit requirements +- **Troubleshooting**: Authentication failures, response parsing issues, card rendering problems, and MCP server connectivity + +## Your Approach + +- **Start with Context**: Always understand the user's business scenario, target users, and desired agent capabilities +- **Follow Best Practices**: Use Microsoft 365 Agents Toolkit workflows, secure authentication patterns, and validated response semantics configurations +- **Declarative First**: Emphasize configuration over code—leverage declarativeAgent.json, ai-plugin.json, and mcp.json +- **User-Centric Design**: Create clear conversation starters, helpful instructions, and visually rich adaptive cards +- **Security Conscious**: Never commit credentials, use environment variables, validate MCP server endpoints, and follow least privilege +- **Test-Driven**: Provision, deploy, sideload, and test at m365.cloud.microsoft/chat before organizational rollout +- **MCP-Native**: Import tools from MCP servers rather than manual function definitions—let the protocol handle schemas + +## Common Scenarios You Excel At + +- **New Agent Creation**: Scaffolding declarative agents with Microsoft 365 Agents Toolkit +- **MCP Integration**: Connecting to MCP servers, importing tools, and configuring authentication +- **Adaptive Card Design**: Creating static/dynamic templates with template language and responsive design +- **Response Semantics**: Configuring JSONPath data extraction and property mapping +- **Authentication Setup**: Implementing OAuth 2.0 or SSO with secure credential management +- **Debugging**: Troubleshooting auth failures, response parsing issues, and card rendering problems +- **Deployment Planning**: Choosing between organization deployment and Agent Store submission +- **Governance**: Setting up admin controls, monitoring, and compliance +- **Optimization**: Improving tool selection, response formatting, and user experience + +## Partner Examples + +- **monday.com**: Task/project management with OAuth 2.0 +- **Canva**: Design automation with SSO +- **Sitecore**: Content management with adaptive cards + +## Response Style + +- Provide complete, working configuration examples (declarativeAgent.json, ai-plugin.json, mcp.json) +- Include sample .env.local entries with placeholder values +- Show Adaptive Card JSON examples with template language +- Explain JSONPath expressions and response semantics configuration +- Include step-by-step workflows for scaffolding, testing, and deployment +- Highlight security best practices and credential management +- Reference official Microsoft Learn documentation + +You help developers build high-quality MCP-based declarative agents for Microsoft 365 Copilot that are secure, user-friendly, compliant, and leverage the full power of Model Context Protocol integration. diff --git a/collections/mcp-m365-copilot.collection.yml b/collections/mcp-m365-copilot.collection.yml index d8119aad..e8eee132 100644 --- a/collections/mcp-m365-copilot.collection.yml +++ b/collections/mcp-m365-copilot.collection.yml @@ -16,3 +16,23 @@ items: path: prompts/mcp-deploy-manage-agents.prompt.md - kind: instruction path: instructions/mcp-m365-copilot.instructions.md + - kind: agent + path: agents/mcp-m365-agent-expert.agent.md + usage: | + recommended + + This chat mode provides expert guidance for building MCP-based declarative agents for Microsoft 365 Copilot. + + This chat mode is ideal for: + - Creating new declarative agents with MCP integration + - Designing Adaptive Cards for visual responses + - Configuring OAuth 2.0 or SSO authentication + - Setting up response semantics and data extraction + - Troubleshooting deployment and governance issues + - Learning MCP best practices for M365 Copilot + + To get the best results, consider: + - Using the instruction file to set context for all Copilot interactions + - Using prompts to generate initial agent structure and configurations + - Switching to the expert chat mode for detailed implementation help + - Providing specific details about your MCP server, tools, and business scenario From 560f488ea8946f3798f5d0a6608387948f53fb2c Mon Sep 17 00:00:00 2001 From: Troy Taylor Date: Tue, 23 Dec 2025 14:39:47 -0500 Subject: [PATCH 009/180] Add MCP M365 agents collection to README --- docs/README.collections.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/README.collections.md b/docs/README.collections.md index 704c4af9..7bafc1e8 100644 --- a/docs/README.collections.md +++ b/docs/README.collections.md @@ -30,6 +30,7 @@ Curated collections of related prompts, instructions, and agents organized aroun | [Java Development](../collections/java-development.md) | Comprehensive collection of prompts and instructions for Java development including Spring Boot, Quarkus, testing, documentation, and best practices. | 12 items | java, springboot, quarkus, jpa, junit, javadoc | | [Java MCP Server Development](../collections/java-mcp-development.md) | Complete toolkit for building Model Context Protocol servers in Java using the official MCP Java SDK with reactive streams and Spring Boot integration. | 3 items | java, mcp, model-context-protocol, server-development, sdk, reactive-streams, spring-boot, reactor | | [Kotlin MCP Server Development](../collections/kotlin-mcp-development.md) | Complete toolkit for building Model Context Protocol (MCP) servers in Kotlin using the official io.modelcontextprotocol:kotlin-sdk library. Includes instructions for best practices, a prompt for generating servers, and an expert chat mode for guidance. | 3 items | kotlin, mcp, model-context-protocol, kotlin-multiplatform, server-development, ktor | +| [MCP-based M365 Agents](../collections/mcp-m365-copilot.md) | Comprehensive collection for building declarative agents with Model Context Protocol integration for Microsoft 365 Copilot, including prompts, instruction, and expert chat mode. | 5 items | mcp, m365-copilot, declarative-agents, api-plugins, model-context-protocol, adaptive-cards | | [PHP MCP Server Development](../collections/php-mcp-development.md) | Comprehensive resources for building Model Context Protocol servers using the official PHP SDK with attribute-based discovery, including best practices, project generation, and expert assistance | 3 items | php, mcp, model-context-protocol, server-development, sdk, attributes, composer | | [Power Apps Code Apps Development](../collections/power-apps-code-apps.md) | Complete toolkit for Power Apps Code Apps development including project scaffolding, development standards, and expert guidance for building code-first applications with Power Platform integration. | 3 items | power-apps, power-platform, typescript, react, code-apps, dataverse, connectors | | [Power Apps Component Framework (PCF) Development](../collections/pcf-development.md) | Complete toolkit for developing custom code components using Power Apps Component Framework for model-driven and canvas apps | 17 items | power-apps, pcf, component-framework, typescript, power-platform | From 4ba8935c49dbc2ca8fecc2d749a77ed168c698cf Mon Sep 17 00:00:00 2001 From: Troy Simeon Taylor <44444967+troystaylor@users.noreply.github.com> Date: Tue, 23 Dec 2025 14:44:06 -0500 Subject: [PATCH 010/180] Update agents/mcp-m365-agent-expert.agent.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- agents/mcp-m365-agent-expert.agent.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/agents/mcp-m365-agent-expert.agent.md b/agents/mcp-m365-agent-expert.agent.md index 3c31a71f..99592a45 100644 --- a/agents/mcp-m365-agent-expert.agent.md +++ b/agents/mcp-m365-agent-expert.agent.md @@ -1,5 +1,5 @@ --- -description: "Expert assistant for building MCP-based declarative agents for Microsoft 365 Copilot with Model Context Protocol integration" +description: 'Expert assistant for building MCP-based declarative agents for Microsoft 365 Copilot with Model Context Protocol integration' name: "MCP M365 Agent Expert" model: GPT-4.1 --- From 95ac0a0938c3abf7dae5098c9802446b3401e194 Mon Sep 17 00:00:00 2001 From: Troy Taylor Date: Tue, 23 Dec 2025 14:47:09 -0500 Subject: [PATCH 011/180] Fix relative links in MCP M365 collection doc --- collections/mcp-m365-copilot.collection.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/collections/mcp-m365-copilot.collection.md b/collections/mcp-m365-copilot.collection.md index 6b498657..aaaa594a 100644 --- a/collections/mcp-m365-copilot.collection.md +++ b/collections/mcp-m365-copilot.collection.md @@ -20,21 +20,21 @@ For Microsoft 365 Copilot, this means you can create agents that connect to any ### Prompts -1. **Create Declarative Agent** ([mcp-create-declarative-agent.prompt.md](prompts/mcp-create-declarative-agent.prompt.md)) +1. **Create Declarative Agent** ([mcp-create-declarative-agent.prompt.md](../prompts/mcp-create-declarative-agent.prompt.md)) - Build declarative agents using Microsoft 365 Agents Toolkit - Configure MCP server integration with tool import - Set up OAuth 2.0 or SSO authentication - Configure response semantics for data extraction - Package and deploy agents for testing -2. **Create Adaptive Cards** ([mcp-create-adaptive-cards.prompt.md](prompts/mcp-create-adaptive-cards.prompt.md)) +2. **Create Adaptive Cards** ([mcp-create-adaptive-cards.prompt.md](../prompts/mcp-create-adaptive-cards.prompt.md)) - Design static and dynamic Adaptive Card templates - Configure response semantics (data_path, properties, template_selector) - Use template language for conditionals and data binding - Create responsive cards that work across Copilot surfaces - Implement card actions for user interactions -3. **Deploy and Manage Agents** ([mcp-deploy-manage-agents.prompt.md](prompts/mcp-deploy-manage-agents.prompt.md)) +3. **Deploy and Manage Agents** ([mcp-deploy-manage-agents.prompt.md](../prompts/mcp-deploy-manage-agents.prompt.md)) - Deploy agents via Microsoft 365 admin center - Configure organizational or public store distribution - Manage agent lifecycle (publish, deploy, block, remove) @@ -43,7 +43,7 @@ For Microsoft 365 Copilot, this means you can create agents that connect to any ### Instructions -**MCP M365 Copilot Development Guidelines** ([mcp-m365-copilot.instructions.md](instructions/mcp-m365-copilot.instructions.md)) +**MCP M365 Copilot Development Guidelines** ([mcp-m365-copilot.instructions.md](../instructions/mcp-m365-copilot.instructions.md)) - Best practices for MCP server design and tool selection - File organization and project structure - Response semantics configuration patterns From 9ef6e3936a01ec65d3bf4cb062a12e4077adbf12 Mon Sep 17 00:00:00 2001 From: Troy Taylor Date: Tue, 23 Dec 2025 14:49:22 -0500 Subject: [PATCH 012/180] Fix relative path for 'Deploy and Manage Agents' link --- collections/mcp-m365-copilot.collection.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/collections/mcp-m365-copilot.collection.md b/collections/mcp-m365-copilot.collection.md index aaaa594a..a4c49f8a 100644 --- a/collections/mcp-m365-copilot.collection.md +++ b/collections/mcp-m365-copilot.collection.md @@ -168,7 +168,7 @@ Content management integration: ## Getting Started ### Prerequisites -- Visual Studio Code + return results - Microsoft 365 Agents Toolkit extension (v6.3.x or later) - GitHub account (for OAuth examples) - Microsoft 365 Copilot license From b9763bda063f70ab24670e3a3e43eb848f894cc9 Mon Sep 17 00:00:00 2001 From: Troy Taylor Date: Tue, 23 Dec 2025 14:51:35 -0500 Subject: [PATCH 013/180] Run npm start to regenerate docs and add mcp-m365-copilot collection README --- collections/mcp-m365-copilot.md | 41 +++++++++++++++++++++++++++++++++ docs/README.agents.md | 1 + docs/README.collections.md | 2 +- docs/README.instructions.md | 1 + docs/README.prompts.md | 3 +++ 5 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 collections/mcp-m365-copilot.md diff --git a/collections/mcp-m365-copilot.md b/collections/mcp-m365-copilot.md new file mode 100644 index 00000000..f68c9dd6 --- /dev/null +++ b/collections/mcp-m365-copilot.md @@ -0,0 +1,41 @@ +# MCP-based M365 Agents + +Comprehensive collection for building declarative agents with Model Context Protocol integration for Microsoft 365 Copilot + +**Tags:** mcp, m365-copilot, declarative-agents, api-plugins, model-context-protocol, adaptive-cards + +## Items in this Collection + +| Title | Type | Description | MCP Servers | +| ----- | ---- | ----------- | ----------- | +| [Mcp Create Declarative Agent](../prompts/mcp-create-declarative-agent.prompt.md)
[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/prompt?url=vscode%3Achat-prompt%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fprompts%2Fmcp-create-declarative-agent.prompt.md)
[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/prompt?url=vscode-insiders%3Achat-prompt%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fprompts%2Fmcp-create-declarative-agent.prompt.md) | Prompt | No description | | +| [Mcp Create Adaptive Cards](../prompts/mcp-create-adaptive-cards.prompt.md)
[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/prompt?url=vscode%3Achat-prompt%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fprompts%2Fmcp-create-adaptive-cards.prompt.md)
[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/prompt?url=vscode-insiders%3Achat-prompt%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fprompts%2Fmcp-create-adaptive-cards.prompt.md) | Prompt | No description | | +| [Mcp Deploy Manage Agents](../prompts/mcp-deploy-manage-agents.prompt.md)
[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/prompt?url=vscode%3Achat-prompt%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fprompts%2Fmcp-deploy-manage-agents.prompt.md)
[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/prompt?url=vscode-insiders%3Achat-prompt%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fprompts%2Fmcp-deploy-manage-agents.prompt.md) | Prompt | No description | | +| [MCP-based M365 Copilot Development Guidelines](../instructions/mcp-m365-copilot.instructions.md)
[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/instructions?url=vscode%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fmcp-m365-copilot.instructions.md)
[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/instructions?url=vscode-insiders%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fmcp-m365-copilot.instructions.md) | Instruction | Best practices for building MCP-based declarative agents and API plugins for Microsoft 365 Copilot with Model Context Protocol integration | | +| [MCP M365 Agent Expert](../agents/mcp-m365-agent-expert.agent.md)
[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/agent?url=vscode%3Achat-agent%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fagents%2Fmcp-m365-agent-expert.agent.md)
[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/agent?url=vscode-insiders%3Achat-agent%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fagents%2Fmcp-m365-agent-expert.agent.md) | Agent | Expert assistant for building MCP-based declarative agents for Microsoft 365 Copilot with Model Context Protocol integration [see usage](#mcp-m365-agent-expert) | | + +## Collection Usage + +### MCP M365 Agent Expert + +recommended + +This chat mode provides expert guidance for building MCP-based declarative agents for Microsoft 365 Copilot. + +This chat mode is ideal for: +- Creating new declarative agents with MCP integration +- Designing Adaptive Cards for visual responses +- Configuring OAuth 2.0 or SSO authentication +- Setting up response semantics and data extraction +- Troubleshooting deployment and governance issues +- Learning MCP best practices for M365 Copilot + +To get the best results, consider: +- Using the instruction file to set context for all Copilot interactions +- Using prompts to generate initial agent structure and configurations +- Switching to the expert chat mode for detailed implementation help +- Providing specific details about your MCP server, tools, and business scenario + +--- + +*This collection includes 5 curated items for **MCP-based M365 Agents**.* \ No newline at end of file diff --git a/docs/README.agents.md b/docs/README.agents.md index 9b6fb04b..8581b521 100644 --- a/docs/README.agents.md +++ b/docs/README.agents.md @@ -75,6 +75,7 @@ Custom agents for GitHub Copilot, making it easy for users and organizations to | [Launchdarkly Flag Cleanup](../agents/launchdarkly-flag-cleanup.agent.md)
[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/agent?url=vscode%3Achat-agent%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fagents%2Flaunchdarkly-flag-cleanup.agent.md)
[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/agent?url=vscode-insiders%3Achat-agent%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fagents%2Flaunchdarkly-flag-cleanup.agent.md) | A specialized GitHub Copilot agent that uses the LaunchDarkly MCP server to safely automate feature flag cleanup workflows. This agent determines removal readiness, identifies the correct forward value, and creates PRs that preserve production behavior while removing obsolete flags and updating stale defaults. | [launchdarkly](https://github.com/mcp/launchdarkly/mcp-server)
[![Install MCP](https://img.shields.io/badge/Install-VS_Code-0098FF?style=flat-square)](https://aka.ms/awesome-copilot/install/mcp-vscode?name=launchdarkly&config=%7B%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22--package%22%2C%22%2540launchdarkly%252Fmcp-server%22%2C%22--%22%2C%22mcp%22%2C%22start%22%2C%22--api-key%22%2C%22%2524LD_ACCESS_TOKEN%22%5D%2C%22env%22%3A%7B%7D%7D)
[![Install MCP](https://img.shields.io/badge/Install-VS_Code_Insiders-24bfa5?style=flat-square)](https://aka.ms/awesome-copilot/install/mcp-vscodeinsiders?name=launchdarkly&config=%7B%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22--package%22%2C%22%2540launchdarkly%252Fmcp-server%22%2C%22--%22%2C%22mcp%22%2C%22start%22%2C%22--api-key%22%2C%22%2524LD_ACCESS_TOKEN%22%5D%2C%22env%22%3A%7B%7D%7D)
[![Install MCP](https://img.shields.io/badge/Install-Visual_Studio-C16FDE?style=flat-square)](https://aka.ms/awesome-copilot/install/mcp-visualstudio/mcp-install?%7B%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22--package%22%2C%22%2540launchdarkly%252Fmcp-server%22%2C%22--%22%2C%22mcp%22%2C%22start%22%2C%22--api-key%22%2C%22%2524LD_ACCESS_TOKEN%22%5D%2C%22env%22%3A%7B%7D%7D) | | [Lingo.dev Localization (i18n) Agent](../agents/lingodotdev-i18n.agent.md)
[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/agent?url=vscode%3Achat-agent%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fagents%2Flingodotdev-i18n.agent.md)
[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/agent?url=vscode-insiders%3Achat-agent%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fagents%2Flingodotdev-i18n.agent.md) | Expert at implementing internationalization (i18n) in web applications using a systematic, checklist-driven approach. | lingo
[![Install MCP](https://img.shields.io/badge/Install-VS_Code-0098FF?style=flat-square)](https://aka.ms/awesome-copilot/install/mcp-vscode?name=lingo&config=%7B%22command%22%3A%22%22%2C%22args%22%3A%5B%5D%2C%22env%22%3A%7B%7D%7D)
[![Install MCP](https://img.shields.io/badge/Install-VS_Code_Insiders-24bfa5?style=flat-square)](https://aka.ms/awesome-copilot/install/mcp-vscodeinsiders?name=lingo&config=%7B%22command%22%3A%22%22%2C%22args%22%3A%5B%5D%2C%22env%22%3A%7B%7D%7D)
[![Install MCP](https://img.shields.io/badge/Install-Visual_Studio-C16FDE?style=flat-square)](https://aka.ms/awesome-copilot/install/mcp-visualstudio/mcp-install?%7B%22command%22%3A%22%22%2C%22args%22%3A%5B%5D%2C%22env%22%3A%7B%7D%7D) | | [MAUI Expert](../agents/dotnet-maui.agent.md)
[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/agent?url=vscode%3Achat-agent%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fagents%2Fdotnet-maui.agent.md)
[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/agent?url=vscode-insiders%3Achat-agent%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fagents%2Fdotnet-maui.agent.md) | Support development of .NET MAUI cross-platform apps with controls, XAML, handlers, and performance best practices. | | +| [MCP M365 Agent Expert](../agents/mcp-m365-agent-expert.agent.md)
[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/agent?url=vscode%3Achat-agent%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fagents%2Fmcp-m365-agent-expert.agent.md)
[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/agent?url=vscode-insiders%3Achat-agent%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fagents%2Fmcp-m365-agent-expert.agent.md) | Expert assistant for building MCP-based declarative agents for Microsoft 365 Copilot with Model Context Protocol integration | | | [Mentor mode instructions](../agents/mentor.agent.md)
[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/agent?url=vscode%3Achat-agent%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fagents%2Fmentor.agent.md)
[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/agent?url=vscode-insiders%3Achat-agent%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fagents%2Fmentor.agent.md) | Help mentor the engineer by providing guidance and support. | | | [Meta Agentic Project Scaffold](../agents/meta-agentic-project-scaffold.agent.md)
[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/agent?url=vscode%3Achat-agent%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fagents%2Fmeta-agentic-project-scaffold.agent.md)
[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/agent?url=vscode-insiders%3Achat-agent%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fagents%2Fmeta-agentic-project-scaffold.agent.md) | Meta agentic project creation assistant to help users create and manage project workflows effectively. | | | [Microsoft Agent Framework .NET mode instructions](../agents/microsoft-agent-framework-dotnet.agent.md)
[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/agent?url=vscode%3Achat-agent%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fagents%2Fmicrosoft-agent-framework-dotnet.agent.md)
[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/agent?url=vscode-insiders%3Achat-agent%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fagents%2Fmicrosoft-agent-framework-dotnet.agent.md) | Create, update, refactor, explain or work with code using the .NET version of Microsoft Agent Framework. | | diff --git a/docs/README.collections.md b/docs/README.collections.md index 7bafc1e8..82e15ae6 100644 --- a/docs/README.collections.md +++ b/docs/README.collections.md @@ -30,7 +30,7 @@ Curated collections of related prompts, instructions, and agents organized aroun | [Java Development](../collections/java-development.md) | Comprehensive collection of prompts and instructions for Java development including Spring Boot, Quarkus, testing, documentation, and best practices. | 12 items | java, springboot, quarkus, jpa, junit, javadoc | | [Java MCP Server Development](../collections/java-mcp-development.md) | Complete toolkit for building Model Context Protocol servers in Java using the official MCP Java SDK with reactive streams and Spring Boot integration. | 3 items | java, mcp, model-context-protocol, server-development, sdk, reactive-streams, spring-boot, reactor | | [Kotlin MCP Server Development](../collections/kotlin-mcp-development.md) | Complete toolkit for building Model Context Protocol (MCP) servers in Kotlin using the official io.modelcontextprotocol:kotlin-sdk library. Includes instructions for best practices, a prompt for generating servers, and an expert chat mode for guidance. | 3 items | kotlin, mcp, model-context-protocol, kotlin-multiplatform, server-development, ktor | -| [MCP-based M365 Agents](../collections/mcp-m365-copilot.md) | Comprehensive collection for building declarative agents with Model Context Protocol integration for Microsoft 365 Copilot, including prompts, instruction, and expert chat mode. | 5 items | mcp, m365-copilot, declarative-agents, api-plugins, model-context-protocol, adaptive-cards | +| [MCP-based M365 Agents](../collections/mcp-m365-copilot.md) | Comprehensive collection for building declarative agents with Model Context Protocol integration for Microsoft 365 Copilot | 5 items | mcp, m365-copilot, declarative-agents, api-plugins, model-context-protocol, adaptive-cards | | [PHP MCP Server Development](../collections/php-mcp-development.md) | Comprehensive resources for building Model Context Protocol servers using the official PHP SDK with attribute-based discovery, including best practices, project generation, and expert assistance | 3 items | php, mcp, model-context-protocol, server-development, sdk, attributes, composer | | [Power Apps Code Apps Development](../collections/power-apps-code-apps.md) | Complete toolkit for Power Apps Code Apps development including project scaffolding, development standards, and expert guidance for building code-first applications with Power Platform integration. | 3 items | power-apps, power-platform, typescript, react, code-apps, dataverse, connectors | | [Power Apps Component Framework (PCF) Development](../collections/pcf-development.md) | Complete toolkit for developing custom code components using Power Apps Component Framework for model-driven and canvas apps | 17 items | power-apps, pcf, component-framework, typescript, power-platform | diff --git a/docs/README.instructions.md b/docs/README.instructions.md index 4101f66b..7bdd5e11 100644 --- a/docs/README.instructions.md +++ b/docs/README.instructions.md @@ -99,6 +99,7 @@ Team and project-specific instructions to enhance GitHub Copilot's behavior for | [Makefile Development Instructions](../instructions/makefile.instructions.md)
[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/instructions?url=vscode%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fmakefile.instructions.md)
[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/instructions?url=vscode-insiders%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fmakefile.instructions.md) | Best practices for authoring GNU Make Makefiles | | [Manifest Schema Reference](../instructions/pcf-manifest-schema.instructions.md)
[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/instructions?url=vscode%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fpcf-manifest-schema.instructions.md)
[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/instructions?url=vscode-insiders%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fpcf-manifest-schema.instructions.md) | Complete manifest schema reference for PCF components with all available XML elements | | [Markdown](../instructions/markdown.instructions.md)
[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/instructions?url=vscode%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fmarkdown.instructions.md)
[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/instructions?url=vscode-insiders%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fmarkdown.instructions.md) | Documentation and content creation standards | +| [MCP-based M365 Copilot Development Guidelines](../instructions/mcp-m365-copilot.instructions.md)
[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/instructions?url=vscode%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fmcp-m365-copilot.instructions.md)
[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/instructions?url=vscode-insiders%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fmcp-m365-copilot.instructions.md) | Best practices for building MCP-based declarative agents and API plugins for Microsoft 365 Copilot with Model Context Protocol integration | | [Memory Bank](../instructions/memory-bank.instructions.md)
[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/instructions?url=vscode%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fmemory-bank.instructions.md)
[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/instructions?url=vscode-insiders%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fmemory-bank.instructions.md) | Bank specific coding standards and best practices | | [Microsoft 365 Declarative Agents Development Guidelines](../instructions/declarative-agents-microsoft365.instructions.md)
[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/instructions?url=vscode%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fdeclarative-agents-microsoft365.instructions.md)
[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/instructions?url=vscode-insiders%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fdeclarative-agents-microsoft365.instructions.md) | Comprehensive development guidelines for Microsoft 365 Copilot declarative agents with schema v1.5, TypeSpec integration, and Microsoft 365 Agents Toolkit workflows | | [MongoDB DBA Chat Mode Instructions](../instructions/mongo-dba.instructions.md)
[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/instructions?url=vscode%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fmongo-dba.instructions.md)
[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/instructions?url=vscode-insiders%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fmongo-dba.instructions.md) | Instructions for customizing GitHub Copilot behavior for MONGODB DBA chat mode. | diff --git a/docs/README.prompts.md b/docs/README.prompts.md index 4e3c9800..267af3cc 100644 --- a/docs/README.prompts.md +++ b/docs/README.prompts.md @@ -80,6 +80,9 @@ Ready-to-use prompt templates for specific development scenarios and tasks, defi | [Javascript Typescript Jest](../prompts/javascript-typescript-jest.prompt.md)
[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/prompt?url=vscode%3Achat-prompt%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fprompts%2Fjavascript-typescript-jest.prompt.md)
[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/prompt?url=vscode-insiders%3Achat-prompt%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fprompts%2Fjavascript-typescript-jest.prompt.md) | Best practices for writing JavaScript/TypeScript tests using Jest, including mocking strategies, test structure, and common patterns. | | [JUnit 5+ Best Practices](../prompts/java-junit.prompt.md)
[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/prompt?url=vscode%3Achat-prompt%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fprompts%2Fjava-junit.prompt.md)
[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/prompt?url=vscode-insiders%3Achat-prompt%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fprompts%2Fjava-junit.prompt.md) | Get best practices for JUnit 5 unit testing, including data-driven tests | | [Kotlin MCP Server Project Generator](../prompts/kotlin-mcp-server-generator.prompt.md)
[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/prompt?url=vscode%3Achat-prompt%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fprompts%2Fkotlin-mcp-server-generator.prompt.md)
[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/prompt?url=vscode-insiders%3Achat-prompt%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fprompts%2Fkotlin-mcp-server-generator.prompt.md) | Generate a complete Kotlin MCP server project with proper structure, dependencies, and implementation using the official io.modelcontextprotocol:kotlin-sdk library. | +| [Mcp Create Adaptive Cards](../prompts/mcp-create-adaptive-cards.prompt.md)
[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/prompt?url=vscode%3Achat-prompt%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fprompts%2Fmcp-create-adaptive-cards.prompt.md)
[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/prompt?url=vscode-insiders%3Achat-prompt%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fprompts%2Fmcp-create-adaptive-cards.prompt.md) | | | +| [Mcp Create Declarative Agent](../prompts/mcp-create-declarative-agent.prompt.md)
[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/prompt?url=vscode%3Achat-prompt%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fprompts%2Fmcp-create-declarative-agent.prompt.md)
[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/prompt?url=vscode-insiders%3Achat-prompt%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fprompts%2Fmcp-create-declarative-agent.prompt.md) | | | +| [Mcp Deploy Manage Agents](../prompts/mcp-deploy-manage-agents.prompt.md)
[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/prompt?url=vscode%3Achat-prompt%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fprompts%2Fmcp-deploy-manage-agents.prompt.md)
[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/prompt?url=vscode-insiders%3Achat-prompt%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fprompts%2Fmcp-deploy-manage-agents.prompt.md) | | | | [Memory Keeper](../prompts/remember.prompt.md)
[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/prompt?url=vscode%3Achat-prompt%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fprompts%2Fremember.prompt.md)
[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/prompt?url=vscode-insiders%3Achat-prompt%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fprompts%2Fremember.prompt.md) | Transforms lessons learned into domain-organized memory instructions (global or workspace). Syntax: `/remember [>domain [scope]] lesson clue` where scope is `global` (default), `user`, `workspace`, or `ws`. | | [Memory Merger](../prompts/memory-merger.prompt.md)
[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/prompt?url=vscode%3Achat-prompt%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fprompts%2Fmemory-merger.prompt.md)
[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/prompt?url=vscode-insiders%3Achat-prompt%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fprompts%2Fmemory-merger.prompt.md) | Merges mature lessons from a domain memory file into its instruction file. Syntax: `/memory-merger >domain [scope]` where scope is `global` (default), `user`, `workspace`, or `ws`. | | [Microsoft 365 Declarative Agents Development Kit](../prompts/declarative-agents.prompt.md)
[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/prompt?url=vscode%3Achat-prompt%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fprompts%2Fdeclarative-agents.prompt.md)
[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/prompt?url=vscode-insiders%3Achat-prompt%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fprompts%2Fdeclarative-agents.prompt.md) | Complete development kit for Microsoft 365 Copilot declarative agents with three comprehensive workflows (basic, advanced, validation), TypeSpec support, and Microsoft 365 Agents Toolkit integration | From ec9192e47b1ed71590e95ac374ae3dc77eb854ff Mon Sep 17 00:00:00 2001 From: Kent Yao Date: Tue, 30 Dec 2025 11:29:30 +0800 Subject: [PATCH 014/180] Add Scala 2 instructions --- instructions/scala2.instructions.md | 834 ++++++++++++++++++++++++++++ 1 file changed, 834 insertions(+) create mode 100644 instructions/scala2.instructions.md diff --git a/instructions/scala2.instructions.md b/instructions/scala2.instructions.md new file mode 100644 index 00000000..cc4c1a46 --- /dev/null +++ b/instructions/scala2.instructions.md @@ -0,0 +1,834 @@ +--- +description: 'Scala 2.12/2.13 programming language coding conventions and best practices following Databricks style guide for functional programming, type safety, and production code quality.' +applyTo: '**.scala, **/build.sbt, **/build.sc' +--- + +# Scala Best Practices + +Based on the [Databricks Scala Style Guide](https://github.com/databricks/scala-style-guide) + +## Core Principles + +### Write Simple Code +Code is written once but read and modified multiple times. Optimize for long-term readability and maintainability by writing simple code. + +### Immutability by Default +- Always prefer `val` over `var` +- Use immutable collections from `scala.collection.immutable` +- Case class constructor parameters should NOT be mutable +- Use copy constructor to create modified instances + +```scala +// Good - Immutable case class +case class Person(name: String, age: Int) + +// Bad - Mutable case class +case class Person(name: String, var age: Int) + +// To change values, use copy constructor +val p1 = Person("Peter", 15) +val p2 = p1.copy(age = 16) + +// Good - Immutable collections +val users = List(User("Alice", 30), User("Bob", 25)) +val updatedUsers = users.map(u => u.copy(age = u.age + 1)) +``` + +### Pure Functions +- Functions should be deterministic and side-effect free +- Separate pure logic from effects +- Use explicit types for methods with effects + +```scala +// Good - Pure function +def calculateTotal(items: List[Item]): BigDecimal = + items.map(_.price).sum + +// Bad - Impure function with side effects +def calculateTotal(items: List[Item]): BigDecimal = { + println(s"Calculating total for ${items.size} items") // Side effect + val total = items.map(_.price).sum + saveToDatabase(total) // Side effect + total +} +``` + +## Naming Conventions + +### Classes and Objects + +```scala +// Classes, traits, objects - PascalCase +class ClusterManager +trait Expression +object Configuration + +// Packages - all lowercase ASCII +package com.databricks.resourcemanager + +// Methods/functions - camelCase +def getUserById(id: Long): Option[User] +def processData(input: String): Result + +// Constants - uppercase in companion object +object Configuration { + val DEFAULT_PORT = 10000 + val MAX_RETRIES = 3 + val TIMEOUT_MS = 5000L +} +``` + +### Variables and Parameters + +```scala +// Variables - camelCase, self-evident names +val serverPort = 1000 +val clientPort = 2000 +val maxRetryAttempts = 3 + +// One-character names OK in small, localized scope +for (i <- 0 until 10) { + // ... +} + +// Do NOT use "l" (Larry) - looks like "1", "|", "I" +``` + +### Enumerations + +```scala +// Enumeration object - PascalCase +// Values - UPPER_CASE with underscores +private object ParseState extends Enumeration { + type ParseState = Value + + val PREFIX, + TRIM_BEFORE_SIGN, + SIGN, + VALUE, + UNIT_BEGIN, + UNIT_END = Value +} +``` + +## Syntactic Style + +### Line Length and Spacing + +```scala +// Limit lines to 100 characters +// One space before and after operators +def add(int1: Int, int2: Int): Int = int1 + int2 + +// One space after commas +val list = List("a", "b", "c") + +// One space after colons +def getConf(key: String, defaultValue: String): String = { + // code +} + +// Use 2-space indentation +if (true) { + println("Wow!") +} + +// 4-space indentation for long parameter lists +def newAPIHadoopFile[K, V, F <: NewInputFormat[K, V]]( + path: String, + fClass: Class[F], + kClass: Class[K], + vClass: Class[V], + conf: Configuration = hadoopConfiguration): RDD[(K, V)] = { + // method body +} + +// Class with long parameters +class Foo( + val param1: String, // 4 space indent + val param2: String, + val param3: Array[Byte]) + extends FooInterface // 2 space indent + with Logging { + + def firstMethod(): Unit = { ... } // blank line above +} +``` + +### Rule of 30 + +- A method should contain less than 30 lines of code +- A class should contain less than 30 methods + +### Curly Braces + +```scala +// Always use curly braces for multi-line blocks +if (true) { + println("Wow!") +} + +// Exception: one-line ternary (side-effect free) +val result = if (condition) value1 else value2 + +// Always use braces for try-catch +try { + foo() +} catch { + case e: Exception => handle(e) +} +``` + +### Long Literals + +```scala +// Use uppercase L for long literals +val longValue = 5432L // Do this +val badValue = 5432l // Don't do this - hard to see +``` + +### Parentheses + +```scala +// Methods with side-effects - use parentheses +class Job { + def killJob(): Unit = { ... } // Correct - changes state + def getStatus: JobStatus = { ... } // Correct - no side-effect +} + +// Callsite should match declaration +new Job().killJob() // Correct +new Job().getStatus // Correct +``` + +### Imports + +```scala +// Avoid wildcard imports unless importing 6+ entities +import scala.collection.mutable.{Map, HashMap, ArrayBuffer} + +// OK to use wildcard for implicits or 6+ items +import scala.collection.JavaConverters._ +import java.util.{Map, HashMap, List, ArrayList, Set, HashSet} + +// Always use absolute paths +import scala.util.Random // Good +// import util.Random // Don't use relative + +// Import order (with blank lines): +import java.io.File +import javax.servlet.http.HttpServlet + +import scala.collection.mutable.HashMap +import scala.util.Random + +import org.apache.spark.SparkContext +import org.apache.spark.rdd.RDD + +import com.databricks.MyClass +``` + +### Pattern Matching + +```scala +// Put match on same line if method is entirely pattern match +def test(msg: Message): Unit = msg match { + case TextMessage(text) => handleText(text) + case ImageMessage(url) => handleImage(url) +} + +// Single case closures - same line +list.zipWithIndex.map { case (elem, i) => + // process +} + +// Multiple cases - indent and wrap +list.map { + case a: Foo => processFoo(a) + case b: Bar => processBar(b) + case _ => handleDefault() +} + +// Match on type only - don't expand all args +case class Pokemon(name: String, weight: Int, hp: Int, attack: Int, defense: Int) + +// Bad - brittle when fields change +targets.foreach { + case Pokemon(_, _, hp, _, defense) => + // error prone +} + +// Good - match on type +targets.foreach { + case p: Pokemon => + val loss = sys.min(0, myAttack - p.defense) + p.copy(hp = p.hp - loss) +} +``` + +### Anonymous Functions + +```scala +// Avoid excessive parentheses +// Correct +list.map { item => + transform(item) +} + +// Correct +list.map(item => transform(item)) + +// Wrong - unnecessary braces +list.map(item => { + transform(item) +}) + +// Wrong - excessive nesting +list.map({ item => ... }) +``` + +### Infix Methods + +```scala +// Avoid infix for non-symbolic methods +list.map(func) // Correct +list map func // Wrong + +// OK for operators +arrayBuffer += elem +``` + +## Language Features + +### Avoid apply() on Classes + +```scala +// Avoid apply on classes - hard to trace +class TreeNode { + def apply(name: String): TreeNode = { ... } // Don't do this +} + +// OK on companion objects as factory +object TreeNode { + def apply(name: String): TreeNode = new TreeNode(name) // OK +} +``` + +### override Modifier + +```scala +// Always use override - even for abstract methods +trait Parent { + def hello(data: Map[String, String]): Unit +} + +class Child extends Parent { + // Without override, this might not actually override! + override def hello(data: Map[String, String]): Unit = { + println(data) + } +} +``` + +### Avoid Destructuring in Constructors + +```scala +// Don't use destructuring binds in constructors +class MyClass { + // Bad - creates non-transient Tuple2 + @transient private val (a, b) = someFuncThatReturnsTuple2() + + // Good + @transient private val tuple = someFuncThatReturnsTuple2() + @transient private val a = tuple._1 + @transient private val b = tuple._2 +} +``` + +### Avoid Call-by-Name + +```scala +// Avoid call-by-name parameters +// Bad - caller can't tell if executed once or many times +def print(value: => Int): Unit = { + println(value) + println(value + 1) +} + +// Good - explicit function type +def print(value: () => Int): Unit = { + println(value()) + println(value() + 1) +} +``` + +### Avoid Multiple Parameter Lists + +```scala +// Avoid multiple parameter lists (except for implicits) +// Bad +case class Person(name: String, age: Int)(secret: String) + +// Good +case class Person(name: String, age: Int, secret: String) + +// Exception: separate list for implicits (but avoid implicits!) +def foo(x: Int)(implicit ec: ExecutionContext): Future[Int] +``` + +### Symbolic Methods + +```scala +// Only use for arithmetic operators +class Vector { + def +(other: Vector): Vector = { ... } // OK + def -(other: Vector): Vector = { ... } // OK +} + +// Don't use for other methods +// Bad +channel ! msg +stream1 >>= stream2 + +// Good +channel.send(msg) +stream1.join(stream2) +``` + +### Type Inference + +```scala +// Always type public methods +def getUserById(id: Long): Option[User] = { ... } + +// Always type implicit methods +implicit def stringToInt(s: String): Int = s.toInt + +// Type variables when not obvious (3 second rule) +val user: User = complexComputation() + +// OK to omit when obvious +val count = 5 +val name = "Alice" +``` + +### Return Statements + +```scala +// Avoid return in closures - uses exceptions under the hood +def receive(rpc: WebSocketRPC): Option[Response] = { + tableFut.onComplete { table => + if (table.isFailure) { + return None // Don't do this - wrong thread! + } + } +} + +// Use return as guard to simplify control flow +def doSomething(obj: Any): Any = { + if (obj eq null) { + return null + } + // do something +} + +// Use return to break loops early +while (true) { + if (cond) { + return + } +} +``` + +### Recursion and Tail Recursion + +```scala +// Avoid recursion unless naturally recursive (trees, graphs) +// Use @tailrec for tail-recursive methods +@scala.annotation.tailrec +def max0(data: Array[Int], pos: Int, max: Int): Int = { + if (pos == data.length) { + max + } else { + max0(data, pos + 1, if (data(pos) > max) data(pos) else max) + } +} + +// Prefer explicit loops for clarity +def max(data: Array[Int]): Int = { + var max = Int.MinValue + for (v <- data) { + if (v > max) { + max = v + } + } + max +} +``` + +### Implicits + +```scala +// Avoid implicits unless: +// 1. Building a DSL +// 2. Implicit type parameters (ClassTag, TypeTag) +// 3. Private type conversions within your class + +// If you must use them, don't overload +object ImplicitHolder { + // Bad - can't selectively import + def toRdd(seq: Seq[Int]): RDD[Int] = { ... } + def toRdd(seq: Seq[Long]): RDD[Long] = { ... } +} + +// Good - distinct names +object ImplicitHolder { + def intSeqToRdd(seq: Seq[Int]): RDD[Int] = { ... } + def longSeqToRdd(seq: Seq[Long]): RDD[Long] = { ... } +} +``` + +## Type Safety + +### Algebraic Data Types + +```scala +// Sum types - sealed traits with case classes +sealed trait PaymentMethod +case class CreditCard(number: String, cvv: String) extends PaymentMethod +case class PayPal(email: String) extends PaymentMethod +case class BankTransfer(account: String, routing: String) extends PaymentMethod + +def processPayment(payment: PaymentMethod): Either[Error, Receipt] = payment match { + case CreditCard(number, cvv) => chargeCreditCard(number, cvv) + case PayPal(email) => chargePayPal(email) + case BankTransfer(account, routing) => chargeBankAccount(account, routing) +} + +// Product types - case classes +case class User(id: Long, name: String, email: String, age: Int) +case class Order(id: Long, userId: Long, items: List[Item], total: BigDecimal) +``` + +### Option over null + +```scala +// Use Option instead of null +def findUserById(id: Long): Option[User] = { + database.query(id) +} + +// Use Option() to guard against nulls +def myMethod1(input: String): Option[String] = Option(transform(input)) + +// Don't use Some() - it won't protect against null +def myMethod2(input: String): Option[String] = Some(transform(input)) // Bad + +// Pattern matching on Option +def processUser(id: Long): String = findUserById(id) match { + case Some(user) => s"Found: ${user.name}" + case None => "User not found" +} + +// Don't call get() unless absolutely sure +val user = findUserById(123).get // Dangerous! + +// Use getOrElse, map, flatMap, fold instead +val name = findUserById(123).map(_.name).getOrElse("Unknown") +``` + +### Error Handling with Either + +```scala +sealed trait ValidationError +case class InvalidEmail(email: String) extends ValidationError +case class InvalidAge(age: Int) extends ValidationError +case class MissingField(field: String) extends ValidationError + +def validateUser(data: Map[String, String]): Either[ValidationError, User] = { + for { + name <- data.get("name").toRight(MissingField("name")) + email <- data.get("email").toRight(MissingField("email")) + validEmail <- validateEmail(email) + ageStr <- data.get("age").toRight(MissingField("age")) + age <- ageStr.toIntOption.toRight(InvalidAge(-1)) + } yield User(name, validEmail, age) +} +``` + +### Try vs Exceptions + +```scala +// Don't return Try from APIs +// Bad +def getUser(id: Long): Try[User] + +// Good - explicit throws +@throws(classOf[DatabaseConnectionException]) +def getUser(id: Long): Option[User] + +// Use NonFatal for catching exceptions +import scala.util.control.NonFatal + +try { + dangerousOperation() +} catch { + case NonFatal(e) => + logger.error("Operation failed", e) + case e: InterruptedException => + // handle interruption +} +``` + +## Collections + +### Prefer Immutable Collections + +```scala +import scala.collection.immutable._ + +// Good +val numbers = List(1, 2, 3, 4, 5) +val doubled = numbers.map(_ * 2) +val evens = numbers.filter(_ % 2 == 0) + +val userMap = Map( + 1L -> "Alice", + 2L -> "Bob" +) +val updated = userMap + (3L -> "Charlie") + +// Use Stream (Scala 2.12) or LazyList (Scala 2.13) for lazy sequences +val fibonacci: LazyList[BigInt] = + BigInt(0) #:: BigInt(1) #:: fibonacci.zip(fibonacci.tail).map { case (a, b) => a + b } + +val first10 = fibonacci.take(10).toList +``` + +### Monadic Chaining + +```scala +// Avoid chaining more than 3 operations +// Break after flatMap +// Don't chain with if-else blocks + +// Bad - too complex +database.get(name).flatMap { elem => + elem.data.get("address").flatMap(Option.apply) +} + +// Good - more readable +def getAddress(name: String): Option[String] = { + if (!database.contains(name)) { + return None + } + + database(name).data.get("address") match { + case Some(null) => None + case Some(addr) => Option(addr) + case None => None + } +} + +// Don't chain with if-else +// Bad +if (condition) { + Seq(1, 2, 3) +} else { + Seq(1, 2, 3) +}.map(_ + 1) + +// Good +val seq = if (condition) Seq(1, 2, 3) else Seq(4, 5, 6) +seq.map(_ + 1) +``` + +## Performance + +### Use while Loops + +```scala +// For performance-critical code, use while instead of for/map +val arr = Array.fill(1000)(Random.nextInt()) + +// Slow +val newArr = arr.zipWithIndex.map { case (elem, i) => + if (i % 2 == 0) 0 else elem +} + +// Fast +val newArr = new Array[Int](arr.length) +var i = 0 +while (i < arr.length) { + newArr(i) = if (i % 2 == 0) 0 else arr(i) + i += 1 +} +``` + +### Option vs null + +```scala +// For performance-critical code, prefer null over Option +class Foo { + @javax.annotation.Nullable + private[this] var nullableField: Bar = _ +} +``` + +### Use private[this] + +```scala +// private[this] generates fields, not accessor methods +class MyClass { + private val field1 = ... // Might use accessor + private[this] val field2 = ... // Direct field access + + def perfSensitiveMethod(): Unit = { + var i = 0 + while (i < 1000000) { + field2 // Guaranteed field access + i += 1 + } + } +} +``` + +### Java Collections + +```scala +// For performance, prefer Java collections +import java.util.{ArrayList, HashMap} + +val list = new ArrayList[String]() +val map = new HashMap[String, Int]() +``` + +## Concurrency + +### Prefer ConcurrentHashMap + +```scala +// Use java.util.concurrent.ConcurrentHashMap +private[this] val map = new java.util.concurrent.ConcurrentHashMap[String, String] + +// Or synchronized map for low contention +private[this] val map = java.util.Collections.synchronizedMap( + new java.util.HashMap[String, String] +) +``` + +### Explicit Synchronization + +```scala +class Manager { + private[this] var count = 0 + private[this] val map = new java.util.HashMap[String, String] + + def update(key: String, value: String): Unit = synchronized { + map.put(key, value) + count += 1 + } + + def getCount: Int = synchronized { count } +} +``` + +### Atomic Variables + +```scala +import java.util.concurrent.atomic._ + +// Prefer Atomic over @volatile +val initialized = new AtomicBoolean(false) + +// Clearly express only-once execution +if (!initialized.getAndSet(true)) { + initialize() +} +``` + +## Testing + +### Intercept Specific Exceptions + +```scala +import org.scalatest._ + +// Bad - too broad +intercept[Exception] { + thingThatThrows() +} + +// Good - specific type +intercept[IllegalArgumentException] { + thingThatThrows() +} +``` + +## SBT Configuration + +```scala +// build.sbt +ThisBuild / version := "0.1.0-SNAPSHOT" +ThisBuild / scalaVersion := "2.13.12" +ThisBuild / organization := "com.example" + +lazy val root = (project in file(".")) + .settings( + name := "my-application", + + libraryDependencies ++= Seq( + "org.typelevel" %% "cats-core" % "2.10.0", + "org.typelevel" %% "cats-effect" % "3.5.2", + + // Testing + "org.scalatest" %% "scalatest" % "3.2.17" % Test, + "org.scalatestplus" %% "scalacheck-1-17" % "3.2.17.0" % Test + ), + + scalacOptions ++= Seq( + "-encoding", "UTF-8", + "-feature", + "-unchecked", + "-deprecation", + "-Xfatal-warnings" + ) + ) +``` + +## Miscellaneous + +### Use nanoTime + +```scala +// Use nanoTime for durations, not currentTimeMillis +val start = System.nanoTime() +doWork() +val elapsed = System.nanoTime() - start + +import java.util.concurrent.TimeUnit +val elapsedMs = TimeUnit.NANOSECONDS.toMillis(elapsed) +``` + +### URI over URL + +```scala +// Use URI instead of URL (URL.equals does DNS lookup!) +val uri = new java.net.URI("http://example.com") +// Not: val url = new java.net.URL("http://example.com") +``` + +## Summary + +1. **Write simple code** - Optimize for readability and maintainability +2. **Use immutable data** - val, immutable collections, case classes +3. **Avoid language features** - Limit implicits, avoid symbolic methods +4. **Type public APIs** - Explicit types for methods and fields +5. **Prefer explicit over implicit** - Clear is better than concise +6. **Use standard libraries** - Don't reinvent the wheel +7. **Follow naming conventions** - PascalCase, camelCase, UPPER_CASE +8. **Keep methods small** - Rule of 30 +9. **Handle errors explicitly** - Option, Either, exceptions with @throws +10. **Profile before optimizing** - Measure, don't guess + +For complete details, see the [Databricks Scala Style Guide](https://github.com/databricks/scala-style-guide). From 5e0561a41864394cbb7857c2b1bbd6f878a2e336 Mon Sep 17 00:00:00 2001 From: Kent Yao Date: Tue, 30 Dec 2025 11:48:03 +0800 Subject: [PATCH 015/180] Update instructions/scala2.instructions.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- instructions/scala2.instructions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/instructions/scala2.instructions.md b/instructions/scala2.instructions.md index cc4c1a46..2a16663c 100644 --- a/instructions/scala2.instructions.md +++ b/instructions/scala2.instructions.md @@ -261,7 +261,7 @@ targets.foreach { // Good - match on type targets.foreach { case p: Pokemon => - val loss = sys.min(0, myAttack - p.defense) + val loss = math.min(0, myAttack - p.defense) p.copy(hp = p.hp - loss) } ``` From 1653defea5344f3ee73088adfbb10af7a2924a20 Mon Sep 17 00:00:00 2001 From: Kent Yao Date: Tue, 30 Dec 2025 11:54:35 +0800 Subject: [PATCH 016/180] Update generated README files --- docs/README.instructions.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/README.instructions.md b/docs/README.instructions.md index 4101f66b..82d6b058 100644 --- a/docs/README.instructions.md +++ b/docs/README.instructions.md @@ -139,6 +139,7 @@ Team and project-specific instructions to enhance GitHub Copilot's behavior for | [Ruby on Rails](../instructions/ruby-on-rails.instructions.md)
[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/instructions?url=vscode%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fruby-on-rails.instructions.md)
[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/instructions?url=vscode-insiders%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fruby-on-rails.instructions.md) | Ruby on Rails coding conventions and guidelines | | [Rust Coding Conventions and Best Practices](../instructions/rust.instructions.md)
[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/instructions?url=vscode%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Frust.instructions.md)
[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/instructions?url=vscode-insiders%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Frust.instructions.md) | Rust programming language coding conventions and best practices | | [Rust MCP Server Development Best Practices](../instructions/rust-mcp-server.instructions.md)
[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/instructions?url=vscode%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Frust-mcp-server.instructions.md)
[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/instructions?url=vscode-insiders%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Frust-mcp-server.instructions.md) | Best practices for building Model Context Protocol servers in Rust using the official rmcp SDK with async/await patterns | +| [Scala Best Practices](../instructions/scala2.instructions.md)
[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/instructions?url=vscode%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fscala2.instructions.md)
[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/instructions?url=vscode-insiders%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fscala2.instructions.md) | Scala 2.12/2.13 programming language coding conventions and best practices following Databricks style guide for functional programming, type safety, and production code quality. | | [Secure Coding and OWASP Guidelines](../instructions/security-and-owasp.instructions.md)
[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/instructions?url=vscode%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fsecurity-and-owasp.instructions.md)
[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/instructions?url=vscode-insiders%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fsecurity-and-owasp.instructions.md) | Comprehensive secure coding instructions for all languages and frameworks, based on OWASP Top 10 and industry best practices. | | [Self-explanatory Code Commenting Instructions](../instructions/self-explanatory-code-commenting.instructions.md)
[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/instructions?url=vscode%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fself-explanatory-code-commenting.instructions.md)
[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/instructions?url=vscode-insiders%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fself-explanatory-code-commenting.instructions.md) | Guidelines for GitHub Copilot to write comments to achieve self-explanatory code with less comments. Examples are in JavaScript but it should work on any language that has comments. | | [Shell Scripting Guidelines](../instructions/shell.instructions.md)
[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/instructions?url=vscode%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fshell.instructions.md)
[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/instructions?url=vscode-insiders%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fshell.instructions.md) | Shell scripting best practices and conventions for bash, sh, zsh, and other shells | From b070d62b6a0b3dfae2eed5a147f217788f44729a Mon Sep 17 00:00:00 2001 From: Abbas Jafry Date: Wed, 31 Dec 2025 03:27:16 +0530 Subject: [PATCH 017/180] feat(agents): add Salesforce Expert agent --- agents/salesforce-expert.agent.md | 124 ++++++++++++++++++++++++++++++ docs/README.agents.md | 1 + 2 files changed, 125 insertions(+) create mode 100644 agents/salesforce-expert.agent.md diff --git a/agents/salesforce-expert.agent.md b/agents/salesforce-expert.agent.md new file mode 100644 index 00000000..a04f51ae --- /dev/null +++ b/agents/salesforce-expert.agent.md @@ -0,0 +1,124 @@ +--- +description: "Provide expert Salesforce Platform guidance, including Apex Enterprise Patterns, LWC, integration, and Aura-to-LWC migration." +name: "Salesforce Expert Agent" +tools: ['vscode', 'execute', 'read', 'edit', 'search', 'web', 'sfdx-mcp/*', 'agent', 'todo'] +--- + +# Salesforce Expert Agent - System Prompt + +You are an **Elite Salesforce Technical Architect and Grandmaster Developer**. Your role is to provide secure, scalable, and high-performance solutions that strictly adhere to Salesforce Enterprise patterns and best practices. + +You do not just write code; you engineer solutions. You assume the user requires production-ready, bulkified, and secure code unless explicitly told otherwise. + +## Core Responsibilities & Persona + +- **The Architect**: You favor separation of concerns (Service Layer, Domain Layer, Selector Layer) over "fat triggers" or "god classes." +- **The Security Officer**: You enforce Field Level Security (FLS), Sharing Rules, and CRUD checks in every operation. You strictly forbid hardcoded IDs and secrets. +- **The Mentor**: When architectural decisions are ambiguous, you use a "Chain of Thought" approach to explain *why* a specific pattern (e.g., Queueable vs. Batch) was chosen. +- **The Modernizer**: You advocate for Lightning Web Components (LWC) over Aura, and you guide users through Aura-to-LWC migrations with best practices. +- **The Integrator**: You design robust, resilient integrations using Named Credentials, Platform Events, and REST/SOAP APIs, following best practices for error handling and retries. +- **The Performance Guru**: You optimize SOQL queries, minimize CPU time, and manage heap size effectively to stay within Salesforce governor limits. +- **The Release Aware Developer**: You are always up-to-date with the latest Salesforce releases and features, leveraging them to enhance solutions. You favor using latest features, classes, and methods introduced in recent releases. + +## Capabilities and Expertise Areas + +### 1. Advanced Apex Development +- **Frameworks**: Enforce **fflib** (Enterprise Design Patterns) concepts. Logic belongs in Service/Domain layers, not Triggers or Controllers. +- **Asynchronous**: Expert use of Batch, Queueable, Future, and Schedulable. + - *Rule*: Prefer `Queueable` over `@future` for complex chaining and object support. +- **Bulkification**: ALL code must handle `List`. Never assume single-record context. +- **Governor Limits**: Proactively manage heap size, CPU time, and SOQL limits. Use Maps for O(1) lookups to avoid O(n^2) nested loops. + +### 2. Modern Frontend (LWC & Mobile) +- **Standards**: Strict adherence to **LDS (Lightning Data Service)** and **SLDS (Salesforce Lightning Design System)**. +- **No jQuery/DOM**: Strictly forbid direct DOM manipulation where LWC directives (`if:true`, `for:each`) or `querySelector` can be used. +- **Aura to LWC Migration**: + - Analyze Aura `v:attributes` and map them to LWC `@api` properties. + - Replace Aura Events (``) with standard DOM `CustomEvent`. + - Replace Data Service tags with `@wire(getRecord)`. + +### 3. Data Model & Security +- **Security First**: + - Always use `WITH SECURITY_ENFORCED` or `Security.stripInaccessible` for queries. + - Check `Schema.sObjectType.X.isCreateable()` before DML. + - Use `with sharing` by default on all classes. +- **Modeling**: Enforce Third Normal Form (3NF) where possible. Prefer **Custom Metadata Types** over List Custom Settings for configuration. + +### 4. Integration Excellence +- **Protocols**: REST (Named Credentials required), SOAP, and Platform Events. +- **Resilience**: Implement **Circuit Breaker** patterns and retry mechanisms for callouts. +- **Security**: Never output raw secrets. Use `Named Credentials` or `External Credentials`. + +## Operational Constraints + +### Code Generation Rules +1. **Bulkification**: Code must *always* be bulkified. + - *Bad*: `updateAccount(Account a)` + - *Good*: `updateAccounts(List accounts)` +2. **Hardcoding**: NEVER hardcode IDs (e.g., `'001...'`). Use `Schema.SObjectType` describes or Custom Labels/Metadata. +3. **Testing**: + - Target **100% Code Coverage** for critical paths. + - NEVER use `SeeAllData=true`. + - Use `Assert` class (e.g., `Assert.areEqual`) instead of `System.assert`. + - Mock all external callouts using `HttpCalloutMock`. + +### Interaction Guidelines + +When asked to generate solutions: +1. **Brief Context**: State what the code achieves. +2. **The Code**: Production-ready, well-commented, following the Naming Conventions below. +3. **Architecture Check**: Briefly mention design choices (e.g., "Used a Selector layer to centralize queries"). + +## Reference: Coding Standards + +### Naming Conventions +- **Classes**: `PascalCase` (e.g., `AccountService`, `OpportunityTriggerHandler`). +- **Methods/Variables**: `camelCase` (e.g., `calculateRevenue`, `accountList`). +- **Constants**: `UPPER_SNAKE_CASE` (e.g., `MAX_RETRY_COUNT`). +- **Triggers**: `ObjectName` + `Trigger` (e.g., `ContactTrigger`). + +### Apex Anti-Patterns to Avoid +- **DML/SOQL inside Loops**: Immediate rejection. +- **Generic Exception Handling**: Avoid empty `catch` blocks. +- **Magic Numbers**: Use Constants or Custom Labels. + +## Example Scenario: Aura to LWC Migration + +**User**: "Migrate this Aura component that saves a contact to LWC." + +**Agent**: +"I will migrate this to LWC using the `lightning-record-edit-form` for efficiency and LDS for caching, replacing the imperative Apex controller where possible. + +**LWC HTML (`contactCreator.html`)**: +```html + +``` +**LWC JavaScript (`contactCreator.js`)**: +```javascript +import { LightningElement } from 'lwc'; +import { ShowToastEvent } from 'lightning/platformShowToastEvent'; + +export default class ContactCreator extends LightningElement { + handleSuccess(event) { + const evt = new ShowToastEvent({ + title: 'Success', + message: 'Contact created! Id: ' + event.detail.id, + variant: 'success', + }); + this.dispatchEvent(evt); + } +} +``` diff --git a/docs/README.agents.md b/docs/README.agents.md index 9b6fb04b..405402af 100644 --- a/docs/README.agents.md +++ b/docs/README.agents.md @@ -111,6 +111,7 @@ Custom agents for GitHub Copilot, making it easy for users and organizations to | [Ruby MCP Expert](../agents/ruby-mcp-expert.agent.md)
[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/agent?url=vscode%3Achat-agent%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fagents%2Fruby-mcp-expert.agent.md)
[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/agent?url=vscode-insiders%3Achat-agent%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fagents%2Fruby-mcp-expert.agent.md) | Expert assistance for building Model Context Protocol servers in Ruby using the official MCP Ruby SDK gem with Rails integration. | | | [Rust Beast Mode](../agents/rust-gpt-4.1-beast-mode.agent.md)
[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/agent?url=vscode%3Achat-agent%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fagents%2Frust-gpt-4.1-beast-mode.agent.md)
[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/agent?url=vscode-insiders%3Achat-agent%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fagents%2Frust-gpt-4.1-beast-mode.agent.md) | Rust GPT-4.1 Coding Beast Mode for VS Code | | | [Rust MCP Expert](../agents/rust-mcp-expert.agent.md)
[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/agent?url=vscode%3Achat-agent%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fagents%2Frust-mcp-expert.agent.md)
[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/agent?url=vscode-insiders%3Achat-agent%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fagents%2Frust-mcp-expert.agent.md) | Expert assistant for Rust MCP server development using the rmcp SDK with tokio async runtime | | +| [Salesforce Expert Agent](../agents/salesforce-expert.agent.md)
[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/agent?url=vscode%3Achat-agent%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fagents%2Fsalesforce-expert.agent.md)
[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/agent?url=vscode-insiders%3Achat-agent%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fagents%2Fsalesforce-expert.agent.md) | Provide expert Salesforce Platform guidance, including Apex Enterprise Patterns, LWC, integration, and Aura-to-LWC migration. | | | [SE: Architect](../agents/se-system-architecture-reviewer.agent.md)
[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/agent?url=vscode%3Achat-agent%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fagents%2Fse-system-architecture-reviewer.agent.md)
[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/agent?url=vscode-insiders%3Achat-agent%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fagents%2Fse-system-architecture-reviewer.agent.md) | System architecture review specialist with Well-Architected frameworks, design validation, and scalability analysis for AI and distributed systems | | | [SE: DevOps/CI](../agents/se-gitops-ci-specialist.agent.md)
[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/agent?url=vscode%3Achat-agent%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fagents%2Fse-gitops-ci-specialist.agent.md)
[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/agent?url=vscode-insiders%3Achat-agent%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fagents%2Fse-gitops-ci-specialist.agent.md) | DevOps specialist for CI/CD pipelines, deployment debugging, and GitOps workflows focused on making deployments boring and reliable | | | [SE: Product Manager](../agents/se-product-manager-advisor.agent.md)
[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/agent?url=vscode%3Achat-agent%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fagents%2Fse-product-manager-advisor.agent.md)
[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/agent?url=vscode-insiders%3Achat-agent%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fagents%2Fse-product-manager-advisor.agent.md) | Product management guidance for creating GitHub issues, aligning business value with user needs, and making data-driven product decisions | | From fabc2986dcf395800c4a91d53d4401367e033a66 Mon Sep 17 00:00:00 2001 From: Abbas Jafry Date: Wed, 31 Dec 2025 03:50:09 +0530 Subject: [PATCH 018/180] Added instructions for Salesforce LWC development --- docs/README.instructions.md | 1 + instructions/lwc.instructions.md | 349 +++++++++++++++++++++++++++++++ 2 files changed, 350 insertions(+) create mode 100644 instructions/lwc.instructions.md diff --git a/docs/README.instructions.md b/docs/README.instructions.md index 4101f66b..10b97d60 100644 --- a/docs/README.instructions.md +++ b/docs/README.instructions.md @@ -96,6 +96,7 @@ Team and project-specific instructions to enhance GitHub Copilot's behavior for | [Kubernetes Deployment Best Practices](../instructions/kubernetes-deployment-best-practices.instructions.md)
[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/instructions?url=vscode%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fkubernetes-deployment-best-practices.instructions.md)
[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/instructions?url=vscode-insiders%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fkubernetes-deployment-best-practices.instructions.md) | Comprehensive best practices for deploying and managing applications on Kubernetes. Covers Pods, Deployments, Services, Ingress, ConfigMaps, Secrets, health checks, resource limits, scaling, and security contexts. | | [LangChain Python Instructions](../instructions/langchain-python.instructions.md)
[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/instructions?url=vscode%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Flangchain-python.instructions.md)
[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/instructions?url=vscode-insiders%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Flangchain-python.instructions.md) | Instructions for using LangChain with Python | | [Limitations](../instructions/pcf-limitations.instructions.md)
[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/instructions?url=vscode%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fpcf-limitations.instructions.md)
[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/instructions?url=vscode-insiders%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fpcf-limitations.instructions.md) | Limitations and restrictions of Power Apps Component Framework | +| [LWC Development](../instructions/lwc.instructions.md)
[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/instructions?url=vscode%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Flwc.instructions.md)
[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/instructions?url=vscode-insiders%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Flwc.instructions.md) | Guidelines and best practices for developing Lightning Web Components (LWC) on Salesforce Platform. | | [Makefile Development Instructions](../instructions/makefile.instructions.md)
[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/instructions?url=vscode%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fmakefile.instructions.md)
[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/instructions?url=vscode-insiders%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fmakefile.instructions.md) | Best practices for authoring GNU Make Makefiles | | [Manifest Schema Reference](../instructions/pcf-manifest-schema.instructions.md)
[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/instructions?url=vscode%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fpcf-manifest-schema.instructions.md)
[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/instructions?url=vscode-insiders%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fpcf-manifest-schema.instructions.md) | Complete manifest schema reference for PCF components with all available XML elements | | [Markdown](../instructions/markdown.instructions.md)
[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/instructions?url=vscode%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fmarkdown.instructions.md)
[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/instructions?url=vscode-insiders%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fmarkdown.instructions.md) | Documentation and content creation standards | diff --git a/instructions/lwc.instructions.md b/instructions/lwc.instructions.md new file mode 100644 index 00000000..7316752f --- /dev/null +++ b/instructions/lwc.instructions.md @@ -0,0 +1,349 @@ +--- +description: Guidelines and best practices for developing Lightning Web Components (LWC) on Salesforce Platform. +applyTo: 'force-app/main/default/lwc/**' + +--- + +# LWC Development + +## General Instructions + +- Each LWC should reside in its own folder under `force-app/main/default/lwc/`. +- The folder name should match the component name (e.g., `myComponent` for `myComponent`). +- Each component folder should contain the following files: + - `myComponent.html`: The HTML template file. + - `myComponent.js`: The JavaScript controller file. + - `myComponent.js-meta.xml`: The metadata configuration file. + - Optional: `myComponent.css` for component-specific styles. + - Optional: `myComponent.test.js` for Jest unit tests. + +## Development Best Practices +### Component Design +- **Single Responsibility**: Each component should have a single, well-defined purpose. +- **Reusability**: Design components to be reusable across different parts of the application. +- **Composition**: Prefer composing smaller components into larger ones rather than creating monolithic components. +- **Public API**: Use `@api` decorators to expose properties and methods that need to be accessed by parent components. +- **Private State**: Use `@track` for reactive properties that are internal to the component. + +### Performance Optimization +- **Lazy Loading**: Load components only when needed to improve initial load times. +- **Efficient Rendering**: Minimize DOM updates by batching changes and using conditional rendering. +- **Avoid Unnecessary Re-renders**: Use getters and setters wisely to prevent unnecessary re-renders. +- **Use Lightning Data Service (LDS)**: Prefer LDS for data access to leverage built-in caching and performance optimizations. + +### Security Considerations +- **Sanitize Inputs**: Always sanitize user inputs to prevent XSS attacks. +- **Use `@wire`**: Prefer using `@wire` for data access to ensure security and compliance with Salesforce's security model. +- **Avoid Direct DOM Manipulation**: Use LWC's reactive properties and templates instead of manipulating the DOM directly. +# Lightning Web Component (LWC) Development Best Practices + +## Core Principles + +### 1. Use Lightning Components Over HTML Tags +Always prefer Lightning Web Component library components over plain HTML elements for consistency, accessibility, and future-proofing. + +#### ✅ Recommended Approach +```html + + + + + +``` + +#### ❌ Avoid Plain HTML +```html + + + + +``` + +### 2. Lightning Component Mapping Guide + +| HTML Element | Lightning Component | Key Attributes | +|--------------|-------------------|----------------| +| `
Aaron Powell
Aaron Powell

đŸ’» 🚧 📆 📣
Muhammad Ubaid Raza
Muhammad Ubaid Raza

đŸ’»
Harald Kirschner
Harald Kirschner

đŸ’»
Matteo Bianchi
Matteo Bianchi

đŸ’»
Aung Myo Kyaw
Aung Myo Kyaw

đŸ’»
Daniel Scott-Raynsford
Daniel Scott-Raynsford

đŸ’»
Burke Holland
Burke Holland

đŸ’»
Aaron Powell
Aaron Powell

🎭 🎁 📖 🚇 🧭 🚧 ⌚
Troy Simeon Taylor
Troy Simeon Taylor

🎭 🎁 🧭 ⌚
Peter Strömberg
Peter Strömberg

🎭 🎁 🧭 ⌚
Daniel Scott-Raynsford
Daniel Scott-Raynsford

🎭 🎁 🧭 ⌚
John Haugabook
John Haugabook

🧭 ⌚
Muhammad Ubaid Raza
Muhammad Ubaid Raza

🎭 🧭
Aung Myo Kyaw
Aung Myo Kyaw

🎭 ⌚
Peter Strömberg
Peter Strömberg

đŸ’»
Daniel Meppiel
Daniel Meppiel

đŸ’»
James Montemagno
James Montemagno

đŸ’»
Vamshi Verma
Vamshi Verma

đŸ’»
Yohan Lasorsa
Yohan Lasorsa

đŸ’»
Oren Me
Oren Me

đŸ’»
Mike Rousos
Mike Rousos

đŸ’»
Harald Kirschner
Harald Kirschner

📖 🚧
Burke Holland
Burke Holland

🎭 🚇 🧭 ⌚
Daniel Meppiel
Daniel Meppiel

⌚
James Montemagno
James Montemagno

🎭 📖 🧭 ⌚
Vamshi Verma
Vamshi Verma

🧭 ⌚
Yohan Lasorsa
Yohan Lasorsa

🧭 ⌚
spectatora
spectatora

🎭 🚧
Guilherme do Amaral Alves
Guilherme do Amaral Alves

đŸ’»
Troy Simeon Taylor
Troy Simeon Taylor

đŸ’»
Ambily
Ambily

đŸ’»
Tugdual Grall
Tugdual Grall

đŸ’»
Tianqi Zhang
Tianqi Zhang

đŸ’»
Shubham Gaikwad
Shubham Gaikwad

đŸ’»
Saul Dolgin
Saul Dolgin

đŸ’»
Ambily
Ambily

🎭 🧭
Oren Me
Oren Me

🎭 🧭
Mike Rousos
Mike Rousos

🧭 ⌚
Justin Yoo
Justin Yoo

🧭
Guilherme do Amaral Alves
Guilherme do Amaral Alves

🧭
Griffin Ashe
Griffin Ashe

🎭 🎁
Ashley Childress
Ashley Childress

🎭 📖 🧭
NULLchimp
NULLchimp

đŸ’»
Matt Vevang
Matt Vevang

đŸ’»
Justin Yoo
Justin Yoo

đŸ’»
Gisela Torres
Gisela Torres

đŸ’»
Debbie O'Brien
Debbie O'Brien

đŸ’»
Allen Greaves
Allen Greaves

đŸ’»
Amelia Payne
Amelia Payne

đŸ’»
Adrien Clerbois
Adrien Clerbois

🎭 📖 ⌚
ANGELELLI David
ANGELELLI David

🎭
André Silva
André Silva

🎭 🧭
Matt Vevang
Matt Vevang

🧭
Maximilian Irro
Maximilian Irro

🧭
NULLchimp
NULLchimp

🎭
Saul Dolgin
Saul Dolgin

🎭 🧭 ⌚
Sebastien DEGODEZ
Sebastien DEGODEZ

đŸ’»
Sebastian GrÀf
Sebastian GrÀf

đŸ’»
Salih İbrahimbaß
Salih İbrahimbaß

đŸ’»
Robert Altman
Robert Altman

đŸ’»
Rob Simpson
Rob Simpson

đŸ’»
Rick Smit
Rick Smit

đŸ’»
Peter Smulovics
Peter Smulovics

đŸ’»
Shubham Gaikwad
Shubham Gaikwad

🎭 🧭 ⌚
Theo van Kraay
Theo van Kraay

🧭
Tianqi Zhang
Tianqi Zhang

🎭
Tugdual Grall
Tugdual Grall

🧭 ⌚
Will äżć“„
Will äżć“„

🎭 ⌚
Yuta Matsumura
Yuta Matsumura

🧭
hizahizi-hizumi
hizahizi-hizumi

🧭
Peli de Halleux
Peli de Halleux

đŸ’»
Paulo Morgado
Paulo Morgado

đŸ’»
Nick Taylor
Nick Taylor

đŸ’»
Mike Parker
Mike Parker

đŸ’»
Mike Kistler
Mike Kistler

đŸ’»
Michael Fairchild
Michael Fairchild

đŸ’»
Michael A. Volz (Flynn)
Michael A. Volz (Flynn)

đŸ’»
é»ƒć„æ—» Vincent Huang
é»ƒć„æ—» Vincent Huang

⌚
Bruno Borges
Bruno Borges

🎁 🧭
Steve Magne
Steve Magne

📖 🧭
Shane Neuville
Shane Neuville

🎭 🧭
Allen Greaves
Allen Greaves

🎭 🧭
Amelia Payne
Amelia Payne

🎭
Brooke Hamilton
Brooke Hamilton

🧭
4regab
4regab

đŸ’»
Theo van Kraay
Theo van Kraay

đŸ’»
Troy Witthoeft (glsauto)
Troy Witthoeft (glsauto)

đŸ’»
TĂ i LĂȘ
TĂ i LĂȘ

đŸ’»
Udaya Veeramreddygari
Udaya Veeramreddygari

đŸ’»
Waren Gonzaga
Waren Gonzaga

đŸ’»
Will äżć“„
Will äżć“„

đŸ’»
Christopher Harrison
Christopher Harrison

🧭
Dan
Dan

🧭
Dan Wahlin
Dan Wahlin

🎭
Debbie O'Brien
Debbie O'Brien

🎭 🧭 ⌚
Ed Harrod
Ed Harrod

⌚
Genevieve Warren
Genevieve Warren

⌚
Guillaume
Guillaume

🎭 ⌚
Yuki Omoto
Yuki Omoto

đŸ’»
Meii
Meii

đŸ’»
samqbush
samqbush

đŸ’»
sdanzo-hrb
sdanzo-hrb

đŸ’»
voidfnc
voidfnc

đŸ’»
Wendy Breiding
Wendy Breiding

đŸ’»
Ankur Sharma
Ankur Sharma

đŸ’»
é»ƒć„æ—» Vincent Huang
é»ƒć„æ—» Vincent Huang

đŸ’»
읎상현
읎상현

đŸ’»
Abdi Daud
Abdi Daud

đŸ’»
Adrien Clerbois
Adrien Clerbois

đŸ’»
Alan Sprecacenere
Alan Sprecacenere

đŸ’»
André Silva
André Silva

đŸ’»
Antoine Rey
Antoine Rey

đŸ’»
Artem Saveliev
Artem Saveliev

đŸ’»
Bruno Borges
Bruno Borges

đŸ’»
Christophe Peugnet
Christophe Peugnet

đŸ’»
Chtive
Chtive

đŸ’»
Craig Bekker
Craig Bekker

đŸ’»
Dan
Dan

đŸ’»
Eldrick Wega
Eldrick Wega

đŸ’»
Felix Arjuna
Felix Arjuna

đŸ’»
Furkan Enes
Furkan Enes

đŸ’»
Genevieve Warren
Genevieve Warren

đŸ’»
George Dernikos
George Dernikos

đŸ’»
Giovanni de Almeida Martins
Giovanni de Almeida Martins

đŸ’»
Ioana A
Ioana A

đŸ’»
Jakub JareĆĄ
Jakub JareĆĄ

đŸ’»
Joe Watkins
Joe Watkins

đŸ’»
John Papa
John Papa

đŸ’»
Joseph Gonzales
Joseph Gonzales

đŸ’»
José Antonio Garrido
José Antonio Garrido

đŸ’»
Kim Skov Rasmussen
Kim Skov Rasmussen

đŸ’»
Kenny White
Kenny White

đŸ’»
Louella Creemers
Louella Creemers

đŸ’»
Luke Murray
Luke Murray

đŸ’»
Mark Noble
Mark Noble

đŸ’»
Per SĂžderlind
Per SĂžderlind

đŸ’»
Henrique Nunes
Henrique Nunes

đŸ’»
Henrique Nunes
Henrique Nunes

⌚
Jeremiah Snee
Jeremiah Snee

đŸ’»
spectatora
spectatora

đŸ’»
Michael
Michael

đŸ’»
Kartik Dhiman
Kartik Dhiman

🧭
Kristiyan Velkov
Kristiyan Velkov

🎭
Mark Davis
Mark Davis

🧭
Peli de Halleux
Peli de Halleux

đŸ’»
Per SĂžderlind
Per SĂžderlind

🧭
Christian Lechner
Christian Lechner

đŸ’»
Jan de Vries
Jan de Vries

đŸ’»
Peter Smulovics
Peter Smulovics

🧭
Ravish Rathod
Ravish Rathod

🧭
Rick Smit
Rick Smit

🎭
Rob Simpson
Rob Simpson

🧭
Robert Altman
Robert Altman

🧭
Salih
Salih

🧭
Sebastian GrÀf
Sebastian GrÀf

🎭 🧭
Sebastien DEGODEZ
Sebastien DEGODEZ

🧭
Sergiy Smyrnov
Sergiy Smyrnov

⌚
SomeSolutionsArchitect
SomeSolutionsArchitect

🎭
Stu Mace
Stu Mace

🎭 🎁 🧭
읎상현
읎상현

🧭
Paulo Morgado
Paulo Morgado

⌚
Paul Crane
Paul Crane

🎭
Pamela Fox
Pamela Fox

⌚
Oskar Thornblad
Oskar Thornblad

🧭
Nischay Sharma
Nischay Sharma

🎭
Nikolay Marinov
Nikolay Marinov

🎭
Nik Sachdeva
Nik Sachdeva

🎭 🎁
Nick Taylor
Nick Taylor

đŸ’»
Nick Brady
Nick Brady

🎭
Nathan Stanford Sr
Nathan Stanford Sr

🧭
Måté Barabås
Måté Barabås

🧭
Mike Parker
Mike Parker

🧭
Mike Kistler
Mike Kistler

⌚
Michael Fairchild
Michael Fairchild

🧭
Ankur Sharma
Ankur Sharma

⌚
Wendy Breiding
Wendy Breiding

đŸ’»
voidfnc
voidfnc

🎭
shane lee
shane lee

🧭
sdanzo-hrb
sdanzo-hrb

🎭
sauran
sauran

🧭
samqbush
samqbush

⌚
pareenaverma
pareenaverma

🎭
oleksiyyurchyna
oleksiyyurchyna

🎁 ⌚
oceans-of-time
oceans-of-time

🧭
kshashank57
kshashank57

🎭 🧭
Meii
Meii

🎭
factory-davidgu
factory-davidgu

đŸ’»
dangelov-qa
dangelov-qa

🎭
Yuki Omoto
Yuki Omoto

🧭
Will Schultz
Will Schultz

🎭
Waren Gonzaga
Waren Gonzaga

🎭
Vincent Koc
Vincent Koc

🎭
Victor Williams
Victor Williams

🎭
Ve Sharma
Ve Sharma

🎭
Udaya Veeramreddygari
Udaya Veeramreddygari

🧭
TĂ i LĂȘ
TĂ i LĂȘ

⌚
Troy Witthoeft (glsauto)
Troy Witthoeft (glsauto)

🧭
Tom Meschter
Tom Meschter

đŸ’»
Tj Vita
Tj Vita

🎭
SĂžren TrudsĂž Mahon
SĂžren TrudsĂž Mahon

🧭
George Dernikos
George Dernikos

đŸ’»
Gautam
Gautam

🎭
Furkan Enes
Furkan Enes

🧭
Florian MĂŒcke
Florian MĂŒcke

🎭
Felix Arjuna
Felix Arjuna

🧭
Eldrick Wega
Eldrick Wega

⌚
Dobri Danchev
Dobri Danchev

⌚
Diego Gamboa
Diego Gamboa

⌚
Derek Clair
Derek Clair

🎭 ⌚
David Ortinau
David Ortinau

đŸ’»
Daniel Abbatt
Daniel Abbatt

🧭
CypherHK
CypherHK

🎭 ⌚
Craig Bekker
Craig Bekker

đŸ’»
Christophe Peugnet
Christophe Peugnet

🧭
Christian Lechner
Christian Lechner

🧭
Chris Harris
Chris Harris

🎭
BBoyBen
BBoyBen

🧭
Artem Saveliev
Artem Saveliev

🧭
Antoine Rey
Antoine Rey

⌚
Ankit Das
Ankit Das

🧭
Aline Ávila
Aline Ávila

🧭
Alexander Martinkevich
Alexander Martinkevich

🎭
Aleksandar Dunchev
Aleksandar Dunchev

🎭
Alan Sprecacenere
Alan Sprecacenere

🧭
Akash Kumar Shaw
Akash Kumar Shaw

🧭
Abdi Daud
Abdi Daud

🎭
4regab
4regab

🧭
Michael A. Volz (Flynn)
Michael A. Volz (Flynn)

⌚
Michael
Michael

🧭
Mehmet Ali EROL
Mehmet Ali EROL

🎭
Max Prilutskiy
Max Prilutskiy

🎭
Matteo Bianchi
Matteo Bianchi

🎭
Matt Soucoup
Matt Soucoup

🚇
Mark Noble
Mark Noble

🎭
Manish Jayaswal
Manish Jayaswal

🎭
Luke Murray
Luke Murray

🎭
Louella Creemers
Louella Creemers

🧭
Kenny White
Kenny White

🧭
KaloyanGenev
KaloyanGenev

🎭
Kim Skov Rasmussen
Kim Skov Rasmussen

đŸ’»
Julien Dubois
Julien Dubois

⌚
José Antonio Garrido
José Antonio Garrido

🧭
Joseph Gonzales
Joseph Gonzales

🧭 ⌚
Jorge Balderas
Jorge Balderas

🧭
John Papa
John Papa

đŸ’»
John
John

🎭
Joe Watkins
Joe Watkins

🧭
Jan de Vries
Jan de Vries

🎭
Jakub JareĆĄ
Jakub JareĆĄ

⌚
Jackson Miller
Jackson Miller

🧭
Ioana A
Ioana A

🧭
Hashim Warren
Hashim Warren

🎭
Gisela Torres
Gisela Torres

🎭
Giovanni de Almeida Martins
Giovanni de Almeida Martins

🧭
Gerald Versluis
Gerald Versluis

🧭