From eb6367cf9419506bba28fb59ceb66d17d85eab02 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Fri, 23 Jan 2026 15:55:19 +0000
Subject: [PATCH 1/4] Initial plan


From fd556ca2443ca12a6b44555f5053b74c7a5cd7de Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Fri, 23 Jan 2026 16:02:30 +0000
Subject: [PATCH 2/4] Fix custom safe-outputs documentation

Co-authored-by: dsyme <7204669+dsyme@users.noreply.github.com>
---
 .../docs/guides/custom-safe-outputs.md        | 320 +++++++++++++++---
 1 file changed, 272 insertions(+), 48 deletions(-)

diff --git a/docs/src/content/docs/guides/custom-safe-outputs.md b/docs/src/content/docs/guides/custom-safe-outputs.md
index 9cd9cadf773..b3173af15b0 100644
--- a/docs/src/content/docs/guides/custom-safe-outputs.md
+++ b/docs/src/content/docs/guides/custom-safe-outputs.md
@@ -38,13 +38,18 @@ safe-outputs:
         - name: Send Slack message
           env:
             SLACK_WEBHOOK: "${{ secrets.SLACK_WEBHOOK }}"
-            MESSAGE: "${{ inputs.message }}"
           run: |
-            # Use jq to safely escape JSON content
-            PAYLOAD=$(jq -n --arg text "$MESSAGE" '{text: $text}')
-            curl -X POST "$SLACK_WEBHOOK" \
-              -H 'Content-Type: application/json' \
-              -d "$PAYLOAD"
+            if [ -f "$GH_AW_AGENT_OUTPUT" ]; then
+              MESSAGE=$(cat "$GH_AW_AGENT_OUTPUT" | jq -r '.items[] | select(.type == "slack_notify") | .message')
+              # Use jq to safely escape JSON content
+              PAYLOAD=$(jq -n --arg text "$MESSAGE" '{text: $text}')
+              curl -X POST "$SLACK_WEBHOOK" \
+                -H 'Content-Type: application/json' \
+                -d "$PAYLOAD"
+            else
+              echo "No agent output found"
+              exit 1
+            fi
 ---
 ```
 
@@ -150,49 +155,65 @@ safe-outputs:
           uses: actions/github-script@v8
           env:
             NOTION_TOKEN: "${{ secrets.NOTION_TOKEN }}"
-            PAGE_ID: "${{ inputs.page_id }}"
-            COMMENT: "${{ inputs.comment }}"
           with:
             script: |
+              const fs = require('fs');
               const notionToken = process.env.NOTION_TOKEN;
-              const pageId = process.env.PAGE_ID;
-              const comment = process.env.COMMENT;
+              const outputFile = process.env.GH_AW_AGENT_OUTPUT;
               
               if (!notionToken) {
                 core.setFailed('NOTION_TOKEN secret is not configured');
                 return;
               }
               
-              core.info(`Adding comment to Notion page: ${pageId}`);
+              if (!outputFile) {
+                core.info('No GH_AW_AGENT_OUTPUT environment variable found');
+                return;
+              }
               
-              try {
-                const response = await fetch('https://api.notion.com/v1/comments', {
-                  method: 'POST',
-                  headers: {
-                    'Authorization': `Bearer ${notionToken}`,
-                    'Notion-Version': '2022-06-28',
-                    'Content-Type': 'application/json'
-                  },
-                  body: JSON.stringify({
-                    parent: { page_id: pageId },
-                    rich_text: [{
-                      type: 'text',
-                      text: { content: comment }
-                    }]
-                  })
-                });
+              // Read and parse agent output
+              const fileContent = fs.readFileSync(outputFile, 'utf8');
+              const agentOutput = JSON.parse(fileContent);
+              
+              // Filter for notion-add-comment items (job name with dashes → underscores)
+              const items = agentOutput.items.filter(item => item.type === 'notion_add_comment');
+              
+              for (const item of items) {
+                const pageId = item.page_id;
+                const comment = item.comment;
                 
-                if (!response.ok) {
-                  const errorData = await response.text();
-                  core.setFailed(`Notion API error (${response.status}): ${errorData}`);
+                core.info(`Adding comment to Notion page: ${pageId}`);
+                
+                try {
+                  const response = await fetch('https://api.notion.com/v1/comments', {
+                    method: 'POST',
+                    headers: {
+                      'Authorization': `Bearer ${notionToken}`,
+                      'Notion-Version': '2022-06-28',
+                      'Content-Type': 'application/json'
+                    },
+                    body: JSON.stringify({
+                      parent: { page_id: pageId },
+                      rich_text: [{
+                        type: 'text',
+                        text: { content: comment }
+                      }]
+                    })
+                  });
+                  
+                  if (!response.ok) {
+                    const errorData = await response.text();
+                    core.setFailed(`Notion API error (${response.status}): ${errorData}`);
+                    return;
+                  }
+                  
+                  const data = await response.json();
+                  core.info('Comment added successfully');
+                  core.info(`Comment ID: ${data.id}`);
+                } catch (error) {
+                  core.setFailed(`Failed to add comment: ${error.message}`);
                   return;
                 }
-                
-                const data = await response.json();
-                core.info('Comment added successfully');
-                core.info(`Comment ID: ${data.id}`);
-              } catch (error) {
-                core.setFailed(`Failed to add comment: ${error.message}`);
               }
 ---
 ```
