diff --git a/.github/workflows/impeccable-skills-reviewer.lock.yml b/.github/workflows/impeccable-skills-reviewer.lock.yml
index 3feb4387503..c0f0418a68b 100644
--- a/.github/workflows/impeccable-skills-reviewer.lock.yml
+++ b/.github/workflows/impeccable-skills-reviewer.lock.yml
@@ -1,4 +1,4 @@
-# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"078e036dc1a46842b6ba0c04f837c6f3b4cd5037fa233a6cdbf6372b59968afe","body_hash":"b435c26a5e5cef9f62e5753e0887491b004baa190720e8923247b24e075dd736","strict":true,"agent_id":"copilot","agent_model":"claude-sonnet-4.6","engine_versions":{"copilot":"1.0.73"}}
+# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"dcc67503304dfe7aab4dc7fe8d2864e75cb1ab41de1cbaa581500f2dffe8f4cc","body_hash":"0df7a92b23cd4452a265ba08251279f34766f7852c439148505e48bd9493c02f","strict":true,"agent_id":"copilot","agent_model":"claude-sonnet-4.6","engine_versions":{"copilot":"1.0.73"}}
 # gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GH_AW_OTEL_GRAFANA_AUTHORIZATION","GH_AW_OTEL_GRAFANA_ENDPOINT","GH_AW_OTEL_SENTRY_AUTHORIZATION","GH_AW_OTEL_SENTRY_ENDPOINT","GITHUB_TOKEN"],"actions":[{"repo":"actions/cache","sha":"55cc8345863c7cc4c66a329aec7e433d2d1c52a9","version":"v6.1.0"},{"repo":"actions/cache/restore","sha":"55cc8345863c7cc4c66a329aec7e433d2d1c52a9","version":"v6.1.0"},{"repo":"actions/cache/save","sha":"55cc8345863c7cc4c66a329aec7e433d2d1c52a9","version":"v6.1.0"},{"repo":"actions/checkout","sha":"9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0","version":"v7.0.0"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-node","sha":"820762786026740c76f36085b0efc47a31fe5020","version":"v7.0.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.27.37","digest":"sha256:0d35e8682845f183c1c634699a8e8a6cbe2c271b867031410df74533243c5f67","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.27.37@sha256:0d35e8682845f183c1c634699a8e8a6cbe2c271b867031410df74533243c5f67"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.37","digest":"sha256:fc2970aadaeae05993e76697d29f03dc8bfb9248ff87a8f3d8b0975485a4b317","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.37@sha256:fc2970aadaeae05993e76697d29f03dc8bfb9248ff87a8f3d8b0975485a4b317"},{"image":"ghcr.io/github/gh-aw-firewall/cli-proxy:0.27.37","digest":"sha256:1d5300d9b08e1c4f2ad1830860656a0656383a83280058f17e805a7c3ecda203","pinned_image":"ghcr.io/github/gh-aw-firewall/cli-proxy:0.27.37@sha256:1d5300d9b08e1c4f2ad1830860656a0656383a83280058f17e805a7c3ecda203"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.27.37","digest":"sha256:5abc51995e5901c5d1daeefc957301ee409980e2e607391ec22c06cb2513327b","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.27.37@sha256:5abc51995e5901c5d1daeefc957301ee409980e2e607391ec22c06cb2513327b"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.4.3","digest":"sha256:3c744710ea275cd5ee65db92a1099e0d980754bd9fafda9ce67704c67004dc83","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.4.3@sha256:3c744710ea275cd5ee65db92a1099e0d980754bd9fafda9ce67704c67004dc83"},{"image":"ghcr.io/github/gh-aw-node","digest":"sha256:529d02eb970b1161aa25c593a9c3df57fdfad5a8add328cb3b6eccef66f3183b","pinned_image":"ghcr.io/github/gh-aw-node@sha256:529d02eb970b1161aa25c593a9c3df57fdfad5a8add328cb3b6eccef66f3183b"},{"image":"ghcr.io/github/github-mcp-server:v1.6.0","digest":"sha256:2b0c48b070f61e9d3969269ead600f62d00fb237b60ac849ef3d166ee7de9ad3","pinned_image":"ghcr.io/github/github-mcp-server:v1.6.0@sha256:2b0c48b070f61e9d3969269ead600f62d00fb237b60ac849ef3d166ee7de9ad3"}],"has_pull_request":true}
 # This file was automatically generated by gh-aw. DO NOT EDIT. To debug this workflow, load the skill at https://github.com/github/gh-aw/blob/main/debug.md
 #
@@ -30,6 +30,7 @@
 #     - shared/github-guard-policy.md
 #     - shared/otlp.md
 #     - shared/pr-code-review-config.md
+#     - shared/pr-diff-data-fetch.md
 #     - shared/pr-review-base.md
 #     - shared/reporting.md
 #
