From 72a110b019c045eb586376ba835b2f4d56ecef7b Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sun, 22 Feb 2026 00:55:24 +0000
Subject: [PATCH 1/4] Initial plan
From 1cbe0ab2c29ad0d8a56572056044df75925984ed Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sun, 22 Feb 2026 01:07:04 +0000
Subject: [PATCH 2/4] Add ideas-man and refactor-proposal workflows
Add two new continuous improvement workflows:
- ideas-man: Proposes well-researched new feature ideas as GitHub issues.
Reviews the codebase and recent activity to propose customer-aligned,
grounded, tractable features. Runs weekdays on schedule.
- refactor-proposal: Senior architect that identifies structural improvements,
partially implements them to prove viability, then pitches via an issue
with proof-of-concept and incremental rollout plan. Runs weekly.
Both workflows follow the scheduled-audit pattern and include:
- Source .md workflow definitions
- example.yml triggers
- README.md documentation
- Compiled .lock.yml files
- Auto-generated trigger files
Also updates quick-setup.sh and gh-agent-workflows/README.md to include
both workflows in the continuous-improvement set.
Co-authored-by: strawgate <6384545+strawgate@users.noreply.github.com>
---
.github/workflows/agentics-maintenance.yml | 2 +-
.github/workflows/gh-aw-ideas-man.lock.yml | 1465 ++++++++++++++++
.github/workflows/gh-aw-ideas-man.md | 153 ++
.../gh-aw-refactor-proposal.lock.yml | 1503 +++++++++++++++++
.github/workflows/gh-aw-refactor-proposal.md | 182 ++
.github/workflows/trigger-ideas-man.yml | 18 +
.../workflows/trigger-refactor-proposal.yml | 18 +
gh-agent-workflows/README.md | 4 +
gh-agent-workflows/ideas-man/README.md | 36 +
gh-agent-workflows/ideas-man/example.yml | 16 +
.../refactor-proposal/README.md | 36 +
.../refactor-proposal/example.yml | 16 +
scripts/quick-setup.sh | 2 +
13 files changed, 3450 insertions(+), 1 deletion(-)
create mode 100644 .github/workflows/gh-aw-ideas-man.lock.yml
create mode 100644 .github/workflows/gh-aw-ideas-man.md
create mode 100644 .github/workflows/gh-aw-refactor-proposal.lock.yml
create mode 100644 .github/workflows/gh-aw-refactor-proposal.md
create mode 100644 .github/workflows/trigger-ideas-man.yml
create mode 100644 .github/workflows/trigger-refactor-proposal.yml
create mode 100644 gh-agent-workflows/ideas-man/README.md
create mode 100644 gh-agent-workflows/ideas-man/example.yml
create mode 100644 gh-agent-workflows/refactor-proposal/README.md
create mode 100644 gh-agent-workflows/refactor-proposal/example.yml
diff --git a/.github/workflows/agentics-maintenance.yml b/.github/workflows/agentics-maintenance.yml
index 89d2058..928d335 100644
--- a/.github/workflows/agentics-maintenance.yml
+++ b/.github/workflows/agentics-maintenance.yml
@@ -31,7 +31,7 @@
# in create-discussions, create-issues, or create-pull-request safe-outputs configuration.
# Schedule frequency is automatically determined by the shortest expiration time.
#
-name: "Internal: Agentic Maintenance"
+name: Agentic Maintenance
on:
schedule:
diff --git a/.github/workflows/gh-aw-ideas-man.lock.yml b/.github/workflows/gh-aw-ideas-man.lock.yml
new file mode 100644
index 0000000..d9799f6
--- /dev/null
+++ b/.github/workflows/gh-aw-ideas-man.lock.yml
@@ -0,0 +1,1465 @@
+#
+# ___ _ _
+# / _ \ | | (_)
+# | |_| | __ _ ___ _ __ | |_ _ ___
+# | _ |/ _` |/ _ \ '_ \| __| |/ __|
+# | | | | (_| | __/ | | | |_| | (__
+# \_| |_/\__, |\___|_| |_|\__|_|\___|
+# __/ |
+# _ _ |___/
+# | | | | / _| |
+# | | | | ___ _ __ _ __| |_| | _____ ____
+# | |/\| |/ _ \ '__| |/ /| _| |/ _ \ \ /\ / / ___|
+# \ /\ / (_) | | | | ( | | | | (_) \ V V /\__ \
+# \/ \/ \___/|_| |_|\_\|_| |_|\___/ \_/\_/ |___/
+#
+# This file was automatically generated by gh-aw. DO NOT EDIT.
+#
+# To update this file, edit the corresponding .md file and run:
+# gh aw compile
+# Not all edits will cause changes to this file.
+#
+# For more information: https://github.github.com/gh-aw/introduction/overview/
+#
+# Propose well-researched new feature ideas as GitHub issues
+#
+# Resolved workflow manifest:
+# Imports:
+# - gh-aw-fragments/elastic-tools.md
+# - gh-aw-fragments/formatting.md
+# - gh-aw-fragments/mcp-pagination.md
+# - gh-aw-fragments/messages-footer.md
+# - gh-aw-fragments/rigor.md
+# - gh-aw-fragments/runtime-setup.md
+# - gh-aw-fragments/safe-output-create-issue.md
+# - gh-aw-fragments/scheduled-audit.md
+#
+# inlined-imports: true
+#
+# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"0573732b18dbf216ac46db50d9cec51bbfa9aea7c348244f3c09b6b6ca7de255"}
+
+name: "Ideas Man"
+"on":
+ # bots: # Bots processed as bot check in pre-activation job
+ # - ${{ inputs.allowed-bot-users }} # Bots processed as bot check in pre-activation job
+ # roles: # Roles processed as role check in pre-activation job
+ # - admin # Roles processed as role check in pre-activation job
+ # - maintainer # Roles processed as role check in pre-activation job
+ # - write # Roles processed as role check in pre-activation job
+ workflow_call:
+ inputs:
+ additional-instructions:
+ default: ""
+ description: Repo-specific instructions appended to the agent prompt
+ required: false
+ type: string
+ allowed-bot-users:
+ default: github-actions[bot]
+ description: Allowlisted bot actor usernames (comma-separated)
+ required: false
+ type: string
+ messages-footer:
+ default: ""
+ description: Footer appended to all agent comments and reviews
+ required: false
+ type: string
+ model:
+ default: gpt-5.3-codex
+ description: AI model to use
+ required: false
+ type: string
+ setup-commands:
+ default: ""
+ description: Shell commands to run before the agent starts (dependency install, build, etc.)
+ required: false
+ type: string
+ secrets:
+ COPILOT_GITHUB_TOKEN:
+ required: true
+
+permissions: {}
+
+concurrency:
+ cancel-in-progress: true
+ group: ideas-man
+
+run-name: "Ideas Man"
+
+jobs:
+ activation:
+ needs: pre_activation
+ if: needs.pre_activation.outputs.activated == 'true'
+ runs-on: ubuntu-slim
+ permissions:
+ contents: read
+ outputs:
+ comment_id: ""
+ comment_repo: ""
+ steps:
+ - name: Setup Scripts
+ uses: github/gh-aw/actions/setup@26b6572ae210580303087bc3142fe58d140bf65c # v0.48.1
+ with:
+ destination: /opt/gh-aw/actions
+ - name: Validate context variables
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
+ setupGlobals(core, github, context, exec, io);
+ const { main } = require('/opt/gh-aw/actions/validate_context_variables.cjs');
+ await main();
+ - name: Checkout .github and .agents folders
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ with:
+ sparse-checkout: |
+ .github
+ .agents
+ fetch-depth: 1
+ persist-credentials: false
+ - name: Check workflow file timestamps
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ env:
+ GH_AW_WORKFLOW_FILE: "gh-aw-ideas-man.lock.yml"
+ with:
+ script: |
+ const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
+ setupGlobals(core, github, context, exec, io);
+ const { main } = require('/opt/gh-aw/actions/check_workflow_timestamp_api.cjs');
+ await main();
+ - name: Create prompt with built-in context
+ env:
+ GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
+ GH_AW_SAFE_OUTPUTS: ${{ env.GH_AW_SAFE_OUTPUTS }}
+ GH_AW_EXPR_49B959F1: ${{ inputs.additional-instructions }}
+ GH_AW_GITHUB_ACTOR: ${{ github.actor }}
+ GH_AW_GITHUB_EVENT_COMMENT_ID: ${{ github.event.comment.id }}
+ GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER: ${{ github.event.discussion.number }}
+ GH_AW_GITHUB_EVENT_ISSUE_NUMBER: ${{ github.event.issue.number }}
+ GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER: ${{ github.event.pull_request.number }}
+ GH_AW_GITHUB_REPOSITORY: ${{ github.repository }}
+ GH_AW_GITHUB_RUN_ID: ${{ github.run_id }}
+ GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }}
+ run: |
+ bash /opt/gh-aw/actions/create_prompt_first.sh
+ cat << 'GH_AW_PROMPT_EOF' > "$GH_AW_PROMPT"
+
+ GH_AW_PROMPT_EOF
+ cat "/opt/gh-aw/prompts/xpia.md" >> "$GH_AW_PROMPT"
+ cat "/opt/gh-aw/prompts/temp_folder_prompt.md" >> "$GH_AW_PROMPT"
+ cat "/opt/gh-aw/prompts/markdown.md" >> "$GH_AW_PROMPT"
+ cat << 'GH_AW_PROMPT_EOF' >> "$GH_AW_PROMPT"
+
+ GitHub API Access Instructions
+
+ The gh CLI is NOT authenticated. Do NOT use gh commands for GitHub operations.
+
+
+ To create or modify GitHub resources (issues, discussions, pull requests, etc.), you MUST call the appropriate safe output tool. Simply writing content will NOT work - the workflow requires actual tool calls.
+
+ Temporary IDs: Some safe output tools support a temporary ID field (usually named temporary_id) so you can reference newly-created items elsewhere in the SAME agent output (for example, using #aw_abc1 in a later body).
+
+ **IMPORTANT - temporary_id format rules:**
+ - If you DON'T need to reference the item later, OMIT the temporary_id field entirely (it will be auto-generated if needed)
+ - If you DO need cross-references/chaining, you MUST match this EXACT validation regex: /^aw_[A-Za-z0-9]{3,8}$/i
+ - Format: aw_ prefix followed by 3 to 8 alphanumeric characters (A-Z, a-z, 0-9, case-insensitive)
+ - Valid alphanumeric characters: ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789
+ - INVALID examples: aw_ab (too short), aw_123456789 (too long), aw_test-id (contains hyphen), aw_id_123 (contains underscore)
+ - VALID examples: aw_abc, aw_abc1, aw_Test123, aw_A1B2C3D4, aw_12345678
+ - To generate valid IDs: use 3-8 random alphanumeric characters or omit the field to let the system auto-generate
+
+ Do NOT invent other aw_* formats — downstream steps will reject them with validation errors matching against /^aw_[A-Za-z0-9]{3,8}$/i.
+
+ Discover available tools from the safeoutputs MCP server.
+
+ **Critical**: Tool calls write structured data that downstream jobs process. Without tool calls, follow-up actions will be skipped.
+
+ **Note**: If you made no other safe output tool calls during this workflow execution, call the "noop" tool to provide a status message indicating completion or that no actions were needed.
+
+ ---
+
+ ## Creating an Issue, Reporting Missing Tools or Functionality, Reporting Missing Data
+
+ **IMPORTANT**: To perform the actions listed above, use the **safeoutputs** tools. Do NOT use `gh`, do NOT call the GitHub API directly. You do not have write access to the GitHub repository.
+
+ **Creating an Issue**
+
+ To create an issue, use the create_issue tool from safeoutputs.
+
+ **Reporting Missing Tools or Functionality**
+
+ To report a missing tool or capability, use the missing_tool tool from safeoutputs.
+
+ **Reporting Missing Data**
+
+ To report missing data required to achieve a goal, use the missing_data tool from safeoutputs.
+
+
+
+
+ The following GitHub context information is available for this workflow:
+ {{#if __GH_AW_GITHUB_ACTOR__ }}
+ - **actor**: __GH_AW_GITHUB_ACTOR__
+ {{/if}}
+ {{#if __GH_AW_GITHUB_REPOSITORY__ }}
+ - **repository**: __GH_AW_GITHUB_REPOSITORY__
+ {{/if}}
+ {{#if __GH_AW_GITHUB_WORKSPACE__ }}
+ - **workspace**: __GH_AW_GITHUB_WORKSPACE__
+ {{/if}}
+ {{#if __GH_AW_GITHUB_EVENT_ISSUE_NUMBER__ }}
+ - **issue-number**: #__GH_AW_GITHUB_EVENT_ISSUE_NUMBER__
+ {{/if}}
+ {{#if __GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER__ }}
+ - **discussion-number**: #__GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER__
+ {{/if}}
+ {{#if __GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER__ }}
+ - **pull-request-number**: #__GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER__
+ {{/if}}
+ {{#if __GH_AW_GITHUB_EVENT_COMMENT_ID__ }}
+ - **comment-id**: __GH_AW_GITHUB_EVENT_COMMENT_ID__
+ {{/if}}
+ {{#if __GH_AW_GITHUB_RUN_ID__ }}
+ - **workflow-run-id**: __GH_AW_GITHUB_RUN_ID__
+ {{/if}}
+
+
+ GH_AW_PROMPT_EOF
+ cat << 'GH_AW_PROMPT_EOF' >> "$GH_AW_PROMPT"
+
+ GH_AW_PROMPT_EOF
+ cat << 'GH_AW_PROMPT_EOF' >> "$GH_AW_PROMPT"
+ ## MCP Servers
+
+ - **`generate_agents_md`** — generates a summary of the repository's structure, conventions, and coding guidelines from AGENTS.md and related files. Call at the start of every workflow to get repo context.
+ - **`search_code`** — grep-style search across public GitHub repositories. Use for finding usage patterns in upstream libraries, reference implementations, or examples in open-source projects. This searches *public GitHub repos*, not the local codebase — if available you can use `grep` and file reading for local code.
+ GH_AW_PROMPT_EOF
+ cat << 'GH_AW_PROMPT_EOF' >> "$GH_AW_PROMPT"
+
+ GH_AW_PROMPT_EOF
+ cat << 'GH_AW_PROMPT_EOF' >> "$GH_AW_PROMPT"
+ ## Formatting Guidelines
+
+ - Lead with the most important information — your first sentence should be the key takeaway
+ - Be concise and actionable — no filler or praise
+ - Use `` and `` tags for long sections to keep responses scannable
+ - Wrap branch names and @-references in backticks to avoid pinging users
+ - Include code snippets with file paths and line numbers when referencing the codebase
+
+ GH_AW_PROMPT_EOF
+ cat << 'GH_AW_PROMPT_EOF' >> "$GH_AW_PROMPT"
+ ## Rigor
+
+ **Silence is better than noise. A false positive wastes a human's time and erodes trust in every future report.**
+
+ - If you claim something is missing or broken, show the exact evidence in the code — file path, line number, and what you observed.
+ - If a conclusion depends on assumptions you haven't confirmed, do not assert it. Verify first; if you cannot verify, do not report.
+ - "I don't know" is better than a wrong answer. `noop` is better than a speculative finding.
+ - It's worth the time to verify now versus guessing and forcing someone else to verify later.
+ - Before filing any issue or opening any PR, re-read your own output as a skeptical reviewer. Ask: "Would a senior engineer on this team find this useful, or would they close it immediately?" If the answer is "close," call `noop` instead.
+ - Only report findings you would confidently defend in a code review. If you feel the need to hedge with "might," "could," or "possibly," the finding is not ready to file.
+
+ GH_AW_PROMPT_EOF
+ cat << 'GH_AW_PROMPT_EOF' >> "$GH_AW_PROMPT"
+ ## MCP Pagination
+
+ MCP tool responses have a **25,000 token limit**. When responses exceed this limit, the call fails and you must retry with pagination — wasting turns and tokens. Use proactive pagination to stay under the limit.
+
+ ### Recommended `perPage` Values
+
+ - **5-10**: For detailed items (PR diffs, files with patches, issues with comments)
+ - **20-30**: For medium-detail lists (commits, review comments, issue lists)
+ - **50-100**: For simple list operations (branches, labels, tags)
+
+ ### Pagination Pattern
+
+ When you need all results from a paginated API:
+
+ 1. Fetch the first page with a conservative `perPage` value
+ 2. Process the results before fetching the next page
+ 3. Continue fetching pages until you receive fewer results than `perPage` (indicating the last page)
+
+ ### Error Recovery
+
+ If you see an error like:
+ - `MCP tool response exceeds maximum allowed tokens (25000)`
+ - `Response too large for tool [tool_name]`
+
+ Retry the same call with a smaller `perPage` value (halve it).
+
+ ### Tips
+
+ - **Start small**: It's better to make multiple small requests than one that fails
+ - **Fetch incrementally**: Get an overview first, then details for specific items
+ - **Use filters**: Combine `perPage` with state, label, or date filters to reduce result size
+ - **Process as you go**: Don't accumulate all pages before acting — process each batch immediately
+
+ GH_AW_PROMPT_EOF
+ cat << 'GH_AW_PROMPT_EOF' >> "$GH_AW_PROMPT"
+ ## Message Footer
+
+ A footer is automatically appended to all comments and reviews. Do not add your own footer or sign-off — the runtime handles this.
+ GH_AW_PROMPT_EOF
+ cat << 'GH_AW_PROMPT_EOF' >> "$GH_AW_PROMPT"
+ ## create-issue Limitations
+
+ - **Title**: Max 128 characters. Sanitized (special characters escaped).
+ - **Labels**: Max 10 labels per issue. Each label max 64 characters. Labels containing only `-` are rejected.
+ - **Assignees**: Max 5 assignees per issue.
+ - **Body**: No strict character limit beyond GitHub's API limit (~65,536 characters), but fields over 16,000 tokens are written to a file reference instead of inlined.
+ - **Bot triggers**: References like `fixes #123` or `closes #456` in the body are neutralized to prevent unintended issue closures.
+ - **Mentions**: `@mentions` in the body are neutralized (backticked) by default.
+ GH_AW_PROMPT_EOF
+ cat << 'GH_AW_PROMPT_EOF' >> "$GH_AW_PROMPT"
+ You are an agent for __GH_AW_GITHUB_REPOSITORY__. You run on a schedule to investigate the repository and file an issue when something needs attention. Your specific assignment is described in the **Report Assignment** section below.
+
+ ## Context
+
+ - **Repository**: __GH_AW_GITHUB_REPOSITORY__
+
+ ## Constraints
+
+ This workflow is for detection and reporting only. You can read files, search code, run commands, and read PR/issue details — but your only output is either a single issue or a noop.
+
+ ## Process
+
+ Follow these steps in order.
+
+ ### Step 1: Gather Context
+
+ 1. Call `generate_agents_md` to get the repository's coding guidelines and conventions. If this fails, continue without it.
+ 2. Follow the data gathering instructions in the **Report Assignment** section.
+
+ ### Step 2: Analyze
+
+ Follow the analysis instructions in the **Report Assignment** section to determine whether an issue should be filed. The Report Assignment defines:
+ - What data to gather and how
+ - What to look for
+ - What constitutes a finding worth reporting
+ - What to skip or ignore
+
+ ### Step 3: Self-Review (Quality Gate)
+
+ Before filing anything, critically evaluate every finding against these criteria:
+
+ 1. **Evidence is concrete** — you can point to exact file paths, line numbers, commit SHAs, or command outputs. No "I believe" or "it seems."
+ 2. **Finding is actionable** — a maintainer reading the issue can act on it without re-investigating from scratch.
+ 3. **Finding is not already tracked** — you checked open issues and recent PRs for duplicates.
+ 4. **Finding is worth a human's time** — the issue is material enough that a maintainer would thank you for filing it, not close it as noise.
+
+ If zero findings pass all four criteria, call `noop` with a brief reason and stop. **Noop is the expected outcome most days.** Filing nothing is a success when there is nothing worth filing.
+
+ ### Step 4: Report
+
+ If there are findings that pass the quality gate, call `create_issue` with a structured report. Use the issue format specified in the Report Assignment if one is provided, otherwise use this default format:
+
+ **Issue title:** Brief summary of findings
+
+ **Issue body:**
+
+ > ## Findings
+ >
+ > ### 1. [Brief description]
+ >
+ > **Evidence:** [Links, references, or data supporting the finding]
+ > **Action needed:** [What should be done]
+ >
+ > ## Suggested Actions
+ >
+ > - [ ] [Actionable checkbox for each finding]
+
+ **Guidelines:**
+ - Group related findings together
+ - Be specific about what needs to happen
+ - Include links and references where possible
+ - Make suggested actions concrete enough to act on without re-investigating
+ - If a finding is ambiguous, it does not pass the quality gate — drop it
+
+ **Report Assignment:**
+
+ GH_AW_PROMPT_EOF
+ cat << 'GH_AW_PROMPT_EOF' >> "$GH_AW_PROMPT"
+ You are the Ideas Man — an enthusiastic product thinker who has already done research on the codebase and genuinely believes each idea "won't be that hard" to implement. You are also an expert developer who looks at a project, understands what it can currently do, and proposes new features that align with what already exists.
+
+ Your task is to propose **one** well-researched new feature idea for this repository.
+
+ ## Report Assignment
+
+ ### Data Gathering
+
+ 1. **Understand the project**
+ - Read `README.md`, `CONTRIBUTING.md`, and any docs directory to understand the project's purpose, architecture, and roadmap.
+ - Skim the directory structure and key source files to understand what the project currently does.
+
+ 2. **Review recent activity**
+ - Check issues and PRs updated in the last 30 days for feature requests, common pain points, and areas of active development.
+ - Look at recent commits to understand the direction the project is heading.
+
+ 3. **Check for duplicates**
+ - Search open issues for existing feature requests: `repo:{owner}/{repo} is:issue is:open (feature OR enhancement OR idea)`.
+ - Search past Ideas Man reports: `repo:{owner}/{repo} is:issue in:title "[ideas-man]"`.
+ - If your idea duplicates an existing request, pick a different angle.
+
+ ### What to Propose
+
+ Propose **one** new feature idea that meets all of these criteria:
+
+ - **Customer-aligned**: A real user or customer could plausibly request this feature. Explain the user need.
+ - **Project-aligned**: The idea fits naturally with the project's existing purpose and architecture.
+ - **Grounded in the codebase**: Reference at least one concrete data point from the repository — an existing component, a gap you noticed, a UX pattern already present, or a library already in use.
+ - **Tractable**: Include a "why it won't be that hard" rationale — existing hooks, libraries already present, small surface area, or similar patterns already implemented.
+ - **Not already proposed**: No open or recently closed issue covers this idea.
+
+ ### Noop
+
+ If you cannot find a genuinely useful, non-duplicate idea that meets all the criteria above, call `noop` with:
+ "Ideas Man skipped — no novel, high-value feature idea found for this repository."
+
+ **Do not force a low-quality idea just to file something.** Noop is the correct outcome when nothing passes the bar.
+
+ ### Issue Format
+
+ **Issue title:** Short, punchy feature name
+
+ **Issue body:**
+
+ > ## 💡 Feature Idea
+ >
+ > **Summary:** One-sentence summary of the idea.
+ >
+ > ## Why a Customer Would Want This
+ > [Explain the user need and who benefits]
+ >
+ > ## Rough Implementation Sketch
+ > - [2–4 bullet points describing the approach]
+ > - [Reference existing code, components, or libraries that make this tractable]
+ >
+ > ## Why It Won't Be That Hard
+ > [Explain why this is feasible with modest effort — existing patterns, available libraries, small surface area]
+ >
+ > ## Evidence
+ > - [Links to files, issues, or PRs that support the idea]
+
+ ### Labeling
+
+ - If the `ideas-man` label exists (check with `github-get_label`), include it in the `create_issue` call; otherwise, rely on the `[ideas-man]` title prefix only.
+
+ __GH_AW_EXPR_49B959F1__
+
+ GH_AW_PROMPT_EOF
+ - name: Interpolate variables and render templates
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ env:
+ GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
+ GH_AW_GITHUB_REPOSITORY: ${{ github.repository }}
+ GH_AW_EXPR_49B959F1: ${{ inputs.additional-instructions }}
+ with:
+ script: |
+ const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
+ setupGlobals(core, github, context, exec, io);
+ const { main } = require('/opt/gh-aw/actions/interpolate_prompt.cjs');
+ await main();
+ - name: Substitute placeholders
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ env:
+ GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
+ GH_AW_EXPR_49B959F1: ${{ inputs.additional-instructions }}
+ GH_AW_GITHUB_ACTOR: ${{ github.actor }}
+ GH_AW_GITHUB_EVENT_COMMENT_ID: ${{ github.event.comment.id }}
+ GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER: ${{ github.event.discussion.number }}
+ GH_AW_GITHUB_EVENT_ISSUE_NUMBER: ${{ github.event.issue.number }}
+ GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER: ${{ github.event.pull_request.number }}
+ GH_AW_GITHUB_REPOSITORY: ${{ github.repository }}
+ GH_AW_GITHUB_RUN_ID: ${{ github.run_id }}
+ GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }}
+ GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_ACTIVATED: ${{ needs.pre_activation.outputs.activated }}
+ GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_MATCHED_COMMAND: ${{ needs.pre_activation.outputs.matched_command }}
+ with:
+ script: |
+ const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
+ setupGlobals(core, github, context, exec, io);
+
+ const substitutePlaceholders = require('/opt/gh-aw/actions/substitute_placeholders.cjs');
+
+ // Call the substitution function
+ return await substitutePlaceholders({
+ file: process.env.GH_AW_PROMPT,
+ substitutions: {
+ GH_AW_EXPR_49B959F1: process.env.GH_AW_EXPR_49B959F1,
+ GH_AW_GITHUB_ACTOR: process.env.GH_AW_GITHUB_ACTOR,
+ GH_AW_GITHUB_EVENT_COMMENT_ID: process.env.GH_AW_GITHUB_EVENT_COMMENT_ID,
+ GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER: process.env.GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER,
+ GH_AW_GITHUB_EVENT_ISSUE_NUMBER: process.env.GH_AW_GITHUB_EVENT_ISSUE_NUMBER,
+ GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER: process.env.GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER,
+ GH_AW_GITHUB_REPOSITORY: process.env.GH_AW_GITHUB_REPOSITORY,
+ GH_AW_GITHUB_RUN_ID: process.env.GH_AW_GITHUB_RUN_ID,
+ GH_AW_GITHUB_WORKSPACE: process.env.GH_AW_GITHUB_WORKSPACE,
+ GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_ACTIVATED: process.env.GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_ACTIVATED,
+ GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_MATCHED_COMMAND: process.env.GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_MATCHED_COMMAND
+ }
+ });
+ - name: Validate prompt placeholders
+ env:
+ GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
+ run: bash /opt/gh-aw/actions/validate_prompt_placeholders.sh
+ - name: Print prompt
+ env:
+ GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
+ run: bash /opt/gh-aw/actions/print_prompt_summary.sh
+ - name: Upload prompt artifact
+ if: success()
+ uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
+ with:
+ name: prompt
+ path: /tmp/gh-aw/aw-prompts/prompt.txt
+ retention-days: 1
+
+ agent:
+ needs: activation
+ runs-on: ubuntu-latest
+ permissions:
+ contents: read
+ issues: read
+ pull-requests: read
+ concurrency:
+ group: "gh-aw-copilot-${{ github.workflow }}"
+ env:
+ DEFAULT_BRANCH: ${{ github.event.repository.default_branch }}
+ GH_AW_ASSETS_ALLOWED_EXTS: ""
+ GH_AW_ASSETS_BRANCH: ""
+ GH_AW_ASSETS_MAX_SIZE_KB: 0
+ GH_AW_MCP_LOG_DIR: /tmp/gh-aw/mcp-logs/safeoutputs
+ GH_AW_SAFE_OUTPUTS: /opt/gh-aw/safeoutputs/outputs.jsonl
+ GH_AW_SAFE_OUTPUTS_CONFIG_PATH: /opt/gh-aw/safeoutputs/config.json
+ GH_AW_SAFE_OUTPUTS_TOOLS_PATH: /opt/gh-aw/safeoutputs/tools.json
+ GH_AW_WORKFLOW_ID_SANITIZED: ghawideasman
+ outputs:
+ checkout_pr_success: ${{ steps.checkout-pr.outputs.checkout_pr_success || 'true' }}
+ has_patch: ${{ steps.collect_output.outputs.has_patch }}
+ model: ${{ steps.generate_aw_info.outputs.model }}
+ output: ${{ steps.collect_output.outputs.output }}
+ output_types: ${{ steps.collect_output.outputs.output_types }}
+ secret_verification_result: ${{ steps.validate-secret.outputs.verification_result }}
+ steps:
+ - name: Setup Scripts
+ uses: github/gh-aw/actions/setup@26b6572ae210580303087bc3142fe58d140bf65c # v0.48.1
+ with:
+ destination: /opt/gh-aw/actions
+ - name: Checkout repository
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ with:
+ persist-credentials: false
+ - name: Create gh-aw temp directory
+ run: bash /opt/gh-aw/actions/create_gh_aw_tmp_dir.sh
+ - if: hashFiles('go.mod') != ''
+ name: Setup Go
+ uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5
+ with:
+ cache: true
+ go-version-file: go.mod
+ - if: hashFiles('.python-version') != ''
+ name: Setup Python
+ uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
+ with:
+ python-version-file: .python-version
+ - if: hashFiles('.node-version') != ''
+ name: Setup Node.js (.node-version)
+ uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6
+ with:
+ node-version-file: .node-version
+ - if: hashFiles('.node-version') == '' && hashFiles('.nvmrc') != ''
+ name: Setup Node.js (.nvmrc)
+ uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6
+ with:
+ node-version-file: .nvmrc
+ - if: hashFiles('.ruby-version') != ''
+ name: Setup Ruby
+ uses: ruby/setup-ruby@09a7688d3b55cf0e976497ff046b70949eeaccfd # v1
+ with:
+ bundler-cache: true
+ ruby-version: .ruby-version
+ - id: setup-uv
+ if: hashFiles('pyproject.toml', 'uv.lock') != ''
+ name: Setup uv
+ uses: astral-sh/setup-uv@e58605a9b6da7c637471fab8847a5e5a6b8df081 # v5
+ - env:
+ UV_PATH: ${{ steps.setup-uv.outputs.uv-path }}
+ WORKSPACE: ${{ github.workspace }}
+ if: hashFiles('pyproject.toml', 'uv.lock') != ''
+ name: Expose uv in workspace
+ run: |-
+ set -euo pipefail
+ install_dir="$WORKSPACE/.gh-aw-tools/bin"
+ mkdir -p "$install_dir"
+ cp "$UV_PATH" "$install_dir/uv"
+ chmod +x "$install_dir/uv"
+ echo "$install_dir" >> "$GITHUB_PATH"
+ shell: bash
+ - env:
+ SETUP_COMMANDS: ${{ inputs.setup-commands }}
+ if: ${{ inputs.setup-commands != '' }}
+ name: Repo-specific setup
+ run: eval "$SETUP_COMMANDS"
+
+ - name: Configure Git credentials
+ env:
+ REPO_NAME: ${{ github.repository }}
+ SERVER_URL: ${{ github.server_url }}
+ run: |
+ git config --global user.email "github-actions[bot]@users.noreply.github.com"
+ git config --global user.name "github-actions[bot]"
+ # Re-authenticate git with GitHub token
+ SERVER_URL_STRIPPED="${SERVER_URL#https://}"
+ git remote set-url origin "https://x-access-token:${{ github.token }}@${SERVER_URL_STRIPPED}/${REPO_NAME}.git"
+ echo "Git configured with standard GitHub Actions identity"
+ - name: Checkout PR branch
+ id: checkout-pr
+ if: |
+ github.event.pull_request
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ env:
+ GH_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
+ with:
+ github-token: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
+ script: |
+ const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
+ setupGlobals(core, github, context, exec, io);
+ const { main } = require('/opt/gh-aw/actions/checkout_pr_branch.cjs');
+ await main();
+ - name: Generate agentic run info
+ id: generate_aw_info
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const fs = require('fs');
+
+ const awInfo = {
+ engine_id: "copilot",
+ engine_name: "GitHub Copilot CLI",
+ model: "${{ inputs.model }}",
+ version: "",
+ agent_version: "0.0.412",
+ workflow_name: "Ideas Man",
+ experimental: false,
+ supports_tools_allowlist: true,
+ run_id: context.runId,
+ run_number: context.runNumber,
+ run_attempt: process.env.GITHUB_RUN_ATTEMPT,
+ repository: context.repo.owner + '/' + context.repo.repo,
+ ref: context.ref,
+ sha: context.sha,
+ actor: context.actor,
+ event_name: context.eventName,
+ staged: false,
+ allowed_domains: ["agents-md-generator.fastmcp.app","artifacts.elastic.co","cloud.elastic.co","defaults","ela.st","elastic.co","github","go","node","public-code-search.fastmcp.app","python","ruby","www.elastic.co"],
+ firewall_enabled: true,
+ awf_version: "v0.20.2",
+ awmg_version: "v0.1.4",
+ steps: {
+ firewall: "squid"
+ },
+ created_at: new Date().toISOString()
+ };
+
+ // Write to /tmp/gh-aw directory to avoid inclusion in PR
+ const tmpPath = '/tmp/gh-aw/aw_info.json';
+ fs.writeFileSync(tmpPath, JSON.stringify(awInfo, null, 2));
+ console.log('Generated aw_info.json at:', tmpPath);
+ console.log(JSON.stringify(awInfo, null, 2));
+
+ // Set model as output for reuse in other steps/jobs
+ core.setOutput('model', awInfo.model);
+ - name: Validate COPILOT_GITHUB_TOKEN secret
+ id: validate-secret
+ run: /opt/gh-aw/actions/validate_multi_secret.sh COPILOT_GITHUB_TOKEN 'GitHub Copilot CLI' https://github.github.com/gh-aw/reference/engines/#github-copilot-default
+ env:
+ COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
+ - name: Install GitHub Copilot CLI
+ run: /opt/gh-aw/actions/install_copilot_cli.sh 0.0.412
+ - name: Install awf binary
+ run: bash /opt/gh-aw/actions/install_awf_binary.sh v0.20.2
+ - name: Determine automatic lockdown mode for GitHub MCP Server
+ id: determine-automatic-lockdown
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ env:
+ GH_AW_GITHUB_TOKEN: ${{ secrets.GH_AW_GITHUB_TOKEN }}
+ GH_AW_GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN }}
+ with:
+ script: |
+ const determineAutomaticLockdown = require('/opt/gh-aw/actions/determine_automatic_lockdown.cjs');
+ await determineAutomaticLockdown(github, context, core);
+ - name: Download container images
+ run: bash /opt/gh-aw/actions/download_docker_images.sh ghcr.io/github/gh-aw-firewall/agent:0.20.2 ghcr.io/github/gh-aw-firewall/api-proxy:0.20.2 ghcr.io/github/gh-aw-firewall/squid:0.20.2 ghcr.io/github/gh-aw-mcpg:v0.1.4 ghcr.io/github/github-mcp-server:v0.31.0 node:lts-alpine
+ - name: Write Safe Outputs Config
+ run: |
+ mkdir -p /opt/gh-aw/safeoutputs
+ mkdir -p /tmp/gh-aw/safeoutputs
+ mkdir -p /tmp/gh-aw/mcp-logs/safeoutputs
+ cat > /opt/gh-aw/safeoutputs/config.json << 'GH_AW_SAFE_OUTPUTS_CONFIG_EOF'
+ {"create_issue":{"expires":168,"max":1},"missing_data":{},"missing_tool":{},"noop":{"max":1}}
+ GH_AW_SAFE_OUTPUTS_CONFIG_EOF
+ cat > /opt/gh-aw/safeoutputs/tools.json << 'GH_AW_SAFE_OUTPUTS_TOOLS_EOF'
+ [
+ {
+ "description": "Create a new GitHub issue for tracking bugs, feature requests, or tasks. Use this for actionable work items that need assignment, labeling, and status tracking. For reports, announcements, or status updates that don't require task tracking, use create_discussion instead. CONSTRAINTS: Maximum 1 issue(s) can be created. Title will be prefixed with \"[ideas-man] \".",
+ "inputSchema": {
+ "additionalProperties": false,
+ "properties": {
+ "body": {
+ "description": "Detailed issue description in Markdown. Do NOT repeat the title as a heading since it already appears as the issue's h1. Include context, reproduction steps, or acceptance criteria as appropriate.",
+ "type": "string"
+ },
+ "labels": {
+ "description": "Labels to categorize the issue (e.g., 'bug', 'enhancement'). Labels must exist in the repository.",
+ "items": {
+ "type": "string"
+ },
+ "type": "array"
+ },
+ "parent": {
+ "description": "Parent issue number for creating sub-issues. This is the numeric ID from the GitHub URL (e.g., 42 in github.com/owner/repo/issues/42). Can also be a temporary_id (e.g., 'aw_abc123', 'aw_Test123') from a previously created issue in the same workflow run.",
+ "type": [
+ "number",
+ "string"
+ ]
+ },
+ "temporary_id": {
+ "description": "Unique temporary identifier for referencing this issue before it's created. Format: 'aw_' followed by 3 to 8 alphanumeric characters (e.g., 'aw_abc1', 'aw_Test123'). Use '#aw_ID' in body text to reference other issues by their temporary_id; these are replaced with actual issue numbers after creation.",
+ "pattern": "^aw_[A-Za-z0-9]{3,8}$",
+ "type": "string"
+ },
+ "title": {
+ "description": "Concise issue title summarizing the bug, feature, or task. The title appears as the main heading, so keep it brief and descriptive.",
+ "type": "string"
+ }
+ },
+ "required": [
+ "title",
+ "body"
+ ],
+ "type": "object"
+ },
+ "name": "create_issue"
+ },
+ {
+ "description": "Report that a tool or capability needed to complete the task is not available, or share any information you deem important about missing functionality or limitations. Use this when you cannot accomplish what was requested because the required functionality is missing or access is restricted.",
+ "inputSchema": {
+ "additionalProperties": false,
+ "properties": {
+ "alternatives": {
+ "description": "Any workarounds, manual steps, or alternative approaches the user could take (max 256 characters).",
+ "type": "string"
+ },
+ "reason": {
+ "description": "Explanation of why this tool is needed or what information you want to share about the limitation (max 256 characters).",
+ "type": "string"
+ },
+ "tool": {
+ "description": "Optional: Name or description of the missing tool or capability (max 128 characters). Be specific about what functionality is needed.",
+ "type": "string"
+ }
+ },
+ "required": [
+ "reason"
+ ],
+ "type": "object"
+ },
+ "name": "missing_tool"
+ },
+ {
+ "description": "Log a transparency message when no significant actions are needed. Use this to confirm workflow completion and provide visibility when analysis is complete but no changes or outputs are required (e.g., 'No issues found', 'All checks passed'). This ensures the workflow produces human-visible output even when no other actions are taken.",
+ "inputSchema": {
+ "additionalProperties": false,
+ "properties": {
+ "message": {
+ "description": "Status or completion message to log. Should explain what was analyzed and the outcome (e.g., 'Code review complete - no issues found', 'Analysis complete - all tests passing').",
+ "type": "string"
+ }
+ },
+ "required": [
+ "message"
+ ],
+ "type": "object"
+ },
+ "name": "noop"
+ },
+ {
+ "description": "Report that data or information needed to complete the task is not available. Use this when you cannot accomplish what was requested because required data, context, or information is missing.",
+ "inputSchema": {
+ "additionalProperties": false,
+ "properties": {
+ "alternatives": {
+ "description": "Any workarounds, manual steps, or alternative approaches the user could take (max 256 characters).",
+ "type": "string"
+ },
+ "context": {
+ "description": "Additional context about the missing data or where it should come from (max 256 characters).",
+ "type": "string"
+ },
+ "data_type": {
+ "description": "Type or description of the missing data or information (max 128 characters). Be specific about what data is needed.",
+ "type": "string"
+ },
+ "reason": {
+ "description": "Explanation of why this data is needed to complete the task (max 256 characters).",
+ "type": "string"
+ }
+ },
+ "required": [],
+ "type": "object"
+ },
+ "name": "missing_data"
+ }
+ ]
+ GH_AW_SAFE_OUTPUTS_TOOLS_EOF
+ cat > /opt/gh-aw/safeoutputs/validation.json << 'GH_AW_SAFE_OUTPUTS_VALIDATION_EOF'
+ {
+ "create_issue": {
+ "defaultMax": 1,
+ "fields": {
+ "body": {
+ "required": true,
+ "type": "string",
+ "sanitize": true,
+ "maxLength": 65000
+ },
+ "labels": {
+ "type": "array",
+ "itemType": "string",
+ "itemSanitize": true,
+ "itemMaxLength": 128
+ },
+ "parent": {
+ "issueOrPRNumber": true
+ },
+ "repo": {
+ "type": "string",
+ "maxLength": 256
+ },
+ "temporary_id": {
+ "type": "string"
+ },
+ "title": {
+ "required": true,
+ "type": "string",
+ "sanitize": true,
+ "maxLength": 128
+ }
+ }
+ },
+ "missing_data": {
+ "defaultMax": 20,
+ "fields": {
+ "alternatives": {
+ "type": "string",
+ "sanitize": true,
+ "maxLength": 256
+ },
+ "context": {
+ "type": "string",
+ "sanitize": true,
+ "maxLength": 256
+ },
+ "data_type": {
+ "type": "string",
+ "sanitize": true,
+ "maxLength": 128
+ },
+ "reason": {
+ "type": "string",
+ "sanitize": true,
+ "maxLength": 256
+ }
+ }
+ },
+ "missing_tool": {
+ "defaultMax": 20,
+ "fields": {
+ "alternatives": {
+ "type": "string",
+ "sanitize": true,
+ "maxLength": 512
+ },
+ "reason": {
+ "required": true,
+ "type": "string",
+ "sanitize": true,
+ "maxLength": 256
+ },
+ "tool": {
+ "type": "string",
+ "sanitize": true,
+ "maxLength": 128
+ }
+ }
+ },
+ "noop": {
+ "defaultMax": 1,
+ "fields": {
+ "message": {
+ "required": true,
+ "type": "string",
+ "sanitize": true,
+ "maxLength": 65000
+ }
+ }
+ }
+ }
+ GH_AW_SAFE_OUTPUTS_VALIDATION_EOF
+ - name: Generate Safe Outputs MCP Server Config
+ id: safe-outputs-config
+ run: |
+ # Generate a secure random API key (360 bits of entropy, 40+ chars)
+ # Mask immediately to prevent timing vulnerabilities
+ API_KEY=$(openssl rand -base64 45 | tr -d '/+=')
+ echo "::add-mask::${API_KEY}"
+
+ PORT=3001
+
+ # Set outputs for next steps
+ {
+ echo "safe_outputs_api_key=${API_KEY}"
+ echo "safe_outputs_port=${PORT}"
+ } >> "$GITHUB_OUTPUT"
+
+ echo "Safe Outputs MCP server will run on port ${PORT}"
+
+ - name: Start Safe Outputs MCP HTTP Server
+ id: safe-outputs-start
+ env:
+ DEBUG: '*'
+ GH_AW_SAFE_OUTPUTS_PORT: ${{ steps.safe-outputs-config.outputs.safe_outputs_port }}
+ GH_AW_SAFE_OUTPUTS_API_KEY: ${{ steps.safe-outputs-config.outputs.safe_outputs_api_key }}
+ GH_AW_SAFE_OUTPUTS_TOOLS_PATH: /opt/gh-aw/safeoutputs/tools.json
+ GH_AW_SAFE_OUTPUTS_CONFIG_PATH: /opt/gh-aw/safeoutputs/config.json
+ GH_AW_MCP_LOG_DIR: /tmp/gh-aw/mcp-logs/safeoutputs
+ run: |
+ # Environment variables are set above to prevent template injection
+ export DEBUG
+ export GH_AW_SAFE_OUTPUTS_PORT
+ export GH_AW_SAFE_OUTPUTS_API_KEY
+ export GH_AW_SAFE_OUTPUTS_TOOLS_PATH
+ export GH_AW_SAFE_OUTPUTS_CONFIG_PATH
+ export GH_AW_MCP_LOG_DIR
+
+ bash /opt/gh-aw/actions/start_safe_outputs_server.sh
+
+ - name: Start MCP Gateway
+ id: start-mcp-gateway
+ env:
+ GH_AW_SAFE_OUTPUTS: ${{ env.GH_AW_SAFE_OUTPUTS }}
+ GH_AW_SAFE_OUTPUTS_API_KEY: ${{ steps.safe-outputs-start.outputs.api_key }}
+ GH_AW_SAFE_OUTPUTS_PORT: ${{ steps.safe-outputs-start.outputs.port }}
+ GITHUB_MCP_LOCKDOWN: ${{ steps.determine-automatic-lockdown.outputs.lockdown == 'true' && '1' || '0' }}
+ GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
+ run: |
+ set -eo pipefail
+ mkdir -p /tmp/gh-aw/mcp-config
+
+ # Export gateway environment variables for MCP config and gateway script
+ export MCP_GATEWAY_PORT="80"
+ export MCP_GATEWAY_DOMAIN="host.docker.internal"
+ MCP_GATEWAY_API_KEY=$(openssl rand -base64 45 | tr -d '/+=')
+ echo "::add-mask::${MCP_GATEWAY_API_KEY}"
+ export MCP_GATEWAY_API_KEY
+ export MCP_GATEWAY_PAYLOAD_DIR="/tmp/gh-aw/mcp-payloads"
+ mkdir -p "${MCP_GATEWAY_PAYLOAD_DIR}"
+ export DEBUG="*"
+
+ export GH_AW_ENGINE="copilot"
+ export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network host -v /var/run/docker.sock:/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_LOCKDOWN -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GH_AW_SAFE_OUTPUTS_PORT -e GH_AW_SAFE_OUTPUTS_API_KEY -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw ghcr.io/github/gh-aw-mcpg:v0.1.4'
+
+ mkdir -p /home/runner/.copilot
+ cat << GH_AW_MCP_CONFIG_EOF | bash /opt/gh-aw/actions/start_mcp_gateway.sh
+ {
+ "mcpServers": {
+ "agents-md-generator": {
+ "type": "http",
+ "url": "https://agents-md-generator.fastmcp.app/mcp",
+ "tools": [
+ "generate_agents_md"
+ ]
+ },
+ "github": {
+ "type": "stdio",
+ "container": "ghcr.io/github/github-mcp-server:v0.31.0",
+ "env": {
+ "GITHUB_LOCKDOWN_MODE": "$GITHUB_MCP_LOCKDOWN",
+ "GITHUB_PERSONAL_ACCESS_TOKEN": "\${GITHUB_MCP_SERVER_TOKEN}",
+ "GITHUB_READ_ONLY": "1",
+ "GITHUB_TOOLSETS": "repos,issues,pull_requests,search,labels"
+ }
+ },
+ "public-code-search": {
+ "type": "http",
+ "url": "https://public-code-search.fastmcp.app/mcp",
+ "tools": [
+ "search_code"
+ ]
+ },
+ "safeoutputs": {
+ "type": "http",
+ "url": "http://host.docker.internal:$GH_AW_SAFE_OUTPUTS_PORT",
+ "headers": {
+ "Authorization": "\${GH_AW_SAFE_OUTPUTS_API_KEY}"
+ }
+ }
+ },
+ "gateway": {
+ "port": $MCP_GATEWAY_PORT,
+ "domain": "${MCP_GATEWAY_DOMAIN}",
+ "apiKey": "${MCP_GATEWAY_API_KEY}",
+ "payloadDir": "${MCP_GATEWAY_PAYLOAD_DIR}"
+ }
+ }
+ GH_AW_MCP_CONFIG_EOF
+ - name: Generate workflow overview
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { generateWorkflowOverview } = require('/opt/gh-aw/actions/generate_workflow_overview.cjs');
+ await generateWorkflowOverview(core);
+ - name: Download prompt artifact
+ uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6
+ with:
+ name: prompt
+ path: /tmp/gh-aw/aw-prompts
+ - name: Clean git credentials
+ run: bash /opt/gh-aw/actions/clean_git_credentials.sh
+ - name: Execute GitHub Copilot CLI
+ id: agentic_execution
+ # Copilot CLI tool arguments (sorted):
+ timeout-minutes: 90
+ run: |
+ set -o pipefail
+ sudo -E awf --env-all --container-workdir "${GITHUB_WORKSPACE}" --allow-domains '*.githubusercontent.com,*.jsr.io,*.pythonhosted.org,*.rvm.io,agents-md-generator.fastmcp.app,anaconda.org,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.npms.io,api.rubygems.org,api.snapcraft.io,archive.ubuntu.com,artifacts.elastic.co,azure.archive.ubuntu.com,binstar.org,bootstrap.pypa.io,bun.sh,bundler.rubygems.org,cache.ruby-lang.org,cdn.jsdelivr.net,cloud.elastic.co,codeload.github.com,conda.anaconda.org,conda.binstar.org,crates.io,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,deb.nodesource.com,deno.land,ela.st,elastic.co,esm.sh,files.pythonhosted.org,gems.rubyforge.org,gems.rubyonrails.org,get.pnpm.io,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.com,github.githubassets.com,go.dev,golang.org,googleapis.deno.dev,googlechromelabs.github.io,goproxy.io,host.docker.internal,index.crates.io,index.rubygems.org,json-schema.org,json.schemastore.org,jsr.io,keyserver.ubuntu.com,lfs.github.com,nodejs.org,npm.pkg.github.com,npmjs.com,npmjs.org,objects.githubusercontent.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,pip.pypa.io,pkg.go.dev,ppa.launchpad.net,proxy.golang.org,public-code-search.fastmcp.app,pypi.org,pypi.python.org,raw.githubusercontent.com,registry.bower.io,registry.npmjs.com,registry.npmjs.org,registry.yarnpkg.com,repo.anaconda.com,repo.continuum.io,repo.yarnpkg.com,rubygems.org,rubygems.pkg.github.com,s.symcb.com,s.symcd.com,security.ubuntu.com,skimdb.npmjs.com,static.crates.io,storage.googleapis.com,sum.golang.org,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.elastic.co,www.npmjs.com,www.npmjs.org,yarnpkg.com' --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --enable-host-access --image-tag 0.20.2 --skip-pull --enable-api-proxy \
+ -- /bin/bash -c '/usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --add-dir "${GITHUB_WORKSPACE}" --disable-builtin-mcps --allow-all-tools --allow-all-paths --prompt "$(cat /tmp/gh-aw/aw-prompts/prompt.txt)"' 2>&1 | tee -a /tmp/gh-aw/agent-stdio.log
+ env:
+ COPILOT_AGENT_RUNNER_TYPE: STANDALONE
+ COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
+ COPILOT_MODEL: ${{ inputs.model }}
+ GH_AW_MCP_CONFIG: /home/runner/.copilot/mcp-config.json
+ GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
+ GH_AW_SAFE_OUTPUTS: ${{ env.GH_AW_SAFE_OUTPUTS }}
+ GITHUB_HEAD_REF: ${{ github.head_ref }}
+ GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
+ GITHUB_REF_NAME: ${{ github.ref_name }}
+ GITHUB_STEP_SUMMARY: ${{ env.GITHUB_STEP_SUMMARY }}
+ GITHUB_WORKSPACE: ${{ github.workspace }}
+ XDG_CONFIG_HOME: /home/runner
+ - name: Configure Git credentials
+ env:
+ REPO_NAME: ${{ github.repository }}
+ SERVER_URL: ${{ github.server_url }}
+ run: |
+ git config --global user.email "github-actions[bot]@users.noreply.github.com"
+ git config --global user.name "github-actions[bot]"
+ # Re-authenticate git with GitHub token
+ SERVER_URL_STRIPPED="${SERVER_URL#https://}"
+ git remote set-url origin "https://x-access-token:${{ github.token }}@${SERVER_URL_STRIPPED}/${REPO_NAME}.git"
+ echo "Git configured with standard GitHub Actions identity"
+ - name: Copy Copilot session state files to logs
+ if: always()
+ continue-on-error: true
+ run: |
+ # Copy Copilot session state files to logs folder for artifact collection
+ # This ensures they are in /tmp/gh-aw/ where secret redaction can scan them
+ SESSION_STATE_DIR="$HOME/.copilot/session-state"
+ LOGS_DIR="/tmp/gh-aw/sandbox/agent/logs"
+
+ if [ -d "$SESSION_STATE_DIR" ]; then
+ echo "Copying Copilot session state files from $SESSION_STATE_DIR to $LOGS_DIR"
+ mkdir -p "$LOGS_DIR"
+ cp -v "$SESSION_STATE_DIR"/*.jsonl "$LOGS_DIR/" 2>/dev/null || true
+ echo "Session state files copied successfully"
+ else
+ echo "No session-state directory found at $SESSION_STATE_DIR"
+ fi
+ - name: Stop MCP Gateway
+ if: always()
+ continue-on-error: true
+ env:
+ MCP_GATEWAY_PORT: ${{ steps.start-mcp-gateway.outputs.gateway-port }}
+ MCP_GATEWAY_API_KEY: ${{ steps.start-mcp-gateway.outputs.gateway-api-key }}
+ GATEWAY_PID: ${{ steps.start-mcp-gateway.outputs.gateway-pid }}
+ run: |
+ bash /opt/gh-aw/actions/stop_mcp_gateway.sh "$GATEWAY_PID"
+ - name: Redact secrets in logs
+ if: always()
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
+ setupGlobals(core, github, context, exec, io);
+ const { main } = require('/opt/gh-aw/actions/redact_secrets.cjs');
+ await main();
+ env:
+ GH_AW_SECRET_NAMES: 'COPILOT_GITHUB_TOKEN,GH_AW_GITHUB_MCP_SERVER_TOKEN,GH_AW_GITHUB_TOKEN,GITHUB_TOKEN'
+ SECRET_COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
+ SECRET_GH_AW_GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN }}
+ SECRET_GH_AW_GITHUB_TOKEN: ${{ secrets.GH_AW_GITHUB_TOKEN }}
+ SECRET_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ - name: Upload Safe Outputs
+ if: always()
+ uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
+ with:
+ name: safe-output
+ path: ${{ env.GH_AW_SAFE_OUTPUTS }}
+ if-no-files-found: warn
+ - name: Ingest agent output
+ id: collect_output
+ if: always()
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ env:
+ GH_AW_SAFE_OUTPUTS: ${{ env.GH_AW_SAFE_OUTPUTS }}
+ GH_AW_ALLOWED_DOMAINS: "*.githubusercontent.com,*.jsr.io,*.pythonhosted.org,*.rvm.io,agents-md-generator.fastmcp.app,anaconda.org,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.npms.io,api.rubygems.org,api.snapcraft.io,archive.ubuntu.com,artifacts.elastic.co,azure.archive.ubuntu.com,binstar.org,bootstrap.pypa.io,bun.sh,bundler.rubygems.org,cache.ruby-lang.org,cdn.jsdelivr.net,cloud.elastic.co,codeload.github.com,conda.anaconda.org,conda.binstar.org,crates.io,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,deb.nodesource.com,deno.land,ela.st,elastic.co,esm.sh,files.pythonhosted.org,gems.rubyforge.org,gems.rubyonrails.org,get.pnpm.io,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.com,github.githubassets.com,go.dev,golang.org,googleapis.deno.dev,googlechromelabs.github.io,goproxy.io,host.docker.internal,index.crates.io,index.rubygems.org,json-schema.org,json.schemastore.org,jsr.io,keyserver.ubuntu.com,lfs.github.com,nodejs.org,npm.pkg.github.com,npmjs.com,npmjs.org,objects.githubusercontent.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,pip.pypa.io,pkg.go.dev,ppa.launchpad.net,proxy.golang.org,public-code-search.fastmcp.app,pypi.org,pypi.python.org,raw.githubusercontent.com,registry.bower.io,registry.npmjs.com,registry.npmjs.org,registry.yarnpkg.com,repo.anaconda.com,repo.continuum.io,repo.yarnpkg.com,rubygems.org,rubygems.pkg.github.com,s.symcb.com,s.symcd.com,security.ubuntu.com,skimdb.npmjs.com,static.crates.io,storage.googleapis.com,sum.golang.org,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.elastic.co,www.npmjs.com,www.npmjs.org,yarnpkg.com"
+ GITHUB_SERVER_URL: ${{ github.server_url }}
+ GITHUB_API_URL: ${{ github.api_url }}
+ with:
+ script: |
+ const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
+ setupGlobals(core, github, context, exec, io);
+ const { main } = require('/opt/gh-aw/actions/collect_ndjson_output.cjs');
+ await main();
+ - name: Upload sanitized agent output
+ if: always() && env.GH_AW_AGENT_OUTPUT
+ uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
+ with:
+ name: agent-output
+ path: ${{ env.GH_AW_AGENT_OUTPUT }}
+ if-no-files-found: warn
+ - name: Upload engine output files
+ uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
+ with:
+ name: agent_outputs
+ path: |
+ /tmp/gh-aw/sandbox/agent/logs/
+ /tmp/gh-aw/redacted-urls.log
+ if-no-files-found: ignore
+ - name: Parse agent logs for step summary
+ if: always()
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ env:
+ GH_AW_AGENT_OUTPUT: /tmp/gh-aw/sandbox/agent/logs/
+ with:
+ script: |
+ const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
+ setupGlobals(core, github, context, exec, io);
+ const { main } = require('/opt/gh-aw/actions/parse_copilot_log.cjs');
+ await main();
+ - name: Parse MCP Gateway logs for step summary
+ if: always()
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
+ setupGlobals(core, github, context, exec, io);
+ const { main } = require('/opt/gh-aw/actions/parse_mcp_gateway_log.cjs');
+ await main();
+ - name: Print firewall logs
+ if: always()
+ continue-on-error: true
+ env:
+ AWF_LOGS_DIR: /tmp/gh-aw/sandbox/firewall/logs
+ run: |
+ # Fix permissions on firewall logs so they can be uploaded as artifacts
+ # AWF runs with sudo, creating files owned by root
+ sudo chmod -R a+r /tmp/gh-aw/sandbox/firewall/logs 2>/dev/null || true
+ # Only run awf logs summary if awf command exists (it may not be installed if workflow failed before install step)
+ if command -v awf &> /dev/null; then
+ awf logs summary | tee -a "$GITHUB_STEP_SUMMARY"
+ else
+ echo 'AWF binary not installed, skipping firewall log summary'
+ fi
+ - name: Upload agent artifacts
+ if: always()
+ continue-on-error: true
+ uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
+ with:
+ name: agent-artifacts
+ path: |
+ /tmp/gh-aw/aw-prompts/prompt.txt
+ /tmp/gh-aw/aw_info.json
+ /tmp/gh-aw/mcp-logs/
+ /tmp/gh-aw/sandbox/firewall/logs/
+ /tmp/gh-aw/agent-stdio.log
+ /tmp/gh-aw/agent/
+ if-no-files-found: ignore
+
+ conclusion:
+ needs:
+ - activation
+ - agent
+ - detection
+ - safe_outputs
+ if: (always()) && (needs.agent.result != 'skipped')
+ runs-on: ubuntu-slim
+ permissions:
+ contents: read
+ issues: write
+ outputs:
+ noop_message: ${{ steps.noop.outputs.noop_message }}
+ tools_reported: ${{ steps.missing_tool.outputs.tools_reported }}
+ total_count: ${{ steps.missing_tool.outputs.total_count }}
+ steps:
+ - name: Setup Scripts
+ uses: github/gh-aw/actions/setup@26b6572ae210580303087bc3142fe58d140bf65c # v0.48.1
+ with:
+ destination: /opt/gh-aw/actions
+ - name: Download agent output artifact
+ continue-on-error: true
+ uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6
+ with:
+ name: agent-output
+ path: /tmp/gh-aw/safeoutputs/
+ - name: Setup agent output environment variable
+ run: |
+ mkdir -p /tmp/gh-aw/safeoutputs/
+ find "/tmp/gh-aw/safeoutputs/" -type f -print
+ echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/safeoutputs/agent_output.json" >> "$GITHUB_ENV"
+ - name: Process No-Op Messages
+ id: noop
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ env:
+ GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }}
+ GH_AW_NOOP_MAX: 1
+ GH_AW_WORKFLOW_NAME: "Ideas Man"
+ with:
+ github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
+ script: |
+ const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
+ setupGlobals(core, github, context, exec, io);
+ const { main } = require('/opt/gh-aw/actions/noop.cjs');
+ await main();
+ - name: Record Missing Tool
+ id: missing_tool
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ env:
+ GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }}
+ GH_AW_WORKFLOW_NAME: "Ideas Man"
+ with:
+ github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
+ script: |
+ const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
+ setupGlobals(core, github, context, exec, io);
+ const { main } = require('/opt/gh-aw/actions/missing_tool.cjs');
+ await main();
+ - name: Handle Agent Failure
+ id: handle_agent_failure
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ env:
+ GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }}
+ GH_AW_WORKFLOW_NAME: "Ideas Man"
+ GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
+ GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }}
+ GH_AW_WORKFLOW_ID: "gh-aw-ideas-man"
+ GH_AW_SECRET_VERIFICATION_RESULT: ${{ needs.agent.outputs.secret_verification_result }}
+ GH_AW_CHECKOUT_PR_SUCCESS: ${{ needs.agent.outputs.checkout_pr_success }}
+ GH_AW_SAFE_OUTPUT_MESSAGES: "{\"footer\":\"${{ inputs.messages-footer || '---\\n[What is this?](https://ela.st/github-ai-tools) | [From workflow: {workflow_name}]({run_url})\\n\\nGive us feedback! React with 🚀 if perfect, 👍 if helpful, 👎 if not.' }}\"}"
+ GH_AW_GROUP_REPORTS: "false"
+ with:
+ github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
+ script: |
+ const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
+ setupGlobals(core, github, context, exec, io);
+ const { main } = require('/opt/gh-aw/actions/handle_agent_failure.cjs');
+ await main();
+ - name: Handle No-Op Message
+ id: handle_noop_message
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ env:
+ GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }}
+ GH_AW_WORKFLOW_NAME: "Ideas Man"
+ GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
+ GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }}
+ GH_AW_NOOP_MESSAGE: ${{ steps.noop.outputs.noop_message }}
+ GH_AW_NOOP_REPORT_AS_ISSUE: "true"
+ with:
+ github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
+ script: |
+ const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
+ setupGlobals(core, github, context, exec, io);
+ const { main } = require('/opt/gh-aw/actions/handle_noop_message.cjs');
+ await main();
+
+ detection:
+ needs: agent
+ if: needs.agent.outputs.output_types != '' || needs.agent.outputs.has_patch == 'true'
+ runs-on: ubuntu-latest
+ permissions: {}
+ concurrency:
+ group: "gh-aw-copilot-${{ github.workflow }}"
+ timeout-minutes: 10
+ outputs:
+ success: ${{ steps.parse_results.outputs.success }}
+ steps:
+ - name: Setup Scripts
+ uses: github/gh-aw/actions/setup@26b6572ae210580303087bc3142fe58d140bf65c # v0.48.1
+ with:
+ destination: /opt/gh-aw/actions
+ - name: Download agent artifacts
+ continue-on-error: true
+ uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6
+ with:
+ name: agent-artifacts
+ path: /tmp/gh-aw/threat-detection/
+ - name: Download agent output artifact
+ continue-on-error: true
+ uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6
+ with:
+ name: agent-output
+ path: /tmp/gh-aw/threat-detection/
+ - name: Print agent output types
+ env:
+ AGENT_OUTPUT_TYPES: ${{ needs.agent.outputs.output_types }}
+ run: |
+ echo "Agent output-types: $AGENT_OUTPUT_TYPES"
+ - name: Setup threat detection
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ env:
+ WORKFLOW_NAME: "Ideas Man"
+ WORKFLOW_DESCRIPTION: "Propose well-researched new feature ideas as GitHub issues"
+ HAS_PATCH: ${{ needs.agent.outputs.has_patch }}
+ with:
+ script: |
+ const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
+ setupGlobals(core, github, context, exec, io);
+ const { main } = require('/opt/gh-aw/actions/setup_threat_detection.cjs');
+ await main();
+ - name: Ensure threat-detection directory and log
+ run: |
+ mkdir -p /tmp/gh-aw/threat-detection
+ touch /tmp/gh-aw/threat-detection/detection.log
+ - name: Validate COPILOT_GITHUB_TOKEN secret
+ id: validate-secret
+ run: /opt/gh-aw/actions/validate_multi_secret.sh COPILOT_GITHUB_TOKEN 'GitHub Copilot CLI' https://github.github.com/gh-aw/reference/engines/#github-copilot-default
+ env:
+ COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
+ - name: Install GitHub Copilot CLI
+ run: /opt/gh-aw/actions/install_copilot_cli.sh 0.0.412
+ - name: Execute GitHub Copilot CLI
+ id: agentic_execution
+ # Copilot CLI tool arguments (sorted):
+ # --allow-tool shell(cat)
+ # --allow-tool shell(grep)
+ # --allow-tool shell(head)
+ # --allow-tool shell(jq)
+ # --allow-tool shell(ls)
+ # --allow-tool shell(tail)
+ # --allow-tool shell(wc)
+ timeout-minutes: 20
+ run: |
+ set -o pipefail
+ COPILOT_CLI_INSTRUCTION="$(cat /tmp/gh-aw/aw-prompts/prompt.txt)"
+ mkdir -p /tmp/
+ mkdir -p /tmp/gh-aw/
+ mkdir -p /tmp/gh-aw/agent/
+ mkdir -p /tmp/gh-aw/sandbox/agent/logs/
+ copilot --add-dir /tmp/ --add-dir /tmp/gh-aw/ --add-dir /tmp/gh-aw/agent/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --allow-tool 'shell(cat)' --allow-tool 'shell(grep)' --allow-tool 'shell(head)' --allow-tool 'shell(jq)' --allow-tool 'shell(ls)' --allow-tool 'shell(tail)' --allow-tool 'shell(wc)' --prompt "$COPILOT_CLI_INSTRUCTION" 2>&1 | tee /tmp/gh-aw/threat-detection/detection.log
+ env:
+ COPILOT_AGENT_RUNNER_TYPE: STANDALONE
+ COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
+ COPILOT_MODEL: ${{ inputs.model }}
+ GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
+ GITHUB_HEAD_REF: ${{ github.head_ref }}
+ GITHUB_REF_NAME: ${{ github.ref_name }}
+ GITHUB_STEP_SUMMARY: ${{ env.GITHUB_STEP_SUMMARY }}
+ GITHUB_WORKSPACE: ${{ github.workspace }}
+ XDG_CONFIG_HOME: /home/runner
+ - name: Parse threat detection results
+ id: parse_results
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
+ setupGlobals(core, github, context, exec, io);
+ const { main } = require('/opt/gh-aw/actions/parse_threat_detection_results.cjs');
+ await main();
+ - name: Upload threat detection log
+ if: always()
+ uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
+ with:
+ name: threat-detection.log
+ path: /tmp/gh-aw/threat-detection/detection.log
+ if-no-files-found: ignore
+
+ pre_activation:
+ runs-on: ubuntu-slim
+ outputs:
+ activated: ${{ steps.check_membership.outputs.is_team_member == 'true' }}
+ steps:
+ - name: Setup Scripts
+ uses: github/gh-aw/actions/setup@26b6572ae210580303087bc3142fe58d140bf65c # v0.48.1
+ with:
+ destination: /opt/gh-aw/actions
+ - name: Check team membership for workflow
+ id: check_membership
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ env:
+ GH_AW_REQUIRED_ROLES: admin,maintainer,write
+ GH_AW_ALLOWED_BOTS: ${{ inputs.allowed-bot-users }}
+ with:
+ github-token: ${{ secrets.GITHUB_TOKEN }}
+ script: |
+ const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
+ setupGlobals(core, github, context, exec, io);
+ const { main } = require('/opt/gh-aw/actions/check_membership.cjs');
+ await main();
+
+ safe_outputs:
+ needs:
+ - agent
+ - detection
+ if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (needs.detection.outputs.success == 'true')
+ runs-on: ubuntu-slim
+ permissions:
+ contents: read
+ issues: write
+ timeout-minutes: 15
+ env:
+ GH_AW_ENGINE_ID: "copilot"
+ GH_AW_ENGINE_MODEL: "${{ inputs.model }}"
+ GH_AW_SAFE_OUTPUT_MESSAGES: "{\"footer\":\"${{ inputs.messages-footer || '---\\n[What is this?](https://ela.st/github-ai-tools) | [From workflow: {workflow_name}]({run_url})\\n\\nGive us feedback! React with 🚀 if perfect, 👍 if helpful, 👎 if not.' }}\"}"
+ GH_AW_WORKFLOW_ID: "gh-aw-ideas-man"
+ GH_AW_WORKFLOW_NAME: "Ideas Man"
+ outputs:
+ create_discussion_error_count: ${{ steps.process_safe_outputs.outputs.create_discussion_error_count }}
+ create_discussion_errors: ${{ steps.process_safe_outputs.outputs.create_discussion_errors }}
+ process_safe_outputs_processed_count: ${{ steps.process_safe_outputs.outputs.processed_count }}
+ process_safe_outputs_temporary_id_map: ${{ steps.process_safe_outputs.outputs.temporary_id_map }}
+ steps:
+ - name: Setup Scripts
+ uses: github/gh-aw/actions/setup@26b6572ae210580303087bc3142fe58d140bf65c # v0.48.1
+ with:
+ destination: /opt/gh-aw/actions
+ - name: Download agent output artifact
+ continue-on-error: true
+ uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6
+ with:
+ name: agent-output
+ path: /tmp/gh-aw/safeoutputs/
+ - name: Setup agent output environment variable
+ run: |
+ mkdir -p /tmp/gh-aw/safeoutputs/
+ find "/tmp/gh-aw/safeoutputs/" -type f -print
+ echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/safeoutputs/agent_output.json" >> "$GITHUB_ENV"
+ - name: Process Safe Outputs
+ id: process_safe_outputs
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ env:
+ GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }}
+ GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"create_issue\":{\"close_older_issues\":true,\"expires\":168,\"max\":1,\"title_prefix\":\"[ideas-man] \"},\"missing_data\":{},\"missing_tool\":{}}"
+ with:
+ github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
+ script: |
+ const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
+ setupGlobals(core, github, context, exec, io);
+ const { main } = require('/opt/gh-aw/actions/safe_output_handler_manager.cjs');
+ await main();
+ - name: Upload safe output items manifest
+ if: always()
+ uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
+ with:
+ name: safe-output-items
+ path: /tmp/safe-output-items.jsonl
+ if-no-files-found: warn
+
diff --git a/.github/workflows/gh-aw-ideas-man.md b/.github/workflows/gh-aw-ideas-man.md
new file mode 100644
index 0000000..a4e4c2d
--- /dev/null
+++ b/.github/workflows/gh-aw-ideas-man.md
@@ -0,0 +1,153 @@
+---
+inlined-imports: true
+name: "Ideas Man"
+description: "Propose well-researched new feature ideas as GitHub issues"
+imports:
+ - gh-aw-fragments/elastic-tools.md
+ - gh-aw-fragments/runtime-setup.md
+ - gh-aw-fragments/formatting.md
+ - gh-aw-fragments/rigor.md
+ - gh-aw-fragments/mcp-pagination.md
+ - gh-aw-fragments/messages-footer.md
+ - gh-aw-fragments/safe-output-create-issue.md
+ - gh-aw-fragments/scheduled-audit.md
+engine:
+ id: copilot
+ model: ${{ inputs.model }}
+on:
+ workflow_call:
+ inputs:
+ model:
+ description: "AI model to use"
+ type: string
+ required: false
+ default: "gpt-5.3-codex"
+ additional-instructions:
+ description: "Repo-specific instructions appended to the agent prompt"
+ type: string
+ required: false
+ default: ""
+ setup-commands:
+ description: "Shell commands to run before the agent starts (dependency install, build, etc.)"
+ type: string
+ required: false
+ default: ""
+ allowed-bot-users:
+ description: "Allowlisted bot actor usernames (comma-separated)"
+ type: string
+ required: false
+ default: "github-actions[bot]"
+ messages-footer:
+ description: "Footer appended to all agent comments and reviews"
+ type: string
+ required: false
+ default: ""
+ secrets:
+ COPILOT_GITHUB_TOKEN:
+ required: true
+ roles: [admin, maintainer, write]
+ bots:
+ - "${{ inputs.allowed-bot-users }}"
+concurrency:
+ group: ideas-man
+ cancel-in-progress: true
+permissions:
+ contents: read
+ issues: read
+ pull-requests: read
+tools:
+ github:
+ toolsets: [repos, issues, pull_requests, search, labels]
+ bash: true
+ web-fetch:
+network:
+ allowed:
+ - defaults
+ - github
+ - go
+ - node
+ - python
+ - ruby
+strict: false
+safe-outputs:
+ noop:
+ create-issue:
+ max: 1
+ title-prefix: "[ideas-man] "
+ close-older-issues: true
+ expires: 7d
+timeout-minutes: 90
+steps:
+ - name: Repo-specific setup
+ if: ${{ inputs.setup-commands != '' }}
+ env:
+ SETUP_COMMANDS: ${{ inputs.setup-commands }}
+ run: eval "$SETUP_COMMANDS"
+---
+
+You are the Ideas Man — an enthusiastic product thinker who has already done research on the codebase and genuinely believes each idea "won't be that hard" to implement. You are also an expert developer who looks at a project, understands what it can currently do, and proposes new features that align with what already exists.
+
+Your task is to propose **one** well-researched new feature idea for this repository.
+
+## Report Assignment
+
+### Data Gathering
+
+1. **Understand the project**
+ - Read `README.md`, `CONTRIBUTING.md`, and any docs directory to understand the project's purpose, architecture, and roadmap.
+ - Skim the directory structure and key source files to understand what the project currently does.
+
+2. **Review recent activity**
+ - Check issues and PRs updated in the last 30 days for feature requests, common pain points, and areas of active development.
+ - Look at recent commits to understand the direction the project is heading.
+
+3. **Check for duplicates**
+ - Search open issues for existing feature requests: `repo:{owner}/{repo} is:issue is:open (feature OR enhancement OR idea)`.
+ - Search past Ideas Man reports: `repo:{owner}/{repo} is:issue in:title "[ideas-man]"`.
+ - If your idea duplicates an existing request, pick a different angle.
+
+### What to Propose
+
+Propose **one** new feature idea that meets all of these criteria:
+
+- **Customer-aligned**: A real user or customer could plausibly request this feature. Explain the user need.
+- **Project-aligned**: The idea fits naturally with the project's existing purpose and architecture.
+- **Grounded in the codebase**: Reference at least one concrete data point from the repository — an existing component, a gap you noticed, a UX pattern already present, or a library already in use.
+- **Tractable**: Include a "why it won't be that hard" rationale — existing hooks, libraries already present, small surface area, or similar patterns already implemented.
+- **Not already proposed**: No open or recently closed issue covers this idea.
+
+### Noop
+
+If you cannot find a genuinely useful, non-duplicate idea that meets all the criteria above, call `noop` with:
+"Ideas Man skipped — no novel, high-value feature idea found for this repository."
+
+**Do not force a low-quality idea just to file something.** Noop is the correct outcome when nothing passes the bar.
+
+### Issue Format
+
+**Issue title:** Short, punchy feature name
+
+**Issue body:**
+
+> ## 💡 Feature Idea
+>
+> **Summary:** One-sentence summary of the idea.
+>
+> ## Why a Customer Would Want This
+> [Explain the user need and who benefits]
+>
+> ## Rough Implementation Sketch
+> - [2–4 bullet points describing the approach]
+> - [Reference existing code, components, or libraries that make this tractable]
+>
+> ## Why It Won't Be That Hard
+> [Explain why this is feasible with modest effort — existing patterns, available libraries, small surface area]
+>
+> ## Evidence
+> - [Links to files, issues, or PRs that support the idea]
+
+### Labeling
+
+- If the `ideas-man` label exists (check with `github-get_label`), include it in the `create_issue` call; otherwise, rely on the `[ideas-man]` title prefix only.
+
+${{ inputs.additional-instructions }}
diff --git a/.github/workflows/gh-aw-refactor-proposal.lock.yml b/.github/workflows/gh-aw-refactor-proposal.lock.yml
new file mode 100644
index 0000000..efce71e
--- /dev/null
+++ b/.github/workflows/gh-aw-refactor-proposal.lock.yml
@@ -0,0 +1,1503 @@
+#
+# ___ _ _
+# / _ \ | | (_)
+# | |_| | __ _ ___ _ __ | |_ _ ___
+# | _ |/ _` |/ _ \ '_ \| __| |/ __|
+# | | | | (_| | __/ | | | |_| | (__
+# \_| |_/\__, |\___|_| |_|\__|_|\___|
+# __/ |
+# _ _ |___/
+# | | | | / _| |
+# | | | | ___ _ __ _ __| |_| | _____ ____
+# | |/\| |/ _ \ '__| |/ /| _| |/ _ \ \ /\ / / ___|
+# \ /\ / (_) | | | | ( | | | | (_) \ V V /\__ \
+# \/ \/ \___/|_| |_|\_\|_| |_|\___/ \_/\_/ |___/
+#
+# This file was automatically generated by gh-aw. DO NOT EDIT.
+#
+# To update this file, edit the corresponding .md file and run:
+# gh aw compile
+# Not all edits will cause changes to this file.
+#
+# For more information: https://github.github.com/gh-aw/introduction/overview/
+#
+# Investigate the codebase as a senior architect, partially implement a refactor to prove viability, and pitch it via an issue
+#
+# Resolved workflow manifest:
+# Imports:
+# - gh-aw-fragments/elastic-tools.md
+# - gh-aw-fragments/ensure-full-history.md
+# - gh-aw-fragments/formatting.md
+# - gh-aw-fragments/mcp-pagination.md
+# - gh-aw-fragments/messages-footer.md
+# - gh-aw-fragments/rigor.md
+# - gh-aw-fragments/runtime-setup.md
+# - gh-aw-fragments/safe-output-create-issue.md
+# - gh-aw-fragments/scheduled-audit.md
+#
+# inlined-imports: true
+#
+# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"5e3d0b0ea9d458332a97c6fa7d9e3bc6e6e04ad345aba3d3d2ad80dd10af00a5"}
+
+name: "Refactor Proposal"
+"on":
+ # bots: # Bots processed as bot check in pre-activation job
+ # - ${{ inputs.allowed-bot-users }} # Bots processed as bot check in pre-activation job
+ # roles: # Roles processed as role check in pre-activation job
+ # - admin # Roles processed as role check in pre-activation job
+ # - maintainer # Roles processed as role check in pre-activation job
+ # - write # Roles processed as role check in pre-activation job
+ workflow_call:
+ inputs:
+ additional-instructions:
+ default: ""
+ description: Repo-specific instructions appended to the agent prompt
+ required: false
+ type: string
+ allowed-bot-users:
+ default: github-actions[bot]
+ description: Allowlisted bot actor usernames (comma-separated)
+ required: false
+ type: string
+ messages-footer:
+ default: ""
+ description: Footer appended to all agent comments and reviews
+ required: false
+ type: string
+ model:
+ default: gpt-5.3-codex
+ description: AI model to use
+ required: false
+ type: string
+ setup-commands:
+ default: ""
+ description: Shell commands to run before the agent starts (dependency install, build, etc.)
+ required: false
+ type: string
+ secrets:
+ COPILOT_GITHUB_TOKEN:
+ required: true
+
+permissions: {}
+
+concurrency:
+ cancel-in-progress: true
+ group: refactor-proposal
+
+run-name: "Refactor Proposal"
+
+jobs:
+ activation:
+ needs: pre_activation
+ if: needs.pre_activation.outputs.activated == 'true'
+ runs-on: ubuntu-slim
+ permissions:
+ contents: read
+ outputs:
+ comment_id: ""
+ comment_repo: ""
+ steps:
+ - name: Setup Scripts
+ uses: github/gh-aw/actions/setup@26b6572ae210580303087bc3142fe58d140bf65c # v0.48.1
+ with:
+ destination: /opt/gh-aw/actions
+ - name: Validate context variables
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
+ setupGlobals(core, github, context, exec, io);
+ const { main } = require('/opt/gh-aw/actions/validate_context_variables.cjs');
+ await main();
+ - name: Checkout .github and .agents folders
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ with:
+ sparse-checkout: |
+ .github
+ .agents
+ fetch-depth: 1
+ persist-credentials: false
+ - name: Check workflow file timestamps
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ env:
+ GH_AW_WORKFLOW_FILE: "gh-aw-refactor-proposal.lock.yml"
+ with:
+ script: |
+ const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
+ setupGlobals(core, github, context, exec, io);
+ const { main } = require('/opt/gh-aw/actions/check_workflow_timestamp_api.cjs');
+ await main();
+ - name: Create prompt with built-in context
+ env:
+ GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
+ GH_AW_SAFE_OUTPUTS: ${{ env.GH_AW_SAFE_OUTPUTS }}
+ GH_AW_EXPR_49B959F1: ${{ inputs.additional-instructions }}
+ GH_AW_GITHUB_ACTOR: ${{ github.actor }}
+ GH_AW_GITHUB_EVENT_COMMENT_ID: ${{ github.event.comment.id }}
+ GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER: ${{ github.event.discussion.number }}
+ GH_AW_GITHUB_EVENT_ISSUE_NUMBER: ${{ github.event.issue.number }}
+ GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER: ${{ github.event.pull_request.number }}
+ GH_AW_GITHUB_REPOSITORY: ${{ github.repository }}
+ GH_AW_GITHUB_RUN_ID: ${{ github.run_id }}
+ GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }}
+ run: |
+ bash /opt/gh-aw/actions/create_prompt_first.sh
+ cat << 'GH_AW_PROMPT_EOF' > "$GH_AW_PROMPT"
+
+ GH_AW_PROMPT_EOF
+ cat "/opt/gh-aw/prompts/xpia.md" >> "$GH_AW_PROMPT"
+ cat "/opt/gh-aw/prompts/temp_folder_prompt.md" >> "$GH_AW_PROMPT"
+ cat "/opt/gh-aw/prompts/markdown.md" >> "$GH_AW_PROMPT"
+ cat << 'GH_AW_PROMPT_EOF' >> "$GH_AW_PROMPT"
+
+ GitHub API Access Instructions
+
+ The gh CLI is NOT authenticated. Do NOT use gh commands for GitHub operations.
+
+
+ To create or modify GitHub resources (issues, discussions, pull requests, etc.), you MUST call the appropriate safe output tool. Simply writing content will NOT work - the workflow requires actual tool calls.
+
+ Temporary IDs: Some safe output tools support a temporary ID field (usually named temporary_id) so you can reference newly-created items elsewhere in the SAME agent output (for example, using #aw_abc1 in a later body).
+
+ **IMPORTANT - temporary_id format rules:**
+ - If you DON'T need to reference the item later, OMIT the temporary_id field entirely (it will be auto-generated if needed)
+ - If you DO need cross-references/chaining, you MUST match this EXACT validation regex: /^aw_[A-Za-z0-9]{3,8}$/i
+ - Format: aw_ prefix followed by 3 to 8 alphanumeric characters (A-Z, a-z, 0-9, case-insensitive)
+ - Valid alphanumeric characters: ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789
+ - INVALID examples: aw_ab (too short), aw_123456789 (too long), aw_test-id (contains hyphen), aw_id_123 (contains underscore)
+ - VALID examples: aw_abc, aw_abc1, aw_Test123, aw_A1B2C3D4, aw_12345678
+ - To generate valid IDs: use 3-8 random alphanumeric characters or omit the field to let the system auto-generate
+
+ Do NOT invent other aw_* formats — downstream steps will reject them with validation errors matching against /^aw_[A-Za-z0-9]{3,8}$/i.
+
+ Discover available tools from the safeoutputs MCP server.
+
+ **Critical**: Tool calls write structured data that downstream jobs process. Without tool calls, follow-up actions will be skipped.
+
+ **Note**: If you made no other safe output tool calls during this workflow execution, call the "noop" tool to provide a status message indicating completion or that no actions were needed.
+
+ ---
+
+ ## Creating an Issue, Reporting Missing Tools or Functionality, Reporting Missing Data
+
+ **IMPORTANT**: To perform the actions listed above, use the **safeoutputs** tools. Do NOT use `gh`, do NOT call the GitHub API directly. You do not have write access to the GitHub repository.
+
+ **Creating an Issue**
+
+ To create an issue, use the create_issue tool from safeoutputs.
+
+ **Reporting Missing Tools or Functionality**
+
+ To report a missing tool or capability, use the missing_tool tool from safeoutputs.
+
+ **Reporting Missing Data**
+
+ To report missing data required to achieve a goal, use the missing_data tool from safeoutputs.
+
+
+
+
+ The following GitHub context information is available for this workflow:
+ {{#if __GH_AW_GITHUB_ACTOR__ }}
+ - **actor**: __GH_AW_GITHUB_ACTOR__
+ {{/if}}
+ {{#if __GH_AW_GITHUB_REPOSITORY__ }}
+ - **repository**: __GH_AW_GITHUB_REPOSITORY__
+ {{/if}}
+ {{#if __GH_AW_GITHUB_WORKSPACE__ }}
+ - **workspace**: __GH_AW_GITHUB_WORKSPACE__
+ {{/if}}
+ {{#if __GH_AW_GITHUB_EVENT_ISSUE_NUMBER__ }}
+ - **issue-number**: #__GH_AW_GITHUB_EVENT_ISSUE_NUMBER__
+ {{/if}}
+ {{#if __GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER__ }}
+ - **discussion-number**: #__GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER__
+ {{/if}}
+ {{#if __GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER__ }}
+ - **pull-request-number**: #__GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER__
+ {{/if}}
+ {{#if __GH_AW_GITHUB_EVENT_COMMENT_ID__ }}
+ - **comment-id**: __GH_AW_GITHUB_EVENT_COMMENT_ID__
+ {{/if}}
+ {{#if __GH_AW_GITHUB_RUN_ID__ }}
+ - **workflow-run-id**: __GH_AW_GITHUB_RUN_ID__
+ {{/if}}
+
+
+ GH_AW_PROMPT_EOF
+ cat << 'GH_AW_PROMPT_EOF' >> "$GH_AW_PROMPT"
+
+ GH_AW_PROMPT_EOF
+ cat << 'GH_AW_PROMPT_EOF' >> "$GH_AW_PROMPT"
+ ## MCP Servers
+
+ - **`generate_agents_md`** — generates a summary of the repository's structure, conventions, and coding guidelines from AGENTS.md and related files. Call at the start of every workflow to get repo context.
+ - **`search_code`** — grep-style search across public GitHub repositories. Use for finding usage patterns in upstream libraries, reference implementations, or examples in open-source projects. This searches *public GitHub repos*, not the local codebase — if available you can use `grep` and file reading for local code.
+ GH_AW_PROMPT_EOF
+ cat << 'GH_AW_PROMPT_EOF' >> "$GH_AW_PROMPT"
+
+ GH_AW_PROMPT_EOF
+ cat << 'GH_AW_PROMPT_EOF' >> "$GH_AW_PROMPT"
+
+ GH_AW_PROMPT_EOF
+ cat << 'GH_AW_PROMPT_EOF' >> "$GH_AW_PROMPT"
+ ## Formatting Guidelines
+
+ - Lead with the most important information — your first sentence should be the key takeaway
+ - Be concise and actionable — no filler or praise
+ - Use `` and `` tags for long sections to keep responses scannable
+ - Wrap branch names and @-references in backticks to avoid pinging users
+ - Include code snippets with file paths and line numbers when referencing the codebase
+
+ GH_AW_PROMPT_EOF
+ cat << 'GH_AW_PROMPT_EOF' >> "$GH_AW_PROMPT"
+ ## Rigor
+
+ **Silence is better than noise. A false positive wastes a human's time and erodes trust in every future report.**
+
+ - If you claim something is missing or broken, show the exact evidence in the code — file path, line number, and what you observed.
+ - If a conclusion depends on assumptions you haven't confirmed, do not assert it. Verify first; if you cannot verify, do not report.
+ - "I don't know" is better than a wrong answer. `noop` is better than a speculative finding.
+ - It's worth the time to verify now versus guessing and forcing someone else to verify later.
+ - Before filing any issue or opening any PR, re-read your own output as a skeptical reviewer. Ask: "Would a senior engineer on this team find this useful, or would they close it immediately?" If the answer is "close," call `noop` instead.
+ - Only report findings you would confidently defend in a code review. If you feel the need to hedge with "might," "could," or "possibly," the finding is not ready to file.
+
+ GH_AW_PROMPT_EOF
+ cat << 'GH_AW_PROMPT_EOF' >> "$GH_AW_PROMPT"
+ ## MCP Pagination
+
+ MCP tool responses have a **25,000 token limit**. When responses exceed this limit, the call fails and you must retry with pagination — wasting turns and tokens. Use proactive pagination to stay under the limit.
+
+ ### Recommended `perPage` Values
+
+ - **5-10**: For detailed items (PR diffs, files with patches, issues with comments)
+ - **20-30**: For medium-detail lists (commits, review comments, issue lists)
+ - **50-100**: For simple list operations (branches, labels, tags)
+
+ ### Pagination Pattern
+
+ When you need all results from a paginated API:
+
+ 1. Fetch the first page with a conservative `perPage` value
+ 2. Process the results before fetching the next page
+ 3. Continue fetching pages until you receive fewer results than `perPage` (indicating the last page)
+
+ ### Error Recovery
+
+ If you see an error like:
+ - `MCP tool response exceeds maximum allowed tokens (25000)`
+ - `Response too large for tool [tool_name]`
+
+ Retry the same call with a smaller `perPage` value (halve it).
+
+ ### Tips
+
+ - **Start small**: It's better to make multiple small requests than one that fails
+ - **Fetch incrementally**: Get an overview first, then details for specific items
+ - **Use filters**: Combine `perPage` with state, label, or date filters to reduce result size
+ - **Process as you go**: Don't accumulate all pages before acting — process each batch immediately
+
+ GH_AW_PROMPT_EOF
+ cat << 'GH_AW_PROMPT_EOF' >> "$GH_AW_PROMPT"
+ ## Message Footer
+
+ A footer is automatically appended to all comments and reviews. Do not add your own footer or sign-off — the runtime handles this.
+ GH_AW_PROMPT_EOF
+ cat << 'GH_AW_PROMPT_EOF' >> "$GH_AW_PROMPT"
+ ## create-issue Limitations
+
+ - **Title**: Max 128 characters. Sanitized (special characters escaped).
+ - **Labels**: Max 10 labels per issue. Each label max 64 characters. Labels containing only `-` are rejected.
+ - **Assignees**: Max 5 assignees per issue.
+ - **Body**: No strict character limit beyond GitHub's API limit (~65,536 characters), but fields over 16,000 tokens are written to a file reference instead of inlined.
+ - **Bot triggers**: References like `fixes #123` or `closes #456` in the body are neutralized to prevent unintended issue closures.
+ - **Mentions**: `@mentions` in the body are neutralized (backticked) by default.
+ GH_AW_PROMPT_EOF
+ cat << 'GH_AW_PROMPT_EOF' >> "$GH_AW_PROMPT"
+ You are an agent for __GH_AW_GITHUB_REPOSITORY__. You run on a schedule to investigate the repository and file an issue when something needs attention. Your specific assignment is described in the **Report Assignment** section below.
+
+ ## Context
+
+ - **Repository**: __GH_AW_GITHUB_REPOSITORY__
+
+ ## Constraints
+
+ This workflow is for detection and reporting only. You can read files, search code, run commands, and read PR/issue details — but your only output is either a single issue or a noop.
+
+ ## Process
+
+ Follow these steps in order.
+
+ ### Step 1: Gather Context
+
+ 1. Call `generate_agents_md` to get the repository's coding guidelines and conventions. If this fails, continue without it.
+ 2. Follow the data gathering instructions in the **Report Assignment** section.
+
+ ### Step 2: Analyze
+
+ Follow the analysis instructions in the **Report Assignment** section to determine whether an issue should be filed. The Report Assignment defines:
+ - What data to gather and how
+ - What to look for
+ - What constitutes a finding worth reporting
+ - What to skip or ignore
+
+ ### Step 3: Self-Review (Quality Gate)
+
+ Before filing anything, critically evaluate every finding against these criteria:
+
+ 1. **Evidence is concrete** — you can point to exact file paths, line numbers, commit SHAs, or command outputs. No "I believe" or "it seems."
+ 2. **Finding is actionable** — a maintainer reading the issue can act on it without re-investigating from scratch.
+ 3. **Finding is not already tracked** — you checked open issues and recent PRs for duplicates.
+ 4. **Finding is worth a human's time** — the issue is material enough that a maintainer would thank you for filing it, not close it as noise.
+
+ If zero findings pass all four criteria, call `noop` with a brief reason and stop. **Noop is the expected outcome most days.** Filing nothing is a success when there is nothing worth filing.
+
+ ### Step 4: Report
+
+ If there are findings that pass the quality gate, call `create_issue` with a structured report. Use the issue format specified in the Report Assignment if one is provided, otherwise use this default format:
+
+ **Issue title:** Brief summary of findings
+
+ **Issue body:**
+
+ > ## Findings
+ >
+ > ### 1. [Brief description]
+ >
+ > **Evidence:** [Links, references, or data supporting the finding]
+ > **Action needed:** [What should be done]
+ >
+ > ## Suggested Actions
+ >
+ > - [ ] [Actionable checkbox for each finding]
+
+ **Guidelines:**
+ - Group related findings together
+ - Be specific about what needs to happen
+ - Include links and references where possible
+ - Make suggested actions concrete enough to act on without re-investigating
+ - If a finding is ambiguous, it does not pass the quality gate — drop it
+
+ **Report Assignment:**
+
+ GH_AW_PROMPT_EOF
+ cat << 'GH_AW_PROMPT_EOF' >> "$GH_AW_PROMPT"
+ You are a senior software architect reviewing this codebase with fresh eyes. Your job is to identify **one** structural improvement (refactor, reorganization, or architectural simplification) that would meaningfully improve the codebase — and then **partially implement it** to prove it is viable before pitching it.
+
+ **The bar is high.** Most codebases are fine as-is; most runs should end with `noop`. Only propose a refactor when you have concrete evidence of a structural problem and have verified the approach works.
+
+ ## Report Assignment
+
+ ### Data Gathering
+
+ 1. **Understand the architecture**
+ - Read `README.md`, `CONTRIBUTING.md`, `DEVELOPING.md`, and any architecture docs.
+ - Map out the high-level module structure — directories, key abstractions, data flow.
+
+ 2. **Identify structural pain points**
+ - Look for: tangled dependencies, duplicated patterns across modules, inconsistent abstractions, overly complex indirection, modules doing too many things, or clear layering violations.
+ - Review `git log --since="60 days ago" --stat` for files that frequently change together (coupling signal) or areas with high churn.
+ - Check recent PRs and issues for complaints about code being "hard to change," "confusing," or "duplicated."
+
+ 3. **Check for existing proposals**
+ - Search open issues: `repo:{owner}/{repo} is:issue is:open (refactor OR restructure OR reorganize OR architecture)`.
+ - Search past proposals: `repo:{owner}/{repo} is:issue in:title "[refactor-proposal]"`.
+ - If your idea overlaps with an existing proposal, pick a different angle or call `noop`.
+
+ ### Analysis and Partial Implementation
+
+ 4. **Select one refactor target**
+ - Choose the single highest-impact structural improvement you found.
+ - The refactor must be decomposable — it should be possible to implement incrementally, not as one massive change.
+
+ 5. **Partially implement to prove viability**
+ - Implement the refactor for **one representative slice** of the codebase (e.g., one module, one file pair, one abstraction boundary).
+ - Run the repository's build/lint/test commands on your partial implementation to verify it compiles, passes linting, and existing tests still pass.
+ - If the partial implementation breaks tests or reveals unexpected complexity, call `noop` — the refactor is not as viable as it appeared.
+
+ 6. **Capture the proof-of-concept**
+ - Record the exact changes you made (file paths, before/after snippets).
+ - Record which commands you ran and their results.
+ - This evidence goes into the issue body as proof that the approach works.
+
+ ### Noop
+
+ Call `noop` if any of these are true:
+ - No structural issue is significant enough to justify a refactor.
+ - The best candidate overlaps with an existing open issue or PR.
+ - Your partial implementation failed — tests broke, unexpected coupling, or the approach does not simplify things as expected.
+ - The refactor cannot be done incrementally (it is all-or-nothing).
+ - The improvement is cosmetic (renaming, reordering) rather than structural.
+
+ "Refactor proposal skipped — no high-impact, viable structural improvement found."
+
+ ### Issue Format
+
+ **Issue title:** Short description of the proposed refactor
+
+ **Issue body:**
+
+ > ## 🏗️ Refactor Proposal
+ >
+ > **Summary:** One-sentence description of the structural improvement.
+ >
+ > ## Problem
+ > [Describe the structural issue — what makes the current code harder to understand, change, or extend. Include concrete evidence: file paths, coupling patterns, duplication counts, or churn data.]
+ >
+ > ## Proposed Approach
+ > [Describe the refactor at a high level — what changes, what stays the same, and why this structure is better.]
+ >
+ > ## Proof of Concept
+ > I partially implemented this refactor on one representative slice to verify viability:
+ >
+ > **Files changed:** [list the files you modified]
+ >
+ > **Before → After:** [show the key structural change with brief code snippets or diffs]
+ >
+ > **Verification:**
+ > - [Commands run and results — build, lint, tests]
+ > - [Confirmation that existing tests still pass]
+ >
+ > ## Incremental Rollout Plan
+ > This refactor can be completed incrementally:
+ > 1. [First batch — what you already proved works]
+ > 2. [Second batch — next logical slice]
+ > 3. [Remaining work — estimate of scope]
+ >
+ > ## Risks and Mitigations
+ > - [Risk 1]: [Mitigation]
+ > - [Risk 2]: [Mitigation]
+ >
+ > ## Evidence
+ > - [Links to files, git log output, issues, or PRs that support the proposal]
+
+ ### Labeling
+
+ - If the `refactor-proposal` label exists (check with `github-get_label`), include it in the `create_issue` call; otherwise, rely on the `[refactor-proposal]` title prefix only.
+
+ __GH_AW_EXPR_49B959F1__
+
+ GH_AW_PROMPT_EOF
+ - name: Interpolate variables and render templates
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ env:
+ GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
+ GH_AW_GITHUB_REPOSITORY: ${{ github.repository }}
+ GH_AW_EXPR_49B959F1: ${{ inputs.additional-instructions }}
+ with:
+ script: |
+ const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
+ setupGlobals(core, github, context, exec, io);
+ const { main } = require('/opt/gh-aw/actions/interpolate_prompt.cjs');
+ await main();
+ - name: Substitute placeholders
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ env:
+ GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
+ GH_AW_EXPR_49B959F1: ${{ inputs.additional-instructions }}
+ GH_AW_GITHUB_ACTOR: ${{ github.actor }}
+ GH_AW_GITHUB_EVENT_COMMENT_ID: ${{ github.event.comment.id }}
+ GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER: ${{ github.event.discussion.number }}
+ GH_AW_GITHUB_EVENT_ISSUE_NUMBER: ${{ github.event.issue.number }}
+ GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER: ${{ github.event.pull_request.number }}
+ GH_AW_GITHUB_REPOSITORY: ${{ github.repository }}
+ GH_AW_GITHUB_RUN_ID: ${{ github.run_id }}
+ GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }}
+ GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_ACTIVATED: ${{ needs.pre_activation.outputs.activated }}
+ GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_MATCHED_COMMAND: ${{ needs.pre_activation.outputs.matched_command }}
+ with:
+ script: |
+ const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
+ setupGlobals(core, github, context, exec, io);
+
+ const substitutePlaceholders = require('/opt/gh-aw/actions/substitute_placeholders.cjs');
+
+ // Call the substitution function
+ return await substitutePlaceholders({
+ file: process.env.GH_AW_PROMPT,
+ substitutions: {
+ GH_AW_EXPR_49B959F1: process.env.GH_AW_EXPR_49B959F1,
+ GH_AW_GITHUB_ACTOR: process.env.GH_AW_GITHUB_ACTOR,
+ GH_AW_GITHUB_EVENT_COMMENT_ID: process.env.GH_AW_GITHUB_EVENT_COMMENT_ID,
+ GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER: process.env.GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER,
+ GH_AW_GITHUB_EVENT_ISSUE_NUMBER: process.env.GH_AW_GITHUB_EVENT_ISSUE_NUMBER,
+ GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER: process.env.GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER,
+ GH_AW_GITHUB_REPOSITORY: process.env.GH_AW_GITHUB_REPOSITORY,
+ GH_AW_GITHUB_RUN_ID: process.env.GH_AW_GITHUB_RUN_ID,
+ GH_AW_GITHUB_WORKSPACE: process.env.GH_AW_GITHUB_WORKSPACE,
+ GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_ACTIVATED: process.env.GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_ACTIVATED,
+ GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_MATCHED_COMMAND: process.env.GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_MATCHED_COMMAND
+ }
+ });
+ - name: Validate prompt placeholders
+ env:
+ GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
+ run: bash /opt/gh-aw/actions/validate_prompt_placeholders.sh
+ - name: Print prompt
+ env:
+ GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
+ run: bash /opt/gh-aw/actions/print_prompt_summary.sh
+ - name: Upload prompt artifact
+ if: success()
+ uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
+ with:
+ name: prompt
+ path: /tmp/gh-aw/aw-prompts/prompt.txt
+ retention-days: 1
+
+ agent:
+ needs: activation
+ runs-on: ubuntu-latest
+ permissions:
+ contents: read
+ issues: read
+ pull-requests: read
+ concurrency:
+ group: "gh-aw-copilot-${{ github.workflow }}"
+ env:
+ DEFAULT_BRANCH: ${{ github.event.repository.default_branch }}
+ GH_AW_ASSETS_ALLOWED_EXTS: ""
+ GH_AW_ASSETS_BRANCH: ""
+ GH_AW_ASSETS_MAX_SIZE_KB: 0
+ GH_AW_MCP_LOG_DIR: /tmp/gh-aw/mcp-logs/safeoutputs
+ GH_AW_SAFE_OUTPUTS: /opt/gh-aw/safeoutputs/outputs.jsonl
+ GH_AW_SAFE_OUTPUTS_CONFIG_PATH: /opt/gh-aw/safeoutputs/config.json
+ GH_AW_SAFE_OUTPUTS_TOOLS_PATH: /opt/gh-aw/safeoutputs/tools.json
+ GH_AW_WORKFLOW_ID_SANITIZED: ghawrefactorproposal
+ outputs:
+ checkout_pr_success: ${{ steps.checkout-pr.outputs.checkout_pr_success || 'true' }}
+ has_patch: ${{ steps.collect_output.outputs.has_patch }}
+ model: ${{ steps.generate_aw_info.outputs.model }}
+ output: ${{ steps.collect_output.outputs.output }}
+ output_types: ${{ steps.collect_output.outputs.output_types }}
+ secret_verification_result: ${{ steps.validate-secret.outputs.verification_result }}
+ steps:
+ - name: Setup Scripts
+ uses: github/gh-aw/actions/setup@26b6572ae210580303087bc3142fe58d140bf65c # v0.48.1
+ with:
+ destination: /opt/gh-aw/actions
+ - name: Checkout repository
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ with:
+ persist-credentials: false
+ - name: Create gh-aw temp directory
+ run: bash /opt/gh-aw/actions/create_gh_aw_tmp_dir.sh
+ - if: hashFiles('go.mod') != ''
+ name: Setup Go
+ uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5
+ with:
+ cache: true
+ go-version-file: go.mod
+ - if: hashFiles('.python-version') != ''
+ name: Setup Python
+ uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
+ with:
+ python-version-file: .python-version
+ - if: hashFiles('.node-version') != ''
+ name: Setup Node.js (.node-version)
+ uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6
+ with:
+ node-version-file: .node-version
+ - if: hashFiles('.node-version') == '' && hashFiles('.nvmrc') != ''
+ name: Setup Node.js (.nvmrc)
+ uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6
+ with:
+ node-version-file: .nvmrc
+ - if: hashFiles('.ruby-version') != ''
+ name: Setup Ruby
+ uses: ruby/setup-ruby@09a7688d3b55cf0e976497ff046b70949eeaccfd # v1
+ with:
+ bundler-cache: true
+ ruby-version: .ruby-version
+ - id: setup-uv
+ if: hashFiles('pyproject.toml', 'uv.lock') != ''
+ name: Setup uv
+ uses: astral-sh/setup-uv@e58605a9b6da7c637471fab8847a5e5a6b8df081 # v5
+ - env:
+ UV_PATH: ${{ steps.setup-uv.outputs.uv-path }}
+ WORKSPACE: ${{ github.workspace }}
+ if: hashFiles('pyproject.toml', 'uv.lock') != ''
+ name: Expose uv in workspace
+ run: |-
+ set -euo pipefail
+ install_dir="$WORKSPACE/.gh-aw-tools/bin"
+ mkdir -p "$install_dir"
+ cp "$UV_PATH" "$install_dir/uv"
+ chmod +x "$install_dir/uv"
+ echo "$install_dir" >> "$GITHUB_PATH"
+ shell: bash
+ - env:
+ GITHUB_TOKEN: ${{ github.token }}
+ REPO_NAME: ${{ github.repository }}
+ SERVER_URL: ${{ github.server_url }}
+ name: Ensure full history
+ run: "if git rev-parse --is-shallow-repository | grep -q true; then\n SERVER_URL_STRIPPED=\"${SERVER_URL#https://}\"\n git remote set-url origin \"https://x-access-token:${GITHUB_TOKEN}@${SERVER_URL_STRIPPED}/${REPO_NAME}.git\"\n git fetch --unshallow --quiet\nfi"
+ - env:
+ SETUP_COMMANDS: ${{ inputs.setup-commands }}
+ if: ${{ inputs.setup-commands != '' }}
+ name: Repo-specific setup
+ run: eval "$SETUP_COMMANDS"
+
+ - name: Configure Git credentials
+ env:
+ REPO_NAME: ${{ github.repository }}
+ SERVER_URL: ${{ github.server_url }}
+ run: |
+ git config --global user.email "github-actions[bot]@users.noreply.github.com"
+ git config --global user.name "github-actions[bot]"
+ # Re-authenticate git with GitHub token
+ SERVER_URL_STRIPPED="${SERVER_URL#https://}"
+ git remote set-url origin "https://x-access-token:${{ github.token }}@${SERVER_URL_STRIPPED}/${REPO_NAME}.git"
+ echo "Git configured with standard GitHub Actions identity"
+ - name: Checkout PR branch
+ id: checkout-pr
+ if: |
+ github.event.pull_request
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ env:
+ GH_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
+ with:
+ github-token: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
+ script: |
+ const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
+ setupGlobals(core, github, context, exec, io);
+ const { main } = require('/opt/gh-aw/actions/checkout_pr_branch.cjs');
+ await main();
+ - name: Generate agentic run info
+ id: generate_aw_info
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const fs = require('fs');
+
+ const awInfo = {
+ engine_id: "copilot",
+ engine_name: "GitHub Copilot CLI",
+ model: "${{ inputs.model }}",
+ version: "",
+ agent_version: "0.0.412",
+ workflow_name: "Refactor Proposal",
+ experimental: false,
+ supports_tools_allowlist: true,
+ run_id: context.runId,
+ run_number: context.runNumber,
+ run_attempt: process.env.GITHUB_RUN_ATTEMPT,
+ repository: context.repo.owner + '/' + context.repo.repo,
+ ref: context.ref,
+ sha: context.sha,
+ actor: context.actor,
+ event_name: context.eventName,
+ staged: false,
+ allowed_domains: ["agents-md-generator.fastmcp.app","artifacts.elastic.co","cloud.elastic.co","defaults","ela.st","elastic.co","github","go","node","public-code-search.fastmcp.app","python","ruby","www.elastic.co"],
+ firewall_enabled: true,
+ awf_version: "v0.20.2",
+ awmg_version: "v0.1.4",
+ steps: {
+ firewall: "squid"
+ },
+ created_at: new Date().toISOString()
+ };
+
+ // Write to /tmp/gh-aw directory to avoid inclusion in PR
+ const tmpPath = '/tmp/gh-aw/aw_info.json';
+ fs.writeFileSync(tmpPath, JSON.stringify(awInfo, null, 2));
+ console.log('Generated aw_info.json at:', tmpPath);
+ console.log(JSON.stringify(awInfo, null, 2));
+
+ // Set model as output for reuse in other steps/jobs
+ core.setOutput('model', awInfo.model);
+ - name: Validate COPILOT_GITHUB_TOKEN secret
+ id: validate-secret
+ run: /opt/gh-aw/actions/validate_multi_secret.sh COPILOT_GITHUB_TOKEN 'GitHub Copilot CLI' https://github.github.com/gh-aw/reference/engines/#github-copilot-default
+ env:
+ COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
+ - name: Install GitHub Copilot CLI
+ run: /opt/gh-aw/actions/install_copilot_cli.sh 0.0.412
+ - name: Install awf binary
+ run: bash /opt/gh-aw/actions/install_awf_binary.sh v0.20.2
+ - name: Determine automatic lockdown mode for GitHub MCP Server
+ id: determine-automatic-lockdown
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ env:
+ GH_AW_GITHUB_TOKEN: ${{ secrets.GH_AW_GITHUB_TOKEN }}
+ GH_AW_GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN }}
+ with:
+ script: |
+ const determineAutomaticLockdown = require('/opt/gh-aw/actions/determine_automatic_lockdown.cjs');
+ await determineAutomaticLockdown(github, context, core);
+ - name: Download container images
+ run: bash /opt/gh-aw/actions/download_docker_images.sh ghcr.io/github/gh-aw-firewall/agent:0.20.2 ghcr.io/github/gh-aw-firewall/api-proxy:0.20.2 ghcr.io/github/gh-aw-firewall/squid:0.20.2 ghcr.io/github/gh-aw-mcpg:v0.1.4 ghcr.io/github/github-mcp-server:v0.31.0 node:lts-alpine
+ - name: Write Safe Outputs Config
+ run: |
+ mkdir -p /opt/gh-aw/safeoutputs
+ mkdir -p /tmp/gh-aw/safeoutputs
+ mkdir -p /tmp/gh-aw/mcp-logs/safeoutputs
+ cat > /opt/gh-aw/safeoutputs/config.json << 'GH_AW_SAFE_OUTPUTS_CONFIG_EOF'
+ {"create_issue":{"expires":168,"max":1},"missing_data":{},"missing_tool":{},"noop":{"max":1}}
+ GH_AW_SAFE_OUTPUTS_CONFIG_EOF
+ cat > /opt/gh-aw/safeoutputs/tools.json << 'GH_AW_SAFE_OUTPUTS_TOOLS_EOF'
+ [
+ {
+ "description": "Create a new GitHub issue for tracking bugs, feature requests, or tasks. Use this for actionable work items that need assignment, labeling, and status tracking. For reports, announcements, or status updates that don't require task tracking, use create_discussion instead. CONSTRAINTS: Maximum 1 issue(s) can be created. Title will be prefixed with \"[refactor-proposal] \".",
+ "inputSchema": {
+ "additionalProperties": false,
+ "properties": {
+ "body": {
+ "description": "Detailed issue description in Markdown. Do NOT repeat the title as a heading since it already appears as the issue's h1. Include context, reproduction steps, or acceptance criteria as appropriate.",
+ "type": "string"
+ },
+ "labels": {
+ "description": "Labels to categorize the issue (e.g., 'bug', 'enhancement'). Labels must exist in the repository.",
+ "items": {
+ "type": "string"
+ },
+ "type": "array"
+ },
+ "parent": {
+ "description": "Parent issue number for creating sub-issues. This is the numeric ID from the GitHub URL (e.g., 42 in github.com/owner/repo/issues/42). Can also be a temporary_id (e.g., 'aw_abc123', 'aw_Test123') from a previously created issue in the same workflow run.",
+ "type": [
+ "number",
+ "string"
+ ]
+ },
+ "temporary_id": {
+ "description": "Unique temporary identifier for referencing this issue before it's created. Format: 'aw_' followed by 3 to 8 alphanumeric characters (e.g., 'aw_abc1', 'aw_Test123'). Use '#aw_ID' in body text to reference other issues by their temporary_id; these are replaced with actual issue numbers after creation.",
+ "pattern": "^aw_[A-Za-z0-9]{3,8}$",
+ "type": "string"
+ },
+ "title": {
+ "description": "Concise issue title summarizing the bug, feature, or task. The title appears as the main heading, so keep it brief and descriptive.",
+ "type": "string"
+ }
+ },
+ "required": [
+ "title",
+ "body"
+ ],
+ "type": "object"
+ },
+ "name": "create_issue"
+ },
+ {
+ "description": "Report that a tool or capability needed to complete the task is not available, or share any information you deem important about missing functionality or limitations. Use this when you cannot accomplish what was requested because the required functionality is missing or access is restricted.",
+ "inputSchema": {
+ "additionalProperties": false,
+ "properties": {
+ "alternatives": {
+ "description": "Any workarounds, manual steps, or alternative approaches the user could take (max 256 characters).",
+ "type": "string"
+ },
+ "reason": {
+ "description": "Explanation of why this tool is needed or what information you want to share about the limitation (max 256 characters).",
+ "type": "string"
+ },
+ "tool": {
+ "description": "Optional: Name or description of the missing tool or capability (max 128 characters). Be specific about what functionality is needed.",
+ "type": "string"
+ }
+ },
+ "required": [
+ "reason"
+ ],
+ "type": "object"
+ },
+ "name": "missing_tool"
+ },
+ {
+ "description": "Log a transparency message when no significant actions are needed. Use this to confirm workflow completion and provide visibility when analysis is complete but no changes or outputs are required (e.g., 'No issues found', 'All checks passed'). This ensures the workflow produces human-visible output even when no other actions are taken.",
+ "inputSchema": {
+ "additionalProperties": false,
+ "properties": {
+ "message": {
+ "description": "Status or completion message to log. Should explain what was analyzed and the outcome (e.g., 'Code review complete - no issues found', 'Analysis complete - all tests passing').",
+ "type": "string"
+ }
+ },
+ "required": [
+ "message"
+ ],
+ "type": "object"
+ },
+ "name": "noop"
+ },
+ {
+ "description": "Report that data or information needed to complete the task is not available. Use this when you cannot accomplish what was requested because required data, context, or information is missing.",
+ "inputSchema": {
+ "additionalProperties": false,
+ "properties": {
+ "alternatives": {
+ "description": "Any workarounds, manual steps, or alternative approaches the user could take (max 256 characters).",
+ "type": "string"
+ },
+ "context": {
+ "description": "Additional context about the missing data or where it should come from (max 256 characters).",
+ "type": "string"
+ },
+ "data_type": {
+ "description": "Type or description of the missing data or information (max 128 characters). Be specific about what data is needed.",
+ "type": "string"
+ },
+ "reason": {
+ "description": "Explanation of why this data is needed to complete the task (max 256 characters).",
+ "type": "string"
+ }
+ },
+ "required": [],
+ "type": "object"
+ },
+ "name": "missing_data"
+ }
+ ]
+ GH_AW_SAFE_OUTPUTS_TOOLS_EOF
+ cat > /opt/gh-aw/safeoutputs/validation.json << 'GH_AW_SAFE_OUTPUTS_VALIDATION_EOF'
+ {
+ "create_issue": {
+ "defaultMax": 1,
+ "fields": {
+ "body": {
+ "required": true,
+ "type": "string",
+ "sanitize": true,
+ "maxLength": 65000
+ },
+ "labels": {
+ "type": "array",
+ "itemType": "string",
+ "itemSanitize": true,
+ "itemMaxLength": 128
+ },
+ "parent": {
+ "issueOrPRNumber": true
+ },
+ "repo": {
+ "type": "string",
+ "maxLength": 256
+ },
+ "temporary_id": {
+ "type": "string"
+ },
+ "title": {
+ "required": true,
+ "type": "string",
+ "sanitize": true,
+ "maxLength": 128
+ }
+ }
+ },
+ "missing_data": {
+ "defaultMax": 20,
+ "fields": {
+ "alternatives": {
+ "type": "string",
+ "sanitize": true,
+ "maxLength": 256
+ },
+ "context": {
+ "type": "string",
+ "sanitize": true,
+ "maxLength": 256
+ },
+ "data_type": {
+ "type": "string",
+ "sanitize": true,
+ "maxLength": 128
+ },
+ "reason": {
+ "type": "string",
+ "sanitize": true,
+ "maxLength": 256
+ }
+ }
+ },
+ "missing_tool": {
+ "defaultMax": 20,
+ "fields": {
+ "alternatives": {
+ "type": "string",
+ "sanitize": true,
+ "maxLength": 512
+ },
+ "reason": {
+ "required": true,
+ "type": "string",
+ "sanitize": true,
+ "maxLength": 256
+ },
+ "tool": {
+ "type": "string",
+ "sanitize": true,
+ "maxLength": 128
+ }
+ }
+ },
+ "noop": {
+ "defaultMax": 1,
+ "fields": {
+ "message": {
+ "required": true,
+ "type": "string",
+ "sanitize": true,
+ "maxLength": 65000
+ }
+ }
+ }
+ }
+ GH_AW_SAFE_OUTPUTS_VALIDATION_EOF
+ - name: Generate Safe Outputs MCP Server Config
+ id: safe-outputs-config
+ run: |
+ # Generate a secure random API key (360 bits of entropy, 40+ chars)
+ # Mask immediately to prevent timing vulnerabilities
+ API_KEY=$(openssl rand -base64 45 | tr -d '/+=')
+ echo "::add-mask::${API_KEY}"
+
+ PORT=3001
+
+ # Set outputs for next steps
+ {
+ echo "safe_outputs_api_key=${API_KEY}"
+ echo "safe_outputs_port=${PORT}"
+ } >> "$GITHUB_OUTPUT"
+
+ echo "Safe Outputs MCP server will run on port ${PORT}"
+
+ - name: Start Safe Outputs MCP HTTP Server
+ id: safe-outputs-start
+ env:
+ DEBUG: '*'
+ GH_AW_SAFE_OUTPUTS_PORT: ${{ steps.safe-outputs-config.outputs.safe_outputs_port }}
+ GH_AW_SAFE_OUTPUTS_API_KEY: ${{ steps.safe-outputs-config.outputs.safe_outputs_api_key }}
+ GH_AW_SAFE_OUTPUTS_TOOLS_PATH: /opt/gh-aw/safeoutputs/tools.json
+ GH_AW_SAFE_OUTPUTS_CONFIG_PATH: /opt/gh-aw/safeoutputs/config.json
+ GH_AW_MCP_LOG_DIR: /tmp/gh-aw/mcp-logs/safeoutputs
+ run: |
+ # Environment variables are set above to prevent template injection
+ export DEBUG
+ export GH_AW_SAFE_OUTPUTS_PORT
+ export GH_AW_SAFE_OUTPUTS_API_KEY
+ export GH_AW_SAFE_OUTPUTS_TOOLS_PATH
+ export GH_AW_SAFE_OUTPUTS_CONFIG_PATH
+ export GH_AW_MCP_LOG_DIR
+
+ bash /opt/gh-aw/actions/start_safe_outputs_server.sh
+
+ - name: Start MCP Gateway
+ id: start-mcp-gateway
+ env:
+ GH_AW_SAFE_OUTPUTS: ${{ env.GH_AW_SAFE_OUTPUTS }}
+ GH_AW_SAFE_OUTPUTS_API_KEY: ${{ steps.safe-outputs-start.outputs.api_key }}
+ GH_AW_SAFE_OUTPUTS_PORT: ${{ steps.safe-outputs-start.outputs.port }}
+ GITHUB_MCP_LOCKDOWN: ${{ steps.determine-automatic-lockdown.outputs.lockdown == 'true' && '1' || '0' }}
+ GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
+ run: |
+ set -eo pipefail
+ mkdir -p /tmp/gh-aw/mcp-config
+
+ # Export gateway environment variables for MCP config and gateway script
+ export MCP_GATEWAY_PORT="80"
+ export MCP_GATEWAY_DOMAIN="host.docker.internal"
+ MCP_GATEWAY_API_KEY=$(openssl rand -base64 45 | tr -d '/+=')
+ echo "::add-mask::${MCP_GATEWAY_API_KEY}"
+ export MCP_GATEWAY_API_KEY
+ export MCP_GATEWAY_PAYLOAD_DIR="/tmp/gh-aw/mcp-payloads"
+ mkdir -p "${MCP_GATEWAY_PAYLOAD_DIR}"
+ export DEBUG="*"
+
+ export GH_AW_ENGINE="copilot"
+ export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network host -v /var/run/docker.sock:/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_LOCKDOWN -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GH_AW_SAFE_OUTPUTS_PORT -e GH_AW_SAFE_OUTPUTS_API_KEY -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw ghcr.io/github/gh-aw-mcpg:v0.1.4'
+
+ mkdir -p /home/runner/.copilot
+ cat << GH_AW_MCP_CONFIG_EOF | bash /opt/gh-aw/actions/start_mcp_gateway.sh
+ {
+ "mcpServers": {
+ "agents-md-generator": {
+ "type": "http",
+ "url": "https://agents-md-generator.fastmcp.app/mcp",
+ "tools": [
+ "generate_agents_md"
+ ]
+ },
+ "github": {
+ "type": "stdio",
+ "container": "ghcr.io/github/github-mcp-server:v0.31.0",
+ "env": {
+ "GITHUB_LOCKDOWN_MODE": "$GITHUB_MCP_LOCKDOWN",
+ "GITHUB_PERSONAL_ACCESS_TOKEN": "\${GITHUB_MCP_SERVER_TOKEN}",
+ "GITHUB_READ_ONLY": "1",
+ "GITHUB_TOOLSETS": "repos,issues,pull_requests,search,labels"
+ }
+ },
+ "public-code-search": {
+ "type": "http",
+ "url": "https://public-code-search.fastmcp.app/mcp",
+ "tools": [
+ "search_code"
+ ]
+ },
+ "safeoutputs": {
+ "type": "http",
+ "url": "http://host.docker.internal:$GH_AW_SAFE_OUTPUTS_PORT",
+ "headers": {
+ "Authorization": "\${GH_AW_SAFE_OUTPUTS_API_KEY}"
+ }
+ }
+ },
+ "gateway": {
+ "port": $MCP_GATEWAY_PORT,
+ "domain": "${MCP_GATEWAY_DOMAIN}",
+ "apiKey": "${MCP_GATEWAY_API_KEY}",
+ "payloadDir": "${MCP_GATEWAY_PAYLOAD_DIR}"
+ }
+ }
+ GH_AW_MCP_CONFIG_EOF
+ - name: Generate workflow overview
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { generateWorkflowOverview } = require('/opt/gh-aw/actions/generate_workflow_overview.cjs');
+ await generateWorkflowOverview(core);
+ - name: Download prompt artifact
+ uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6
+ with:
+ name: prompt
+ path: /tmp/gh-aw/aw-prompts
+ - name: Clean git credentials
+ run: bash /opt/gh-aw/actions/clean_git_credentials.sh
+ - name: Execute GitHub Copilot CLI
+ id: agentic_execution
+ # Copilot CLI tool arguments (sorted):
+ timeout-minutes: 90
+ run: |
+ set -o pipefail
+ sudo -E awf --env-all --container-workdir "${GITHUB_WORKSPACE}" --allow-domains '*.githubusercontent.com,*.jsr.io,*.pythonhosted.org,*.rvm.io,agents-md-generator.fastmcp.app,anaconda.org,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.npms.io,api.rubygems.org,api.snapcraft.io,archive.ubuntu.com,artifacts.elastic.co,azure.archive.ubuntu.com,binstar.org,bootstrap.pypa.io,bun.sh,bundler.rubygems.org,cache.ruby-lang.org,cdn.jsdelivr.net,cloud.elastic.co,codeload.github.com,conda.anaconda.org,conda.binstar.org,crates.io,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,deb.nodesource.com,deno.land,ela.st,elastic.co,esm.sh,files.pythonhosted.org,gems.rubyforge.org,gems.rubyonrails.org,get.pnpm.io,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.com,github.githubassets.com,go.dev,golang.org,googleapis.deno.dev,googlechromelabs.github.io,goproxy.io,host.docker.internal,index.crates.io,index.rubygems.org,json-schema.org,json.schemastore.org,jsr.io,keyserver.ubuntu.com,lfs.github.com,nodejs.org,npm.pkg.github.com,npmjs.com,npmjs.org,objects.githubusercontent.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,pip.pypa.io,pkg.go.dev,ppa.launchpad.net,proxy.golang.org,public-code-search.fastmcp.app,pypi.org,pypi.python.org,raw.githubusercontent.com,registry.bower.io,registry.npmjs.com,registry.npmjs.org,registry.yarnpkg.com,repo.anaconda.com,repo.continuum.io,repo.yarnpkg.com,rubygems.org,rubygems.pkg.github.com,s.symcb.com,s.symcd.com,security.ubuntu.com,skimdb.npmjs.com,static.crates.io,storage.googleapis.com,sum.golang.org,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.elastic.co,www.npmjs.com,www.npmjs.org,yarnpkg.com' --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --enable-host-access --image-tag 0.20.2 --skip-pull --enable-api-proxy \
+ -- /bin/bash -c '/usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --add-dir "${GITHUB_WORKSPACE}" --disable-builtin-mcps --allow-all-tools --allow-all-paths --prompt "$(cat /tmp/gh-aw/aw-prompts/prompt.txt)"' 2>&1 | tee -a /tmp/gh-aw/agent-stdio.log
+ env:
+ COPILOT_AGENT_RUNNER_TYPE: STANDALONE
+ COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
+ COPILOT_MODEL: ${{ inputs.model }}
+ GH_AW_MCP_CONFIG: /home/runner/.copilot/mcp-config.json
+ GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
+ GH_AW_SAFE_OUTPUTS: ${{ env.GH_AW_SAFE_OUTPUTS }}
+ GITHUB_HEAD_REF: ${{ github.head_ref }}
+ GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
+ GITHUB_REF_NAME: ${{ github.ref_name }}
+ GITHUB_STEP_SUMMARY: ${{ env.GITHUB_STEP_SUMMARY }}
+ GITHUB_WORKSPACE: ${{ github.workspace }}
+ XDG_CONFIG_HOME: /home/runner
+ - name: Configure Git credentials
+ env:
+ REPO_NAME: ${{ github.repository }}
+ SERVER_URL: ${{ github.server_url }}
+ run: |
+ git config --global user.email "github-actions[bot]@users.noreply.github.com"
+ git config --global user.name "github-actions[bot]"
+ # Re-authenticate git with GitHub token
+ SERVER_URL_STRIPPED="${SERVER_URL#https://}"
+ git remote set-url origin "https://x-access-token:${{ github.token }}@${SERVER_URL_STRIPPED}/${REPO_NAME}.git"
+ echo "Git configured with standard GitHub Actions identity"
+ - name: Copy Copilot session state files to logs
+ if: always()
+ continue-on-error: true
+ run: |
+ # Copy Copilot session state files to logs folder for artifact collection
+ # This ensures they are in /tmp/gh-aw/ where secret redaction can scan them
+ SESSION_STATE_DIR="$HOME/.copilot/session-state"
+ LOGS_DIR="/tmp/gh-aw/sandbox/agent/logs"
+
+ if [ -d "$SESSION_STATE_DIR" ]; then
+ echo "Copying Copilot session state files from $SESSION_STATE_DIR to $LOGS_DIR"
+ mkdir -p "$LOGS_DIR"
+ cp -v "$SESSION_STATE_DIR"/*.jsonl "$LOGS_DIR/" 2>/dev/null || true
+ echo "Session state files copied successfully"
+ else
+ echo "No session-state directory found at $SESSION_STATE_DIR"
+ fi
+ - name: Stop MCP Gateway
+ if: always()
+ continue-on-error: true
+ env:
+ MCP_GATEWAY_PORT: ${{ steps.start-mcp-gateway.outputs.gateway-port }}
+ MCP_GATEWAY_API_KEY: ${{ steps.start-mcp-gateway.outputs.gateway-api-key }}
+ GATEWAY_PID: ${{ steps.start-mcp-gateway.outputs.gateway-pid }}
+ run: |
+ bash /opt/gh-aw/actions/stop_mcp_gateway.sh "$GATEWAY_PID"
+ - name: Redact secrets in logs
+ if: always()
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
+ setupGlobals(core, github, context, exec, io);
+ const { main } = require('/opt/gh-aw/actions/redact_secrets.cjs');
+ await main();
+ env:
+ GH_AW_SECRET_NAMES: 'COPILOT_GITHUB_TOKEN,GH_AW_GITHUB_MCP_SERVER_TOKEN,GH_AW_GITHUB_TOKEN,GITHUB_TOKEN'
+ SECRET_COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
+ SECRET_GH_AW_GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN }}
+ SECRET_GH_AW_GITHUB_TOKEN: ${{ secrets.GH_AW_GITHUB_TOKEN }}
+ SECRET_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ - name: Upload Safe Outputs
+ if: always()
+ uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
+ with:
+ name: safe-output
+ path: ${{ env.GH_AW_SAFE_OUTPUTS }}
+ if-no-files-found: warn
+ - name: Ingest agent output
+ id: collect_output
+ if: always()
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ env:
+ GH_AW_SAFE_OUTPUTS: ${{ env.GH_AW_SAFE_OUTPUTS }}
+ GH_AW_ALLOWED_DOMAINS: "*.githubusercontent.com,*.jsr.io,*.pythonhosted.org,*.rvm.io,agents-md-generator.fastmcp.app,anaconda.org,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.npms.io,api.rubygems.org,api.snapcraft.io,archive.ubuntu.com,artifacts.elastic.co,azure.archive.ubuntu.com,binstar.org,bootstrap.pypa.io,bun.sh,bundler.rubygems.org,cache.ruby-lang.org,cdn.jsdelivr.net,cloud.elastic.co,codeload.github.com,conda.anaconda.org,conda.binstar.org,crates.io,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,deb.nodesource.com,deno.land,ela.st,elastic.co,esm.sh,files.pythonhosted.org,gems.rubyforge.org,gems.rubyonrails.org,get.pnpm.io,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.com,github.githubassets.com,go.dev,golang.org,googleapis.deno.dev,googlechromelabs.github.io,goproxy.io,host.docker.internal,index.crates.io,index.rubygems.org,json-schema.org,json.schemastore.org,jsr.io,keyserver.ubuntu.com,lfs.github.com,nodejs.org,npm.pkg.github.com,npmjs.com,npmjs.org,objects.githubusercontent.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,pip.pypa.io,pkg.go.dev,ppa.launchpad.net,proxy.golang.org,public-code-search.fastmcp.app,pypi.org,pypi.python.org,raw.githubusercontent.com,registry.bower.io,registry.npmjs.com,registry.npmjs.org,registry.yarnpkg.com,repo.anaconda.com,repo.continuum.io,repo.yarnpkg.com,rubygems.org,rubygems.pkg.github.com,s.symcb.com,s.symcd.com,security.ubuntu.com,skimdb.npmjs.com,static.crates.io,storage.googleapis.com,sum.golang.org,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.elastic.co,www.npmjs.com,www.npmjs.org,yarnpkg.com"
+ GITHUB_SERVER_URL: ${{ github.server_url }}
+ GITHUB_API_URL: ${{ github.api_url }}
+ with:
+ script: |
+ const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
+ setupGlobals(core, github, context, exec, io);
+ const { main } = require('/opt/gh-aw/actions/collect_ndjson_output.cjs');
+ await main();
+ - name: Upload sanitized agent output
+ if: always() && env.GH_AW_AGENT_OUTPUT
+ uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
+ with:
+ name: agent-output
+ path: ${{ env.GH_AW_AGENT_OUTPUT }}
+ if-no-files-found: warn
+ - name: Upload engine output files
+ uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
+ with:
+ name: agent_outputs
+ path: |
+ /tmp/gh-aw/sandbox/agent/logs/
+ /tmp/gh-aw/redacted-urls.log
+ if-no-files-found: ignore
+ - name: Parse agent logs for step summary
+ if: always()
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ env:
+ GH_AW_AGENT_OUTPUT: /tmp/gh-aw/sandbox/agent/logs/
+ with:
+ script: |
+ const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
+ setupGlobals(core, github, context, exec, io);
+ const { main } = require('/opt/gh-aw/actions/parse_copilot_log.cjs');
+ await main();
+ - name: Parse MCP Gateway logs for step summary
+ if: always()
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
+ setupGlobals(core, github, context, exec, io);
+ const { main } = require('/opt/gh-aw/actions/parse_mcp_gateway_log.cjs');
+ await main();
+ - name: Print firewall logs
+ if: always()
+ continue-on-error: true
+ env:
+ AWF_LOGS_DIR: /tmp/gh-aw/sandbox/firewall/logs
+ run: |
+ # Fix permissions on firewall logs so they can be uploaded as artifacts
+ # AWF runs with sudo, creating files owned by root
+ sudo chmod -R a+r /tmp/gh-aw/sandbox/firewall/logs 2>/dev/null || true
+ # Only run awf logs summary if awf command exists (it may not be installed if workflow failed before install step)
+ if command -v awf &> /dev/null; then
+ awf logs summary | tee -a "$GITHUB_STEP_SUMMARY"
+ else
+ echo 'AWF binary not installed, skipping firewall log summary'
+ fi
+ - name: Upload agent artifacts
+ if: always()
+ continue-on-error: true
+ uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
+ with:
+ name: agent-artifacts
+ path: |
+ /tmp/gh-aw/aw-prompts/prompt.txt
+ /tmp/gh-aw/aw_info.json
+ /tmp/gh-aw/mcp-logs/
+ /tmp/gh-aw/sandbox/firewall/logs/
+ /tmp/gh-aw/agent-stdio.log
+ /tmp/gh-aw/agent/
+ if-no-files-found: ignore
+
+ conclusion:
+ needs:
+ - activation
+ - agent
+ - detection
+ - safe_outputs
+ if: (always()) && (needs.agent.result != 'skipped')
+ runs-on: ubuntu-slim
+ permissions:
+ contents: read
+ issues: write
+ outputs:
+ noop_message: ${{ steps.noop.outputs.noop_message }}
+ tools_reported: ${{ steps.missing_tool.outputs.tools_reported }}
+ total_count: ${{ steps.missing_tool.outputs.total_count }}
+ steps:
+ - name: Setup Scripts
+ uses: github/gh-aw/actions/setup@26b6572ae210580303087bc3142fe58d140bf65c # v0.48.1
+ with:
+ destination: /opt/gh-aw/actions
+ - name: Download agent output artifact
+ continue-on-error: true
+ uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6
+ with:
+ name: agent-output
+ path: /tmp/gh-aw/safeoutputs/
+ - name: Setup agent output environment variable
+ run: |
+ mkdir -p /tmp/gh-aw/safeoutputs/
+ find "/tmp/gh-aw/safeoutputs/" -type f -print
+ echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/safeoutputs/agent_output.json" >> "$GITHUB_ENV"
+ - name: Process No-Op Messages
+ id: noop
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ env:
+ GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }}
+ GH_AW_NOOP_MAX: 1
+ GH_AW_WORKFLOW_NAME: "Refactor Proposal"
+ with:
+ github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
+ script: |
+ const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
+ setupGlobals(core, github, context, exec, io);
+ const { main } = require('/opt/gh-aw/actions/noop.cjs');
+ await main();
+ - name: Record Missing Tool
+ id: missing_tool
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ env:
+ GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }}
+ GH_AW_WORKFLOW_NAME: "Refactor Proposal"
+ with:
+ github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
+ script: |
+ const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
+ setupGlobals(core, github, context, exec, io);
+ const { main } = require('/opt/gh-aw/actions/missing_tool.cjs');
+ await main();
+ - name: Handle Agent Failure
+ id: handle_agent_failure
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ env:
+ GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }}
+ GH_AW_WORKFLOW_NAME: "Refactor Proposal"
+ GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
+ GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }}
+ GH_AW_WORKFLOW_ID: "gh-aw-refactor-proposal"
+ GH_AW_SECRET_VERIFICATION_RESULT: ${{ needs.agent.outputs.secret_verification_result }}
+ GH_AW_CHECKOUT_PR_SUCCESS: ${{ needs.agent.outputs.checkout_pr_success }}
+ GH_AW_SAFE_OUTPUT_MESSAGES: "{\"footer\":\"${{ inputs.messages-footer || '---\\n[What is this?](https://ela.st/github-ai-tools) | [From workflow: {workflow_name}]({run_url})\\n\\nGive us feedback! React with 🚀 if perfect, 👍 if helpful, 👎 if not.' }}\"}"
+ GH_AW_GROUP_REPORTS: "false"
+ with:
+ github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
+ script: |
+ const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
+ setupGlobals(core, github, context, exec, io);
+ const { main } = require('/opt/gh-aw/actions/handle_agent_failure.cjs');
+ await main();
+ - name: Handle No-Op Message
+ id: handle_noop_message
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ env:
+ GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }}
+ GH_AW_WORKFLOW_NAME: "Refactor Proposal"
+ GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
+ GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }}
+ GH_AW_NOOP_MESSAGE: ${{ steps.noop.outputs.noop_message }}
+ GH_AW_NOOP_REPORT_AS_ISSUE: "true"
+ with:
+ github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
+ script: |
+ const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
+ setupGlobals(core, github, context, exec, io);
+ const { main } = require('/opt/gh-aw/actions/handle_noop_message.cjs');
+ await main();
+
+ detection:
+ needs: agent
+ if: needs.agent.outputs.output_types != '' || needs.agent.outputs.has_patch == 'true'
+ runs-on: ubuntu-latest
+ permissions: {}
+ concurrency:
+ group: "gh-aw-copilot-${{ github.workflow }}"
+ timeout-minutes: 10
+ outputs:
+ success: ${{ steps.parse_results.outputs.success }}
+ steps:
+ - name: Setup Scripts
+ uses: github/gh-aw/actions/setup@26b6572ae210580303087bc3142fe58d140bf65c # v0.48.1
+ with:
+ destination: /opt/gh-aw/actions
+ - name: Download agent artifacts
+ continue-on-error: true
+ uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6
+ with:
+ name: agent-artifacts
+ path: /tmp/gh-aw/threat-detection/
+ - name: Download agent output artifact
+ continue-on-error: true
+ uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6
+ with:
+ name: agent-output
+ path: /tmp/gh-aw/threat-detection/
+ - name: Print agent output types
+ env:
+ AGENT_OUTPUT_TYPES: ${{ needs.agent.outputs.output_types }}
+ run: |
+ echo "Agent output-types: $AGENT_OUTPUT_TYPES"
+ - name: Setup threat detection
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ env:
+ WORKFLOW_NAME: "Refactor Proposal"
+ WORKFLOW_DESCRIPTION: "Investigate the codebase as a senior architect, partially implement a refactor to prove viability, and pitch it via an issue"
+ HAS_PATCH: ${{ needs.agent.outputs.has_patch }}
+ with:
+ script: |
+ const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
+ setupGlobals(core, github, context, exec, io);
+ const { main } = require('/opt/gh-aw/actions/setup_threat_detection.cjs');
+ await main();
+ - name: Ensure threat-detection directory and log
+ run: |
+ mkdir -p /tmp/gh-aw/threat-detection
+ touch /tmp/gh-aw/threat-detection/detection.log
+ - name: Validate COPILOT_GITHUB_TOKEN secret
+ id: validate-secret
+ run: /opt/gh-aw/actions/validate_multi_secret.sh COPILOT_GITHUB_TOKEN 'GitHub Copilot CLI' https://github.github.com/gh-aw/reference/engines/#github-copilot-default
+ env:
+ COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
+ - name: Install GitHub Copilot CLI
+ run: /opt/gh-aw/actions/install_copilot_cli.sh 0.0.412
+ - name: Execute GitHub Copilot CLI
+ id: agentic_execution
+ # Copilot CLI tool arguments (sorted):
+ # --allow-tool shell(cat)
+ # --allow-tool shell(grep)
+ # --allow-tool shell(head)
+ # --allow-tool shell(jq)
+ # --allow-tool shell(ls)
+ # --allow-tool shell(tail)
+ # --allow-tool shell(wc)
+ timeout-minutes: 20
+ run: |
+ set -o pipefail
+ COPILOT_CLI_INSTRUCTION="$(cat /tmp/gh-aw/aw-prompts/prompt.txt)"
+ mkdir -p /tmp/
+ mkdir -p /tmp/gh-aw/
+ mkdir -p /tmp/gh-aw/agent/
+ mkdir -p /tmp/gh-aw/sandbox/agent/logs/
+ copilot --add-dir /tmp/ --add-dir /tmp/gh-aw/ --add-dir /tmp/gh-aw/agent/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --allow-tool 'shell(cat)' --allow-tool 'shell(grep)' --allow-tool 'shell(head)' --allow-tool 'shell(jq)' --allow-tool 'shell(ls)' --allow-tool 'shell(tail)' --allow-tool 'shell(wc)' --prompt "$COPILOT_CLI_INSTRUCTION" 2>&1 | tee /tmp/gh-aw/threat-detection/detection.log
+ env:
+ COPILOT_AGENT_RUNNER_TYPE: STANDALONE
+ COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
+ COPILOT_MODEL: ${{ inputs.model }}
+ GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
+ GITHUB_HEAD_REF: ${{ github.head_ref }}
+ GITHUB_REF_NAME: ${{ github.ref_name }}
+ GITHUB_STEP_SUMMARY: ${{ env.GITHUB_STEP_SUMMARY }}
+ GITHUB_WORKSPACE: ${{ github.workspace }}
+ XDG_CONFIG_HOME: /home/runner
+ - name: Parse threat detection results
+ id: parse_results
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
+ setupGlobals(core, github, context, exec, io);
+ const { main } = require('/opt/gh-aw/actions/parse_threat_detection_results.cjs');
+ await main();
+ - name: Upload threat detection log
+ if: always()
+ uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
+ with:
+ name: threat-detection.log
+ path: /tmp/gh-aw/threat-detection/detection.log
+ if-no-files-found: ignore
+
+ pre_activation:
+ runs-on: ubuntu-slim
+ outputs:
+ activated: ${{ steps.check_membership.outputs.is_team_member == 'true' }}
+ steps:
+ - name: Setup Scripts
+ uses: github/gh-aw/actions/setup@26b6572ae210580303087bc3142fe58d140bf65c # v0.48.1
+ with:
+ destination: /opt/gh-aw/actions
+ - name: Check team membership for workflow
+ id: check_membership
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ env:
+ GH_AW_REQUIRED_ROLES: admin,maintainer,write
+ GH_AW_ALLOWED_BOTS: ${{ inputs.allowed-bot-users }}
+ with:
+ github-token: ${{ secrets.GITHUB_TOKEN }}
+ script: |
+ const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
+ setupGlobals(core, github, context, exec, io);
+ const { main } = require('/opt/gh-aw/actions/check_membership.cjs');
+ await main();
+
+ safe_outputs:
+ needs:
+ - agent
+ - detection
+ if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (needs.detection.outputs.success == 'true')
+ runs-on: ubuntu-slim
+ permissions:
+ contents: read
+ issues: write
+ timeout-minutes: 15
+ env:
+ GH_AW_ENGINE_ID: "copilot"
+ GH_AW_ENGINE_MODEL: "${{ inputs.model }}"
+ GH_AW_SAFE_OUTPUT_MESSAGES: "{\"footer\":\"${{ inputs.messages-footer || '---\\n[What is this?](https://ela.st/github-ai-tools) | [From workflow: {workflow_name}]({run_url})\\n\\nGive us feedback! React with 🚀 if perfect, 👍 if helpful, 👎 if not.' }}\"}"
+ GH_AW_WORKFLOW_ID: "gh-aw-refactor-proposal"
+ GH_AW_WORKFLOW_NAME: "Refactor Proposal"
+ outputs:
+ create_discussion_error_count: ${{ steps.process_safe_outputs.outputs.create_discussion_error_count }}
+ create_discussion_errors: ${{ steps.process_safe_outputs.outputs.create_discussion_errors }}
+ process_safe_outputs_processed_count: ${{ steps.process_safe_outputs.outputs.processed_count }}
+ process_safe_outputs_temporary_id_map: ${{ steps.process_safe_outputs.outputs.temporary_id_map }}
+ steps:
+ - name: Setup Scripts
+ uses: github/gh-aw/actions/setup@26b6572ae210580303087bc3142fe58d140bf65c # v0.48.1
+ with:
+ destination: /opt/gh-aw/actions
+ - name: Download agent output artifact
+ continue-on-error: true
+ uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6
+ with:
+ name: agent-output
+ path: /tmp/gh-aw/safeoutputs/
+ - name: Setup agent output environment variable
+ run: |
+ mkdir -p /tmp/gh-aw/safeoutputs/
+ find "/tmp/gh-aw/safeoutputs/" -type f -print
+ echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/safeoutputs/agent_output.json" >> "$GITHUB_ENV"
+ - name: Process Safe Outputs
+ id: process_safe_outputs
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ env:
+ GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }}
+ GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"create_issue\":{\"close_older_issues\":true,\"expires\":168,\"max\":1,\"title_prefix\":\"[refactor-proposal] \"},\"missing_data\":{},\"missing_tool\":{}}"
+ with:
+ github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
+ script: |
+ const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
+ setupGlobals(core, github, context, exec, io);
+ const { main } = require('/opt/gh-aw/actions/safe_output_handler_manager.cjs');
+ await main();
+ - name: Upload safe output items manifest
+ if: always()
+ uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
+ with:
+ name: safe-output-items
+ path: /tmp/safe-output-items.jsonl
+ if-no-files-found: warn
+
diff --git a/.github/workflows/gh-aw-refactor-proposal.md b/.github/workflows/gh-aw-refactor-proposal.md
new file mode 100644
index 0000000..23130c3
--- /dev/null
+++ b/.github/workflows/gh-aw-refactor-proposal.md
@@ -0,0 +1,182 @@
+---
+inlined-imports: true
+name: "Refactor Proposal"
+description: "Investigate the codebase as a senior architect, partially implement a refactor to prove viability, and pitch it via an issue"
+imports:
+ - gh-aw-fragments/elastic-tools.md
+ - gh-aw-fragments/runtime-setup.md
+ - gh-aw-fragments/ensure-full-history.md
+ - gh-aw-fragments/formatting.md
+ - gh-aw-fragments/rigor.md
+ - gh-aw-fragments/mcp-pagination.md
+ - gh-aw-fragments/messages-footer.md
+ - gh-aw-fragments/safe-output-create-issue.md
+ - gh-aw-fragments/scheduled-audit.md
+engine:
+ id: copilot
+ model: ${{ inputs.model }}
+on:
+ workflow_call:
+ inputs:
+ model:
+ description: "AI model to use"
+ type: string
+ required: false
+ default: "gpt-5.3-codex"
+ additional-instructions:
+ description: "Repo-specific instructions appended to the agent prompt"
+ type: string
+ required: false
+ default: ""
+ setup-commands:
+ description: "Shell commands to run before the agent starts (dependency install, build, etc.)"
+ type: string
+ required: false
+ default: ""
+ allowed-bot-users:
+ description: "Allowlisted bot actor usernames (comma-separated)"
+ type: string
+ required: false
+ default: "github-actions[bot]"
+ messages-footer:
+ description: "Footer appended to all agent comments and reviews"
+ type: string
+ required: false
+ default: ""
+ secrets:
+ COPILOT_GITHUB_TOKEN:
+ required: true
+ roles: [admin, maintainer, write]
+ bots:
+ - "${{ inputs.allowed-bot-users }}"
+concurrency:
+ group: refactor-proposal
+ cancel-in-progress: true
+permissions:
+ contents: read
+ issues: read
+ pull-requests: read
+tools:
+ github:
+ toolsets: [repos, issues, pull_requests, search, labels]
+ bash: true
+ web-fetch:
+network:
+ allowed:
+ - defaults
+ - github
+ - go
+ - node
+ - python
+ - ruby
+strict: false
+safe-outputs:
+ noop:
+ create-issue:
+ max: 1
+ title-prefix: "[refactor-proposal] "
+ close-older-issues: true
+ expires: 7d
+timeout-minutes: 90
+steps:
+ - name: Repo-specific setup
+ if: ${{ inputs.setup-commands != '' }}
+ env:
+ SETUP_COMMANDS: ${{ inputs.setup-commands }}
+ run: eval "$SETUP_COMMANDS"
+---
+
+You are a senior software architect reviewing this codebase with fresh eyes. Your job is to identify **one** structural improvement (refactor, reorganization, or architectural simplification) that would meaningfully improve the codebase — and then **partially implement it** to prove it is viable before pitching it.
+
+**The bar is high.** Most codebases are fine as-is; most runs should end with `noop`. Only propose a refactor when you have concrete evidence of a structural problem and have verified the approach works.
+
+## Report Assignment
+
+### Data Gathering
+
+1. **Understand the architecture**
+ - Read `README.md`, `CONTRIBUTING.md`, `DEVELOPING.md`, and any architecture docs.
+ - Map out the high-level module structure — directories, key abstractions, data flow.
+
+2. **Identify structural pain points**
+ - Look for: tangled dependencies, duplicated patterns across modules, inconsistent abstractions, overly complex indirection, modules doing too many things, or clear layering violations.
+ - Review `git log --since="60 days ago" --stat` for files that frequently change together (coupling signal) or areas with high churn.
+ - Check recent PRs and issues for complaints about code being "hard to change," "confusing," or "duplicated."
+
+3. **Check for existing proposals**
+ - Search open issues: `repo:{owner}/{repo} is:issue is:open (refactor OR restructure OR reorganize OR architecture)`.
+ - Search past proposals: `repo:{owner}/{repo} is:issue in:title "[refactor-proposal]"`.
+ - If your idea overlaps with an existing proposal, pick a different angle or call `noop`.
+
+### Analysis and Partial Implementation
+
+4. **Select one refactor target**
+ - Choose the single highest-impact structural improvement you found.
+ - The refactor must be decomposable — it should be possible to implement incrementally, not as one massive change.
+
+5. **Partially implement to prove viability**
+ - Implement the refactor for **one representative slice** of the codebase (e.g., one module, one file pair, one abstraction boundary).
+ - Run the repository's build/lint/test commands on your partial implementation to verify it compiles, passes linting, and existing tests still pass.
+ - If the partial implementation breaks tests or reveals unexpected complexity, call `noop` — the refactor is not as viable as it appeared.
+
+6. **Capture the proof-of-concept**
+ - Record the exact changes you made (file paths, before/after snippets).
+ - Record which commands you ran and their results.
+ - This evidence goes into the issue body as proof that the approach works.
+
+### Noop
+
+Call `noop` if any of these are true:
+- No structural issue is significant enough to justify a refactor.
+- The best candidate overlaps with an existing open issue or PR.
+- Your partial implementation failed — tests broke, unexpected coupling, or the approach does not simplify things as expected.
+- The refactor cannot be done incrementally (it is all-or-nothing).
+- The improvement is cosmetic (renaming, reordering) rather than structural.
+
+"Refactor proposal skipped — no high-impact, viable structural improvement found."
+
+### Issue Format
+
+**Issue title:** Short description of the proposed refactor
+
+**Issue body:**
+
+> ## 🏗️ Refactor Proposal
+>
+> **Summary:** One-sentence description of the structural improvement.
+>
+> ## Problem
+> [Describe the structural issue — what makes the current code harder to understand, change, or extend. Include concrete evidence: file paths, coupling patterns, duplication counts, or churn data.]
+>
+> ## Proposed Approach
+> [Describe the refactor at a high level — what changes, what stays the same, and why this structure is better.]
+>
+> ## Proof of Concept
+> I partially implemented this refactor on one representative slice to verify viability:
+>
+> **Files changed:** [list the files you modified]
+>
+> **Before → After:** [show the key structural change with brief code snippets or diffs]
+>
+> **Verification:**
+> - [Commands run and results — build, lint, tests]
+> - [Confirmation that existing tests still pass]
+>
+> ## Incremental Rollout Plan
+> This refactor can be completed incrementally:
+> 1. [First batch — what you already proved works]
+> 2. [Second batch — next logical slice]
+> 3. [Remaining work — estimate of scope]
+>
+> ## Risks and Mitigations
+> - [Risk 1]: [Mitigation]
+> - [Risk 2]: [Mitigation]
+>
+> ## Evidence
+> - [Links to files, git log output, issues, or PRs that support the proposal]
+
+### Labeling
+
+- If the `refactor-proposal` label exists (check with `github-get_label`), include it in the `create_issue` call; otherwise, rely on the `[refactor-proposal]` title prefix only.
+
+${{ inputs.additional-instructions }}
diff --git a/.github/workflows/trigger-ideas-man.yml b/.github/workflows/trigger-ideas-man.yml
new file mode 100644
index 0000000..c41d92f
--- /dev/null
+++ b/.github/workflows/trigger-ideas-man.yml
@@ -0,0 +1,18 @@
+# This file is auto-generated by scripts/dogfood.sh. Do not edit directly.
+# Edit gh-agent-workflows/ideas-man/example.yml and run 'make compile' to regenerate.
+name: Trigger Ideas Man
+on:
+ schedule:
+ - cron: "0 10 * * 1-5"
+ workflow_dispatch:
+
+permissions:
+ contents: read
+ issues: write
+ pull-requests: read
+
+jobs:
+ run:
+ uses: ./.github/workflows/gh-aw-ideas-man.lock.yml
+ secrets:
+ COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
diff --git a/.github/workflows/trigger-refactor-proposal.yml b/.github/workflows/trigger-refactor-proposal.yml
new file mode 100644
index 0000000..9808eac
--- /dev/null
+++ b/.github/workflows/trigger-refactor-proposal.yml
@@ -0,0 +1,18 @@
+# This file is auto-generated by scripts/dogfood.sh. Do not edit directly.
+# Edit gh-agent-workflows/refactor-proposal/example.yml and run 'make compile' to regenerate.
+name: Trigger Refactor Proposal
+on:
+ schedule:
+ - cron: "0 14 * * 1"
+ workflow_dispatch:
+
+permissions:
+ contents: read
+ issues: write
+ pull-requests: read
+
+jobs:
+ run:
+ uses: ./.github/workflows/gh-aw-refactor-proposal.lock.yml
+ secrets:
+ COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
diff --git a/gh-agent-workflows/README.md b/gh-agent-workflows/README.md
index a103f37..89debf0 100644
--- a/gh-agent-workflows/README.md
+++ b/gh-agent-workflows/README.md
@@ -28,6 +28,8 @@ Pre-built workflows with domain-specific prompts. These import the same base fra
- [Code Duplication Detector](code-duplication-detector/) — find duplicate code
- [Breaking Change Detector](breaking-change-detector/) — find breaking changes
- [Docs Patrol](docs-patrol/) — detect stale documentation
+- [Ideas Man](ideas-man/) — propose well-researched new feature ideas
+- [Refactor Proposal](refactor-proposal/) — pitch proven refactors with partial implementations
- [Stale Issues](stale-issues/) — detect stale issues
**Fixers** (create PRs):
@@ -63,7 +65,9 @@ workflows, or `--repo OWNER/REPO` when auto-detection is not available.
- `bug-exterminator`
- `code-simplifier`
- `docs-patrol`
+- `ideas-man`
- `newbie-contributor-patrol`
+- `refactor-proposal`
- `small-problem-fixer`
- `stale-issues`
- `test-improver`
diff --git a/gh-agent-workflows/ideas-man/README.md b/gh-agent-workflows/ideas-man/README.md
new file mode 100644
index 0000000..7c75e9e
--- /dev/null
+++ b/gh-agent-workflows/ideas-man/README.md
@@ -0,0 +1,36 @@
+# Ideas Man
+
+Propose well-researched new feature ideas as GitHub issues.
+
+## How it works
+
+Reviews the codebase, recent activity, and existing issues to propose a single new feature idea that is customer-aligned, grounded in the existing code, and tractable. Each idea includes a rough implementation sketch and a "why it won't be that hard" rationale. Only files an issue when a genuinely useful, non-duplicate idea is found — most runs end with `noop`.
+
+## Quick Install
+
+```bash
+mkdir -p .github/workflows && curl -sL \
+ https://raw.githubusercontent.com/elastic/ai-github-actions/v0/gh-agent-workflows/ideas-man/example.yml \
+ -o .github/workflows/ideas-man.yml
+```
+
+See [example.yml](example.yml) for the full workflow file.
+
+## Trigger
+
+| Event | Schedule |
+| --- | --- |
+| `schedule` | Weekdays |
+| `workflow_dispatch` | Manual |
+
+## Inputs
+
+| Input | Description | Required | Default |
+| --- | --- | --- | --- |
+| `additional-instructions` | Repo-specific instructions appended to the agent prompt | No | `""` |
+| `setup-commands` | Shell commands run before the agent starts | No | `""` |
+| `allowed-bot-users` | Allowlisted bot actor usernames (comma-separated) | No | `github-actions[bot]` |
+
+## Safe Outputs
+
+- `create-issue` — file a feature idea (max 1, auto-closes older reports)
diff --git a/gh-agent-workflows/ideas-man/example.yml b/gh-agent-workflows/ideas-man/example.yml
new file mode 100644
index 0000000..adf1329
--- /dev/null
+++ b/gh-agent-workflows/ideas-man/example.yml
@@ -0,0 +1,16 @@
+name: Ideas Man
+on:
+ schedule:
+ - cron: "0 10 * * 1-5"
+ workflow_dispatch:
+
+permissions:
+ contents: read
+ issues: write
+ pull-requests: read
+
+jobs:
+ run:
+ uses: elastic/ai-github-actions/.github/workflows/gh-aw-ideas-man.lock.yml@v0
+ secrets:
+ COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
diff --git a/gh-agent-workflows/refactor-proposal/README.md b/gh-agent-workflows/refactor-proposal/README.md
new file mode 100644
index 0000000..d19204e
--- /dev/null
+++ b/gh-agent-workflows/refactor-proposal/README.md
@@ -0,0 +1,36 @@
+# Refactor Proposal
+
+Investigate the codebase as a senior architect, partially implement a refactor to prove viability, and pitch it via an issue.
+
+## How it works
+
+Reviews the codebase architecture, identifies structural pain points (tangled dependencies, duplicated patterns, inconsistent abstractions), and selects the highest-impact improvement. **Partially implements** the refactor on one representative slice to prove it works — running build, lint, and tests to verify viability — then files an issue with the proof-of-concept and an incremental rollout plan. Most runs end with `noop`.
+
+## Quick Install
+
+```bash
+mkdir -p .github/workflows && curl -sL \
+ https://raw.githubusercontent.com/elastic/ai-github-actions/v0/gh-agent-workflows/refactor-proposal/example.yml \
+ -o .github/workflows/refactor-proposal.yml
+```
+
+See [example.yml](example.yml) for the full workflow file.
+
+## Trigger
+
+| Event | Schedule |
+| --- | --- |
+| `schedule` | Weekly |
+| `workflow_dispatch` | Manual |
+
+## Inputs
+
+| Input | Description | Required | Default |
+| --- | --- | --- | --- |
+| `additional-instructions` | Repo-specific instructions appended to the agent prompt | No | `""` |
+| `setup-commands` | Shell commands run before the agent starts | No | `""` |
+| `allowed-bot-users` | Allowlisted bot actor usernames (comma-separated) | No | `github-actions[bot]` |
+
+## Safe Outputs
+
+- `create-issue` — file a refactor proposal with proof-of-concept (max 1, auto-closes older reports)
diff --git a/gh-agent-workflows/refactor-proposal/example.yml b/gh-agent-workflows/refactor-proposal/example.yml
new file mode 100644
index 0000000..beb2511
--- /dev/null
+++ b/gh-agent-workflows/refactor-proposal/example.yml
@@ -0,0 +1,16 @@
+name: Refactor Proposal
+on:
+ schedule:
+ - cron: "0 14 * * 1"
+ workflow_dispatch:
+
+permissions:
+ contents: read
+ issues: write
+ pull-requests: read
+
+jobs:
+ run:
+ uses: elastic/ai-github-actions/.github/workflows/gh-aw-refactor-proposal.lock.yml@v0
+ secrets:
+ COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
diff --git a/scripts/quick-setup.sh b/scripts/quick-setup.sh
index 513d4a4..dd48592 100755
--- a/scripts/quick-setup.sh
+++ b/scripts/quick-setup.sh
@@ -130,7 +130,9 @@ continuous_improvement_workflows=(
bug-exterminator
code-simplifier
docs-patrol
+ ideas-man
newbie-contributor-patrol
+ refactor-proposal
small-problem-fixer
stale-issues
test-improver
From c5855c16db95632f4f2ce51aca6721fd0c1e10ea Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sun, 22 Feb 2026 02:38:55 +0000
Subject: [PATCH 3/4] Rename ideas-man to product-manager-impersonator and
refactor-proposal to refactor-opportunist
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Renames both workflows per review feedback:
- ideas-man → product-manager-impersonator
- refactor-proposal → refactor-opportunist
Updates all source files, examples, READMEs, triggers, lock files,
gh-agent-workflows/README.md, and scripts/quick-setup.sh.
Co-authored-by: strawgate <6384545+strawgate@users.noreply.github.com>
---
...-aw-product-manager-impersonator.lock.yml} | 42 +++++++++----------
... => gh-aw-product-manager-impersonator.md} | 14 +++----
...ml => gh-aw-refactor-opportunist.lock.yml} | 40 +++++++++---------
...posal.md => gh-aw-refactor-opportunist.md} | 12 +++---
... trigger-product-manager-impersonator.yml} | 6 +--
...l.yml => trigger-refactor-opportunist.yml} | 6 +--
gh-agent-workflows/README.md | 8 ++--
.../README.md | 6 +--
.../example.yml | 4 +-
.../README.md | 6 +--
.../example.yml | 4 +-
scripts/quick-setup.sh | 4 +-
12 files changed, 76 insertions(+), 76 deletions(-)
rename .github/workflows/{gh-aw-ideas-man.lock.yml => gh-aw-product-manager-impersonator.lock.yml} (97%)
rename .github/workflows/{gh-aw-ideas-man.md => gh-aw-product-manager-impersonator.md} (84%)
rename .github/workflows/{gh-aw-refactor-proposal.lock.yml => gh-aw-refactor-opportunist.lock.yml} (98%)
rename .github/workflows/{gh-aw-refactor-proposal.md => gh-aw-refactor-opportunist.md} (94%)
rename .github/workflows/{trigger-ideas-man.yml => trigger-product-manager-impersonator.yml} (57%)
rename .github/workflows/{trigger-refactor-proposal.yml => trigger-refactor-opportunist.yml} (60%)
rename gh-agent-workflows/{ideas-man => product-manager-impersonator}/README.md (88%)
rename gh-agent-workflows/{ideas-man => product-manager-impersonator}/example.yml (62%)
rename gh-agent-workflows/{refactor-proposal => refactor-opportunist}/README.md (91%)
rename gh-agent-workflows/{refactor-proposal => refactor-opportunist}/example.yml (83%)
diff --git a/.github/workflows/gh-aw-ideas-man.lock.yml b/.github/workflows/gh-aw-product-manager-impersonator.lock.yml
similarity index 97%
rename from .github/workflows/gh-aw-ideas-man.lock.yml
rename to .github/workflows/gh-aw-product-manager-impersonator.lock.yml
index d9799f6..70830b1 100644
--- a/.github/workflows/gh-aw-ideas-man.lock.yml
+++ b/.github/workflows/gh-aw-product-manager-impersonator.lock.yml
@@ -36,9 +36,9 @@
#
# inlined-imports: true
#
-# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"0573732b18dbf216ac46db50d9cec51bbfa9aea7c348244f3c09b6b6ca7de255"}
+# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"6dc575c54b5359615c24519a1ddb737587d34b0492f39f64206e3f1a9463285e"}
-name: "Ideas Man"
+name: "Product Manager Impersonator"
"on":
# bots: # Bots processed as bot check in pre-activation job
# - ${{ inputs.allowed-bot-users }} # Bots processed as bot check in pre-activation job
@@ -81,9 +81,9 @@ permissions: {}
concurrency:
cancel-in-progress: true
- group: ideas-man
+ group: product-manager-impersonator
-run-name: "Ideas Man"
+run-name: "Product Manager Impersonator"
jobs:
activation:
@@ -119,7 +119,7 @@ jobs:
- name: Check workflow file timestamps
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
env:
- GH_AW_WORKFLOW_FILE: "gh-aw-ideas-man.lock.yml"
+ GH_AW_WORKFLOW_FILE: "gh-aw-product-manager-impersonator.lock.yml"
with:
script: |
const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
@@ -378,7 +378,7 @@ jobs:
GH_AW_PROMPT_EOF
cat << 'GH_AW_PROMPT_EOF' >> "$GH_AW_PROMPT"
- You are the Ideas Man — an enthusiastic product thinker who has already done research on the codebase and genuinely believes each idea "won't be that hard" to implement. You are also an expert developer who looks at a project, understands what it can currently do, and proposes new features that align with what already exists.
+ You are the Product Manager Impersonator — an enthusiastic product thinker who has already done research on the codebase and genuinely believes each idea "won't be that hard" to implement. You are also an expert developer who looks at a project, understands what it can currently do, and proposes new features that align with what already exists.
Your task is to propose **one** well-researched new feature idea for this repository.
@@ -396,7 +396,7 @@ jobs:
3. **Check for duplicates**
- Search open issues for existing feature requests: `repo:{owner}/{repo} is:issue is:open (feature OR enhancement OR idea)`.
- - Search past Ideas Man reports: `repo:{owner}/{repo} is:issue in:title "[ideas-man]"`.
+ - Search past reports: `repo:{owner}/{repo} is:issue in:title "[product-manager-impersonator]"`.
- If your idea duplicates an existing request, pick a different angle.
### What to Propose
@@ -412,7 +412,7 @@ jobs:
### Noop
If you cannot find a genuinely useful, non-duplicate idea that meets all the criteria above, call `noop` with:
- "Ideas Man skipped — no novel, high-value feature idea found for this repository."
+ "Product Manager Impersonator skipped — no novel, high-value feature idea found for this repository."
**Do not force a low-quality idea just to file something.** Noop is the correct outcome when nothing passes the bar.
@@ -441,7 +441,7 @@ jobs:
### Labeling
- - If the `ideas-man` label exists (check with `github-get_label`), include it in the `create_issue` call; otherwise, rely on the `[ideas-man]` title prefix only.
+ - If the `product-manager-impersonator` label exists (check with `github-get_label`), include it in the `create_issue` call; otherwise, rely on the `[product-manager-impersonator]` title prefix only.
__GH_AW_EXPR_49B959F1__
@@ -531,7 +531,7 @@ jobs:
GH_AW_SAFE_OUTPUTS: /opt/gh-aw/safeoutputs/outputs.jsonl
GH_AW_SAFE_OUTPUTS_CONFIG_PATH: /opt/gh-aw/safeoutputs/config.json
GH_AW_SAFE_OUTPUTS_TOOLS_PATH: /opt/gh-aw/safeoutputs/tools.json
- GH_AW_WORKFLOW_ID_SANITIZED: ghawideasman
+ GH_AW_WORKFLOW_ID_SANITIZED: ghawproductmanagerimpersonator
outputs:
checkout_pr_success: ${{ steps.checkout-pr.outputs.checkout_pr_success || 'true' }}
has_patch: ${{ steps.collect_output.outputs.has_patch }}
@@ -638,7 +638,7 @@ jobs:
model: "${{ inputs.model }}",
version: "",
agent_version: "0.0.412",
- workflow_name: "Ideas Man",
+ workflow_name: "Product Manager Impersonator",
experimental: false,
supports_tools_allowlist: true,
run_id: context.runId,
@@ -700,7 +700,7 @@ jobs:
cat > /opt/gh-aw/safeoutputs/tools.json << 'GH_AW_SAFE_OUTPUTS_TOOLS_EOF'
[
{
- "description": "Create a new GitHub issue for tracking bugs, feature requests, or tasks. Use this for actionable work items that need assignment, labeling, and status tracking. For reports, announcements, or status updates that don't require task tracking, use create_discussion instead. CONSTRAINTS: Maximum 1 issue(s) can be created. Title will be prefixed with \"[ideas-man] \".",
+ "description": "Create a new GitHub issue for tracking bugs, feature requests, or tasks. Use this for actionable work items that need assignment, labeling, and status tracking. For reports, announcements, or status updates that don't require task tracking, use create_discussion instead. CONSTRAINTS: Maximum 1 issue(s) can be created. Title will be prefixed with \"[product-manager-impersonator] \".",
"inputSchema": {
"additionalProperties": false,
"properties": {
@@ -1222,7 +1222,7 @@ jobs:
env:
GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }}
GH_AW_NOOP_MAX: 1
- GH_AW_WORKFLOW_NAME: "Ideas Man"
+ GH_AW_WORKFLOW_NAME: "Product Manager Impersonator"
with:
github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
script: |
@@ -1235,7 +1235,7 @@ jobs:
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
env:
GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }}
- GH_AW_WORKFLOW_NAME: "Ideas Man"
+ GH_AW_WORKFLOW_NAME: "Product Manager Impersonator"
with:
github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
script: |
@@ -1248,10 +1248,10 @@ jobs:
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
env:
GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }}
- GH_AW_WORKFLOW_NAME: "Ideas Man"
+ GH_AW_WORKFLOW_NAME: "Product Manager Impersonator"
GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }}
- GH_AW_WORKFLOW_ID: "gh-aw-ideas-man"
+ GH_AW_WORKFLOW_ID: "gh-aw-product-manager-impersonator"
GH_AW_SECRET_VERIFICATION_RESULT: ${{ needs.agent.outputs.secret_verification_result }}
GH_AW_CHECKOUT_PR_SUCCESS: ${{ needs.agent.outputs.checkout_pr_success }}
GH_AW_SAFE_OUTPUT_MESSAGES: "{\"footer\":\"${{ inputs.messages-footer || '---\\n[What is this?](https://ela.st/github-ai-tools) | [From workflow: {workflow_name}]({run_url})\\n\\nGive us feedback! React with 🚀 if perfect, 👍 if helpful, 👎 if not.' }}\"}"
@@ -1268,7 +1268,7 @@ jobs:
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
env:
GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }}
- GH_AW_WORKFLOW_NAME: "Ideas Man"
+ GH_AW_WORKFLOW_NAME: "Product Manager Impersonator"
GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }}
GH_AW_NOOP_MESSAGE: ${{ steps.noop.outputs.noop_message }}
@@ -1316,7 +1316,7 @@ jobs:
- name: Setup threat detection
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
env:
- WORKFLOW_NAME: "Ideas Man"
+ WORKFLOW_NAME: "Product Manager Impersonator"
WORKFLOW_DESCRIPTION: "Propose well-researched new feature ideas as GitHub issues"
HAS_PATCH: ${{ needs.agent.outputs.has_patch }}
with:
@@ -1419,8 +1419,8 @@ jobs:
GH_AW_ENGINE_ID: "copilot"
GH_AW_ENGINE_MODEL: "${{ inputs.model }}"
GH_AW_SAFE_OUTPUT_MESSAGES: "{\"footer\":\"${{ inputs.messages-footer || '---\\n[What is this?](https://ela.st/github-ai-tools) | [From workflow: {workflow_name}]({run_url})\\n\\nGive us feedback! React with 🚀 if perfect, 👍 if helpful, 👎 if not.' }}\"}"
- GH_AW_WORKFLOW_ID: "gh-aw-ideas-man"
- GH_AW_WORKFLOW_NAME: "Ideas Man"
+ GH_AW_WORKFLOW_ID: "gh-aw-product-manager-impersonator"
+ GH_AW_WORKFLOW_NAME: "Product Manager Impersonator"
outputs:
create_discussion_error_count: ${{ steps.process_safe_outputs.outputs.create_discussion_error_count }}
create_discussion_errors: ${{ steps.process_safe_outputs.outputs.create_discussion_errors }}
@@ -1447,7 +1447,7 @@ jobs:
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
env:
GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }}
- GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"create_issue\":{\"close_older_issues\":true,\"expires\":168,\"max\":1,\"title_prefix\":\"[ideas-man] \"},\"missing_data\":{},\"missing_tool\":{}}"
+ GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"create_issue\":{\"close_older_issues\":true,\"expires\":168,\"max\":1,\"title_prefix\":\"[product-manager-impersonator] \"},\"missing_data\":{},\"missing_tool\":{}}"
with:
github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
script: |
diff --git a/.github/workflows/gh-aw-ideas-man.md b/.github/workflows/gh-aw-product-manager-impersonator.md
similarity index 84%
rename from .github/workflows/gh-aw-ideas-man.md
rename to .github/workflows/gh-aw-product-manager-impersonator.md
index a4e4c2d..e86ff9d 100644
--- a/.github/workflows/gh-aw-ideas-man.md
+++ b/.github/workflows/gh-aw-product-manager-impersonator.md
@@ -1,6 +1,6 @@
---
inlined-imports: true
-name: "Ideas Man"
+name: "Product Manager Impersonator"
description: "Propose well-researched new feature ideas as GitHub issues"
imports:
- gh-aw-fragments/elastic-tools.md
@@ -49,7 +49,7 @@ on:
bots:
- "${{ inputs.allowed-bot-users }}"
concurrency:
- group: ideas-man
+ group: product-manager-impersonator
cancel-in-progress: true
permissions:
contents: read
@@ -73,7 +73,7 @@ safe-outputs:
noop:
create-issue:
max: 1
- title-prefix: "[ideas-man] "
+ title-prefix: "[product-manager-impersonator] "
close-older-issues: true
expires: 7d
timeout-minutes: 90
@@ -85,7 +85,7 @@ steps:
run: eval "$SETUP_COMMANDS"
---
-You are the Ideas Man — an enthusiastic product thinker who has already done research on the codebase and genuinely believes each idea "won't be that hard" to implement. You are also an expert developer who looks at a project, understands what it can currently do, and proposes new features that align with what already exists.
+You are the Product Manager Impersonator — an enthusiastic product thinker who has already done research on the codebase and genuinely believes each idea "won't be that hard" to implement. You are also an expert developer who looks at a project, understands what it can currently do, and proposes new features that align with what already exists.
Your task is to propose **one** well-researched new feature idea for this repository.
@@ -103,7 +103,7 @@ Your task is to propose **one** well-researched new feature idea for this reposi
3. **Check for duplicates**
- Search open issues for existing feature requests: `repo:{owner}/{repo} is:issue is:open (feature OR enhancement OR idea)`.
- - Search past Ideas Man reports: `repo:{owner}/{repo} is:issue in:title "[ideas-man]"`.
+ - Search past reports: `repo:{owner}/{repo} is:issue in:title "[product-manager-impersonator]"`.
- If your idea duplicates an existing request, pick a different angle.
### What to Propose
@@ -119,7 +119,7 @@ Propose **one** new feature idea that meets all of these criteria:
### Noop
If you cannot find a genuinely useful, non-duplicate idea that meets all the criteria above, call `noop` with:
-"Ideas Man skipped — no novel, high-value feature idea found for this repository."
+"Product Manager Impersonator skipped — no novel, high-value feature idea found for this repository."
**Do not force a low-quality idea just to file something.** Noop is the correct outcome when nothing passes the bar.
@@ -148,6 +148,6 @@ If you cannot find a genuinely useful, non-duplicate idea that meets all the cri
### Labeling
-- If the `ideas-man` label exists (check with `github-get_label`), include it in the `create_issue` call; otherwise, rely on the `[ideas-man]` title prefix only.
+- If the `product-manager-impersonator` label exists (check with `github-get_label`), include it in the `create_issue` call; otherwise, rely on the `[product-manager-impersonator]` title prefix only.
${{ inputs.additional-instructions }}
diff --git a/.github/workflows/gh-aw-refactor-proposal.lock.yml b/.github/workflows/gh-aw-refactor-opportunist.lock.yml
similarity index 98%
rename from .github/workflows/gh-aw-refactor-proposal.lock.yml
rename to .github/workflows/gh-aw-refactor-opportunist.lock.yml
index efce71e..a475712 100644
--- a/.github/workflows/gh-aw-refactor-proposal.lock.yml
+++ b/.github/workflows/gh-aw-refactor-opportunist.lock.yml
@@ -37,9 +37,9 @@
#
# inlined-imports: true
#
-# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"5e3d0b0ea9d458332a97c6fa7d9e3bc6e6e04ad345aba3d3d2ad80dd10af00a5"}
+# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"f9cb8094f3906047b06fecb53304fe5eed953e8d0ea4f1fabac16eb45041a2ae"}
-name: "Refactor Proposal"
+name: "Refactor Opportunist"
"on":
# bots: # Bots processed as bot check in pre-activation job
# - ${{ inputs.allowed-bot-users }} # Bots processed as bot check in pre-activation job
@@ -82,9 +82,9 @@ permissions: {}
concurrency:
cancel-in-progress: true
- group: refactor-proposal
+ group: refactor-opportunist
-run-name: "Refactor Proposal"
+run-name: "Refactor Opportunist"
jobs:
activation:
@@ -120,7 +120,7 @@ jobs:
- name: Check workflow file timestamps
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
env:
- GH_AW_WORKFLOW_FILE: "gh-aw-refactor-proposal.lock.yml"
+ GH_AW_WORKFLOW_FILE: "gh-aw-refactor-opportunist.lock.yml"
with:
script: |
const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
@@ -401,7 +401,7 @@ jobs:
3. **Check for existing proposals**
- Search open issues: `repo:{owner}/{repo} is:issue is:open (refactor OR restructure OR reorganize OR architecture)`.
- - Search past proposals: `repo:{owner}/{repo} is:issue in:title "[refactor-proposal]"`.
+ - Search past proposals: `repo:{owner}/{repo} is:issue in:title "[refactor-opportunist]"`.
- If your idea overlaps with an existing proposal, pick a different angle or call `noop`.
### Analysis and Partial Implementation
@@ -429,7 +429,7 @@ jobs:
- The refactor cannot be done incrementally (it is all-or-nothing).
- The improvement is cosmetic (renaming, reordering) rather than structural.
- "Refactor proposal skipped — no high-impact, viable structural improvement found."
+ "Refactor Opportunist skipped — no high-impact, viable structural improvement found."
### Issue Format
@@ -473,7 +473,7 @@ jobs:
### Labeling
- - If the `refactor-proposal` label exists (check with `github-get_label`), include it in the `create_issue` call; otherwise, rely on the `[refactor-proposal]` title prefix only.
+ - If the `refactor-opportunist` label exists (check with `github-get_label`), include it in the `create_issue` call; otherwise, rely on the `[refactor-opportunist]` title prefix only.
__GH_AW_EXPR_49B959F1__
@@ -563,7 +563,7 @@ jobs:
GH_AW_SAFE_OUTPUTS: /opt/gh-aw/safeoutputs/outputs.jsonl
GH_AW_SAFE_OUTPUTS_CONFIG_PATH: /opt/gh-aw/safeoutputs/config.json
GH_AW_SAFE_OUTPUTS_TOOLS_PATH: /opt/gh-aw/safeoutputs/tools.json
- GH_AW_WORKFLOW_ID_SANITIZED: ghawrefactorproposal
+ GH_AW_WORKFLOW_ID_SANITIZED: ghawrefactoropportunist
outputs:
checkout_pr_success: ${{ steps.checkout-pr.outputs.checkout_pr_success || 'true' }}
has_patch: ${{ steps.collect_output.outputs.has_patch }}
@@ -676,7 +676,7 @@ jobs:
model: "${{ inputs.model }}",
version: "",
agent_version: "0.0.412",
- workflow_name: "Refactor Proposal",
+ workflow_name: "Refactor Opportunist",
experimental: false,
supports_tools_allowlist: true,
run_id: context.runId,
@@ -738,7 +738,7 @@ jobs:
cat > /opt/gh-aw/safeoutputs/tools.json << 'GH_AW_SAFE_OUTPUTS_TOOLS_EOF'
[
{
- "description": "Create a new GitHub issue for tracking bugs, feature requests, or tasks. Use this for actionable work items that need assignment, labeling, and status tracking. For reports, announcements, or status updates that don't require task tracking, use create_discussion instead. CONSTRAINTS: Maximum 1 issue(s) can be created. Title will be prefixed with \"[refactor-proposal] \".",
+ "description": "Create a new GitHub issue for tracking bugs, feature requests, or tasks. Use this for actionable work items that need assignment, labeling, and status tracking. For reports, announcements, or status updates that don't require task tracking, use create_discussion instead. CONSTRAINTS: Maximum 1 issue(s) can be created. Title will be prefixed with \"[refactor-opportunist] \".",
"inputSchema": {
"additionalProperties": false,
"properties": {
@@ -1260,7 +1260,7 @@ jobs:
env:
GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }}
GH_AW_NOOP_MAX: 1
- GH_AW_WORKFLOW_NAME: "Refactor Proposal"
+ GH_AW_WORKFLOW_NAME: "Refactor Opportunist"
with:
github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
script: |
@@ -1273,7 +1273,7 @@ jobs:
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
env:
GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }}
- GH_AW_WORKFLOW_NAME: "Refactor Proposal"
+ GH_AW_WORKFLOW_NAME: "Refactor Opportunist"
with:
github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
script: |
@@ -1286,10 +1286,10 @@ jobs:
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
env:
GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }}
- GH_AW_WORKFLOW_NAME: "Refactor Proposal"
+ GH_AW_WORKFLOW_NAME: "Refactor Opportunist"
GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }}
- GH_AW_WORKFLOW_ID: "gh-aw-refactor-proposal"
+ GH_AW_WORKFLOW_ID: "gh-aw-refactor-opportunist"
GH_AW_SECRET_VERIFICATION_RESULT: ${{ needs.agent.outputs.secret_verification_result }}
GH_AW_CHECKOUT_PR_SUCCESS: ${{ needs.agent.outputs.checkout_pr_success }}
GH_AW_SAFE_OUTPUT_MESSAGES: "{\"footer\":\"${{ inputs.messages-footer || '---\\n[What is this?](https://ela.st/github-ai-tools) | [From workflow: {workflow_name}]({run_url})\\n\\nGive us feedback! React with 🚀 if perfect, 👍 if helpful, 👎 if not.' }}\"}"
@@ -1306,7 +1306,7 @@ jobs:
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
env:
GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }}
- GH_AW_WORKFLOW_NAME: "Refactor Proposal"
+ GH_AW_WORKFLOW_NAME: "Refactor Opportunist"
GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }}
GH_AW_NOOP_MESSAGE: ${{ steps.noop.outputs.noop_message }}
@@ -1354,7 +1354,7 @@ jobs:
- name: Setup threat detection
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
env:
- WORKFLOW_NAME: "Refactor Proposal"
+ WORKFLOW_NAME: "Refactor Opportunist"
WORKFLOW_DESCRIPTION: "Investigate the codebase as a senior architect, partially implement a refactor to prove viability, and pitch it via an issue"
HAS_PATCH: ${{ needs.agent.outputs.has_patch }}
with:
@@ -1457,8 +1457,8 @@ jobs:
GH_AW_ENGINE_ID: "copilot"
GH_AW_ENGINE_MODEL: "${{ inputs.model }}"
GH_AW_SAFE_OUTPUT_MESSAGES: "{\"footer\":\"${{ inputs.messages-footer || '---\\n[What is this?](https://ela.st/github-ai-tools) | [From workflow: {workflow_name}]({run_url})\\n\\nGive us feedback! React with 🚀 if perfect, 👍 if helpful, 👎 if not.' }}\"}"
- GH_AW_WORKFLOW_ID: "gh-aw-refactor-proposal"
- GH_AW_WORKFLOW_NAME: "Refactor Proposal"
+ GH_AW_WORKFLOW_ID: "gh-aw-refactor-opportunist"
+ GH_AW_WORKFLOW_NAME: "Refactor Opportunist"
outputs:
create_discussion_error_count: ${{ steps.process_safe_outputs.outputs.create_discussion_error_count }}
create_discussion_errors: ${{ steps.process_safe_outputs.outputs.create_discussion_errors }}
@@ -1485,7 +1485,7 @@ jobs:
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
env:
GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }}
- GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"create_issue\":{\"close_older_issues\":true,\"expires\":168,\"max\":1,\"title_prefix\":\"[refactor-proposal] \"},\"missing_data\":{},\"missing_tool\":{}}"
+ GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"create_issue\":{\"close_older_issues\":true,\"expires\":168,\"max\":1,\"title_prefix\":\"[refactor-opportunist] \"},\"missing_data\":{},\"missing_tool\":{}}"
with:
github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
script: |
diff --git a/.github/workflows/gh-aw-refactor-proposal.md b/.github/workflows/gh-aw-refactor-opportunist.md
similarity index 94%
rename from .github/workflows/gh-aw-refactor-proposal.md
rename to .github/workflows/gh-aw-refactor-opportunist.md
index 23130c3..1b132d7 100644
--- a/.github/workflows/gh-aw-refactor-proposal.md
+++ b/.github/workflows/gh-aw-refactor-opportunist.md
@@ -1,6 +1,6 @@
---
inlined-imports: true
-name: "Refactor Proposal"
+name: "Refactor Opportunist"
description: "Investigate the codebase as a senior architect, partially implement a refactor to prove viability, and pitch it via an issue"
imports:
- gh-aw-fragments/elastic-tools.md
@@ -50,7 +50,7 @@ on:
bots:
- "${{ inputs.allowed-bot-users }}"
concurrency:
- group: refactor-proposal
+ group: refactor-opportunist
cancel-in-progress: true
permissions:
contents: read
@@ -74,7 +74,7 @@ safe-outputs:
noop:
create-issue:
max: 1
- title-prefix: "[refactor-proposal] "
+ title-prefix: "[refactor-opportunist] "
close-older-issues: true
expires: 7d
timeout-minutes: 90
@@ -105,7 +105,7 @@ You are a senior software architect reviewing this codebase with fresh eyes. You
3. **Check for existing proposals**
- Search open issues: `repo:{owner}/{repo} is:issue is:open (refactor OR restructure OR reorganize OR architecture)`.
- - Search past proposals: `repo:{owner}/{repo} is:issue in:title "[refactor-proposal]"`.
+ - Search past proposals: `repo:{owner}/{repo} is:issue in:title "[refactor-opportunist]"`.
- If your idea overlaps with an existing proposal, pick a different angle or call `noop`.
### Analysis and Partial Implementation
@@ -133,7 +133,7 @@ Call `noop` if any of these are true:
- The refactor cannot be done incrementally (it is all-or-nothing).
- The improvement is cosmetic (renaming, reordering) rather than structural.
-"Refactor proposal skipped — no high-impact, viable structural improvement found."
+"Refactor Opportunist skipped — no high-impact, viable structural improvement found."
### Issue Format
@@ -177,6 +177,6 @@ Call `noop` if any of these are true:
### Labeling
-- If the `refactor-proposal` label exists (check with `github-get_label`), include it in the `create_issue` call; otherwise, rely on the `[refactor-proposal]` title prefix only.
+- If the `refactor-opportunist` label exists (check with `github-get_label`), include it in the `create_issue` call; otherwise, rely on the `[refactor-opportunist]` title prefix only.
${{ inputs.additional-instructions }}
diff --git a/.github/workflows/trigger-ideas-man.yml b/.github/workflows/trigger-product-manager-impersonator.yml
similarity index 57%
rename from .github/workflows/trigger-ideas-man.yml
rename to .github/workflows/trigger-product-manager-impersonator.yml
index c41d92f..93edbd3 100644
--- a/.github/workflows/trigger-ideas-man.yml
+++ b/.github/workflows/trigger-product-manager-impersonator.yml
@@ -1,6 +1,6 @@
# This file is auto-generated by scripts/dogfood.sh. Do not edit directly.
-# Edit gh-agent-workflows/ideas-man/example.yml and run 'make compile' to regenerate.
-name: Trigger Ideas Man
+# Edit gh-agent-workflows/product-manager-impersonator/example.yml and run 'make compile' to regenerate.
+name: Trigger Product Manager Impersonator
on:
schedule:
- cron: "0 10 * * 1-5"
@@ -13,6 +13,6 @@ permissions:
jobs:
run:
- uses: ./.github/workflows/gh-aw-ideas-man.lock.yml
+ uses: ./.github/workflows/gh-aw-product-manager-impersonator.lock.yml
secrets:
COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
diff --git a/.github/workflows/trigger-refactor-proposal.yml b/.github/workflows/trigger-refactor-opportunist.yml
similarity index 60%
rename from .github/workflows/trigger-refactor-proposal.yml
rename to .github/workflows/trigger-refactor-opportunist.yml
index 9808eac..b6b5a0a 100644
--- a/.github/workflows/trigger-refactor-proposal.yml
+++ b/.github/workflows/trigger-refactor-opportunist.yml
@@ -1,6 +1,6 @@
# This file is auto-generated by scripts/dogfood.sh. Do not edit directly.
-# Edit gh-agent-workflows/refactor-proposal/example.yml and run 'make compile' to regenerate.
-name: Trigger Refactor Proposal
+# Edit gh-agent-workflows/refactor-opportunist/example.yml and run 'make compile' to regenerate.
+name: Trigger Refactor Opportunist
on:
schedule:
- cron: "0 14 * * 1"
@@ -13,6 +13,6 @@ permissions:
jobs:
run:
- uses: ./.github/workflows/gh-aw-refactor-proposal.lock.yml
+ uses: ./.github/workflows/gh-aw-refactor-opportunist.lock.yml
secrets:
COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
diff --git a/gh-agent-workflows/README.md b/gh-agent-workflows/README.md
index 89debf0..c58bb18 100644
--- a/gh-agent-workflows/README.md
+++ b/gh-agent-workflows/README.md
@@ -28,8 +28,8 @@ Pre-built workflows with domain-specific prompts. These import the same base fra
- [Code Duplication Detector](code-duplication-detector/) — find duplicate code
- [Breaking Change Detector](breaking-change-detector/) — find breaking changes
- [Docs Patrol](docs-patrol/) — detect stale documentation
-- [Ideas Man](ideas-man/) — propose well-researched new feature ideas
-- [Refactor Proposal](refactor-proposal/) — pitch proven refactors with partial implementations
+- [Product Manager Impersonator](product-manager-impersonator/) — propose well-researched new feature ideas
+- [Refactor Opportunist](refactor-opportunist/) — pitch proven refactors with partial implementations
- [Stale Issues](stale-issues/) — detect stale issues
**Fixers** (create PRs):
@@ -65,9 +65,9 @@ workflows, or `--repo OWNER/REPO` when auto-detection is not available.
- `bug-exterminator`
- `code-simplifier`
- `docs-patrol`
-- `ideas-man`
- `newbie-contributor-patrol`
-- `refactor-proposal`
+- `product-manager-impersonator`
+- `refactor-opportunist`
- `small-problem-fixer`
- `stale-issues`
- `test-improver`
diff --git a/gh-agent-workflows/ideas-man/README.md b/gh-agent-workflows/product-manager-impersonator/README.md
similarity index 88%
rename from gh-agent-workflows/ideas-man/README.md
rename to gh-agent-workflows/product-manager-impersonator/README.md
index 7c75e9e..6b3b25f 100644
--- a/gh-agent-workflows/ideas-man/README.md
+++ b/gh-agent-workflows/product-manager-impersonator/README.md
@@ -1,4 +1,4 @@
-# Ideas Man
+# Product Manager Impersonator
Propose well-researched new feature ideas as GitHub issues.
@@ -10,8 +10,8 @@ Reviews the codebase, recent activity, and existing issues to propose a single n
```bash
mkdir -p .github/workflows && curl -sL \
- https://raw.githubusercontent.com/elastic/ai-github-actions/v0/gh-agent-workflows/ideas-man/example.yml \
- -o .github/workflows/ideas-man.yml
+ https://raw.githubusercontent.com/elastic/ai-github-actions/v0/gh-agent-workflows/product-manager-impersonator/example.yml \
+ -o .github/workflows/product-manager-impersonator.yml
```
See [example.yml](example.yml) for the full workflow file.
diff --git a/gh-agent-workflows/ideas-man/example.yml b/gh-agent-workflows/product-manager-impersonator/example.yml
similarity index 62%
rename from gh-agent-workflows/ideas-man/example.yml
rename to gh-agent-workflows/product-manager-impersonator/example.yml
index adf1329..82d2fcb 100644
--- a/gh-agent-workflows/ideas-man/example.yml
+++ b/gh-agent-workflows/product-manager-impersonator/example.yml
@@ -1,4 +1,4 @@
-name: Ideas Man
+name: Product Manager Impersonator
on:
schedule:
- cron: "0 10 * * 1-5"
@@ -11,6 +11,6 @@ permissions:
jobs:
run:
- uses: elastic/ai-github-actions/.github/workflows/gh-aw-ideas-man.lock.yml@v0
+ uses: elastic/ai-github-actions/.github/workflows/gh-aw-product-manager-impersonator.lock.yml@v0
secrets:
COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
diff --git a/gh-agent-workflows/refactor-proposal/README.md b/gh-agent-workflows/refactor-opportunist/README.md
similarity index 91%
rename from gh-agent-workflows/refactor-proposal/README.md
rename to gh-agent-workflows/refactor-opportunist/README.md
index d19204e..6446905 100644
--- a/gh-agent-workflows/refactor-proposal/README.md
+++ b/gh-agent-workflows/refactor-opportunist/README.md
@@ -1,4 +1,4 @@
-# Refactor Proposal
+# Refactor Opportunist
Investigate the codebase as a senior architect, partially implement a refactor to prove viability, and pitch it via an issue.
@@ -10,8 +10,8 @@ Reviews the codebase architecture, identifies structural pain points (tangled de
```bash
mkdir -p .github/workflows && curl -sL \
- https://raw.githubusercontent.com/elastic/ai-github-actions/v0/gh-agent-workflows/refactor-proposal/example.yml \
- -o .github/workflows/refactor-proposal.yml
+ https://raw.githubusercontent.com/elastic/ai-github-actions/v0/gh-agent-workflows/refactor-opportunist/example.yml \
+ -o .github/workflows/refactor-opportunist.yml
```
See [example.yml](example.yml) for the full workflow file.
diff --git a/gh-agent-workflows/refactor-proposal/example.yml b/gh-agent-workflows/refactor-opportunist/example.yml
similarity index 83%
rename from gh-agent-workflows/refactor-proposal/example.yml
rename to gh-agent-workflows/refactor-opportunist/example.yml
index beb2511..5823737 100644
--- a/gh-agent-workflows/refactor-proposal/example.yml
+++ b/gh-agent-workflows/refactor-opportunist/example.yml
@@ -1,4 +1,4 @@
-name: Refactor Proposal
+name: Refactor Opportunist
on:
schedule:
- cron: "0 14 * * 1"
@@ -11,6 +11,6 @@ permissions:
jobs:
run:
- uses: elastic/ai-github-actions/.github/workflows/gh-aw-refactor-proposal.lock.yml@v0
+ uses: elastic/ai-github-actions/.github/workflows/gh-aw-refactor-opportunist.lock.yml@v0
secrets:
COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
diff --git a/scripts/quick-setup.sh b/scripts/quick-setup.sh
index dd48592..a722502 100755
--- a/scripts/quick-setup.sh
+++ b/scripts/quick-setup.sh
@@ -130,9 +130,9 @@ continuous_improvement_workflows=(
bug-exterminator
code-simplifier
docs-patrol
- ideas-man
newbie-contributor-patrol
- refactor-proposal
+ product-manager-impersonator
+ refactor-opportunist
small-problem-fixer
stale-issues
test-improver
From 387fde3f320cc8ceacef5204684c8e95a5ae076d Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sun, 22 Feb 2026 16:54:22 +0000
Subject: [PATCH 4/4] Remove close-older-issues from
product-manager-impersonator and refactor-opportunist
Each run proposes a unique idea/refactor, so older reports should not
be auto-closed when a new one is filed.
Co-authored-by: strawgate <6384545+strawgate@users.noreply.github.com>
---
.../workflows/gh-aw-product-manager-impersonator.lock.yml | 6 +++---
.github/workflows/gh-aw-product-manager-impersonator.md | 2 --
.github/workflows/gh-aw-refactor-opportunist.lock.yml | 6 +++---
.github/workflows/gh-aw-refactor-opportunist.md | 2 --
4 files changed, 6 insertions(+), 10 deletions(-)
diff --git a/.github/workflows/gh-aw-product-manager-impersonator.lock.yml b/.github/workflows/gh-aw-product-manager-impersonator.lock.yml
index 70830b1..b807d46 100644
--- a/.github/workflows/gh-aw-product-manager-impersonator.lock.yml
+++ b/.github/workflows/gh-aw-product-manager-impersonator.lock.yml
@@ -36,7 +36,7 @@
#
# inlined-imports: true
#
-# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"6dc575c54b5359615c24519a1ddb737587d34b0492f39f64206e3f1a9463285e"}
+# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"c15396d9f044f735ee98889da834824e38d77b749e345e149f4e4a8e24ca4d99"}
name: "Product Manager Impersonator"
"on":
@@ -695,7 +695,7 @@ jobs:
mkdir -p /tmp/gh-aw/safeoutputs
mkdir -p /tmp/gh-aw/mcp-logs/safeoutputs
cat > /opt/gh-aw/safeoutputs/config.json << 'GH_AW_SAFE_OUTPUTS_CONFIG_EOF'
- {"create_issue":{"expires":168,"max":1},"missing_data":{},"missing_tool":{},"noop":{"max":1}}
+ {"create_issue":{"max":1},"missing_data":{},"missing_tool":{},"noop":{"max":1}}
GH_AW_SAFE_OUTPUTS_CONFIG_EOF
cat > /opt/gh-aw/safeoutputs/tools.json << 'GH_AW_SAFE_OUTPUTS_TOOLS_EOF'
[
@@ -1447,7 +1447,7 @@ jobs:
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
env:
GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }}
- GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"create_issue\":{\"close_older_issues\":true,\"expires\":168,\"max\":1,\"title_prefix\":\"[product-manager-impersonator] \"},\"missing_data\":{},\"missing_tool\":{}}"
+ GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"create_issue\":{\"max\":1,\"title_prefix\":\"[product-manager-impersonator] \"},\"missing_data\":{},\"missing_tool\":{}}"
with:
github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
script: |
diff --git a/.github/workflows/gh-aw-product-manager-impersonator.md b/.github/workflows/gh-aw-product-manager-impersonator.md
index e86ff9d..e063c5b 100644
--- a/.github/workflows/gh-aw-product-manager-impersonator.md
+++ b/.github/workflows/gh-aw-product-manager-impersonator.md
@@ -74,8 +74,6 @@ safe-outputs:
create-issue:
max: 1
title-prefix: "[product-manager-impersonator] "
- close-older-issues: true
- expires: 7d
timeout-minutes: 90
steps:
- name: Repo-specific setup
diff --git a/.github/workflows/gh-aw-refactor-opportunist.lock.yml b/.github/workflows/gh-aw-refactor-opportunist.lock.yml
index a475712..c91f6bd 100644
--- a/.github/workflows/gh-aw-refactor-opportunist.lock.yml
+++ b/.github/workflows/gh-aw-refactor-opportunist.lock.yml
@@ -37,7 +37,7 @@
#
# inlined-imports: true
#
-# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"f9cb8094f3906047b06fecb53304fe5eed953e8d0ea4f1fabac16eb45041a2ae"}
+# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"f76207a32db8525afba95c4665deb639f83f1677dde58bb21eb8ab286b547286"}
name: "Refactor Opportunist"
"on":
@@ -733,7 +733,7 @@ jobs:
mkdir -p /tmp/gh-aw/safeoutputs
mkdir -p /tmp/gh-aw/mcp-logs/safeoutputs
cat > /opt/gh-aw/safeoutputs/config.json << 'GH_AW_SAFE_OUTPUTS_CONFIG_EOF'
- {"create_issue":{"expires":168,"max":1},"missing_data":{},"missing_tool":{},"noop":{"max":1}}
+ {"create_issue":{"max":1},"missing_data":{},"missing_tool":{},"noop":{"max":1}}
GH_AW_SAFE_OUTPUTS_CONFIG_EOF
cat > /opt/gh-aw/safeoutputs/tools.json << 'GH_AW_SAFE_OUTPUTS_TOOLS_EOF'
[
@@ -1485,7 +1485,7 @@ jobs:
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
env:
GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }}
- GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"create_issue\":{\"close_older_issues\":true,\"expires\":168,\"max\":1,\"title_prefix\":\"[refactor-opportunist] \"},\"missing_data\":{},\"missing_tool\":{}}"
+ GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"create_issue\":{\"max\":1,\"title_prefix\":\"[refactor-opportunist] \"},\"missing_data\":{},\"missing_tool\":{}}"
with:
github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
script: |
diff --git a/.github/workflows/gh-aw-refactor-opportunist.md b/.github/workflows/gh-aw-refactor-opportunist.md
index 1b132d7..36fd4f4 100644
--- a/.github/workflows/gh-aw-refactor-opportunist.md
+++ b/.github/workflows/gh-aw-refactor-opportunist.md
@@ -75,8 +75,6 @@ safe-outputs:
create-issue:
max: 1
title-prefix: "[refactor-opportunist] "
- close-older-issues: true
- expires: 7d
timeout-minutes: 90
steps:
- name: Repo-specific setup