@@ -271,13 +292,93 @@ inputs:
 
 ### Environment Variables
 
+Custom safe-output jobs have access to these environment variables:
+
 | Variable | Description |
 |----------|-------------|
-| `GH_AW_AGENT_OUTPUT` | Path to JSON file with agent output |
-| `GH_AW_SAFE_OUTPUTS_STAGED` | Set to `"true"` in staged mode |
-| `${{ inputs.NAME }}` | Each input as a variable |
+| `GH_AW_AGENT_OUTPUT` | Path to JSON file containing the agent's output data |
+| `GH_AW_SAFE_OUTPUTS_STAGED` | Set to `"true"` when running in staged/preview mode |
+
+**Important**: The `inputs:` field defines the MCP tool schema for the AI agent, not GitHub Actions workflow inputs. You **cannot** use `${{ inputs.name }}` syntax in custom safe-output jobs. Instead, read and parse the `GH_AW_AGENT_OUTPUT` JSON file to access the agent's provided values.
+
+### Accessing Agent Output
+
+Custom safe-output jobs receive the agent's data through the `GH_AW_AGENT_OUTPUT` environment variable, which contains a path to a JSON file. This file has the structure:
+
+```json
+{
+  "items": [
+    {
+      "type": "job_name_with_underscores",
+      "field1": "value1",
+      "field2": "value2"
+    }
+  ]
+}
+```
+
+The `type` field matches your job name with dashes converted to underscores (e.g., job `webhook-notify` → type `webhook_notify`).
+
+#### Bash Example
+
+```yaml
+steps:
+  - name: Process output
+    run: |
+      if [ -f "$GH_AW_AGENT_OUTPUT" ]; then
+        # Extract specific field from matching items
+        MESSAGE=$(cat "$GH_AW_AGENT_OUTPUT" | jq -r '.items[] | select(.type == "my_job") | .message')
+        echo "Message: $MESSAGE"
+      else
+        echo "No agent output found"
+        exit 1
+      fi
+```
+
+#### JavaScript Example
+
+```yaml
+steps:
+  - name: Process output
+    uses: actions/github-script@v8
+    with:
+      script: |
+        const fs = require('fs');
+        const outputFile = process.env.GH_AW_AGENT_OUTPUT;
+        
+        if (!outputFile) {
+          core.info('No GH_AW_AGENT_OUTPUT environment variable found');
+          return;
+        }
+        
+        // Read and parse the JSON file
+        const fileContent = fs.readFileSync(outputFile, 'utf8');
+        const agentOutput = JSON.parse(fileContent);
+        
+        // Filter for items matching this job (job-name → job_name)
+        const items = agentOutput.items.filter(item => item.type === 'my_job');
+        
+        // Process each item
+        for (const item of items) {
+          const message = item.message;
+          core.info(`Processing: ${message}`);
+          // Your logic here
+        }
+```
+
+### Understanding `inputs:`
+
+The `inputs:` field in your job definition serves **two purposes**:
+
+1. **Tool Discovery**: Defines the MCP tool schema that the AI agent sees
+2. **Validation**: Describes what fields the agent should provide in its output
+
+**What `inputs:` does NOT do**:
+- ❌ Create GitHub Actions workflow inputs
+- ❌ Make `${{ inputs.* }}` expressions available in steps
+- ❌ Pass data directly to job steps
 
