From 997d6302bd7940b9a73edee8acd10ffbd12bd207 Mon Sep 17 00:00:00 2001 From: Bruno Borges Date: Fri, 20 Feb 2026 15:28:28 -0800 Subject: [PATCH 1/6] Add Agentic Workflows as a new resource type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for contributing Agentic Workflows — AI-powered repository automations that run coding agents in GitHub Actions, defined in markdown with natural language instructions (https://github.github.com/gh-aw). Changes: - Create workflows/ directory for community-contributed workflows - Add workflow metadata parsing (yaml-parser.mjs) - Add workflow README generation (update-readme.mjs, constants.mjs) - Add workflow data to website generation (generate-website-data.mjs) - Update README.md, CONTRIBUTING.md, and AGENTS.md with workflow docs, contributing guidelines, and code review checklists Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- AGENTS.md | 35 ++++++++++++- CONTRIBUTING.md | 67 +++++++++++++++++++++++- README.md | 11 +++- docs/README.workflows.md | 31 ++++++++++++ eng/constants.mjs | 34 ++++++++++++- eng/generate-website-data.mjs | 95 ++++++++++++++++++++++++++++++++++- eng/update-readme.mjs | 74 +++++++++++++++++++++++++++ eng/yaml-parser.mjs | 62 +++++++++++++++++++++++ workflows/.gitkeep | 0 9 files changed, 402 insertions(+), 7 deletions(-) create mode 100644 docs/README.workflows.md create mode 100644 workflows/.gitkeep diff --git a/AGENTS.md b/AGENTS.md index b2dbd6fdb..faed71272 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 (folders with README.md + workflow .md files) ├── 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 Folders (workflows/*/README.md) +- Each workflow is a folder containing a `README.md` file with frontmatter and one or more `.md` workflow files +- README.md must have `name` field (human-readable name) +- README.md must have `description` field (wrapped in single quotes, not empty) +- README.md should have `triggers` field (array of trigger types, e.g., `['schedule', 'issues']`) +- Workflow `.md` files contain YAML frontmatter (`on`, `permissions`, `safe-outputs`) and natural language instructions +- Folder names should be lower case with words separated by hyphens +- Can include bundled assets (scripts, configuration files) +- 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,15 @@ 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 folder in `workflows/` with a descriptive name +2. Create `README.md` with proper frontmatter (name, description, triggers, tags) +3. Add one or more `.md` workflow files with `on`, `permissions`, and `safe-outputs` frontmatter +4. Add any bundled scripts or assets to the folder +5. Update the README.md by running: `npm run build` +6. 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 +263,17 @@ 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 folders (workflows/*/): +- [ ] Folder contains a README.md file with 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 +- [ ] Folder name is lower case with hyphens +- [ ] Contains at least one `.md` workflow file with `on` and `permissions` in frontmatter +- [ ] Workflow uses least-privilege permissions and safe outputs +- [ ] 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..da0b2d5d5 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -161,11 +161,75 @@ 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 a new workflow folder**: Add a new folder in the `workflows/` directory with a descriptive name (e.g., `daily-issues-report`) +2. **Create a `README.md`**: Add a `README.md` with frontmatter containing `name`, `description`, `triggers`, and optionally `tags` +3. **Add workflow files**: Include one or more `.md` workflow files with YAML frontmatter (`on`, `permissions`, `safe-outputs`) and natural language instructions +4. **Add optional assets**: Include any helper scripts or configuration files referenced by the workflow +5. **Update the README**: Run `npm run build` to update the generated README tables + +#### Workflow folder structure + +``` +workflows/daily-issues-report/ +├── README.md # Workflow documentation with frontmatter +└── daily-issues-report.md # Agentic workflow file +``` + +#### README.md frontmatter 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'] +--- +``` + +#### Workflow file example + +```markdown +--- +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 folder names with hyphens +- **Test locally**: Use `gh aw run` to test workflows before contributing +- **Documentation**: Include a thorough README explaining what the workflow does and how to use it +- 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 +298,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..026b70588 --- /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 folder containing a `README.md` and one or more `.md` workflow files +- 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..bf5a89043 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 folder containing a \`README.md\` and one or more \`.md\` workflow files +- 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..28b20fadc 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,67 @@ function generateHooksData(gitDates) { }; } +/** + * Generate workflows metadata (folder-based, similar to hooks) + */ +function generateWorkflowsData(gitDates) { + const workflows = []; + + if (!fs.existsSync(WORKFLOWS_DIR)) { + return { + items: workflows, + filters: { + triggers: [], + tags: [], + }, + }; + } + + const workflowFolders = fs.readdirSync(WORKFLOWS_DIR).filter((file) => { + const filePath = path.join(WORKFLOWS_DIR, file); + return fs.statSync(filePath).isDirectory(); + }); + + const allTriggers = new Set(); + const allTags = new Set(); + + for (const folder of workflowFolders) { + const workflowPath = path.join(WORKFLOWS_DIR, folder); + const metadata = parseWorkflowMetadata(workflowPath); + if (!metadata) continue; + + const relativePath = path + .relative(ROOT_FOLDER, workflowPath) + .replace(/\\/g, "/"); + const readmeRelativePath = `${relativePath}/README.md`; + + (metadata.triggers || []).forEach((t) => allTriggers.add(t)); + (metadata.tags || []).forEach((t) => allTags.add(t)); + + workflows.push({ + id: folder, + title: metadata.name, + description: metadata.description, + triggers: metadata.triggers || [], + tags: metadata.tags || [], + assets: metadata.assets || [], + path: relativePath, + readmeFile: readmeRelativePath, + lastUpdated: gitDates.get(readmeRelativePath) || 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 +669,7 @@ function generateSearchIndex( prompts, instructions, hooks, + workflows, skills, plugins ) { @@ -665,6 +729,20 @@ function generateSearchIndex( }); } + for (const workflow of workflows) { + index.push({ + type: "workflow", + id: workflow.id, + title: workflow.title, + description: workflow.description, + path: workflow.readmeFile, + 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 +877,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 +895,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 +941,7 @@ async function main() { prompts, instructions, hooks, + workflows, skills, plugins ); @@ -873,6 +958,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 +1007,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..534a591ae 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,67 @@ 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 workflow folders (directories) + const workflowFolders = fs.readdirSync(workflowsDir).filter((file) => { + const filePath = path.join(workflowsDir, file); + return fs.statSync(filePath).isDirectory(); + }); + + // Parse each workflow folder + const workflowEntries = workflowFolders + .map((folder) => { + const workflowPath = path.join(workflowsDir, folder); + const metadata = parseWorkflowMetadata(workflowPath); + if (!metadata) return null; + + return { + folder, + name: metadata.name, + description: metadata.description, + triggers: metadata.triggers, + tags: metadata.tags, + assets: metadata.assets, + }; + }) + .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 | Bundled Assets |\n| ---- | ----------- | -------- | -------------- |\n"; + + // Generate table rows for each workflow + for (const workflow of workflowEntries) { + const link = `../workflows/${workflow.folder}/README.md`; + const triggers = workflow.triggers.length > 0 ? workflow.triggers.join(", ") : "N/A"; + const assetsList = + workflow.assets.length > 0 + ? workflow.assets.map((a) => `\`${a}\``).join("
") + : "None"; + + content += `| [${workflow.name}](${link}) | ${formatTableCell( + workflow.description + )} | ${triggers} | ${assetsList} |\n`; + } + + return `${TEMPLATES.workflowsSection}\n${TEMPLATES.workflowsUsage}\n\n${content}`; +} + /** * Generate the skills section with a table of all skills */ @@ -921,6 +984,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 +1023,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 +1063,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..ded432690 100644 --- a/eng/yaml-parser.mjs +++ b/eng/yaml-parser.mjs @@ -253,6 +253,67 @@ function parseHookMetadata(hookPath) { ); } +/** + * Parse workflow metadata from a workflow folder + * @param {string} workflowPath - Path to the workflow folder + * @returns {object|null} Workflow metadata or null on error + */ +function parseWorkflowMetadata(workflowPath) { + return safeFileOperation( + () => { + const readmeFile = path.join(workflowPath, "README.md"); + if (!fs.existsSync(readmeFile)) { + return null; + } + + const frontmatter = parseFrontmatter(readmeFile); + + // Validate required fields + if (!frontmatter?.name || !frontmatter?.description) { + console.warn( + `Invalid workflow at ${workflowPath}: missing name or description in frontmatter` + ); + return null; + } + + // Extract triggers from frontmatter if present + const triggers = frontmatter.triggers || []; + + // List bundled assets (all files except README.md), recursing through subdirectories + const getAllFiles = (dirPath, arrayOfFiles = []) => { + const files = fs.readdirSync(dirPath); + + files.forEach((file) => { + const filePath = path.join(dirPath, file); + if (fs.statSync(filePath).isDirectory()) { + arrayOfFiles = getAllFiles(filePath, arrayOfFiles); + } else { + const relativePath = path.relative(workflowPath, filePath); + if (relativePath !== "README.md") { + arrayOfFiles.push(relativePath.replace(/\\/g, "/")); + } + } + }); + + return arrayOfFiles; + }; + + const assets = getAllFiles(workflowPath).sort(); + + return { + name: frontmatter.name, + description: frontmatter.description, + triggers, + tags: frontmatter.tags || [], + assets, + path: workflowPath, + }; + }, + workflowPath, + null + ); +} + /** * Parse a generic YAML file (used for tools.yml and other config files) * @param {string} filePath - Path to the YAML file @@ -276,6 +337,7 @@ export { parseFrontmatter, parseSkillMetadata, parseHookMetadata, + parseWorkflowMetadata, parseYamlFile, safeFileOperation, }; diff --git a/workflows/.gitkeep b/workflows/.gitkeep new file mode 100644 index 000000000..e69de29bb From 78eaeb22b7b07c79d2494240691ad75f96645766 Mon Sep 17 00:00:00 2001 From: Bruno Borges Date: Fri, 20 Feb 2026 15:33:28 -0800 Subject: [PATCH 2/6] Add CI workflow to validate agentic workflow compilation Adds validate-agentic-workflows.yml that runs on PRs touching workflows/. Uses gh-aw CLI setup action to install the compiler, then runs 'gh aw compile --validate' on each workflow .md file. Posts a sticky PR comment with fix instructions on failure. Also adds workflows/** to validate-readme.yml path triggers so README tables are regenerated when workflows change. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../workflows/validate-agentic-workflows.yml | 73 +++++++++++++++++++ .github/workflows/validate-readme.yml | 1 + 2 files changed, 74 insertions(+) create mode 100644 .github/workflows/validate-agentic-workflows.yml diff --git a/.github/workflows/validate-agentic-workflows.yml b/.github/workflows/validate-agentic-workflows.yml new file mode 100644 index 000000000..7c8ab391d --- /dev/null +++ b/.github/workflows/validate-agentic-workflows.yml @@ -0,0 +1,73 @@ +name: Validate Agentic Workflows + +on: + pull_request: + branches: [staged] + types: [opened, synchronize, reopened] + paths: + - "workflows/**" + +permissions: + contents: read + pull-requests: write + +jobs: + validate-workflows: + 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: Find and compile workflow files + id: compile + run: | + exit_code=0 + found=0 + + # Find all .md files in workflows/ subfolders (excluding README.md) + for workflow_file in workflows/*/*.md; do + [ -f "$workflow_file" ] || continue + basename=$(basename "$workflow_file") + [ "$basename" = "README.md" ] && 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 (README.md files are excluded)." + 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/**" From e83cc6efee1dc3c43c31e55e94436617912fd3c6 Mon Sep 17 00:00:00 2001 From: Bruno Borges Date: Fri, 20 Feb 2026 15:37:51 -0800 Subject: [PATCH 3/6] Add CI guard to block forbidden files in workflows/ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prevents contributors from pushing compiled YAML (.yml, .yaml, .lock.yml) or .github/ directories into the workflows/ directory. Only .md markdown source files are accepted — compilation happens downstream via gh aw compile. This is a security measure to prevent malicious GitHub Actions code from being introduced through contributed agentic workflows. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/workflows/block-workflow-yaml.yml | 64 +++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 .github/workflows/block-workflow-yaml.yml diff --git a/.github/workflows/block-workflow-yaml.yml b/.github/workflows/block-workflow-yaml.yml new file mode 100644 index 000000000..25844308e --- /dev/null +++ b/.github/workflows/block-workflow-yaml.yml @@ -0,0 +1,64 @@ +name: Block Forbidden Workflow Contribution Files + +on: + pull_request: + branches: [staged] + types: [opened, synchronize, reopened] + paths: + - "workflows/**" + +permissions: + contents: read + pull-requests: write + +jobs: + check-forbidden-files: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Check for forbidden files in workflows/ + 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 in workflows/" + 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. From 53401cb560ffd4e76e43eadedd5c71ea9b1d770c Mon Sep 17 00:00:00 2001 From: Bruno Borges Date: Fri, 20 Feb 2026 15:53:03 -0800 Subject: [PATCH 4/6] Simplify workflows to flat .md files instead of folders MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Workflows are now standalone .md files in workflows/ — no subfolders or README.md needed. Each file contains both the metadata frontmatter (name, description, triggers, tags) and the agentic workflow definition (on, permissions, safe-outputs) in a single file. Updated all build scripts, CI workflows, docs, and review checklists. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../workflows/validate-agentic-workflows.yml | 8 ++-- AGENTS.md | 38 +++++++++--------- CONTRIBUTING.md | 32 +++++---------- docs/README.workflows.md | 2 +- eng/constants.mjs | 2 +- eng/generate-website-data.mjs | 25 ++++++------ eng/update-readme.mjs | 30 ++++++-------- eng/yaml-parser.mjs | 39 ++++--------------- 8 files changed, 64 insertions(+), 112 deletions(-) diff --git a/.github/workflows/validate-agentic-workflows.yml b/.github/workflows/validate-agentic-workflows.yml index 7c8ab391d..9cdab41d4 100644 --- a/.github/workflows/validate-agentic-workflows.yml +++ b/.github/workflows/validate-agentic-workflows.yml @@ -27,11 +27,9 @@ jobs: exit_code=0 found=0 - # Find all .md files in workflows/ subfolders (excluding README.md) - for workflow_file in workflows/*/*.md; do + # Find all .md files directly in workflows/ + for workflow_file in workflows/*.md; do [ -f "$workflow_file" ] || continue - basename=$(basename "$workflow_file") - [ "$basename" = "README.md" ] && continue found=$((found + 1)) echo "::group::Compiling $workflow_file" @@ -45,7 +43,7 @@ jobs: done if [ "$found" -eq 0 ]; then - echo "No workflow .md files found to validate (README.md files are excluded)." + echo "No workflow .md files found to validate." else echo "Validated $found workflow file(s)." fi diff --git a/AGENTS.md b/AGENTS.md index faed71272..6bda52038 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -21,7 +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 (folders with README.md + workflow .md files) +├── 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 @@ -98,14 +98,14 @@ 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 Folders (workflows/*/README.md) -- Each workflow is a folder containing a `README.md` file with frontmatter and one or more `.md` workflow files -- README.md must have `name` field (human-readable name) -- README.md must have `description` field (wrapped in single quotes, not empty) -- README.md should have `triggers` field (array of trigger types, e.g., `['schedule', 'issues']`) -- Workflow `.md` files contain YAML frontmatter (`on`, `permissions`, `safe-outputs`) and natural language instructions -- Folder names should be lower case with words separated by hyphens -- Can include bundled assets (scripts, configuration files) +#### 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) @@ -139,12 +139,11 @@ When adding a new agent, prompt, instruction, skill, hook, workflow, or plugin: **For Workflows:** -1. Create a new folder in `workflows/` with a descriptive name -2. Create `README.md` with proper frontmatter (name, description, triggers, tags) -3. Add one or more `.md` workflow files with `on`, `permissions`, and `safe-outputs` frontmatter -4. Add any bundled scripts or assets to the folder -5. Update the README.md by running: `npm run build` -6. Verify the workflow appears in the generated README +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:** @@ -263,14 +262,15 @@ 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 folders (workflows/*/): -- [ ] Folder contains a README.md file with markdown front matter +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 -- [ ] Folder name is lower case with hyphens -- [ ] Contains at least one `.md` workflow file with `on` and `permissions` in frontmatter +- [ ] 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 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index da0b2d5d5..63e7630c8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -165,21 +165,14 @@ plugins/my-plugin-id/ [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 a new workflow folder**: Add a new folder in the `workflows/` directory with a descriptive name (e.g., `daily-issues-report`) -2. **Create a `README.md`**: Add a `README.md` with frontmatter containing `name`, `description`, `triggers`, and optionally `tags` -3. **Add workflow files**: Include one or more `.md` workflow files with YAML frontmatter (`on`, `permissions`, `safe-outputs`) and natural language instructions -4. **Add optional assets**: Include any helper scripts or configuration files referenced by the workflow -5. **Update the README**: Run `npm run build` to update the generated README tables +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 -#### Workflow folder structure +> **Note:** Only `.md` files are accepted — do not include compiled `.lock.yml` or `.yml` files. CI will block them. -``` -workflows/daily-issues-report/ -├── README.md # Workflow documentation with frontmatter -└── daily-issues-report.md # Agentic workflow file -``` - -#### README.md frontmatter example +#### Workflow file example ```markdown --- @@ -187,13 +180,6 @@ 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'] ---- -``` - -#### Workflow file example - -```markdown ---- on: schedule: daily on weekdays permissions: @@ -220,9 +206,9 @@ Create a daily summary of open issues for the team. - **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 folder names with hyphens -- **Test locally**: Use `gh aw run` to test workflows before contributing -- **Documentation**: Include a thorough README explaining what the workflow does and how to use it +- **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 diff --git a/docs/README.workflows.md b/docs/README.workflows.md index 026b70588..93bdfdca4 100644 --- a/docs/README.workflows.md +++ b/docs/README.workflows.md @@ -5,7 +5,7 @@ ### How to Use Agentic Workflows **What's Included:** -- Each workflow is a folder containing a `README.md` and one or more `.md` workflow files +- 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) diff --git a/eng/constants.mjs b/eng/constants.mjs index bf5a89043..6736c243b 100644 --- a/eng/constants.mjs +++ b/eng/constants.mjs @@ -135,7 +135,7 @@ Hooks enable automated workflows triggered by specific events during GitHub Copi workflowsUsage: `### How to Use Agentic Workflows **What's Included:** -- Each workflow is a folder containing a \`README.md\` and one or more \`.md\` workflow files +- 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) diff --git a/eng/generate-website-data.mjs b/eng/generate-website-data.mjs index 28b20fadc..9eb3da00c 100644 --- a/eng/generate-website-data.mjs +++ b/eng/generate-website-data.mjs @@ -195,7 +195,7 @@ function generateHooksData(gitDates) { } /** - * Generate workflows metadata (folder-based, similar to hooks) + * Generate workflows metadata (flat .md files) */ function generateWorkflowsData(gitDates) { const workflows = []; @@ -210,37 +210,34 @@ function generateWorkflowsData(gitDates) { }; } - const workflowFolders = fs.readdirSync(WORKFLOWS_DIR).filter((file) => { - const filePath = path.join(WORKFLOWS_DIR, file); - return fs.statSync(filePath).isDirectory(); + const workflowFiles = fs.readdirSync(WORKFLOWS_DIR).filter((file) => { + return file.endsWith(".md") && file !== ".gitkeep"; }); const allTriggers = new Set(); const allTags = new Set(); - for (const folder of workflowFolders) { - const workflowPath = path.join(WORKFLOWS_DIR, folder); - const metadata = parseWorkflowMetadata(workflowPath); + 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, workflowPath) + .relative(ROOT_FOLDER, filePath) .replace(/\\/g, "/"); - const readmeRelativePath = `${relativePath}/README.md`; (metadata.triggers || []).forEach((t) => allTriggers.add(t)); (metadata.tags || []).forEach((t) => allTags.add(t)); + const id = path.basename(file, ".md"); workflows.push({ - id: folder, + id, title: metadata.name, description: metadata.description, triggers: metadata.triggers || [], tags: metadata.tags || [], - assets: metadata.assets || [], path: relativePath, - readmeFile: readmeRelativePath, - lastUpdated: gitDates.get(readmeRelativePath) || null, + lastUpdated: gitDates.get(relativePath) || null, }); } @@ -735,7 +732,7 @@ function generateSearchIndex( id: workflow.id, title: workflow.title, description: workflow.description, - path: workflow.readmeFile, + path: workflow.path, lastUpdated: workflow.lastUpdated, searchText: `${workflow.title} ${workflow.description} ${workflow.triggers.join( " " diff --git a/eng/update-readme.mjs b/eng/update-readme.mjs index 534a591ae..3456d5c65 100644 --- a/eng/update-readme.mjs +++ b/eng/update-readme.mjs @@ -588,26 +588,24 @@ function generateWorkflowsSection(workflowsDir) { return ""; } - // Get all workflow folders (directories) - const workflowFolders = fs.readdirSync(workflowsDir).filter((file) => { - const filePath = path.join(workflowsDir, file); - return fs.statSync(filePath).isDirectory(); + // Get all .md workflow files (flat, no subfolders) + const workflowFiles = fs.readdirSync(workflowsDir).filter((file) => { + return file.endsWith(".md") && file !== ".gitkeep"; }); - // Parse each workflow folder - const workflowEntries = workflowFolders - .map((folder) => { - const workflowPath = path.join(workflowsDir, folder); - const metadata = parseWorkflowMetadata(workflowPath); + // Parse each workflow file + const workflowEntries = workflowFiles + .map((file) => { + const filePath = path.join(workflowsDir, file); + const metadata = parseWorkflowMetadata(filePath); if (!metadata) return null; return { - folder, + file, name: metadata.name, description: metadata.description, triggers: metadata.triggers, tags: metadata.tags, - assets: metadata.assets, }; }) .filter((entry) => entry !== null) @@ -621,20 +619,16 @@ function generateWorkflowsSection(workflowsDir) { // Create table header let content = - "| Name | Description | Triggers | Bundled Assets |\n| ---- | ----------- | -------- | -------------- |\n"; + "| Name | Description | Triggers |\n| ---- | ----------- | -------- |\n"; // Generate table rows for each workflow for (const workflow of workflowEntries) { - const link = `../workflows/${workflow.folder}/README.md`; + const link = `../workflows/${workflow.file}`; const triggers = workflow.triggers.length > 0 ? workflow.triggers.join(", ") : "N/A"; - const assetsList = - workflow.assets.length > 0 - ? workflow.assets.map((a) => `\`${a}\``).join("
") - : "None"; content += `| [${workflow.name}](${link}) | ${formatTableCell( workflow.description - )} | ${triggers} | ${assetsList} |\n`; + )} | ${triggers} |\n`; } return `${TEMPLATES.workflowsSection}\n${TEMPLATES.workflowsUsage}\n\n${content}`; diff --git a/eng/yaml-parser.mjs b/eng/yaml-parser.mjs index ded432690..88d16582f 100644 --- a/eng/yaml-parser.mjs +++ b/eng/yaml-parser.mjs @@ -254,24 +254,23 @@ function parseHookMetadata(hookPath) { } /** - * Parse workflow metadata from a workflow folder - * @param {string} workflowPath - Path to the workflow folder + * 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(workflowPath) { +function parseWorkflowMetadata(filePath) { return safeFileOperation( () => { - const readmeFile = path.join(workflowPath, "README.md"); - if (!fs.existsSync(readmeFile)) { + if (!fs.existsSync(filePath)) { return null; } - const frontmatter = parseFrontmatter(readmeFile); + const frontmatter = parseFrontmatter(filePath); // Validate required fields if (!frontmatter?.name || !frontmatter?.description) { console.warn( - `Invalid workflow at ${workflowPath}: missing name or description in frontmatter` + `Invalid workflow at ${filePath}: missing name or description in frontmatter` ); return null; } @@ -279,37 +278,15 @@ function parseWorkflowMetadata(workflowPath) { // Extract triggers from frontmatter if present const triggers = frontmatter.triggers || []; - // List bundled assets (all files except README.md), recursing through subdirectories - const getAllFiles = (dirPath, arrayOfFiles = []) => { - const files = fs.readdirSync(dirPath); - - files.forEach((file) => { - const filePath = path.join(dirPath, file); - if (fs.statSync(filePath).isDirectory()) { - arrayOfFiles = getAllFiles(filePath, arrayOfFiles); - } else { - const relativePath = path.relative(workflowPath, filePath); - if (relativePath !== "README.md") { - arrayOfFiles.push(relativePath.replace(/\\/g, "/")); - } - } - }); - - return arrayOfFiles; - }; - - const assets = getAllFiles(workflowPath).sort(); - return { name: frontmatter.name, description: frontmatter.description, triggers, tags: frontmatter.tags || [], - assets, - path: workflowPath, + path: filePath, }; }, - workflowPath, + filePath, null ); } From e470afe0cb9c2843e0f2ae3a46039ec524f43ecd Mon Sep 17 00:00:00 2001 From: Bruno Borges Date: Fri, 20 Feb 2026 15:59:44 -0800 Subject: [PATCH 5/6] Add Agentic Workflow option to PR template Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/pull_request_template.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) 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): --- From f058d7cd440405ae149b6e792b73d125c28cc193 Mon Sep 17 00:00:00 2001 From: Bruno Borges Date: Fri, 20 Feb 2026 16:03:07 -0800 Subject: [PATCH 6/6] Combine workflow CI checks into single multi-job workflow Merges the two separate action workflows (block-workflow-yaml.yml and validate-agentic-workflows.yml) into a single validate-agentic-workflows-pr.yml with two jobs: check-forbidden-files runs first, then compile-workflows runs only if the file check passes. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/workflows/block-workflow-yaml.yml | 64 --------- .../validate-agentic-workflows-pr.yml | 125 ++++++++++++++++++ .../workflows/validate-agentic-workflows.yml | 71 ---------- 3 files changed, 125 insertions(+), 135 deletions(-) delete mode 100644 .github/workflows/block-workflow-yaml.yml create mode 100644 .github/workflows/validate-agentic-workflows-pr.yml delete mode 100644 .github/workflows/validate-agentic-workflows.yml diff --git a/.github/workflows/block-workflow-yaml.yml b/.github/workflows/block-workflow-yaml.yml deleted file mode 100644 index 25844308e..000000000 --- a/.github/workflows/block-workflow-yaml.yml +++ /dev/null @@ -1,64 +0,0 @@ -name: Block Forbidden Workflow Contribution Files - -on: - pull_request: - branches: [staged] - types: [opened, synchronize, reopened] - paths: - - "workflows/**" - -permissions: - contents: read - pull-requests: write - -jobs: - check-forbidden-files: - runs-on: ubuntu-latest - steps: - - name: Checkout code - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - name: Check for forbidden files in workflows/ - 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 in workflows/" - 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. 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-agentic-workflows.yml b/.github/workflows/validate-agentic-workflows.yml deleted file mode 100644 index 9cdab41d4..000000000 --- a/.github/workflows/validate-agentic-workflows.yml +++ /dev/null @@ -1,71 +0,0 @@ -name: Validate Agentic Workflows - -on: - pull_request: - branches: [staged] - types: [opened, synchronize, reopened] - paths: - - "workflows/**" - -permissions: - contents: read - pull-requests: write - -jobs: - validate-workflows: - 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: Find and 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.