diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 5f99cf4c8..603c306b1 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,10 +1,10 @@ ## Pull Request Checklist - [ ] I have read and followed the [CONTRIBUTING.md](https://github.com/github/awesome-copilot/blob/main/CONTRIBUTING.md) guidelines. -- [ ] My contribution adds a new instruction, prompt, agent, or skill file in the correct directory. +- [ ] My contribution adds a new instruction, prompt, agent, skill, or workflow file in the correct directory. - [ ] The file follows the required naming convention. - [ ] The content is clearly structured and follows the example format. -- [ ] I have tested my instructions, prompt, agent, or skill with GitHub Copilot. +- [ ] I have tested my instructions, prompt, agent, skill, or workflow with GitHub Copilot. - [ ] I have run `npm start` and verified that `README.md` is up to date. --- @@ -22,7 +22,8 @@ - [ ] New agent file. - [ ] New plugin. - [ ] New skill file. -- [ ] Update to existing instruction, prompt, agent, plugin, or skill. +- [ ] New agentic workflow. +- [ ] Update to existing instruction, prompt, agent, plugin, skill, or workflow. - [ ] Other (please specify): --- diff --git a/.github/workflows/validate-agentic-workflows-pr.yml b/.github/workflows/validate-agentic-workflows-pr.yml new file mode 100644 index 000000000..5f5ff2813 --- /dev/null +++ b/.github/workflows/validate-agentic-workflows-pr.yml @@ -0,0 +1,125 @@ +name: Validate Agentic Workflow Contributions + +on: + pull_request: + branches: [staged] + types: [opened, synchronize, reopened] + paths: + - "workflows/**" + +permissions: + contents: read + pull-requests: write + +jobs: + check-forbidden-files: + name: Block forbidden files + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Check for forbidden files + id: check + run: | + # Check for YAML/lock files in workflows/ and any .github/ modifications + forbidden=$(git diff --name-only --diff-filter=ACM origin/${{ github.base_ref }}...HEAD -- \ + 'workflows/**/*.yml' \ + 'workflows/**/*.yaml' \ + 'workflows/**/*.lock.yml' \ + '.github/*' \ + '.github/**') + + if [ -n "$forbidden" ]; then + echo "❌ Forbidden files detected:" + echo "$forbidden" + echo "files<> "$GITHUB_OUTPUT" + echo "$forbidden" >> "$GITHUB_OUTPUT" + echo "EOF" >> "$GITHUB_OUTPUT" + exit 1 + else + echo "✅ No forbidden files found" + fi + + - name: Comment on PR + if: failure() + uses: marocchino/sticky-pull-request-comment@v2 + with: + header: workflow-forbidden-files + message: | + ## 🚫 Forbidden files in `workflows/` + + Only `.md` markdown files are accepted in the `workflows/` directory. The following are **not allowed**: + - Compiled workflow files (`.yml`, `.yaml`, `.lock.yml`) — could contain untrusted Actions code + - `.github/` modifications — workflow contributions must not modify repository configuration + + **Files that must be removed:** + ``` + ${{ steps.check.outputs.files }} + ``` + + Contributors provide the workflow **source** (`.md`) only. Compilation happens downstream via `gh aw compile`. + + Please remove these files and push again. + + compile-workflows: + name: Compile and validate + needs: check-forbidden-files + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Install gh-aw CLI + uses: github/gh-aw/actions/setup-cli@main + + - name: Compile workflow files + id: compile + run: | + exit_code=0 + found=0 + + # Find all .md files directly in workflows/ + for workflow_file in workflows/*.md; do + [ -f "$workflow_file" ] || continue + + found=$((found + 1)) + echo "::group::Compiling $workflow_file" + if gh aw compile --validate "$workflow_file"; then + echo "✅ $workflow_file compiled successfully" + else + echo "❌ $workflow_file failed to compile" + exit_code=1 + fi + echo "::endgroup::" + done + + if [ "$found" -eq 0 ]; then + echo "No workflow .md files found to validate." + else + echo "Validated $found workflow file(s)." + fi + + echo "status=$( [ $exit_code -eq 0 ] && echo success || echo failure )" >> "$GITHUB_OUTPUT" + exit $exit_code + + - name: Comment on PR if compilation failed + if: failure() + uses: marocchino/sticky-pull-request-comment@v2 + with: + header: workflow-validation + message: | + ## ❌ Agentic Workflow compilation failed + + One or more workflow files in `workflows/` failed to compile with `gh aw compile --validate`. + + Please fix the errors and push again. You can test locally with: + + ```bash + gh extension install github/gh-aw + gh aw compile --validate .md + ``` + + See the [Agentic Workflows documentation](https://github.github.com/gh-aw) for help. diff --git a/.github/workflows/validate-readme.yml b/.github/workflows/validate-readme.yml index 6df185e35..e9ae9dfee 100644 --- a/.github/workflows/validate-readme.yml +++ b/.github/workflows/validate-readme.yml @@ -9,6 +9,7 @@ on: - "prompts/**" - "agents/**" - "plugins/**" + - "workflows/**" - "*.js" - "README.md" - "docs/**" diff --git a/AGENTS.md b/AGENTS.md index b2dbd6fdb..6bda52038 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -9,6 +9,7 @@ The Awesome GitHub Copilot repository is a community-driven collection of custom - **Instructions** - Coding standards and best practices applied to specific file patterns - **Skills** - Self-contained folders with instructions and bundled resources for specialized tasks - **Hooks** - Automated workflows triggered by specific events during development +- **Workflows** - [Agentic Workflows](https://github.github.com/gh-aw) for AI-powered repository automation in GitHub Actions - **Plugins** - Installable packages that group related agents, commands, and skills around specific themes ## Repository Structure @@ -20,6 +21,7 @@ The Awesome GitHub Copilot repository is a community-driven collection of custom ├── instructions/ # Coding standards and guidelines (.instructions.md files) ├── skills/ # Agent Skills folders (each with SKILL.md and optional bundled assets) ├── hooks/ # Automated workflow hooks (folders with README.md + hooks.json) +├── workflows/ # Agentic Workflows (.md files for GitHub Actions automation) ├── plugins/ # Installable plugin packages (folders with plugin.json) ├── docs/ # Documentation for different resource types ├── eng/ # Build and automation scripts @@ -96,6 +98,17 @@ All agent files (`*.agent.md`), prompt files (`*.prompt.md`), and instruction fi - Follow the [GitHub Copilot hooks specification](https://docs.github.com/en/copilot/how-tos/use-copilot-agents/coding-agent/use-hooks) - Optionally includes `tags` field for categorization +#### Workflow Files (workflows/*.md) +- Each workflow is a standalone `.md` file in the `workflows/` directory +- Must have `name` field (human-readable name) +- Must have `description` field (wrapped in single quotes, not empty) +- Should have `triggers` field (array of trigger types, e.g., `['schedule', 'issues']`) +- Contains agentic workflow frontmatter (`on`, `permissions`, `safe-outputs`) and natural language instructions +- File names should be lower case with words separated by hyphens +- Only `.md` files are accepted — `.yml`, `.yaml`, and `.lock.yml` files are blocked by CI +- Optionally includes `tags` field for categorization +- Follow the [GitHub Agentic Workflows specification](https://github.github.com/gh-aw) + #### Plugin Folders (plugins/*) - Each plugin is a folder containing a `.github/plugin/plugin.json` file with metadata - plugin.json must have `name` field (matching the folder name) @@ -107,7 +120,7 @@ All agent files (`*.agent.md`), prompt files (`*.prompt.md`), and instruction fi ### Adding New Resources -When adding a new agent, prompt, instruction, skill, hook, or plugin: +When adding a new agent, prompt, instruction, skill, hook, workflow, or plugin: **For Agents, Prompts, and Instructions:** 1. Create the file with proper front matter @@ -125,6 +138,14 @@ When adding a new agent, prompt, instruction, skill, hook, or plugin: 7. Verify the hook appears in the generated README +**For Workflows:** +1. Create a new `.md` file in `workflows/` with a descriptive name (e.g., `daily-issues-report.md`) +2. Include frontmatter with `name`, `description`, `triggers`, plus agentic workflow fields (`on`, `permissions`, `safe-outputs`) +3. Compile with `gh aw compile --validate` to verify it's valid +4. Update the README.md by running: `npm run build` +5. Verify the workflow appears in the generated README + + **For Skills:** 1. Run `npm run skill:create` to scaffold a new skill folder 2. Edit the generated SKILL.md file with your instructions @@ -241,6 +262,18 @@ For hook folders (hooks/*/): - [ ] Follows [GitHub Copilot hooks specification](https://docs.github.com/en/copilot/how-tos/use-copilot-agents/coding-agent/use-hooks) - [ ] Optionally includes `tags` array field for categorization +For workflow files (workflows/*.md): +- [ ] File has markdown front matter +- [ ] Has `name` field with human-readable name +- [ ] Has non-empty `description` field wrapped in single quotes +- [ ] Has `triggers` array field listing workflow trigger types +- [ ] File name is lower case with hyphens +- [ ] Contains `on` and `permissions` in frontmatter +- [ ] Workflow uses least-privilege permissions and safe outputs +- [ ] No `.yml`, `.yaml`, or `.lock.yml` files included +- [ ] Follows [GitHub Agentic Workflows specification](https://github.github.com/gh-aw) +- [ ] Optionally includes `tags` array field for categorization + For plugins (plugins/*/): - [ ] Directory contains a `.github/plugin/plugin.json` file - [ ] Directory contains a `README.md` file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index da0d4e918..63e7630c8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -161,11 +161,61 @@ plugins/my-plugin-id/ - **Clear purpose**: The plugin should solve a specific problem or workflow - **Validate before submitting**: Run `npm run plugin:validate` to ensure your plugin is valid +### Adding Agentic Workflows + +[Agentic Workflows](https://github.github.com/gh-aw) are AI-powered repository automations that run coding agents in GitHub Actions. Defined in markdown with natural language instructions, they enable scheduled and event-triggered automation with built-in guardrails. + +1. **Create your workflow file**: Add a new `.md` file in the `workflows/` directory (e.g., `daily-issues-report.md`) +2. **Include frontmatter**: Add `name`, `description`, `triggers`, and optionally `tags` at the top, followed by agentic workflow frontmatter (`on`, `permissions`, `safe-outputs`) and natural language instructions +3. **Test locally**: Compile with `gh aw compile --validate` to verify it's valid +4. **Update the README**: Run `npm run build` to update the generated README tables + +> **Note:** Only `.md` files are accepted — do not include compiled `.lock.yml` or `.yml` files. CI will block them. + +#### Workflow file example + +```markdown +--- +name: 'Daily Issues Report' +description: 'Generates a daily summary of open issues and recent activity as a GitHub issue' +triggers: ['schedule'] +tags: ['reporting', 'issues', 'automation'] +on: + schedule: daily on weekdays +permissions: + contents: read + issues: read +safe-outputs: + create-issue: + title-prefix: "[daily-report] " + labels: [report] +--- + +## Daily Issues Report + +Create a daily summary of open issues for the team. + +## What to Include + +- New issues opened in the last 24 hours +- Issues closed or resolved +- Stale issues that need attention +``` + +#### Workflow Guidelines + +- **Security first**: Use least-privilege permissions and safe outputs instead of direct write access +- **Clear instructions**: Write clear natural language instructions in the workflow body +- **Descriptive names**: Use lowercase filenames with hyphens (e.g., `daily-issues-report.md`) +- **Test locally**: Use `gh aw compile --validate` to verify your workflow compiles +- **No compiled files**: Only submit the `.md` source — `.lock.yml` and `.yml` files are not accepted +- Learn more at the [Agentic Workflows documentation](https://github.github.com/gh-aw) + ## Submitting Your Contribution 1. **Fork this repository** 2. **Create a new branch** for your contribution -3. **Add your instruction, prompt file, chatmode, or plugin** following the guidelines above +3. **Add your instruction, prompt file, chatmode, workflow, or plugin** following the guidelines above 4. **Run the update script**: `npm start` to update the README with your new file (make sure you run `npm install` first if you haven't already) - A GitHub Actions workflow will verify that this step was performed correctly - If the README.md would be modified by running the script, the PR check will fail with a comment showing the required changes @@ -234,6 +284,7 @@ We welcome many kinds of contributions, including the custom categories below: | **Prompts** | Reusable or one-off prompts for GitHub Copilot | ⌨️ | | **Agents** | Defined GitHub Copilot roles or personalities | 🎭 | | **Skills** | Specialized knowledge of a task for GitHub Copilot | 🧰 | +| **Workflows** | Agentic Workflows for AI-powered repository automation | ⚡ | | **Plugins** | Installable packages of related prompts, agents, or skills | 🎁 | In addition, all standard contribution types supported by [All Contributors](https://allcontributors.org/emoji-key/) are recognized. diff --git a/README.md b/README.md index 82e62f646..595783606 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,7 @@ This repository provides a comprehensive toolkit for enhancing GitHub Copilot wi - **👉 [Awesome Prompts](docs/README.prompts.md)** - Focused, task-specific prompts for generating code, documentation, and solving specific problems - **👉 [Awesome Instructions](docs/README.instructions.md)** - Comprehensive coding standards and best practices that apply to specific file patterns or entire projects - **👉 [Awesome Hooks](docs/README.hooks.md)** - Automated workflows triggered by specific events during development, testing, and deployment +- **👉 [Awesome Agentic Workflows](docs/README.workflows.md)** - AI-powered repository automations that run coding agents in GitHub Actions with natural language instructions - **👉 [Awesome Skills](docs/README.skills.md)** - Self-contained folders with instructions and bundled resources that enhance AI capabilities for specialized tasks - **👉 [Awesome Plugins](docs/README.plugins.md)** - Curated plugins of related prompts, agents, and skills organized around specific themes and workflows - **👉 [Awesome Cookbook Recipes](cookbook/README.md)** - Practical, copy-paste-ready code snippets and real-world examples for working with GitHub Copilot tools and features @@ -101,6 +102,10 @@ Instructions automatically apply to files based on their patterns and provide co Hooks enable automated workflows triggered by specific events during GitHub Copilot coding agent sessions (like sessionStart, sessionEnd, userPromptSubmitted). They can automate tasks like logging, auto-committing changes, or integrating with external services. +### ⚡ Agentic Workflows + +[Agentic Workflows](https://github.github.com/gh-aw) are AI-powered repository automations that run coding agents in GitHub Actions. Defined in markdown with natural language instructions, they enable event-triggered and scheduled automation — from issue triage to daily reports. + ## 🎯 Why Use Awesome GitHub Copilot? - **Productivity**: Pre-built agents, prompts and instructions save time and provide consistent results. @@ -112,7 +117,7 @@ Hooks enable automated workflows triggered by specific events during GitHub Copi We welcome contributions! Please see our [Contributing Guidelines](CONTRIBUTING.md) for details on how to: -- Add new prompts, instructions, hooks, agents, or skills +- Add new prompts, instructions, hooks, workflows, agents, or skills - Improve existing content - Report issues or suggest enhancements @@ -131,6 +136,8 @@ For AI coding agents working with this project, refer to [AGENTS.md](AGENTS.md) ├── prompts/ # Task-specific prompts (.prompt.md) ├── instructions/ # Coding standards and best practices (.instructions.md) ├── agents/ # AI personas and specialized modes (.agent.md) +├── hooks/ # Automated hooks for Copilot coding agent sessions +├── workflows/ # Agentic Workflows for GitHub Actions automation ├── plugins/ # Installable plugins bundling related items ├── scripts/ # Utility scripts for maintenance └── skills/ # AI capabilities for specialized tasks @@ -152,7 +159,7 @@ The customizations in this repository are sourced from and created by third-part --- -**Ready to supercharge your coding experience?** Start exploring our [prompts](docs/README.prompts.md), [instructions](docs/README.instructions.md), [hooks](docs/README.hooks.md), and [custom agents](docs/README.agents.md)! +**Ready to supercharge your coding experience?** Start exploring our [prompts](docs/README.prompts.md), [instructions](docs/README.instructions.md), [hooks](docs/README.hooks.md), [agentic workflows](docs/README.workflows.md), and [custom agents](docs/README.agents.md)! ## Contributors ✨ diff --git a/docs/README.workflows.md b/docs/README.workflows.md new file mode 100644 index 000000000..93bdfdca4 --- /dev/null +++ b/docs/README.workflows.md @@ -0,0 +1,31 @@ +# ⚡ Agentic Workflows + +[Agentic Workflows](https://github.github.com/gh-aw) are AI-powered repository automations that run coding agents in GitHub Actions. Defined in markdown with natural language instructions, they enable event-triggered and scheduled automation with built-in guardrails and security-first design. + +### How to Use Agentic Workflows + +**What's Included:** +- Each workflow is a single `.md` file with YAML frontmatter and natural language instructions +- Workflows are compiled to `.lock.yml` GitHub Actions files via `gh aw compile` +- Workflows follow the [GitHub Agentic Workflows specification](https://github.github.com/gh-aw) + +**To Install:** +- Install the `gh aw` CLI extension: `gh extension install github/gh-aw` +- Copy the workflow `.md` file to your repository's `.github/workflows/` directory +- Compile with `gh aw compile` to generate the `.lock.yml` file +- Commit both the `.md` and `.lock.yml` files + +**To Activate/Use:** +- Workflows run automatically based on their configured triggers (schedules, events, slash commands) +- Use `gh aw run ` to trigger a manual run +- Monitor runs with `gh aw status` and `gh aw logs` + +**When to Use:** +- Automate issue triage and labeling +- Generate daily status reports +- Maintain documentation automatically +- Run scheduled code quality checks +- Respond to slash commands in issues and PRs +- Orchestrate multi-step repository automation + +_No entries found yet._ \ No newline at end of file diff --git a/eng/constants.mjs b/eng/constants.mjs index 1f1e95ec3..6736c243b 100644 --- a/eng/constants.mjs +++ b/eng/constants.mjs @@ -127,6 +127,36 @@ Hooks enable automated workflows triggered by specific events during GitHub Copi - Track usage analytics - Integrate with external tools and services - Custom session workflows`, + + workflowsSection: `## ⚡ Agentic Workflows + +[Agentic Workflows](https://github.github.com/gh-aw) are AI-powered repository automations that run coding agents in GitHub Actions. Defined in markdown with natural language instructions, they enable event-triggered and scheduled automation with built-in guardrails and security-first design.`, + + workflowsUsage: `### How to Use Agentic Workflows + +**What's Included:** +- Each workflow is a single \`.md\` file with YAML frontmatter and natural language instructions +- Workflows are compiled to \`.lock.yml\` GitHub Actions files via \`gh aw compile\` +- Workflows follow the [GitHub Agentic Workflows specification](https://github.github.com/gh-aw) + +**To Install:** +- Install the \`gh aw\` CLI extension: \`gh extension install github/gh-aw\` +- Copy the workflow \`.md\` file to your repository's \`.github/workflows/\` directory +- Compile with \`gh aw compile\` to generate the \`.lock.yml\` file +- Commit both the \`.md\` and \`.lock.yml\` files + +**To Activate/Use:** +- Workflows run automatically based on their configured triggers (schedules, events, slash commands) +- Use \`gh aw run \` to trigger a manual run +- Monitor runs with \`gh aw status\` and \`gh aw logs\` + +**When to Use:** +- Automate issue triage and labeling +- Generate daily status reports +- Maintain documentation automatically +- Run scheduled code quality checks +- Respond to slash commands in issues and PRs +- Orchestrate multi-step repository automation`, }; const vscodeInstallImage = @@ -152,6 +182,7 @@ const AGENTS_DIR = path.join(ROOT_FOLDER, "agents"); const SKILLS_DIR = path.join(ROOT_FOLDER, "skills"); const HOOKS_DIR = path.join(ROOT_FOLDER, "hooks"); const PLUGINS_DIR = path.join(ROOT_FOLDER, "plugins"); +const WORKFLOWS_DIR = path.join(ROOT_FOLDER, "workflows"); const COOKBOOK_DIR = path.join(ROOT_FOLDER, "cookbook"); const MAX_PLUGIN_ITEMS = 50; @@ -182,6 +213,7 @@ export { SKILLS_DIR, TEMPLATES, vscodeInsidersInstallImage, - vscodeInstallImage + vscodeInstallImage, + WORKFLOWS_DIR }; diff --git a/eng/generate-website-data.mjs b/eng/generate-website-data.mjs index 5ac93e319..9eb3da00c 100644 --- a/eng/generate-website-data.mjs +++ b/eng/generate-website-data.mjs @@ -17,13 +17,15 @@ import { PLUGINS_DIR, PROMPTS_DIR, ROOT_FOLDER, - SKILLS_DIR + SKILLS_DIR, + WORKFLOWS_DIR } from "./constants.mjs"; import { getGitFileDates } from "./utils/git-dates.mjs"; import { parseFrontmatter, parseSkillMetadata, parseHookMetadata, + parseWorkflowMetadata, parseYamlFile, } from "./yaml-parser.mjs"; @@ -192,6 +194,64 @@ function generateHooksData(gitDates) { }; } +/** + * Generate workflows metadata (flat .md files) + */ +function generateWorkflowsData(gitDates) { + const workflows = []; + + if (!fs.existsSync(WORKFLOWS_DIR)) { + return { + items: workflows, + filters: { + triggers: [], + tags: [], + }, + }; + } + + const workflowFiles = fs.readdirSync(WORKFLOWS_DIR).filter((file) => { + return file.endsWith(".md") && file !== ".gitkeep"; + }); + + const allTriggers = new Set(); + const allTags = new Set(); + + for (const file of workflowFiles) { + const filePath = path.join(WORKFLOWS_DIR, file); + const metadata = parseWorkflowMetadata(filePath); + if (!metadata) continue; + + const relativePath = path + .relative(ROOT_FOLDER, filePath) + .replace(/\\/g, "/"); + + (metadata.triggers || []).forEach((t) => allTriggers.add(t)); + (metadata.tags || []).forEach((t) => allTags.add(t)); + + const id = path.basename(file, ".md"); + workflows.push({ + id, + title: metadata.name, + description: metadata.description, + triggers: metadata.triggers || [], + tags: metadata.tags || [], + path: relativePath, + lastUpdated: gitDates.get(relativePath) || null, + }); + } + + const sortedWorkflows = workflows.sort((a, b) => a.title.localeCompare(b.title)); + + return { + items: sortedWorkflows, + filters: { + triggers: Array.from(allTriggers).sort(), + tags: Array.from(allTags).sort(), + }, + }; +} + /** * Generate prompts metadata */ @@ -606,6 +666,7 @@ function generateSearchIndex( prompts, instructions, hooks, + workflows, skills, plugins ) { @@ -665,6 +726,20 @@ function generateSearchIndex( }); } + for (const workflow of workflows) { + index.push({ + type: "workflow", + id: workflow.id, + title: workflow.title, + description: workflow.description, + path: workflow.path, + lastUpdated: workflow.lastUpdated, + searchText: `${workflow.title} ${workflow.description} ${workflow.triggers.join( + " " + )} ${workflow.tags.join(" ")}`.toLowerCase(), + }); + } + for (const skill of skills) { index.push({ type: "skill", @@ -799,7 +874,7 @@ async function main() { // Load git dates for all resource files (single efficient git command) console.log("Loading git history for last updated dates..."); const gitDates = getGitFileDates( - ["agents/", "prompts/", "instructions/", "hooks/", "skills/", "plugins/"], + ["agents/", "prompts/", "instructions/", "hooks/", "workflows/", "skills/", "plugins/"], ROOT_FOLDER ); console.log(`✓ Loaded dates for ${gitDates.size} files\n`); @@ -817,6 +892,12 @@ async function main() { `✓ Generated ${hooks.length} hooks (${hooksData.filters.hooks.length} hook types, ${hooksData.filters.tags.length} tags)` ); + const workflowsData = generateWorkflowsData(gitDates); + const workflows = workflowsData.items; + console.log( + `✓ Generated ${workflows.length} workflows (${workflowsData.filters.triggers.length} triggers, ${workflowsData.filters.tags.length} tags)` + ); + const promptsData = generatePromptsData(gitDates); const prompts = promptsData.items; console.log( @@ -857,6 +938,7 @@ async function main() { prompts, instructions, hooks, + workflows, skills, plugins ); @@ -873,6 +955,11 @@ async function main() { JSON.stringify(hooksData, null, 2) ); + fs.writeFileSync( + path.join(WEBSITE_DATA_DIR, "workflows.json"), + JSON.stringify(workflowsData, null, 2) + ); + fs.writeFileSync( path.join(WEBSITE_DATA_DIR, "prompts.json"), JSON.stringify(promptsData, null, 2) @@ -917,6 +1004,7 @@ async function main() { instructions: instructions.length, skills: skills.length, hooks: hooks.length, + workflows: workflows.length, plugins: plugins.length, tools: tools.length, samples: samplesData.totalRecipes, diff --git a/eng/update-readme.mjs b/eng/update-readme.mjs index f14a0bc01..3456d5c65 100644 --- a/eng/update-readme.mjs +++ b/eng/update-readme.mjs @@ -17,12 +17,14 @@ import { TEMPLATES, vscodeInsidersInstallImage, vscodeInstallImage, + WORKFLOWS_DIR, } from "./constants.mjs"; import { extractMcpServerConfigs, parseFrontmatter, parseSkillMetadata, parseHookMetadata, + parseWorkflowMetadata, } from "./yaml-parser.mjs"; const __filename = fileURLToPath(import.meta.url); @@ -577,6 +579,61 @@ function generateHooksSection(hooksDir) { return `${TEMPLATES.hooksSection}\n${TEMPLATES.hooksUsage}\n\n${content}`; } +/** + * Generate the workflows section with a table of all agentic workflows + */ +function generateWorkflowsSection(workflowsDir) { + if (!fs.existsSync(workflowsDir)) { + console.log(`Workflows directory does not exist: ${workflowsDir}`); + return ""; + } + + // Get all .md workflow files (flat, no subfolders) + const workflowFiles = fs.readdirSync(workflowsDir).filter((file) => { + return file.endsWith(".md") && file !== ".gitkeep"; + }); + + // Parse each workflow file + const workflowEntries = workflowFiles + .map((file) => { + const filePath = path.join(workflowsDir, file); + const metadata = parseWorkflowMetadata(filePath); + if (!metadata) return null; + + return { + file, + name: metadata.name, + description: metadata.description, + triggers: metadata.triggers, + tags: metadata.tags, + }; + }) + .filter((entry) => entry !== null) + .sort((a, b) => a.name.localeCompare(b.name)); + + console.log(`Found ${workflowEntries.length} workflow(s)`); + + if (workflowEntries.length === 0) { + return ""; + } + + // Create table header + let content = + "| Name | Description | Triggers |\n| ---- | ----------- | -------- |\n"; + + // Generate table rows for each workflow + for (const workflow of workflowEntries) { + const link = `../workflows/${workflow.file}`; + const triggers = workflow.triggers.length > 0 ? workflow.triggers.join(", ") : "N/A"; + + content += `| [${workflow.name}](${link}) | ${formatTableCell( + workflow.description + )} | ${triggers} |\n`; + } + + return `${TEMPLATES.workflowsSection}\n${TEMPLATES.workflowsUsage}\n\n${content}`; +} + /** * Generate the skills section with a table of all skills */ @@ -921,6 +978,7 @@ async function main() { const promptsHeader = TEMPLATES.promptsSection.replace(/^##\s/m, "# "); const agentsHeader = TEMPLATES.agentsSection.replace(/^##\s/m, "# "); const hooksHeader = TEMPLATES.hooksSection.replace(/^##\s/m, "# "); + const workflowsHeader = TEMPLATES.workflowsSection.replace(/^##\s/m, "# "); const skillsHeader = TEMPLATES.skillsSection.replace(/^##\s/m, "# "); const pluginsHeader = TEMPLATES.pluginsSection.replace( /^##\s/m, @@ -959,6 +1017,15 @@ async function main() { registryNames ); + // Generate workflows README + const workflowsReadme = buildCategoryReadme( + generateWorkflowsSection, + WORKFLOWS_DIR, + workflowsHeader, + TEMPLATES.workflowsUsage, + registryNames + ); + // Generate skills README const skillsReadme = buildCategoryReadme( generateSkillsSection, @@ -990,6 +1057,7 @@ async function main() { writeFileIfChanged(path.join(DOCS_DIR, "README.prompts.md"), promptsReadme); writeFileIfChanged(path.join(DOCS_DIR, "README.agents.md"), agentsReadme); writeFileIfChanged(path.join(DOCS_DIR, "README.hooks.md"), hooksReadme); + writeFileIfChanged(path.join(DOCS_DIR, "README.workflows.md"), workflowsReadme); writeFileIfChanged(path.join(DOCS_DIR, "README.skills.md"), skillsReadme); writeFileIfChanged( path.join(DOCS_DIR, "README.plugins.md"), diff --git a/eng/yaml-parser.mjs b/eng/yaml-parser.mjs index 8ef9f8a7d..88d16582f 100644 --- a/eng/yaml-parser.mjs +++ b/eng/yaml-parser.mjs @@ -253,6 +253,44 @@ function parseHookMetadata(hookPath) { ); } +/** + * Parse workflow metadata from a standalone .md workflow file + * @param {string} filePath - Path to the workflow .md file + * @returns {object|null} Workflow metadata or null on error + */ +function parseWorkflowMetadata(filePath) { + return safeFileOperation( + () => { + if (!fs.existsSync(filePath)) { + return null; + } + + const frontmatter = parseFrontmatter(filePath); + + // Validate required fields + if (!frontmatter?.name || !frontmatter?.description) { + console.warn( + `Invalid workflow at ${filePath}: missing name or description in frontmatter` + ); + return null; + } + + // Extract triggers from frontmatter if present + const triggers = frontmatter.triggers || []; + + return { + name: frontmatter.name, + description: frontmatter.description, + triggers, + tags: frontmatter.tags || [], + path: filePath, + }; + }, + filePath, + null + ); +} + /** * Parse a generic YAML file (used for tools.yml and other config files) * @param {string} filePath - Path to the YAML file @@ -276,6 +314,7 @@ export { parseFrontmatter, parseSkillMetadata, parseHookMetadata, + parseWorkflowMetadata, parseYamlFile, safeFileOperation, }; diff --git a/workflows/.gitkeep b/workflows/.gitkeep new file mode 100644 index 000000000..e69de29bb