-Access inputs using `${{ inputs.name }}` in steps or via `process.env` in JavaScript.
+The agent uses the `inputs:` schema to understand what parameters to include when calling your custom job. The actual values are written to the `GH_AW_AGENT_OUTPUT` JSON file, which your job must read and parse.
 
 ## Complete Example
 
@@ -299,16 +400,49 @@ safe-outputs:
           type: string
       steps:
         - name: Send webhook
+          uses: actions/github-script@v8
           env:
             WEBHOOK_URL: "${{ secrets.WEBHOOK_URL }}"
-            TITLE: "${{ inputs.title }}"
-            BODY: "${{ inputs.body }}"
-          run: |
-            PAYLOAD=$(jq -n --arg title "$TITLE" --arg body "$BODY" \
-              '{title: $title, body: $body}')
-            curl -X POST "$WEBHOOK_URL" \
-              -H "Content-Type: application/json" \
-              -d "$PAYLOAD"
+          with:
+            script: |
+              const fs = require('fs');
+              const webhookUrl = process.env.WEBHOOK_URL;
+              const outputFile = process.env.GH_AW_AGENT_OUTPUT;
+              
+              if (!webhookUrl) {
+                core.setFailed('WEBHOOK_URL secret is not configured');
+                return;
+              }
+              
+              if (!outputFile) {
+                core.info('No GH_AW_AGENT_OUTPUT environment variable found');
+                return;
+              }
+              
+              // Read and parse agent output
+              const fileContent = fs.readFileSync(outputFile, 'utf8');
+              const agentOutput = JSON.parse(fileContent);
+              
+              // Filter for webhook-notify items (job name with dashes → underscores)
+              const items = agentOutput.items.filter(item => item.type === 'webhook_notify');
+              
+              for (const item of items) {
+                const title = item.title;
+                const body = item.body;
+                
+                const response = await fetch(webhookUrl, {
+                  method: 'POST',
+                  headers: { 'Content-Type': 'application/json' },
+                  body: JSON.stringify({ title, body })
+                });
+                
+                if (!response.ok) {
+                  core.setFailed(`Webhook failed: ${response.status}`);
+                  return;
+                }
+              }
+              
+              core.info('Notification sent successfully');
 ```
 
 ## Importing Custom Jobs
@@ -373,6 +507,96 @@ if (process.env.GH_AW_SAFE_OUTPUTS_STAGED === 'true') {
 // Actually send the notification
 ```
 