@@ -298,20 +299,20 @@ jobs:
         run: |
           bash "${RUNNER_TEMP}/gh-aw/actions/create_prompt_first.sh"
           {
-          cat << 'GH_AW_PROMPT_6cb4a7bbd64e8acd_EOF'
+          cat << 'GH_AW_PROMPT_1ecd0bff414ab596_EOF'
           <system>
-          GH_AW_PROMPT_6cb4a7bbd64e8acd_EOF
+          GH_AW_PROMPT_1ecd0bff414ab596_EOF
           cat "${RUNNER_TEMP}/gh-aw/prompts/xpia.md"
           cat "${RUNNER_TEMP}/gh-aw/prompts/temp_folder_prompt.md"
           cat "${RUNNER_TEMP}/gh-aw/prompts/markdown.md"
           cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_prompt.md"
-          cat << 'GH_AW_PROMPT_6cb4a7bbd64e8acd_EOF'
+          cat << 'GH_AW_PROMPT_1ecd0bff414ab596_EOF'
           <safe-output-tools>
           Tools: add_comment, create_pull_request_review_comment(max:10), submit_pull_request_review, create_check_run, missing_tool, missing_data, noop
           </safe-output-tools>
-          GH_AW_PROMPT_6cb4a7bbd64e8acd_EOF
+          GH_AW_PROMPT_1ecd0bff414ab596_EOF
           cat "${RUNNER_TEMP}/gh-aw/prompts/mcp_cli_tools_prompt.md"
-          cat << 'GH_AW_PROMPT_6cb4a7bbd64e8acd_EOF'
+          cat << 'GH_AW_PROMPT_1ecd0bff414ab596_EOF'
           <github-context>
           The following GitHub context information is available for this workflow:
           {{#if github.actor}}
@@ -340,16 +341,17 @@ jobs:
           {{/if}}
           </github-context>
 
-          GH_AW_PROMPT_6cb4a7bbd64e8acd_EOF
+          GH_AW_PROMPT_1ecd0bff414ab596_EOF
           cat "${RUNNER_TEMP}/gh-aw/prompts/cli_proxy_with_safeoutputs_prompt.md"
-          cat << 'GH_AW_PROMPT_6cb4a7bbd64e8acd_EOF'
+          cat << 'GH_AW_PROMPT_1ecd0bff414ab596_EOF'
           </system>
           {{#runtime-import .github/workflows/shared/reporting.md}}
           {{#runtime-import .github/workflows/shared/otlp.md}}
+          {{#runtime-import .github/workflows/shared/pr-diff-data-fetch.md}}
           {{#runtime-import .github/workflows/shared/github-guard-policy.md}}
           {{#runtime-import .github/workflows/shared/pr-code-review-config.md}}
           {{#runtime-import .github/workflows/impeccable-skills-reviewer.md}}
-          GH_AW_PROMPT_6cb4a7bbd64e8acd_EOF
+          GH_AW_PROMPT_1ecd0bff414ab596_EOF
           } > "$GH_AW_PROMPT"
       - name: Interpolate variables and render templates
         uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
@@ -593,9 +595,9 @@ jobs:
           EXPR_GITHUB_REPOSITORY: ${{ github.repository }}
           GH_TOKEN: ${{ github.token }}
           PR_DIFF_MAX_LINES: "3000"
-          PR_NUMBER: ${{ github.event.pull_request.number }}
+          PR_NUMBER: ${{ github.event.issue.number || github.event.pull_request.number }}
         name: Pre-fetch PR diff and review comments
-        run: "set -euo pipefail\nmkdir -p /tmp/gh-aw/agent\n# Skip fetch if cache already populated this data (actions/cache restore)\nif [ -f /tmp/gh-aw/agent/pr-diff.patch ] && [ -f /tmp/gh-aw/agent/pr-meta.json ] && [ -f /tmp/gh-aw/agent/pr-review-comments.json ]; then\n  LINES=$(wc -l < /tmp/gh-aw/agent/pr-diff.patch)\n  COMMENT_COUNT=$(jq 'length' /tmp/gh-aw/agent/pr-review-comments.json)\n  echo \"Cache hit: using pre-fetched PR data (${LINES} diff lines, ${COMMENT_COUNT} review comments)\"\nelse\n  { gh pr diff \"$PR_NUMBER\" --repo $EXPR_GITHUB_REPOSITORY \\\n      --exclude '**/*.lock.yml' \\\n      --exclude '**/generated/**' \\\n      --exclude '**/dist/**' \\\n      --exclude '**/build/**' \\\n      || true; } | head -n \"${PR_DIFF_MAX_LINES}\" > /tmp/gh-aw/agent/pr-diff.patch\n  LINES=$(wc -l < /tmp/gh-aw/agent/pr-diff.patch)\n  gh pr view \"$PR_NUMBER\" \\\n    --repo $EXPR_GITHUB_REPOSITORY \\\n    --json number,title,body,headRefName,additions,deletions,changedFiles,files \\\n    > /tmp/gh-aw/agent/pr-meta.json\n  gh api \"repos/$EXPR_GITHUB_REPOSITORY/pulls/$PR_NUMBER/comments\" \\\n    --paginate \\\n    --jq '.[] | {id, path, line: (.line // .original_line), body: .body[:200], user: .user.login}' \\\n    2>/dev/null | jq -s '.' > /tmp/gh-aw/agent/pr-review-comments.json \\\n    || echo '[]' > /tmp/gh-aw/agent/pr-review-comments.json\n  COMMENT_COUNT=$(jq 'length' /tmp/gh-aw/agent/pr-review-comments.json)\n  echo \"Pre-fetched PR diff (${LINES} lines), metadata, and ${COMMENT_COUNT} existing review comments\"\nfi"
+        run: "set -euo pipefail\nmkdir -p /tmp/gh-aw/agent\n# Skip fetch if cache already populated this data (actions/cache restore)\nif [ -f /tmp/gh-aw/agent/pr-diff.patch ] && [ -f /tmp/gh-aw/agent/pr-meta.json ] && [ -f /tmp/gh-aw/agent/pr-review-comments.json ]; then\n  LINES=$(wc -l < /tmp/gh-aw/agent/pr-diff.patch)\n  COMMENT_COUNT=$(jq 'length' /tmp/gh-aw/agent/pr-review-comments.json)\n  echo \"Cache hit: using pre-fetched PR data (${LINES} diff lines, ${COMMENT_COUNT} review comments)\"\nelse\n  { gh pr diff \"$PR_NUMBER\" --repo $EXPR_GITHUB_REPOSITORY \\\n      --exclude '**/*.lock.yml' \\\n      --exclude '**/generated/**' \\\n      --exclude '**/dist/**' \\\n      --exclude '**/build/**' \\\n      || true; } | head -n \"${PR_DIFF_MAX_LINES}\" > /tmp/gh-aw/agent/pr-diff.patch\n  LINES=$(wc -l < /tmp/gh-aw/agent/pr-diff.patch)\n  gh pr view \"$PR_NUMBER\" \\\n    --repo $EXPR_GITHUB_REPOSITORY \\\n    --json number,title,body,headRefName,additions,deletions,changedFiles,files \\\n    > /tmp/gh-aw/agent/pr-meta.json\n  gh api \"repos/$EXPR_GITHUB_REPOSITORY/pulls/$PR_NUMBER/comments\" \\\n    --paginate \\\n    --jq '.[] | {id, path, line: (.line // .original_line), body: .body[:200], user: .user.login}' \\\n    2>/dev/null | jq -s '.' > /tmp/gh-aw/agent/pr-review-comments.json \\\n    || echo '[]' > /tmp/gh-aw/agent/pr-review-comments.json\n  COMMENT_COUNT=$(jq 'length' /tmp/gh-aw/agent/pr-review-comments.json)\n  echo \"Pre-fetched PR diff (${LINES} lines), metadata, and ${COMMENT_COUNT} existing review comments\"\nfi\n"
 
       - name: Download container images
         run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.27.37@sha256:0d35e8682845f183c1c634699a8e8a6cbe2c271b867031410df74533243c5f67 ghcr.io/github/gh-aw-firewall/api-proxy:0.27.37@sha256:fc2970aadaeae05993e76697d29f03dc8bfb9248ff87a8f3d8b0975485a4b317 ghcr.io/github/gh-aw-firewall/cli-proxy:0.27.37@sha256:1d5300d9b08e1c4f2ad1830860656a0656383a83280058f17e805a7c3ecda203 ghcr.io/github/gh-aw-firewall/squid:0.27.37@sha256:5abc51995e5901c5d1daeefc957301ee409980e2e607391ec22c06cb2513327b ghcr.io/github/gh-aw-mcpg:v0.4.3@sha256:3c744710ea275cd5ee65db92a1099e0d980754bd9fafda9ce67704c67004dc83 ghcr.io/github/gh-aw-node@sha256:529d02eb970b1161aa25c593a9c3df57fdfad5a8add328cb3b6eccef66f3183b ghcr.io/github/github-mcp-server:v1.6.0@sha256:2b0c48b070f61e9d3969269ead600f62d00fb237b60ac849ef3d166ee7de9ad3
diff --git a/.github/workflows/impeccable-skills-reviewer.md b/.github/workflows/impeccable-skills-reviewer.md
index e5c65343c75..66385969935 100644
--- a/.github/workflows/impeccable-skills-reviewer.md
+++ b/.github/workflows/impeccable-skills-reviewer.md
@@ -31,41 +31,7 @@ imports:
       min-integrity: approved
   - shared/reporting.md
   - shared/otlp.md
-pre-agent-steps:
-  - name: Pre-fetch PR diff and review comments
-    env:
-      GH_TOKEN: ${{ github.token }}
-      PR_NUMBER: ${{ github.event.pull_request.number }}
-      EXPR_GITHUB_REPOSITORY: ${{ github.repository }}
-      PR_DIFF_MAX_LINES: "3000"
-    run: |
-      set -euo pipefail
-      mkdir -p /tmp/gh-aw/agent
-      # Skip fetch if cache already populated this data (actions/cache restore)
-      if [ -f /tmp/gh-aw/agent/pr-diff.patch ] && [ -f /tmp/gh-aw/agent/pr-meta.json ] && [ -f /tmp/gh-aw/agent/pr-review-comments.json ]; then
-        LINES=$(wc -l < /tmp/gh-aw/agent/pr-diff.patch)
-        COMMENT_COUNT=$(jq 'length' /tmp/gh-aw/agent/pr-review-comments.json)
-        echo "Cache hit: using pre-fetched PR data (${LINES} diff lines, ${COMMENT_COUNT} review comments)"
-      else
-        { gh pr diff "$PR_NUMBER" --repo $EXPR_GITHUB_REPOSITORY \
-            --exclude '**/*.lock.yml' \
-            --exclude '**/generated/**' \
-            --exclude '**/dist/**' \
-            --exclude '**/build/**' \
-            || true; } | head -n "${PR_DIFF_MAX_LINES}" > /tmp/gh-aw/agent/pr-diff.patch
-        LINES=$(wc -l < /tmp/gh-aw/agent/pr-diff.patch)
-        gh pr view "$PR_NUMBER" \
-          --repo $EXPR_GITHUB_REPOSITORY \
-          --json number,title,body,headRefName,additions,deletions,changedFiles,files \
-          > /tmp/gh-aw/agent/pr-meta.json
-        gh api "repos/$EXPR_GITHUB_REPOSITORY/pulls/$PR_NUMBER/comments" \
-          --paginate \
-          --jq '.[] | {id, path, line: (.line // .original_line), body: .body[:200], user: .user.login}' \
-          2>/dev/null | jq -s '.' > /tmp/gh-aw/agent/pr-review-comments.json \
-          || echo '[]' > /tmp/gh-aw/agent/pr-review-comments.json
-        COMMENT_COUNT=$(jq 'length' /tmp/gh-aw/agent/pr-review-comments.json)
-        echo "Pre-fetched PR diff (${LINES} lines), metadata, and ${COMMENT_COUNT} existing review comments"
-      fi
+  - shared/pr-diff-data-fetch.md
 tools:
   cli-proxy: true
   github:
diff --git a/.github/workflows/mattpocock-skills-reviewer.lock.yml b/.github/workflows/mattpocock-skills-reviewer.lock.yml
index 0beeb34a34c..45a29339f7d 100644
--- a/.github/workflows/mattpocock-skills-reviewer.lock.yml
+++ b/.github/workflows/mattpocock-skills-reviewer.lock.yml
@@ -1,4 +1,4 @@
-# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"969935ad2761c6daf7158f7830cc4e1401f4f9a681fe22f46727fce79de514fb","body_hash":"c3f13ade4281614d5d35cd7ef735b734cbaa16e58f505b5b3e6670f75b405b42","strict":true,"agent_id":"copilot","agent_model":"claude-sonnet-4.6","engine_versions":{"copilot":"1.0.73"}}
+# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"abd182c5f361df971b0e3c98e6648ca7bdf0f41a7f4db09563dc917970e665c9","body_hash":"c3f13ade4281614d5d35cd7ef735b734cbaa16e58f505b5b3e6670f75b405b42","strict":true,"agent_id":"copilot","agent_model":"claude-sonnet-4.6","engine_versions":{"copilot":"1.0.73"}}
 # gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GH_AW_OTEL_GRAFANA_AUTHORIZATION","GH_AW_OTEL_GRAFANA_ENDPOINT","GH_AW_OTEL_SENTRY_AUTHORIZATION","GH_AW_OTEL_SENTRY_ENDPOINT","GITHUB_TOKEN"],"actions":[{"repo":"actions/cache","sha":"55cc8345863c7cc4c66a329aec7e433d2d1c52a9","version":"v6.1.0"},{"repo":"actions/cache/restore","sha":"55cc8345863c7cc4c66a329aec7e433d2d1c52a9","version":"v6.1.0"},{"repo":"actions/cache/save","sha":"55cc8345863c7cc4c66a329aec7e433d2d1c52a9","version":"v6.1.0"},{"repo":"actions/checkout","sha":"9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0","version":"v7.0.0"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-node","sha":"820762786026740c76f36085b0efc47a31fe5020","version":"v7.0.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"}],"skills":["mattpocock/skills/codebase-design@e9fcdf95b402d360f90f1db8d776d5dd450f9234","mattpocock/skills/diagnosing-bugs@e9fcdf95b402d360f90f1db8d776d5dd450f9234","mattpocock/skills/domain-modeling@e9fcdf95b402d360f90f1db8d776d5dd450f9234","mattpocock/skills/grill-with-docs@e9fcdf95b402d360f90f1db8d776d5dd450f9234","mattpocock/skills/improve-codebase-architecture@e9fcdf95b402d360f90f1db8d776d5dd450f9234","mattpocock/skills/tdd@e9fcdf95b402d360f90f1db8d776d5dd450f9234","mattpocock/skills/to-prd@e9fcdf95b402d360f90f1db8d776d5dd450f9234"],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.27.37","digest":"sha256:0d35e8682845f183c1c634699a8e8a6cbe2c271b867031410df74533243c5f67","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.27.37@sha256:0d35e8682845f183c1c634699a8e8a6cbe2c271b867031410df74533243c5f67"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.37","digest":"sha256:fc2970aadaeae05993e76697d29f03dc8bfb9248ff87a8f3d8b0975485a4b317","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.37@sha256:fc2970aadaeae05993e76697d29f03dc8bfb9248ff87a8f3d8b0975485a4b317"},{"image":"ghcr.io/github/gh-aw-firewall/cli-proxy:0.27.37","digest":"sha256:1d5300d9b08e1c4f2ad1830860656a0656383a83280058f17e805a7c3ecda203","pinned_image":"ghcr.io/github/gh-aw-firewall/cli-proxy:0.27.37@sha256:1d5300d9b08e1c4f2ad1830860656a0656383a83280058f17e805a7c3ecda203"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.27.37","digest":"sha256:5abc51995e5901c5d1daeefc957301ee409980e2e607391ec22c06cb2513327b","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.27.37@sha256:5abc51995e5901c5d1daeefc957301ee409980e2e607391ec22c06cb2513327b"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.4.3","digest":"sha256:3c744710ea275cd5ee65db92a1099e0d980754bd9fafda9ce67704c67004dc83","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.4.3@sha256:3c744710ea275cd5ee65db92a1099e0d980754bd9fafda9ce67704c67004dc83"},{"image":"ghcr.io/github/gh-aw-node","digest":"sha256:529d02eb970b1161aa25c593a9c3df57fdfad5a8add328cb3b6eccef66f3183b","pinned_image":"ghcr.io/github/gh-aw-node@sha256:529d02eb970b1161aa25c593a9c3df57fdfad5a8add328cb3b6eccef66f3183b"},{"image":"ghcr.io/github/github-mcp-server:v1.6.0","digest":"sha256:2b0c48b070f61e9d3969269ead600f62d00fb237b60ac849ef3d166ee7de9ad3","pinned_image":"ghcr.io/github/github-mcp-server:v1.6.0@sha256:2b0c48b070f61e9d3969269ead600f62d00fb237b60ac849ef3d166ee7de9ad3"}],"has_pull_request":true}
 # This file was automatically generated by gh-aw. DO NOT EDIT. To debug this workflow, load the skill at https://github.com/github/gh-aw/blob/main/debug.md
 #
@@ -30,6 +30,7 @@
 #     - shared/github-guard-policy.md
 #     - shared/otlp.md
 #     - shared/pr-code-review-config.md
+#     - shared/pr-diff-data-fetch.md
 #     - shared/pr-review-base.md
 #
 # Secrets used:
@@ -440,20 +441,20 @@ jobs:
         run: |
           bash "${RUNNER_TEMP}/gh-aw/actions/create_prompt_first.sh"
           {
-          cat << 'GH_AW_PROMPT_ea16154323c40356_EOF'
+          cat << 'GH_AW_PROMPT_2cd9473c357e7085_EOF'
           <system>
-          GH_AW_PROMPT_ea16154323c40356_EOF
+          GH_AW_PROMPT_2cd9473c357e7085_EOF
           cat "${RUNNER_TEMP}/gh-aw/prompts/xpia.md"
           cat "${RUNNER_TEMP}/gh-aw/prompts/temp_folder_prompt.md"
           cat "${RUNNER_TEMP}/gh-aw/prompts/markdown.md"
           cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_prompt.md"
-          cat << 'GH_AW_PROMPT_ea16154323c40356_EOF'
+          cat << 'GH_AW_PROMPT_2cd9473c357e7085_EOF'
           <safe-output-tools>
           Tools: add_comment, create_pull_request_review_comment(max:10), submit_pull_request_review, create_check_run, missing_tool, missing_data, noop
           </safe-output-tools>
-          GH_AW_PROMPT_ea16154323c40356_EOF
+          GH_AW_PROMPT_2cd9473c357e7085_EOF
           cat "${RUNNER_TEMP}/gh-aw/prompts/mcp_cli_tools_prompt.md"
-          cat << 'GH_AW_PROMPT_ea16154323c40356_EOF'
+          cat << 'GH_AW_PROMPT_2cd9473c357e7085_EOF'
           <github-context>
           The following GitHub context information is available for this workflow:
           {{#if github.actor}}
@@ -482,18 +483,19 @@ jobs:
           {{/if}}
           </github-context>
 
-          GH_AW_PROMPT_ea16154323c40356_EOF
+          GH_AW_PROMPT_2cd9473c357e7085_EOF
           cat "${RUNNER_TEMP}/gh-aw/prompts/cli_proxy_with_safeoutputs_prompt.md"
           if [ "$GITHUB_EVENT_NAME" = "issue_comment" ] && [ -n "$GH_AW_IS_PR_COMMENT" ] || [ "$GITHUB_EVENT_NAME" = "pull_request_review_comment" ] || [ "$GITHUB_EVENT_NAME" = "pull_request_review" ]; then
             cat "${RUNNER_TEMP}/gh-aw/prompts/pr_context_prompt.md"
           fi
-          cat << 'GH_AW_PROMPT_ea16154323c40356_EOF'
+          cat << 'GH_AW_PROMPT_2cd9473c357e7085_EOF'
           </system>
           {{#runtime-import .github/workflows/shared/otlp.md}}
+          {{#runtime-import .github/workflows/shared/pr-diff-data-fetch.md}}
           {{#runtime-import .github/workflows/shared/github-guard-policy.md}}
           {{#runtime-import .github/workflows/shared/pr-code-review-config.md}}
           {{#runtime-import .github/workflows/mattpocock-skills-reviewer.md}}
-          GH_AW_PROMPT_ea16154323c40356_EOF
+          GH_AW_PROMPT_2cd9473c357e7085_EOF
           } > "$GH_AW_PROMPT"
       - name: Interpolate variables and render templates
         uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
@@ -740,9 +742,10 @@ jobs:
       - env:
           EXPR_GITHUB_REPOSITORY: ${{ github.repository }}
           GH_TOKEN: ${{ github.token }}
-          PR_NUMBER: ${{ github.event.pull_request.number }}
+          PR_DIFF_MAX_LINES: "3000"
+          PR_NUMBER: ${{ github.event.issue.number || github.event.pull_request.number }}
         name: Pre-fetch PR diff and review comments
-        run: "set -euo pipefail\nmkdir -p /tmp/gh-aw/agent\n# Skip fetch if cache already populated this data (actions/cache restore)\nif [ -f /tmp/gh-aw/agent/pr-diff.patch ] && [ -f /tmp/gh-aw/agent/pr-meta.json ] && [ -f /tmp/gh-aw/agent/pr-review-comments.json ]; then\n  LINES=$(wc -l < /tmp/gh-aw/agent/pr-diff.patch)\n  COMMENT_COUNT=$(jq 'length' /tmp/gh-aw/agent/pr-review-comments.json)\n  echo \"Cache hit: using pre-fetched PR data (${LINES} diff lines, ${COMMENT_COUNT} review comments)\"\nelse\n  { gh pr diff \"$PR_NUMBER\" --repo $EXPR_GITHUB_REPOSITORY \\\n      --exclude '**/*.lock.yml' \\\n      --exclude '**/generated/**' \\\n      --exclude '**/dist/**' \\\n      --exclude '**/build/**' \\\n      || true; } | head -n 3000 > /tmp/gh-aw/agent/pr-diff.patch\n  LINES=$(wc -l < /tmp/gh-aw/agent/pr-diff.patch)\n  gh pr view \"$PR_NUMBER\" \\\n    --repo $EXPR_GITHUB_REPOSITORY \\\n    --json number,title,body,headRefName,additions,deletions,changedFiles,files \\\n    > /tmp/gh-aw/agent/pr-meta.json\n  gh api \"repos/$EXPR_GITHUB_REPOSITORY/pulls/$PR_NUMBER/comments\" \\\n    --paginate \\\n    --jq '.[] | {id, path, line: (.line // .original_line), body: .body[:200], user: .user.login}' \\\n    2>/dev/null | jq -s '.' > /tmp/gh-aw/agent/pr-review-comments.json \\\n    || echo '[]' > /tmp/gh-aw/agent/pr-review-comments.json\n  COMMENT_COUNT=$(jq 'length' /tmp/gh-aw/agent/pr-review-comments.json)\n  echo \"Pre-fetched PR diff (${LINES} lines), metadata, and ${COMMENT_COUNT} existing review comments\"\nfi"
+        run: "set -euo pipefail\nmkdir -p /tmp/gh-aw/agent\n# Skip fetch if cache already populated this data (actions/cache restore)\nif [ -f /tmp/gh-aw/agent/pr-diff.patch ] && [ -f /tmp/gh-aw/agent/pr-meta.json ] && [ -f /tmp/gh-aw/agent/pr-review-comments.json ]; then\n  LINES=$(wc -l < /tmp/gh-aw/agent/pr-diff.patch)\n  COMMENT_COUNT=$(jq 'length' /tmp/gh-aw/agent/pr-review-comments.json)\n  echo \"Cache hit: using pre-fetched PR data (${LINES} diff lines, ${COMMENT_COUNT} review comments)\"\nelse\n  { gh pr diff \"$PR_NUMBER\" --repo $EXPR_GITHUB_REPOSITORY \\\n      --exclude '**/*.lock.yml' \\\n      --exclude '**/generated/**' \\\n      --exclude '**/dist/**' \\\n      --exclude '**/build/**' \\\n      || true; } | head -n \"${PR_DIFF_MAX_LINES}\" > /tmp/gh-aw/agent/pr-diff.patch\n  LINES=$(wc -l < /tmp/gh-aw/agent/pr-diff.patch)\n  gh pr view \"$PR_NUMBER\" \\\n    --repo $EXPR_GITHUB_REPOSITORY \\\n    --json number,title,body,headRefName,additions,deletions,changedFiles,files \\\n    > /tmp/gh-aw/agent/pr-meta.json\n  gh api \"repos/$EXPR_GITHUB_REPOSITORY/pulls/$PR_NUMBER/comments\" \\\n    --paginate \\\n    --jq '.[] | {id, path, line: (.line // .original_line), body: .body[:200], user: .user.login}' \\\n    2>/dev/null | jq -s '.' > /tmp/gh-aw/agent/pr-review-comments.json \\\n    || echo '[]' > /tmp/gh-aw/agent/pr-review-comments.json\n  COMMENT_COUNT=$(jq 'length' /tmp/gh-aw/agent/pr-review-comments.json)\n  echo \"Pre-fetched PR diff (${LINES} lines), metadata, and ${COMMENT_COUNT} existing review comments\"\nfi\n"
 
       - name: Download container images
         run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.27.37@sha256:0d35e8682845f183c1c634699a8e8a6cbe2c271b867031410df74533243c5f67 ghcr.io/github/gh-aw-firewall/api-proxy:0.27.37@sha256:fc2970aadaeae05993e76697d29f03dc8bfb9248ff87a8f3d8b0975485a4b317 ghcr.io/github/gh-aw-firewall/cli-proxy:0.27.37@sha256:1d5300d9b08e1c4f2ad1830860656a0656383a83280058f17e805a7c3ecda203 ghcr.io/github/gh-aw-firewall/squid:0.27.37@sha256:5abc51995e5901c5d1daeefc957301ee409980e2e607391ec22c06cb2513327b ghcr.io/github/gh-aw-mcpg:v0.4.3@sha256:3c744710ea275cd5ee65db92a1099e0d980754bd9fafda9ce67704c67004dc83 ghcr.io/github/gh-aw-node@sha256:529d02eb970b1161aa25c593a9c3df57fdfad5a8add328cb3b6eccef66f3183b ghcr.io/github/github-mcp-server:v1.6.0@sha256:2b0c48b070f61e9d3969269ead600f62d00fb237b60ac849ef3d166ee7de9ad3
diff --git a/.github/workflows/mattpocock-skills-reviewer.md b/.github/workflows/mattpocock-skills-reviewer.md
index 626fa9fac87..f961b788978 100644
--- a/.github/workflows/mattpocock-skills-reviewer.md
+++ b/.github/workflows/mattpocock-skills-reviewer.md
@@ -15,6 +15,7 @@ imports:
   with:
     min-integrity: approved
 - shared/otlp.md
+- shared/pr-diff-data-fetch.md
 max-daily-ai-credits: 10000
 "on":
   pull_request:
@@ -36,13 +37,6 @@ permissions:
   contents: read
   copilot-requests: write
   pull-requests: read
-pre-agent-steps:
-- env:
-    EXPR_GITHUB_REPOSITORY: ${{ github.repository }}
-    GH_TOKEN: ${{ github.token }}
-    PR_NUMBER: ${{ github.event.pull_request.number }}
-  name: Pre-fetch PR diff and review comments
-  run: "set -euo pipefail\nmkdir -p /tmp/gh-aw/agent\n# Skip fetch if cache already populated this data (actions/cache restore)\nif [ -f /tmp/gh-aw/agent/pr-diff.patch ] && [ -f /tmp/gh-aw/agent/pr-meta.json ] && [ -f /tmp/gh-aw/agent/pr-review-comments.json ]; then\n  LINES=$(wc -l < /tmp/gh-aw/agent/pr-diff.patch)\n  COMMENT_COUNT=$(jq 'length' /tmp/gh-aw/agent/pr-review-comments.json)\n  echo \"Cache hit: using pre-fetched PR data (${LINES} diff lines, ${COMMENT_COUNT} review comments)\"\nelse\n  { gh pr diff \"$PR_NUMBER\" --repo $EXPR_GITHUB_REPOSITORY \\\n      --exclude '**/*.lock.yml' \\\n      --exclude '**/generated/**' \\\n      --exclude '**/dist/**' \\\n      --exclude '**/build/**' \\\n      || true; } | head -n 3000 > /tmp/gh-aw/agent/pr-diff.patch\n  LINES=$(wc -l < /tmp/gh-aw/agent/pr-diff.patch)\n  gh pr view \"$PR_NUMBER\" \\\n    --repo $EXPR_GITHUB_REPOSITORY \\\n    --json number,title,body,headRefName,additions,deletions,changedFiles,files \\\n    > /tmp/gh-aw/agent/pr-meta.json\n  gh api \"repos/$EXPR_GITHUB_REPOSITORY/pulls/$PR_NUMBER/comments\" \\\n    --paginate \\\n    --jq '.[] | {id, path, line: (.line // .original_line), body: .body[:200], user: .user.login}' \\\n    2>/dev/null | jq -s '.' > /tmp/gh-aw/agent/pr-review-comments.json \\\n    || echo '[]' > /tmp/gh-aw/agent/pr-review-comments.json\n  COMMENT_COUNT=$(jq 'length' /tmp/gh-aw/agent/pr-review-comments.json)\n  echo \"Pre-fetched PR diff (${LINES} lines), metadata, and ${COMMENT_COUNT} existing review comments\"\nfi\n"
 private: true
 safe-outputs:
   add-comment:
diff --git a/.github/workflows/pr-code-quality-reviewer.lock.yml b/.github/workflows/pr-code-quality-reviewer.lock.yml
index 33d32653f30..74df6cfc1d1 100644
--- a/.github/workflows/pr-code-quality-reviewer.lock.yml
+++ b/.github/workflows/pr-code-quality-reviewer.lock.yml
@@ -1,4 +1,4 @@
-# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"0c69e6deb2f09caf40c0be4b50c85cfaab267aa309a6dba5f814f206f1ce8bb4","body_hash":"4d55b623130b9bead500146cadaa2e5eca54cc42cee576aee4c10ed8414d3a61","strict":true,"agent_id":"copilot","engine_versions":{"copilot":"1.0.73","copilot-sdk":"1.0.7"}}
+# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"d007a0c73e765f7ec52a80be0da757eb62e04678741ee889512feffc7ca64fc3","body_hash":"4890b58adb822a064eec8f86b1770258890fab221abd2308d69ebb840746adda","strict":true,"agent_id":"copilot","engine_versions":{"copilot":"1.0.73","copilot-sdk":"1.0.7"}}
 # gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GH_AW_OTEL_GRAFANA_AUTHORIZATION","GH_AW_OTEL_GRAFANA_ENDPOINT","GH_AW_OTEL_SENTRY_AUTHORIZATION","GH_AW_OTEL_SENTRY_ENDPOINT","GITHUB_TOKEN"],"actions":[{"repo":"actions/cache","sha":"55cc8345863c7cc4c66a329aec7e433d2d1c52a9","version":"v6.1.0"},{"repo":"actions/cache/restore","sha":"55cc8345863c7cc4c66a329aec7e433d2d1c52a9","version":"v6.1.0"},{"repo":"actions/cache/save","sha":"55cc8345863c7cc4c66a329aec7e433d2d1c52a9","version":"v6.1.0"},{"repo":"actions/checkout","sha":"9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0","version":"v7.0.0"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-node","sha":"820762786026740c76f36085b0efc47a31fe5020","version":"v7.0.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.27.37","digest":"sha256:0d35e8682845f183c1c634699a8e8a6cbe2c271b867031410df74533243c5f67","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.27.37@sha256:0d35e8682845f183c1c634699a8e8a6cbe2c271b867031410df74533243c5f67"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.37","digest":"sha256:fc2970aadaeae05993e76697d29f03dc8bfb9248ff87a8f3d8b0975485a4b317","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.37@sha256:fc2970aadaeae05993e76697d29f03dc8bfb9248ff87a8f3d8b0975485a4b317"},{"image":"ghcr.io/github/gh-aw-firewall/cli-proxy:0.27.37","digest":"sha256:1d5300d9b08e1c4f2ad1830860656a0656383a83280058f17e805a7c3ecda203","pinned_image":"ghcr.io/github/gh-aw-firewall/cli-proxy:0.27.37@sha256:1d5300d9b08e1c4f2ad1830860656a0656383a83280058f17e805a7c3ecda203"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.27.37","digest":"sha256:5abc51995e5901c5d1daeefc957301ee409980e2e607391ec22c06cb2513327b","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.27.37@sha256:5abc51995e5901c5d1daeefc957301ee409980e2e607391ec22c06cb2513327b"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.4.3","digest":"sha256:3c744710ea275cd5ee65db92a1099e0d980754bd9fafda9ce67704c67004dc83","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.4.3@sha256:3c744710ea275cd5ee65db92a1099e0d980754bd9fafda9ce67704c67004dc83"},{"image":"ghcr.io/github/gh-aw-node","digest":"sha256:529d02eb970b1161aa25c593a9c3df57fdfad5a8add328cb3b6eccef66f3183b","pinned_image":"ghcr.io/github/gh-aw-node@sha256:529d02eb970b1161aa25c593a9c3df57fdfad5a8add328cb3b6eccef66f3183b"},{"image":"ghcr.io/github/github-mcp-server:v1.6.0","digest":"sha256:2b0c48b070f61e9d3969269ead600f62d00fb237b60ac849ef3d166ee7de9ad3","pinned_image":"ghcr.io/github/github-mcp-server:v1.6.0@sha256:2b0c48b070f61e9d3969269ead600f62d00fb237b60ac849ef3d166ee7de9ad3"}],"has_pull_request":true}
 # This file was automatically generated by gh-aw. DO NOT EDIT. To debug this workflow, load the skill at https://github.com/github/gh-aw/blob/main/debug.md
 #
@@ -30,6 +30,7 @@
 #     - shared/github-guard-policy.md
 #     - shared/otlp.md
 #     - shared/pr-code-review-config.md
+#     - shared/pr-diff-data-fetch.md
 #     - shared/pr-review-base.md
 #
 # Secrets used:
@@ -326,21 +327,21 @@ jobs:
         run: |
           bash "${RUNNER_TEMP}/gh-aw/actions/create_prompt_first.sh"
           {
-          cat << 'GH_AW_PROMPT_88dd0adb3937cc31_EOF'
+          cat << 'GH_AW_PROMPT_896d10e6e512745a_EOF'
           <system>
-          GH_AW_PROMPT_88dd0adb3937cc31_EOF
+          GH_AW_PROMPT_896d10e6e512745a_EOF
           cat "${RUNNER_TEMP}/gh-aw/prompts/xpia.md"
           cat "${RUNNER_TEMP}/gh-aw/prompts/temp_folder_prompt.md"
           cat "${RUNNER_TEMP}/gh-aw/prompts/markdown.md"
           cat "${RUNNER_TEMP}/gh-aw/prompts/cache_memory_prompt.md"
           cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_prompt.md"
-          cat << 'GH_AW_PROMPT_88dd0adb3937cc31_EOF'
+          cat << 'GH_AW_PROMPT_896d10e6e512745a_EOF'
           <safe-output-tools>
           Tools: create_pull_request_review_comment(max:10), submit_pull_request_review, create_check_run, missing_tool, missing_data, noop
           </safe-output-tools>
-          GH_AW_PROMPT_88dd0adb3937cc31_EOF
+          GH_AW_PROMPT_896d10e6e512745a_EOF
           cat "${RUNNER_TEMP}/gh-aw/prompts/mcp_cli_tools_prompt.md"
-          cat << 'GH_AW_PROMPT_88dd0adb3937cc31_EOF'
+          cat << 'GH_AW_PROMPT_896d10e6e512745a_EOF'
           <github-context>
           The following GitHub context information is available for this workflow:
           {{#if github.actor}}
@@ -369,18 +370,19 @@ jobs:
           {{/if}}
           </github-context>
 
-          GH_AW_PROMPT_88dd0adb3937cc31_EOF
+          GH_AW_PROMPT_896d10e6e512745a_EOF
           cat "${RUNNER_TEMP}/gh-aw/prompts/cli_proxy_with_safeoutputs_prompt.md"
           if [ "$GITHUB_EVENT_NAME" = "issue_comment" ] && [ -n "$GH_AW_IS_PR_COMMENT" ] || [ "$GITHUB_EVENT_NAME" = "pull_request_review_comment" ] || [ "$GITHUB_EVENT_NAME" = "pull_request_review" ]; then
             cat "${RUNNER_TEMP}/gh-aw/prompts/pr_context_prompt.md"
           fi
-          cat << 'GH_AW_PROMPT_88dd0adb3937cc31_EOF'
+          cat << 'GH_AW_PROMPT_896d10e6e512745a_EOF'
           </system>
           {{#runtime-import .github/workflows/shared/otlp.md}}
+          {{#runtime-import .github/workflows/shared/pr-diff-data-fetch.md}}
           {{#runtime-import .github/workflows/shared/github-guard-policy.md}}
           {{#runtime-import .github/workflows/shared/pr-code-review-config.md}}
           {{#runtime-import .github/workflows/pr-code-quality-reviewer.md}}
-          GH_AW_PROMPT_88dd0adb3937cc31_EOF
+          GH_AW_PROMPT_896d10e6e512745a_EOF
           } > "$GH_AW_PROMPT"
       - name: Interpolate variables and render templates
         uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
@@ -654,7 +656,7 @@ jobs:
           PR_DIFF_MAX_LINES: "3000"
           PR_NUMBER: ${{ github.event.issue.number || github.event.pull_request.number }}
         name: Pre-fetch PR diff and review comments
-        run: "set -euo pipefail\nmkdir -p /tmp/gh-aw/agent\n# Skip fetch if cache already populated this data (actions/cache restore)\nif [ -f /tmp/gh-aw/agent/pr-diff.patch ] && [ -f /tmp/gh-aw/agent/pr-meta.json ] && [ -f /tmp/gh-aw/agent/pr-review-comments.json ]; then\n  LINES=$(wc -l < /tmp/gh-aw/agent/pr-diff.patch)\n  COMMENT_COUNT=$(jq 'length' /tmp/gh-aw/agent/pr-review-comments.json)\n  echo \"Cache hit: using pre-fetched PR data (${LINES} diff lines, ${COMMENT_COUNT} review comments)\"\nelse\n  { gh pr diff \"$PR_NUMBER\" --repo $EXPR_GITHUB_REPOSITORY \\\n      --exclude '**/*.lock.yml' \\\n      --exclude '**/generated/**' \\\n      --exclude '**/dist/**' \\\n      --exclude '**/build/**' \\\n      || true; } | head -n \"${PR_DIFF_MAX_LINES}\" > /tmp/gh-aw/agent/pr-diff.patch\n  LINES=$(wc -l < /tmp/gh-aw/agent/pr-diff.patch)\n  gh pr view \"$PR_NUMBER\" \\\n    --repo $EXPR_GITHUB_REPOSITORY \\\n    --json number,title,body,headRefName,additions,deletions,changedFiles,files \\\n    > /tmp/gh-aw/agent/pr-meta.json\n  gh api \"repos/$EXPR_GITHUB_REPOSITORY/pulls/$PR_NUMBER/comments\" \\\n    --paginate \\\n    --jq '.[] | {id, path, line: (.line // .original_line), body: .body[:200], user: .user.login}' \\\n    2>/dev/null | jq -s '.' > /tmp/gh-aw/agent/pr-review-comments.json \\\n    || echo '[]' > /tmp/gh-aw/agent/pr-review-comments.json\n  COMMENT_COUNT=$(jq 'length' /tmp/gh-aw/agent/pr-review-comments.json)\n  echo \"Pre-fetched PR diff (${LINES} lines), metadata, and ${COMMENT_COUNT} existing review comments\"\nfi"
+        run: "set -euo pipefail\nmkdir -p /tmp/gh-aw/agent\n# Skip fetch if cache already populated this data (actions/cache restore)\nif [ -f /tmp/gh-aw/agent/pr-diff.patch ] && [ -f /tmp/gh-aw/agent/pr-meta.json ] && [ -f /tmp/gh-aw/agent/pr-review-comments.json ]; then\n  LINES=$(wc -l < /tmp/gh-aw/agent/pr-diff.patch)\n  COMMENT_COUNT=$(jq 'length' /tmp/gh-aw/agent/pr-review-comments.json)\n  echo \"Cache hit: using pre-fetched PR data (${LINES} diff lines, ${COMMENT_COUNT} review comments)\"\nelse\n  { gh pr diff \"$PR_NUMBER\" --repo $EXPR_GITHUB_REPOSITORY \\\n      --exclude '**/*.lock.yml' \\\n      --exclude '**/generated/**' \\\n      --exclude '**/dist/**' \\\n      --exclude '**/build/**' \\\n      || true; } | head -n \"${PR_DIFF_MAX_LINES}\" > /tmp/gh-aw/agent/pr-diff.patch\n  LINES=$(wc -l < /tmp/gh-aw/agent/pr-diff.patch)\n  gh pr view \"$PR_NUMBER\" \\\n    --repo $EXPR_GITHUB_REPOSITORY \\\n    --json number,title,body,headRefName,additions,deletions,changedFiles,files \\\n    > /tmp/gh-aw/agent/pr-meta.json\n  gh api \"repos/$EXPR_GITHUB_REPOSITORY/pulls/$PR_NUMBER/comments\" \\\n    --paginate \\\n    --jq '.[] | {id, path, line: (.line // .original_line), body: .body[:200], user: .user.login}' \\\n    2>/dev/null | jq -s '.' > /tmp/gh-aw/agent/pr-review-comments.json \\\n    || echo '[]' > /tmp/gh-aw/agent/pr-review-comments.json\n  COMMENT_COUNT=$(jq 'length' /tmp/gh-aw/agent/pr-review-comments.json)\n  echo \"Pre-fetched PR diff (${LINES} lines), metadata, and ${COMMENT_COUNT} existing review comments\"\nfi\n"
 
       - name: Download container images
         run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.27.37@sha256:0d35e8682845f183c1c634699a8e8a6cbe2c271b867031410df74533243c5f67 ghcr.io/github/gh-aw-firewall/api-proxy:0.27.37@sha256:fc2970aadaeae05993e76697d29f03dc8bfb9248ff87a8f3d8b0975485a4b317 ghcr.io/github/gh-aw-firewall/cli-proxy:0.27.37@sha256:1d5300d9b08e1c4f2ad1830860656a0656383a83280058f17e805a7c3ecda203 ghcr.io/github/gh-aw-firewall/squid:0.27.37@sha256:5abc51995e5901c5d1daeefc957301ee409980e2e607391ec22c06cb2513327b ghcr.io/github/gh-aw-mcpg:v0.4.3@sha256:3c744710ea275cd5ee65db92a1099e0d980754bd9fafda9ce67704c67004dc83 ghcr.io/github/gh-aw-node@sha256:529d02eb970b1161aa25c593a9c3df57fdfad5a8add328cb3b6eccef66f3183b ghcr.io/github/github-mcp-server:v1.6.0@sha256:2b0c48b070f61e9d3969269ead600f62d00fb237b60ac849ef3d166ee7de9ad3
diff --git a/.github/workflows/pr-code-quality-reviewer.md b/.github/workflows/pr-code-quality-reviewer.md
index 32e7c37fcd3..b2e4ccfd688 100644
--- a/.github/workflows/pr-code-quality-reviewer.md
+++ b/.github/workflows/pr-code-quality-reviewer.md
@@ -39,6 +39,7 @@ imports:
     with:
       min-integrity: approved
   - shared/otlp.md
+  - shared/pr-diff-data-fetch.md
 tools:
   cli-proxy: true
   github:
@@ -60,41 +61,6 @@ safe-outputs:
     run-started: "🔎 [{workflow_name}]({run_url}) is reviewing code quality for this {event_type}..."
     run-success: "✅ [{workflow_name}]({run_url}) completed the code quality review."
     run-failure: "⚠️ [{workflow_name}]({run_url}) {status} during code quality review."
-pre-agent-steps:
-  - name: Pre-fetch PR diff and review comments
-    env:
-      GH_TOKEN: ${{ github.token }}
-      PR_NUMBER: ${{ github.event.issue.number || github.event.pull_request.number }}
-      EXPR_GITHUB_REPOSITORY: ${{ github.repository }}
-      PR_DIFF_MAX_LINES: "3000"
-    run: |
-      set -euo pipefail
-      mkdir -p /tmp/gh-aw/agent
-      # Skip fetch if cache already populated this data (actions/cache restore)
-      if [ -f /tmp/gh-aw/agent/pr-diff.patch ] && [ -f /tmp/gh-aw/agent/pr-meta.json ] && [ -f /tmp/gh-aw/agent/pr-review-comments.json ]; then
-        LINES=$(wc -l < /tmp/gh-aw/agent/pr-diff.patch)
-        COMMENT_COUNT=$(jq 'length' /tmp/gh-aw/agent/pr-review-comments.json)
-        echo "Cache hit: using pre-fetched PR data (${LINES} diff lines, ${COMMENT_COUNT} review comments)"
-      else
-        { gh pr diff "$PR_NUMBER" --repo $EXPR_GITHUB_REPOSITORY \
-            --exclude '**/*.lock.yml' \
-            --exclude '**/generated/**' \
-            --exclude '**/dist/**' \
-            --exclude '**/build/**' \
-            || true; } | head -n "${PR_DIFF_MAX_LINES}" > /tmp/gh-aw/agent/pr-diff.patch
-        LINES=$(wc -l < /tmp/gh-aw/agent/pr-diff.patch)
-        gh pr view "$PR_NUMBER" \
-          --repo $EXPR_GITHUB_REPOSITORY \
-          --json number,title,body,headRefName,additions,deletions,changedFiles,files \
-          > /tmp/gh-aw/agent/pr-meta.json
-        gh api "repos/$EXPR_GITHUB_REPOSITORY/pulls/$PR_NUMBER/comments" \
-          --paginate \
-          --jq '.[] | {id, path, line: (.line // .original_line), body: .body[:200], user: .user.login}' \
-          2>/dev/null | jq -s '.' > /tmp/gh-aw/agent/pr-review-comments.json \
-          || echo '[]' > /tmp/gh-aw/agent/pr-review-comments.json
-        COMMENT_COUNT=$(jq 'length' /tmp/gh-aw/agent/pr-review-comments.json)
-        echo "Pre-fetched PR diff (${LINES} lines), metadata, and ${COMMENT_COUNT} existing review comments"
-      fi
 timeout-minutes: 15
 evals:
   - id: review_posted
diff --git a/.github/workflows/pr-data-prefetch.yml b/.github/workflows/pr-data-prefetch.yml
new file mode 100644
index 00000000000..a94dbb8f62e
--- /dev/null
+++ b/.github/workflows/pr-data-prefetch.yml
@@ -0,0 +1,66 @@
+name: PR Data Prefetch
+# Fetches PR diff, metadata, and review comments once per commit and saves to
+# the Actions cache (key: pr-prefetch-<sha>), so the three PR reviewer workflows
+# can restore from cache rather than each independently calling the GitHub API.
+#
+# Because this workflow has no AI engine, it completes in ~30-60 s — before the
+# reviewer workflows' activation jobs finish. When the reviewer agent jobs start
+# and restore the pr-prefetch-<sha> cache they get a hit and skip their own fetch.
+
+on:
+  pull_request:
+    types: [ready_for_review]
+    paths-ignore:
+      - '*.md'
+      - 'docs/**'
+      - '.changeset/**'
+      - 'socials/**'
+      - 'scratchpad/**'
+
+permissions:
+  contents: read
+  pull-requests: read
+
+concurrency:
+  # One prefetch per commit; do not cancel to avoid a gap between save and reviewer restore.
+  group: pr-data-prefetch-${{ github.event.pull_request.head.sha }}
+  cancel-in-progress: false
+
+jobs:
+  prefetch:
+    runs-on: ubuntu-latest
+    timeout-minutes: 5
+    steps:
+      - name: Pre-fetch PR diff and review comments
+        env:
+          GH_TOKEN: ${{ github.token }}
+          PR_NUMBER: ${{ github.event.pull_request.number }}
+          GITHUB_REPOSITORY: ${{ github.repository }}
+          PR_DIFF_MAX_LINES: "3000"
+        run: |
+          set -euo pipefail
+          mkdir -p /tmp/gh-aw/agent
+          { gh pr diff "$PR_NUMBER" --repo "$GITHUB_REPOSITORY" \
+              --exclude '**/*.lock.yml' \
+              --exclude '**/generated/**' \
+              --exclude '**/dist/**' \
+              --exclude '**/build/**' \
+              || true; } | head -n "${PR_DIFF_MAX_LINES}" > /tmp/gh-aw/agent/pr-diff.patch
+          LINES=$(wc -l < /tmp/gh-aw/agent/pr-diff.patch)
+          gh pr view "$PR_NUMBER" \
+            --repo "$GITHUB_REPOSITORY" \
+            --json number,title,body,headRefName,additions,deletions,changedFiles,files \
+            > /tmp/gh-aw/agent/pr-meta.json
+          gh api "repos/$GITHUB_REPOSITORY/pulls/$PR_NUMBER/comments" \
+            --paginate \
+            --jq '.[] | {id, path, line: (.line // .original_line), body: .body[:200], user: .user.login}' \
+            2>/dev/null | jq -s '.' > /tmp/gh-aw/agent/pr-review-comments.json \
+            || echo '[]' > /tmp/gh-aw/agent/pr-review-comments.json
+          COMMENT_COUNT=$(jq 'length' /tmp/gh-aw/agent/pr-review-comments.json)
+          echo "Pre-fetched PR diff (${LINES} lines), metadata, and ${COMMENT_COUNT} existing review comments"
+
+      - name: Save PR data to cache
+        uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
+        with:
+          key: pr-prefetch-${{ github.event.pull_request.head.sha }}
+          path: /tmp/gh-aw/agent
diff --git a/.github/workflows/shared/pr-diff-data-fetch.md b/.github/workflows/shared/pr-diff-data-fetch.md
new file mode 100644
index 00000000000..22c462ea27b
--- /dev/null
+++ b/.github/workflows/shared/pr-diff-data-fetch.md
@@ -0,0 +1,90 @@
+---
+# Shared pre-agent-steps for pre-fetching PR diff, metadata, and review comments.
+# Works for both pull_request events and slash_command (issue) events on PRs.
+#
+# Outputs written to:
+#   /tmp/gh-aw/agent/pr-diff.patch          — unified diff (up to 3000 lines)
+#   /tmp/gh-aw/agent/pr-meta.json           — PR metadata (number, title, body, etc.)
+#   /tmp/gh-aw/agent/pr-review-comments.json — existing inline review comments
+#
+# Skip-check: if all three files already exist (cache hit), fetch is skipped.
+#
+# Usage:
+#   cache:
+#     key: pr-prefetch-${{ github.event.pull_request.head.sha || github.event.issue.number }}
+#     path: /tmp/gh-aw/agent
+#     restore-keys:
+#       - pr-prefetch-${{ github.event.pull_request.number || github.event.issue.number }}-
+#   imports:
+#     - shared/pr-diff-data-fetch.md
+
+pre-agent-steps:
+  - name: Pre-fetch PR diff and review comments
+    env:
+      GH_TOKEN: ${{ github.token }}
+      PR_NUMBER: ${{ github.event.issue.number || github.event.pull_request.number }}
+      EXPR_GITHUB_REPOSITORY: ${{ github.repository }}
+      PR_DIFF_MAX_LINES: "3000"
+    run: |
+      set -euo pipefail
+      mkdir -p /tmp/gh-aw/agent
+      # Skip fetch if cache already populated this data (actions/cache restore)
+      if [ -f /tmp/gh-aw/agent/pr-diff.patch ] && [ -f /tmp/gh-aw/agent/pr-meta.json ] && [ -f /tmp/gh-aw/agent/pr-review-comments.json ]; then
+        LINES=$(wc -l < /tmp/gh-aw/agent/pr-diff.patch)
+        COMMENT_COUNT=$(jq 'length' /tmp/gh-aw/agent/pr-review-comments.json)
+        echo "Cache hit: using pre-fetched PR data (${LINES} diff lines, ${COMMENT_COUNT} review comments)"
+      else
+        { gh pr diff "$PR_NUMBER" --repo $EXPR_GITHUB_REPOSITORY \
+            --exclude '**/*.lock.yml' \
+            --exclude '**/generated/**' \
+            --exclude '**/dist/**' \
+            --exclude '**/build/**' \
+            || true; } | head -n "${PR_DIFF_MAX_LINES}" > /tmp/gh-aw/agent/pr-diff.patch
+        LINES=$(wc -l < /tmp/gh-aw/agent/pr-diff.patch)
+        gh pr view "$PR_NUMBER" \
+          --repo $EXPR_GITHUB_REPOSITORY \
+          --json number,title,body,headRefName,additions,deletions,changedFiles,files \
+          > /tmp/gh-aw/agent/pr-meta.json
+        gh api "repos/$EXPR_GITHUB_REPOSITORY/pulls/$PR_NUMBER/comments" \
+          --paginate \
+          --jq '.[] | {id, path, line: (.line // .original_line), body: .body[:200], user: .user.login}' \
+          2>/dev/null | jq -s '.' > /tmp/gh-aw/agent/pr-review-comments.json \
+          || echo '[]' > /tmp/gh-aw/agent/pr-review-comments.json
+        COMMENT_COUNT=$(jq 'length' /tmp/gh-aw/agent/pr-review-comments.json)
+        echo "Pre-fetched PR diff (${LINES} lines), metadata, and ${COMMENT_COUNT} existing review comments"
+      fi
+---
+
+<!--
+## PR Diff Data Fetch
+
+Shared pre-agent-steps component used by PR reviewer workflows to pre-fetch PR
+diff, metadata, and inline review comments before the agent starts.
+
+### Why this shared component exists
+
+Three reviewer workflows (pr-code-quality-reviewer, impeccable-skills-reviewer,
+mattpocock-skills-reviewer) previously each duplicated identical pre-fetch shell
+steps. Extracting them into this shared component eliminates the duplication and
+ensures all three workflows use the same fetch logic and cache key, so that the
+dedicated `pr-data-prefetch.yml` workflow can warm the cache once per commit
+before the reviewer agents start.
+
+### How the cache works
+
+1. `pr-data-prefetch.yml` triggers simultaneously with the reviewer workflows on
+   `pull_request: [ready_for_review]` events. Because it has no AI engine, it
+   completes (and saves the `pr-prefetch-<sha>` Actions cache) in ~30–60 s.
+2. Reviewer workflows' activation jobs take ~60–90 s; their agent jobs restore
+   the cache before running `pre-agent-steps`.
+3. When the cache is warm, this shared step detects the pre-fetched files and
+   skips all GitHub API calls.
+
+### Output files
+
+| File | Content |
+|---|---|
+| `/tmp/gh-aw/agent/pr-diff.patch` | Unified diff (lock/generated/dist/build excluded, capped at 3000 lines) |
+| `/tmp/gh-aw/agent/pr-meta.json` | `number, title, body, headRefName, additions, deletions, changedFiles, files` |
+| `/tmp/gh-aw/agent/pr-review-comments.json` | Array of `{id, path, line, body, user}` (body capped at 200 chars) |
+-->