+## Common Mistakes
+
+### ❌ Using `${{ inputs.* }}` Syntax
+
+**This does NOT work:**
+
+```yaml
+steps:
+  - name: Wrong approach
+    env:
+      MESSAGE: "${{ inputs.message }}"  # ❌ This will be empty!
+    run: |
+      echo "$MESSAGE"  # Empty - inputs.* is not available
+```
+
+**Why it fails**: The `inputs:` field defines the MCP tool schema for the AI agent, not GitHub Actions workflow inputs. The `${{ inputs.* }}` syntax only works with workflow_dispatch inputs, not custom safe-output jobs.
+
+**✅ Correct approach:**
+
+```yaml
+steps:
+  - name: Correct approach
+    run: |
+      if [ -f "$GH_AW_AGENT_OUTPUT" ]; then
+        MESSAGE=$(cat "$GH_AW_AGENT_OUTPUT" | jq -r '.items[] | select(.type == "my_job") | .message')
+        echo "$MESSAGE"
+      fi
+```
+
+### ❌ Wrong Job Type Name
+
+**This does NOT work:**
+
+```yaml
+safe-outputs:
+  jobs:
+    notify-user:  # Job name with dashes
+      # ...
+      steps:
+        - run: |
+            # Wrong: using dashes in type filter
+            jq '.items[] | select(.type == "notify-user")'  # ❌ Won't match!
+```
+
+**Why it fails**: Job names with dashes are converted to underscores in the `type` field.
+
+**✅ Correct approach:**
+
+```yaml
+safe-outputs:
+  jobs:
+    notify-user:  # Job name with dashes
+      # ...
+      steps:
+        - run: |
+            # Correct: use underscores in type filter
+            jq '.items[] | select(.type == "notify_user")'  # ✅ Matches!
+```
+
+### ❌ Not Checking for Agent Output
+
+**This does NOT work:**
+
+```yaml
+steps:
+  - run: |
+      # ❌ Assumes file exists without checking
+      MESSAGE=$(cat "$GH_AW_AGENT_OUTPUT" | jq -r '.items[0].message')
+```
+
+**Why it fails**: If the agent doesn't call your tool, the file might not exist or be empty, causing errors.
+
+**✅ Correct approach:**
+
+```yaml
+steps:
+  - run: |
+      if [ -f "$GH_AW_AGENT_OUTPUT" ]; then
+        ITEMS=$(cat "$GH_AW_AGENT_OUTPUT" | jq '.items[] | select(.type == "my_job")')
+        if [ -z "$ITEMS" ]; then
+          echo "No items found for this job"
+          exit 0
+        fi
+        # Process items...
+      else
+        echo "No agent output file found"
+        exit 1
+      fi
+```
+
 ## Troubleshooting
 
 | Issue | Solution |

From 136077a4a1759a9eb23be060d42da56cf8cc99cc Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Fri, 23 Jan 2026 16:08:48 +0000
Subject: [PATCH 3/4] Complete documentation fix

Co-authored-by: dsyme <7204669+dsyme@users.noreply.github.com>
---
 docs/package-lock.json                        | 19 ++++++++++++++++++-
 .../src/content/docs/agent-factory-status.mdx |  2 ++
 2 files changed, 20 insertions(+), 1 deletion(-)

diff --git a/docs/package-lock.json b/docs/package-lock.json
index ba024078c4f..874f76f0452 100644
--- a/docs/package-lock.json
+++ b/docs/package-lock.json
@@ -165,6 +165,7 @@
       "resolved": "https://registry.npmjs.org/@astrojs/starlight/-/starlight-0.37.3.tgz",
       "integrity": "sha512-p7cqbAkBYkBTiK1NIomxAEoF9Wko+mTV503qDm5Wgh+0MGGJnSsIzCSSJ+rWm8toFk9mnzNwNbxcnjwzIBEU3w==",
       "license": "MIT",
+      "peer": true,
       "dependencies": {
         "@astrojs/markdown-remark": "^6.3.1",
         "@astrojs/mdx": "^4.2.3",
@@ -400,6 +401,7 @@
       "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==",
       "dev": true,
       "license": "MIT",
+      "peer": true,
       "dependencies": {
         "cssesc": "^3.0.0",
         "util-deprecate": "^1.0.2"
@@ -1235,6 +1237,7 @@
       "integrity": "sha512-DNCbwkAKugzCtiHJg/7DciIRwnKwAI2QH3VWWC1cVxoBBQTPnH5D9HcWqpDdduUqnCuW2PY78afVo+QlaInDdQ==",
       "dev": true,
       "license": "MIT",
+      "peer": true,
       "dependencies": {
         "@csstools/postcss-is-pseudo-class": "^5.0.3",
         "cssesc": "^3.0.0",
@@ -2258,6 +2261,7 @@
       "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
       "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
       "license": "MIT",
+      "peer": true,
       "bin": {
         "acorn": "bin/acorn"
       },
@@ -2456,6 +2460,7 @@
       "resolved": "https://registry.npmjs.org/astro/-/astro-5.16.12.tgz",
       "integrity": "sha512-R2LH1GW4JexpSMWffbpzkeZDAwbdZwI5BclXEwi+vIUPxQI+7Y9ZogJ5u4ukdYFGrcrie/0z+Od4i3MlR0nELQ==",
       "license": "MIT",
+      "peer": true,
       "dependencies": {
         "@astrojs/compiler": "^2.13.0",
         "@astrojs/internal-helpers": "0.7.5",
@@ -2979,6 +2984,7 @@
       "resolved": "https://registry.npmjs.org/chevrotain/-/chevrotain-11.0.3.tgz",
       "integrity": "sha512-ci2iJH6LeIkvP9eJW6gpueU8cnZhv85ELY8w8WiFtNjMHA5ad6pQLaJo9mEly/9qUyCpvqX8/POVUTf18/HFdw==",
       "license": "Apache-2.0",
+      "peer": true,
       "dependencies": {
         "@chevrotain/cst-dts-gen": "11.0.3",
         "@chevrotain/gast": "11.0.3",
@@ -3409,6 +3415,7 @@
       "resolved": "https://registry.npmjs.org/cytoscape/-/cytoscape-3.33.1.tgz",
       "integrity": "sha512-iJc4TwyANnOGR1OmWhsS9ayRS3s+XQ185FmuHObThD+5AeJCakAAbWv8KimMTt08xCCLNgneQwFp+JRJOr9qGQ==",
       "license": "MIT",
+      "peer": true,
       "engines": {
         "node": ">=0.10"
       }
@@ -3809,6 +3816,7 @@
       "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz",
       "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==",
       "license": "ISC",
+      "peer": true,
       "engines": {
         "node": ">=12"
       }
@@ -4049,7 +4057,8 @@
       "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1534754.tgz",
       "integrity": "sha512-26T91cV5dbOYnXdJi5qQHoTtUoNEqwkHcAyu/IKtjIAxiEqPMrDiRkDOPWVsGfNZGmlQVHQbZRSjD8sxagWVsQ==",
       "dev": true,
-      "license": "BSD-3-Clause"
+      "license": "BSD-3-Clause",
+      "peer": true
     },
     "node_modules/diff": {
       "version": "8.0.3",
@@ -6020,6 +6029,7 @@
       "resolved": "https://registry.npmjs.org/marked/-/marked-16.4.2.tgz",
       "integrity": "sha512-TI3V8YYWvkVf3KJe1dRkpnjs68JUPyEa5vjKrp1XEEJUAOaQc+Qj+L1qWbPd0SJuAdQkFU0h73sXXqwDYxsiDA==",
       "license": "MIT",
+      "peer": true,
       "bin": {
         "marked": "bin/marked.js"
       },
@@ -6422,6 +6432,7 @@
       "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-11.12.2.tgz",
       "integrity": "sha512-n34QPDPEKmaeCG4WDMGy0OT6PSyxKCfy2pJgShP+Qow2KLrvWjclwbc3yXfSIf4BanqWEhQEpngWwNp/XhZt6w==",
       "license": "MIT",
+      "peer": true,
       "dependencies": {
         "@braintree/sanitize-url": "^7.1.1",
         "@iconify/utils": "^3.0.1",
@@ -7833,6 +7844,7 @@
         }
       ],
       "license": "MIT",
+      "peer": true,
       "dependencies": {
         "nanoid": "^3.3.11",
         "picocolors": "^1.1.1",
@@ -7947,6 +7959,7 @@
       "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==",
       "dev": true,
       "license": "MIT",
+      "peer": true,
       "dependencies": {
         "cssesc": "^3.0.0",
         "util-deprecate": "^1.0.2"
@@ -8579,6 +8592,7 @@
       "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.50.1.tgz",
       "integrity": "sha512-78E9voJHwnXQMiQdiqswVLZwJIzdBKJ1GdI5Zx6XwoFKUIk09/sSrr+05QFzvYb8q6Y9pPV45zzDuYa3907TZA==",
       "license": "MIT",
+      "peer": true,
       "dependencies": {
         "@types/estree": "1.0.8"
       },
@@ -10157,6 +10171,7 @@
       "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.1.tgz",
       "integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==",
       "license": "MIT",
+      "peer": true,
       "dependencies": {
         "esbuild": "^0.25.0",
         "fdir": "^6.4.4",
@@ -10447,6 +10462,7 @@
       "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.2.tgz",
       "integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==",
       "license": "ISC",
+      "peer": true,
       "bin": {
         "yaml": "bin.mjs"
       },
@@ -10585,6 +10601,7 @@
       "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz",
       "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==",
       "license": "MIT",
+      "peer": true,
       "funding": {
         "url": "https://github.com/sponsors/colinhacks"
       }
diff --git a/docs/src/content/docs/agent-factory-status.mdx b/docs/src/content/docs/agent-factory-status.mdx
index a7566330623..545d0068e43 100644
--- a/docs/src/content/docs/agent-factory-status.mdx
+++ b/docs/src/content/docs/agent-factory-status.mdx
@@ -25,6 +25,7 @@ These are experimental agentic workflows used by the GitHub Next team to learn,
 | [Brave Web Search Agent](https://github.com/githubnext/gh-aw/blob/main/.github/workflows/brave.md) | copilot | [![Brave Web Search Agent](https://github.com/githubnext/gh-aw/actions/workflows/brave.lock.yml/badge.svg)](https://github.com/githubnext/gh-aw/actions/workflows/brave.lock.yml) | - | `/brave` |
 | [Breaking Change Checker](https://github.com/githubnext/gh-aw/blob/main/.github/workflows/breaking-change-checker.md) | copilot | [![Breaking Change Checker](https://github.com/githubnext/gh-aw/actions/workflows/breaking-change-checker.lock.yml/badge.svg)](https://github.com/githubnext/gh-aw/actions/workflows/breaking-change-checker.lock.yml) | - | - |
 | [Changeset Generator](https://github.com/githubnext/gh-aw/blob/main/.github/workflows/changeset.md) | codex | [![Changeset Generator](https://github.com/githubnext/gh-aw/actions/workflows/changeset.lock.yml/badge.svg)](https://github.com/githubnext/gh-aw/actions/workflows/changeset.lock.yml) | - | - |
+| [Chroma Issue Indexer](https://github.com/githubnext/gh-aw/blob/main/.github/workflows/chroma-issue-indexer.md) | copilot | [![Chroma Issue Indexer](https://github.com/githubnext/gh-aw/actions/workflows/chroma-issue-indexer.lock.yml/badge.svg)](https://github.com/githubnext/gh-aw/actions/workflows/chroma-issue-indexer.lock.yml) | `0 */4 * * *` | - |
 | [CI Cleaner](https://github.com/githubnext/gh-aw/blob/main/.github/workflows/hourly-ci-cleaner.md) | copilot | [![CI Cleaner](https://github.com/githubnext/gh-aw/actions/workflows/hourly-ci-cleaner.lock.yml/badge.svg)](https://github.com/githubnext/gh-aw/actions/workflows/hourly-ci-cleaner.lock.yml) | `0 6,18 * * *` | - |
 | [CI Failure Doctor](https://github.com/githubnext/gh-aw/blob/main/.github/workflows/ci-doctor.md) | copilot | [![CI Failure Doctor](https://github.com/githubnext/gh-aw/actions/workflows/ci-doctor.lock.yml/badge.svg)](https://github.com/githubnext/gh-aw/actions/workflows/ci-doctor.lock.yml) | - | - |
 | [CI Optimization Coach](https://github.com/githubnext/gh-aw/blob/main/.github/workflows/ci-coach.md) | copilot | [![CI Optimization Coach](https://github.com/githubnext/gh-aw/actions/workflows/ci-coach.lock.yml/badge.svg)](https://github.com/githubnext/gh-aw/actions/workflows/ci-coach.lock.yml) | `0 13 * * 1-5` | - |
@@ -59,6 +60,7 @@ These are experimental agentic workflows used by the GitHub Next team to learn,
 | [Daily Regulatory Report Generator](https://github.com/githubnext/gh-aw/blob/main/.github/workflows/daily-regulatory.md) | copilot | [![Daily Regulatory Report Generator](https://github.com/githubnext/gh-aw/actions/workflows/daily-regulatory.lock.yml/badge.svg)](https://github.com/githubnext/gh-aw/actions/workflows/daily-regulatory.lock.yml) | - | - |
 | [Daily Safe Output Tool Optimizer](https://github.com/githubnext/gh-aw/blob/main/.github/workflows/daily-safe-output-optimizer.md) | claude | [![Daily Safe Output Tool Optimizer](https://github.com/githubnext/gh-aw/actions/workflows/daily-safe-output-optimizer.lock.yml/badge.svg)](https://github.com/githubnext/gh-aw/actions/workflows/daily-safe-output-optimizer.lock.yml) | - | - |
 | [Daily Secrets Analysis Agent](https://github.com/githubnext/gh-aw/blob/main/.github/workflows/daily-secrets-analysis.md) | copilot | [![Daily Secrets Analysis Agent](https://github.com/githubnext/gh-aw/actions/workflows/daily-secrets-analysis.lock.yml/badge.svg)](https://github.com/githubnext/gh-aw/actions/workflows/daily-secrets-analysis.lock.yml) | - | - |
+| [Daily Semgrep Scan](https://github.com/githubnext/gh-aw/blob/main/.github/workflows/daily-semgrep-scan.md) | copilot | [![Daily Semgrep Scan](https://github.com/githubnext/gh-aw/actions/workflows/daily-semgrep-scan.lock.yml/badge.svg)](https://github.com/githubnext/gh-aw/actions/workflows/daily-semgrep-scan.lock.yml) | - | - |
 | [Daily Team Evolution Insights](https://github.com/githubnext/gh-aw/blob/main/.github/workflows/daily-team-evolution-insights.md) | claude | [![Daily Team Evolution Insights](https://github.com/githubnext/gh-aw/actions/workflows/daily-team-evolution-insights.lock.yml/badge.svg)](https://github.com/githubnext/gh-aw/actions/workflows/daily-team-evolution-insights.lock.yml) | - | - |
 | [Daily Team Status](https://github.com/githubnext/gh-aw/blob/main/.github/workflows/daily-team-status.md) | copilot | [![Daily Team Status](https://github.com/githubnext/gh-aw/actions/workflows/daily-team-status.lock.yml/badge.svg)](https://github.com/githubnext/gh-aw/actions/workflows/daily-team-status.lock.yml) | - | - |
 | [Daily Testify Uber Super Expert](https://github.com/githubnext/gh-aw/blob/main/.github/workflows/daily-testify-uber-super-expert.md) | copilot | [![Daily Testify Uber Super Expert](https://github.com/githubnext/gh-aw/actions/workflows/daily-testify-uber-super-expert.lock.yml/badge.svg)](https://github.com/githubnext/gh-aw/actions/workflows/daily-testify-uber-super-expert.lock.yml) | - | - |

From 9f13d5e8bdb46115259d6704c62ffa7990851d33 Mon Sep 17 00:00:00 2001
From: Don Syme <dsyme@users.noreply.github.com>
Date: Fri, 23 Jan 2026 16:15:43 +0000
Subject: [PATCH 4/4] Clarify 'inputs:' field usage in custom safe-outputs

Removed misleading information about the 'inputs:' field in custom safe-output jobs and added clarification on its purpose. Also, removed a complete example of sending a webhook notification to streamline the documentation.
---
 .../docs/guides/custom-safe-outputs.md        | 74 -------------------
 1 file changed, 74 deletions(-)

diff --git a/docs/src/content/docs/guides/custom-safe-outputs.md b/docs/src/content/docs/guides/custom-safe-outputs.md
index b3173af15b0..cacf7dce6e3 100644
--- a/docs/src/content/docs/guides/custom-safe-outputs.md
+++ b/docs/src/content/docs/guides/custom-safe-outputs.md
@@ -299,8 +299,6 @@ Custom safe-output jobs have access to these environment variables:
 | `GH_AW_AGENT_OUTPUT` | Path to JSON file containing the agent's output data |
 | `GH_AW_SAFE_OUTPUTS_STAGED` | Set to `"true"` when running in staged/preview mode |
 
-**Important**: The `inputs:` field defines the MCP tool schema for the AI agent, not GitHub Actions workflow inputs. You **cannot** use `${{ inputs.name }}` syntax in custom safe-output jobs. Instead, read and parse the `GH_AW_AGENT_OUTPUT` JSON file to access the agent's provided values.
-
 ### Accessing Agent Output
 
 Custom safe-output jobs receive the agent's data through the `GH_AW_AGENT_OUTPUT` environment variable, which contains a path to a JSON file. This file has the structure:
@@ -373,78 +371,8 @@ The `inputs:` field in your job definition serves **two purposes**:
 1. **Tool Discovery**: Defines the MCP tool schema that the AI agent sees
 2. **Validation**: Describes what fields the agent should provide in its output
 
-**What `inputs:` does NOT do**:
-- ❌ Create GitHub Actions workflow inputs
-- ❌ Make `${{ inputs.* }}` expressions available in steps
-- ❌ Pass data directly to job steps
-
 The agent uses the `inputs:` schema to understand what parameters to include when calling your custom job. The actual values are written to the `GH_AW_AGENT_OUTPUT` JSON file, which your job must read and parse.
 
-## Complete Example
-
-```yaml wrap title="Send a webhook notification"
-safe-outputs:
-  jobs:
-    webhook-notify:
-      description: "Send a notification to a webhook URL"
-      runs-on: ubuntu-latest
-      output: "Notification sent!"
-      inputs:
-        title:
-          description: "Notification title"
-          required: true
-          type: string
-        body:
-          description: "Notification body"
-          required: true
-          type: string
-      steps:
-        - name: Send webhook
-          uses: actions/github-script@v8
-          env:
-            WEBHOOK_URL: "${{ secrets.WEBHOOK_URL }}"
-          with:
-            script: |
-              const fs = require('fs');
-              const webhookUrl = process.env.WEBHOOK_URL;
-              const outputFile = process.env.GH_AW_AGENT_OUTPUT;
-              
-              if (!webhookUrl) {
-                core.setFailed('WEBHOOK_URL secret is not configured');
-                return;
-              }
-              
-              if (!outputFile) {
-                core.info('No GH_AW_AGENT_OUTPUT environment variable found');
-                return;
-              }
-              
-              // Read and parse agent output
-              const fileContent = fs.readFileSync(outputFile, 'utf8');
-              const agentOutput = JSON.parse(fileContent);
-              
-              // Filter for webhook-notify items (job name with dashes → underscores)
-              const items = agentOutput.items.filter(item => item.type === 'webhook_notify');
-              
-              for (const item of items) {
-                const title = item.title;
-                const body = item.body;
-                
-                const response = await fetch(webhookUrl, {
-                  method: 'POST',
-                  headers: { 'Content-Type': 'application/json' },
-                  body: JSON.stringify({ title, body })
-                });
-                
-                if (!response.ok) {
-                  core.setFailed(`Webhook failed: ${response.status}`);
-                  return;
-                }
-              }
-              
-              core.info('Notification sent successfully');
-```
-
 ## Importing Custom Jobs
 
 Define jobs in shared files under `.github/workflows/shared/` and import them:
@@ -522,8 +450,6 @@ steps:
       echo "$MESSAGE"  # Empty - inputs.* is not available
 ```
 
-**Why it fails**: The `inputs:` field defines the MCP tool schema for the AI agent, not GitHub Actions workflow inputs. The `${{ inputs.* }}` syntax only works with workflow_dispatch inputs, not custom safe-output jobs.
-
 **✅ Correct approach:**
 
 ```yaml
