diff --git a/.github/workflows/downstream-users.lock.yml b/.github/workflows/downstream-users.lock.yml index 31e39eb6..76c00a73 100644 --- a/.github/workflows/downstream-users.lock.yml +++ b/.github/workflows/downstream-users.lock.yml @@ -36,7 +36,7 @@ # # inlined-imports: true # -# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"6c7c54eef66da79ace3f26a7c4cc39896e2319c7f86597f1a15baeb27def7f4b"} +# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"fb6d0081e858bc1c87b90fdb2778ed61764a2e78c55707312a68639281f08357"} name: "Internal: Downstream Users" "on": @@ -866,7 +866,9 @@ jobs: if (contributing) checklist.push(`Review the contributing guide (${contributing}) before opening or updating a PR.`); if (prTemplate) checklist.push(`Follow the PR template (${prTemplate}) for title, description, and validation notes.`); checklist.push('Confirm the requested task is fully completed and validated before creating or pushing PR changes.'); - return { status: 'ok', checklist, contributing_guide: contributing, pr_template: prTemplate }; + const result = { status: 'ok', checklist, contributing_guide: contributing, pr_template: prTemplate }; + console.log(JSON.stringify(result)); + return result; } module.exports = { execute }; GH_AW_SAFE_INPUTS_JS_READY-TO-MAKE-PR_EOF diff --git a/.github/workflows/gh-aw-autonomy-atomicity-analyzer.lock.yml b/.github/workflows/gh-aw-autonomy-atomicity-analyzer.lock.yml new file mode 100644 index 00000000..ab4770cd --- /dev/null +++ b/.github/workflows/gh-aw-autonomy-atomicity-analyzer.lock.yml @@ -0,0 +1,1480 @@ +# +# ___ _ _ +# / _ \ | | (_) +# | |_| | __ _ ___ _ __ | |_ _ ___ +# | _ |/ _` |/ _ \ '_ \| __| |/ __| +# | | | | (_| | __/ | | | |_| | (__ +# \_| |_/\__, |\___|_| |_|\__|_|\___| +# __/ | +# _ _ |___/ +# | | | | / _| | +# | | | | ___ _ __ _ __| |_| | _____ ____ +# | |/\| |/ _ \ '__| |/ /| _| |/ _ \ \ /\ / / ___| +# \ /\ / (_) | | | | ( | | | | (_) \ 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/ +# +# Find patterns that block concurrent development by multiple agents or developers +# +# Resolved workflow manifest: +# Imports: +# - gh-aw-fragments/best-of-three-investigation.md +# - 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/network-ecosystems.md +# - gh-aw-fragments/previous-findings.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":"0febb361a71adf4c7251e2ce62368a2811b2d53e8ec41e44f4c9ea3006000c46"} + +name: "Autonomy Atomicity Analyzer" +"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 + title-prefix: + default: "[autonomy-atomicity]" + description: Title prefix for created issues (e.g. '[autonomy-atomicity]') + required: false + type: string + secrets: + COPILOT_GITHUB_TOKEN: + required: true + +permissions: {} + +concurrency: + cancel-in-progress: true + group: autonomy-atomicity-analyzer + +run-name: "Autonomy Atomicity Analyzer" + +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@90ebf8057e8e005103b8d123732d2c64c30e9b27 # v0.50.4 + 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-autonomy-atomicity-analyzer.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_EXPR_BF503D80: ${{ inputs.title-prefix }} + 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_EOF + cat "/opt/gh-aw/prompts/xpia.md" + cat "/opt/gh-aw/prompts/temp_folder_prompt.md" + cat "/opt/gh-aw/prompts/markdown.md" + cat "/opt/gh-aw/prompts/safe_outputs_prompt.md" + cat << 'GH_AW_PROMPT_EOF' + + Tools: create_issue, missing_tool, missing_data + + + 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_EOF + cat << 'GH_AW_PROMPT_EOF' + ## 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_EOF + cat << 'GH_AW_PROMPT_EOF' + ## 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' + ## 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 submitting any output, re-read it 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. + - Be thorough, spend the time to investigate and verify. There is no rush. Do your best work. + GH_AW_PROMPT_EOF + cat << 'GH_AW_PROMPT_EOF' + ## 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' + ## 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' + ## 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' + ## Previous Findings + + Before filing a new issue, check `/tmp/previous-findings.json` for issues this agent has already filed. + + - Run `cat /tmp/previous-findings.json` to read the list of previously filed issue numbers and titles. + - If your finding closely matches an open or recently-closed issue in that list, call `noop` instead of filing a duplicate. + - Only file a new issue when the finding is genuinely distinct from all previous findings. + GH_AW_PROMPT_EOF + cat << 'GH_AW_PROMPT_EOF' + ### Best-of-Three Investigation + + For your initial investigation, use multiple sub-agents to explore the codebase and gather the best possible result. Give each sub-agent a unique instruction to explore a different starting point or angle — e.g., different starting points, different approaches, or different heuristics. + + Wait for all the sub-agents to complete. Do not proceed until every sub-agent has returned its result. + + Evaluate the candidates by comparing evidence quality, specificity, and actionability. Prefer candidates with concrete file paths, line numbers, and verifiable evidence over general observations. If most or all sub-agents recommend `noop`, that is a strong signal to `noop`. + + Select the single best candidate and proceed with it. Discard the others. If no candidate meets the quality gate, call `noop`. + GH_AW_PROMPT_EOF + cat << 'GH_AW_PROMPT_EOF' + 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. + + ## 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_EOF + cat << 'GH_AW_PROMPT_EOF' + You are the Autonomy & Atomicity Analyzer — an expert in concurrent development workflows who identifies patterns that cause problems when multiple agents or developers work on the repository simultaneously. + + Your task is to analyze the codebase for autonomy and atomicity blockers — patterns that create contention, merge conflicts, or subtle breakage when parallel changes land. + + **The bar is high.** Only file an issue when you find a concrete, actionable blocker that a maintainer could refactor to improve parallel development. + + ## 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 blockers** + - Scan the project structure and identify files with the highest import fan-in and fan-out. + - Look for arrays, objects, or switch statements that act as registries where every new feature must add an entry. + - Identify test files whose scope spans multiple unrelated features. + - Check for module-level mutable state (e.g., `let` declarations at module scope, mutable singletons). + - Review the store/state management layer for patterns that force all features into a single shared object. + + 3. **Check for duplicates** + - Search open issues: `repo:{owner}/{repo} is:issue is:open in:title "__GH_AW_EXPR_BF503D80__"`. + - Review `/tmp/previous-findings.json` for issues already filed by this agent. + + ### What to Look For + + 1. **Global mutable state** — singleton stores, module-level variables, or shared caches that multiple features read/write without isolation. Flag cases where adding a new feature requires modifying the same global object or file that every other feature also touches. + 2. **Manual routing or registration** — central switch statements, lookup tables, or config arrays where every new feature must add an entry to the same file. These are merge-conflict magnets. + 3. **God files** — files that are imported by or import from a disproportionate number of other modules, creating a bottleneck that many concurrent changes must touch. + 4. **Over-broad tests** — test files that assert on large snapshots, full-page renders, or integration scenarios covering multiple unrelated features in a single test. These break whenever any of the covered features change, even if the change is correct. + 5. **Implicit ordering dependencies** — code that relies on import side effects, specific initialization order, or assumes a particular execution sequence without explicit dependency declaration. + 6. **Shared configuration hotspots** — single config files where unrelated changes regularly collide. + + ### What to Skip + + - Minor style issues or theoretical problems with no current impact + - Patterns that are already well-isolated or that the team has intentionally centralized + - Issues already tracked by an open issue + + ### Quality Gate — When to Noop + + Call `noop` if: + - No concrete, actionable blocker is found. + - Every finding is theoretical with no evidence of actual contention. + - A similar issue is already open. + + "Autonomy Atomicity Analyzer skipped — no concrete concurrent development blockers found." + + ### Issue Format + + **Issue title:** Brief summary of the blocker (e.g., "Central visualization registry is a merge-conflict hotspot") + + **Issue body:** + + > ## Autonomy / Atomicity Findings + > + > ### 1. [Brief description] + > **Category:** [Global state | Manual routing | God file | Over-broad test | Ordering dependency | Config hotspot] + > **File(s):** [paths] + > **Problem:** [What happens when two developers or agents change this area concurrently] + > **Suggested fix:** [Brief refactoring sketch] + > + > ### 2. [Next finding...] + > + > ## Suggested Actions + > - [ ] [Specific, actionable checkbox for each improvement] + + ### Labeling + + - If the `autonomy-atomicity` label exists (check with `github-get_label`), include it in the `create_issue` call; otherwise, rely on the `__GH_AW_EXPR_BF503D80__` title prefix only. + + __GH_AW_EXPR_49B959F1__ + + GH_AW_PROMPT_EOF + } > "$GH_AW_PROMPT" + - 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_EXPR_49B959F1: ${{ inputs.additional-instructions }} + GH_AW_EXPR_BF503D80: ${{ inputs.title-prefix }} + 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_EXPR_BF503D80: ${{ inputs.title-prefix }} + 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 }} + 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_EXPR_BF503D80: process.env.GH_AW_EXPR_BF503D80, + 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 + } + }); + - 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 + 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: ghawautonomyatomicityanalyzer + outputs: + checkout_pr_success: ${{ steps.checkout-pr.outputs.checkout_pr_success || 'true' }} + detection_conclusion: ${{ steps.detection_conclusion.outputs.conclusion }} + detection_success: ${{ steps.detection_conclusion.outputs.success }} + 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@90ebf8057e8e005103b8d123732d2c64c30e9b27 # v0.50.4 + 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: + GH_TOKEN: ${{ github.token }} + TITLE_PREFIX: ${{ inputs.title-prefix }} + name: List previous findings + run: "set -euo pipefail\ngh issue list \\\n --repo \"$GITHUB_REPOSITORY\" \\\n --search \"in:title \\\"$TITLE_PREFIX\\\"\" \\\n --state all \\\n --limit 100 \\\n --json number,title,state \\\n > /tmp/previous-findings.json || { echo \"::warning::Failed to fetch previous findings — dedup will be skipped\"; echo \"[]\" > /tmp/previous-findings.json; }" + - 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]" + git config --global am.keepcr true + # 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.417", + workflow_name: "Autonomy Atomicity Analyzer", + 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","clojure","cloud.elastic.co","containers","dart","defaults","dotnet","ela.st","elastic.co","elastic.dev","elixir","fonts","github","github-actions","go","haskell","java","kotlin","linux-distros","node","node-cdns","perl","php","playwright","public-code-search.fastmcp.app","python","ruby","rust","scala","swift","terraform","www.elastic.co","zig"], + firewall_enabled: true, + awf_version: "v0.23.0", + awmg_version: "v0.1.5", + 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.417 + - name: Install awf binary + run: bash /opt/gh-aw/actions/install_awf_binary.sh v0.23.0 + - 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.23.0 ghcr.io/github/gh-aw-firewall/api-proxy:0.23.0 ghcr.io/github/gh-aw-firewall/squid:0.23.0 ghcr.io/github/gh-aw-mcpg:v0.1.5 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":{"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 \"${{ inputs.title-prefix }} \".", + "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.5' + + 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 + # shellcheck disable=SC1003 + sudo -E awf --env-all --container-workdir "${GITHUB_WORKSPACE}" --allow-domains "*.docker.com,*.docker.io,*.githubusercontent.com,*.hackage.haskell.org,*.jsr.io,*.pythonhosted.org,*.rvm.io,*.vsblob.vsassets.io,adoptium.net,agents-md-generator.fastmcp.app,anaconda.org,api.adoptium.net,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.foojay.io,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.npms.io,api.nuget.org,api.rubygems.org,api.snapcraft.io,apt.llvm.org,apt.releases.hashicorp.com,archive.apache.org,archive.ubuntu.com,archlinux.org,artifacts.elastic.co,auth.docker.io,azure.archive.ubuntu.com,azuresearch-usnc.nuget.org,azuresearch-ussc.nuget.org,binstar.org,bitbucket.org,bootstrap.pypa.io,builds.dotnet.microsoft.com,builds.hex.pm,bun.sh,bundler.rubygems.org,cache.ruby-lang.org,cdn.azul.com,cdn.cocoapods.org,cdn.hex.pm,cdn.jsdelivr.net,cdn.playwright.dev,cdn.redhat.com,cdn.sheetjs.com,central.sonatype.com,ci.dot.net,clojars.org,cloud.elastic.co,cocoapods.org,code.jquery.com,codeload.github.com,conda.anaconda.org,conda.binstar.org,cpan.metacpan.org,cpan.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,data.jsdelivr.com,dc.services.visualstudio.com,deb.debian.org,deb.nodesource.com,debian.map.fastlydns.net,deno.land,dist.nuget.org,dl-cdn.alpinelinux.org,dl.bintray.com,dl.fedoraproject.org,dl.google.com,dl.k8s.io,dlcdn.apache.org,dot.net,dotnet.microsoft.com,dotnetcli.blob.core.windows.net,download.eclipse.org,download.fedoraproject.org,download.java.net,download.opensuse.org,download.oracle.com,download.swift.org,downloads.gradle-dn.com,downloads.haskell.org,ela.st,elastic.co,elastic.dev,esm.sh,fastly.hex.pm,files.pythonhosted.org,fonts.googleapis.com,fonts.gstatic.com,gcr.io,ge.jetbrains.com,gems.rubyforge.org,gems.rubyonrails.org,get-ghcup.haskell.org,get.pnpm.io,getcomposer.org,ghcr.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,gradle.org,haskell.org,hex.pm,host.docker.internal,index.crates.io,index.rubygems.org,jcenter.bintray.com,jdk.java.net,jitpack.io,json-schema.org,json.schemastore.org,jsr.io,keyring.debian.org,keyserver.ubuntu.com,kotlin.bintray.com,lfs.github.com,maven.apache.org,maven.google.com,maven.oracle.com,maven.pkg.github.com,mcr.microsoft.com,metacpan.org,mirror.archlinux.org,mirror.centos.org,mirrors.fedoraproject.org,nodejs.org,npm.pkg.github.com,npmjs.com,npmjs.org,nuget.org,nuget.pkg.github.com,nugetregistryv2prod.blob.core.windows.net,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,oneocsp.microsoft.com,packagecloud.io,packages.cloud.google.com,packages.debian.org,packages.jetbrains.team,packages.microsoft.com,packagist.org,pip.pypa.io,pkg.alpinelinux.org,pkg.go.dev,pkg.machengine.org,pkgs.dev.azure.com,pkgs.k8s.io,playwright.download.prss.microsoft.com,plugins-artifacts.gradle.org,plugins.gradle.org,ppa.launchpad.net,production.cloudflare.docker.com,productionresultssa0.blob.core.windows.net,productionresultssa1.blob.core.windows.net,productionresultssa10.blob.core.windows.net,productionresultssa11.blob.core.windows.net,productionresultssa12.blob.core.windows.net,productionresultssa13.blob.core.windows.net,productionresultssa14.blob.core.windows.net,productionresultssa15.blob.core.windows.net,productionresultssa16.blob.core.windows.net,productionresultssa17.blob.core.windows.net,productionresultssa18.blob.core.windows.net,productionresultssa19.blob.core.windows.net,productionresultssa2.blob.core.windows.net,productionresultssa3.blob.core.windows.net,productionresultssa4.blob.core.windows.net,productionresultssa5.blob.core.windows.net,productionresultssa6.blob.core.windows.net,productionresultssa7.blob.core.windows.net,productionresultssa8.blob.core.windows.net,productionresultssa9.blob.core.windows.net,proxy.golang.org,pub.dartlang.org,pub.dev,public-code-search.fastmcp.app,pypi.org,pypi.python.org,quay.io,raw.githubusercontent.com,registry.bower.io,registry.hub.docker.com,registry.npmjs.com,registry.npmjs.org,registry.terraform.io,registry.yarnpkg.com,releases.hashicorp.com,repo.anaconda.com,repo.clojars.org,repo.continuum.io,repo.gradle.org,repo.grails.org,repo.hex.pm,repo.maven.apache.org,repo.packagist.org,repo.scala-sbt.org,repo.spring.io,repo.typesafe.com,repo.yarnpkg.com,repo1.maven.org,rubygems.org,rubygems.pkg.github.com,s.symcb.com,s.symcd.com,scala-ci.typesafe.com,security.debian.org,security.ubuntu.com,services.gradle.org,sh.rustup.rs,skimdb.npmjs.com,static.crates.io,static.rust-lang.org,storage.googleapis.com,sum.golang.org,swift.org,telemetry.enterprise.githubcopilot.com,telemetry.vercel.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,vault.centos.org,www.cpan.org,www.elastic.co,www.java.com,www.microsoft.com,www.npmjs.com,www.npmjs.org,yarnpkg.com,yum.releases.hashicorp.com,ziglang.org" --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --enable-host-access --image-tag 0.23.0 --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]" + git config --global am.keepcr true + # 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: "*.docker.com,*.docker.io,*.githubusercontent.com,*.hackage.haskell.org,*.jsr.io,*.pythonhosted.org,*.rvm.io,*.vsblob.vsassets.io,adoptium.net,agents-md-generator.fastmcp.app,anaconda.org,api.adoptium.net,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.foojay.io,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.npms.io,api.nuget.org,api.rubygems.org,api.snapcraft.io,apt.llvm.org,apt.releases.hashicorp.com,archive.apache.org,archive.ubuntu.com,archlinux.org,artifacts.elastic.co,auth.docker.io,azure.archive.ubuntu.com,azuresearch-usnc.nuget.org,azuresearch-ussc.nuget.org,binstar.org,bitbucket.org,bootstrap.pypa.io,builds.dotnet.microsoft.com,builds.hex.pm,bun.sh,bundler.rubygems.org,cache.ruby-lang.org,cdn.azul.com,cdn.cocoapods.org,cdn.hex.pm,cdn.jsdelivr.net,cdn.playwright.dev,cdn.redhat.com,cdn.sheetjs.com,central.sonatype.com,ci.dot.net,clojars.org,cloud.elastic.co,cocoapods.org,code.jquery.com,codeload.github.com,conda.anaconda.org,conda.binstar.org,cpan.metacpan.org,cpan.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,data.jsdelivr.com,dc.services.visualstudio.com,deb.debian.org,deb.nodesource.com,debian.map.fastlydns.net,deno.land,dist.nuget.org,dl-cdn.alpinelinux.org,dl.bintray.com,dl.fedoraproject.org,dl.google.com,dl.k8s.io,dlcdn.apache.org,dot.net,dotnet.microsoft.com,dotnetcli.blob.core.windows.net,download.eclipse.org,download.fedoraproject.org,download.java.net,download.opensuse.org,download.oracle.com,download.swift.org,downloads.gradle-dn.com,downloads.haskell.org,ela.st,elastic.co,elastic.dev,esm.sh,fastly.hex.pm,files.pythonhosted.org,fonts.googleapis.com,fonts.gstatic.com,gcr.io,ge.jetbrains.com,gems.rubyforge.org,gems.rubyonrails.org,get-ghcup.haskell.org,get.pnpm.io,getcomposer.org,ghcr.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,gradle.org,haskell.org,hex.pm,host.docker.internal,index.crates.io,index.rubygems.org,jcenter.bintray.com,jdk.java.net,jitpack.io,json-schema.org,json.schemastore.org,jsr.io,keyring.debian.org,keyserver.ubuntu.com,kotlin.bintray.com,lfs.github.com,maven.apache.org,maven.google.com,maven.oracle.com,maven.pkg.github.com,mcr.microsoft.com,metacpan.org,mirror.archlinux.org,mirror.centos.org,mirrors.fedoraproject.org,nodejs.org,npm.pkg.github.com,npmjs.com,npmjs.org,nuget.org,nuget.pkg.github.com,nugetregistryv2prod.blob.core.windows.net,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,oneocsp.microsoft.com,packagecloud.io,packages.cloud.google.com,packages.debian.org,packages.jetbrains.team,packages.microsoft.com,packagist.org,pip.pypa.io,pkg.alpinelinux.org,pkg.go.dev,pkg.machengine.org,pkgs.dev.azure.com,pkgs.k8s.io,playwright.download.prss.microsoft.com,plugins-artifacts.gradle.org,plugins.gradle.org,ppa.launchpad.net,production.cloudflare.docker.com,productionresultssa0.blob.core.windows.net,productionresultssa1.blob.core.windows.net,productionresultssa10.blob.core.windows.net,productionresultssa11.blob.core.windows.net,productionresultssa12.blob.core.windows.net,productionresultssa13.blob.core.windows.net,productionresultssa14.blob.core.windows.net,productionresultssa15.blob.core.windows.net,productionresultssa16.blob.core.windows.net,productionresultssa17.blob.core.windows.net,productionresultssa18.blob.core.windows.net,productionresultssa19.blob.core.windows.net,productionresultssa2.blob.core.windows.net,productionresultssa3.blob.core.windows.net,productionresultssa4.blob.core.windows.net,productionresultssa5.blob.core.windows.net,productionresultssa6.blob.core.windows.net,productionresultssa7.blob.core.windows.net,productionresultssa8.blob.core.windows.net,productionresultssa9.blob.core.windows.net,proxy.golang.org,pub.dartlang.org,pub.dev,public-code-search.fastmcp.app,pypi.org,pypi.python.org,quay.io,raw.githubusercontent.com,registry.bower.io,registry.hub.docker.com,registry.npmjs.com,registry.npmjs.org,registry.terraform.io,registry.yarnpkg.com,releases.hashicorp.com,repo.anaconda.com,repo.clojars.org,repo.continuum.io,repo.gradle.org,repo.grails.org,repo.hex.pm,repo.maven.apache.org,repo.packagist.org,repo.scala-sbt.org,repo.spring.io,repo.typesafe.com,repo.yarnpkg.com,repo1.maven.org,rubygems.org,rubygems.pkg.github.com,s.symcb.com,s.symcd.com,scala-ci.typesafe.com,security.debian.org,security.ubuntu.com,services.gradle.org,sh.rustup.rs,skimdb.npmjs.com,static.crates.io,static.rust-lang.org,storage.googleapis.com,sum.golang.org,swift.org,telemetry.enterprise.githubcopilot.com,telemetry.vercel.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,vault.centos.org,www.cpan.org,www.elastic.co,www.java.com,www.microsoft.com,www.npmjs.com,www.npmjs.org,yarnpkg.com,yum.releases.hashicorp.com,ziglang.org" + 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 + # --- Threat Detection (inline) --- + - name: Check if detection needed + id: detection_guard + if: always() + env: + OUTPUT_TYPES: ${{ steps.collect_output.outputs.output_types }} + HAS_PATCH: ${{ steps.collect_output.outputs.has_patch }} + run: | + if [[ -n "$OUTPUT_TYPES" || "$HAS_PATCH" == "true" ]]; then + echo "run_detection=true" >> "$GITHUB_OUTPUT" + echo "Detection will run: output_types=$OUTPUT_TYPES, has_patch=$HAS_PATCH" + else + echo "run_detection=false" >> "$GITHUB_OUTPUT" + echo "Detection skipped: no agent outputs or patches to analyze" + fi + - name: Clear MCP configuration for detection + if: always() && steps.detection_guard.outputs.run_detection == 'true' + run: | + rm -f /tmp/gh-aw/mcp-config/mcp-servers.json + rm -f /home/runner/.copilot/mcp-config.json + rm -f "$GITHUB_WORKSPACE/.gemini/settings.json" + - name: Prepare threat detection files + if: always() && steps.detection_guard.outputs.run_detection == 'true' + run: | + mkdir -p /tmp/gh-aw/threat-detection/aw-prompts + cp /tmp/gh-aw/aw-prompts/prompt.txt /tmp/gh-aw/threat-detection/aw-prompts/prompt.txt 2>/dev/null || true + cp /tmp/gh-aw/agent_output.json /tmp/gh-aw/threat-detection/agent_output.json 2>/dev/null || true + for f in /tmp/gh-aw/aw-*.patch; do + [ -f "$f" ] && cp "$f" /tmp/gh-aw/threat-detection/ 2>/dev/null || true + done + echo "Prepared threat detection files:" + ls -la /tmp/gh-aw/threat-detection/ 2>/dev/null || true + - name: Setup threat detection + if: always() && steps.detection_guard.outputs.run_detection == 'true' + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + env: + WORKFLOW_NAME: "Autonomy Atomicity Analyzer" + WORKFLOW_DESCRIPTION: "Find patterns that block concurrent development by multiple agents or developers" + HAS_PATCH: ${{ steps.collect_output.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 + if: always() && steps.detection_guard.outputs.run_detection == 'true' + run: | + mkdir -p /tmp/gh-aw/threat-detection + touch /tmp/gh-aw/threat-detection/detection.log + - name: Execute GitHub Copilot CLI + if: always() && steps.detection_guard.outputs.run_detection == 'true' + id: detection_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 + # shellcheck disable=SC1003 + sudo -E awf --env-all --container-workdir "${GITHUB_WORKSPACE}" --allow-domains "api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,github.com,host.docker.internal,raw.githubusercontent.com,registry.npmjs.org,telemetry.enterprise.githubcopilot.com" --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --enable-host-access --image-tag 0.23.0 --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-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 "$(cat /tmp/gh-aw/aw-prompts/prompt.txt)"' 2>&1 | tee -a /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_detection_results + if: always() && steps.detection_guard.outputs.run_detection == 'true' + 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() && steps.detection_guard.outputs.run_detection == 'true' + uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 + with: + name: threat-detection.log + path: /tmp/gh-aw/threat-detection/detection.log + if-no-files-found: ignore + - name: Set detection conclusion + id: detection_conclusion + if: always() + env: + RUN_DETECTION: ${{ steps.detection_guard.outputs.run_detection }} + DETECTION_SUCCESS: ${{ steps.parse_detection_results.outputs.success }} + run: | + if [[ "$RUN_DETECTION" != "true" ]]; then + echo "conclusion=skipped" >> "$GITHUB_OUTPUT" + echo "success=true" >> "$GITHUB_OUTPUT" + echo "Detection was not needed, marking as skipped" + elif [[ "$DETECTION_SUCCESS" == "true" ]]; then + echo "conclusion=success" >> "$GITHUB_OUTPUT" + echo "success=true" >> "$GITHUB_OUTPUT" + echo "Detection passed successfully" + else + echo "conclusion=failure" >> "$GITHUB_OUTPUT" + echo "success=false" >> "$GITHUB_OUTPUT" + echo "Detection found issues" + fi + + conclusion: + needs: + - activation + - agent + - 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@90ebf8057e8e005103b8d123732d2c64c30e9b27 # v0.50.4 + 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: "Autonomy Atomicity Analyzer" + 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: "Autonomy Atomicity Analyzer" + 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: "Autonomy Atomicity Analyzer" + 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-autonomy-atomicity-analyzer" + 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.' }}\",\"activationComments\":\"false\"}" + 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: "Autonomy Atomicity Analyzer" + 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(); + + pre_activation: + runs-on: ubuntu-slim + outputs: + activated: ${{ steps.check_membership.outputs.is_team_member == 'true' }} + matched_command: '' + steps: + - name: Setup Scripts + uses: github/gh-aw/actions/setup@90ebf8057e8e005103b8d123732d2c64c30e9b27 # v0.50.4 + 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 + if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (needs.agent.outputs.detection_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.' }}\",\"activationComments\":\"false\"}" + GH_AW_WORKFLOW_ID: "gh-aw-autonomy-atomicity-analyzer" + GH_AW_WORKFLOW_NAME: "Autonomy Atomicity Analyzer" + outputs: + code_push_failure_count: ${{ steps.process_safe_outputs.outputs.code_push_failure_count }} + code_push_failure_errors: ${{ steps.process_safe_outputs.outputs.code_push_failure_errors }} + 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@90ebf8057e8e005103b8d123732d2c64c30e9b27 # v0.50.4 + 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\":{\"max\":1,\"title_prefix\":\"${{ inputs.title-prefix }} \"},\"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-autonomy-atomicity-analyzer.md b/.github/workflows/gh-aw-autonomy-atomicity-analyzer.md new file mode 100644 index 00000000..e688a111 --- /dev/null +++ b/.github/workflows/gh-aw-autonomy-atomicity-analyzer.md @@ -0,0 +1,159 @@ +--- +inlined-imports: true +name: "Autonomy Atomicity Analyzer" +description: "Find patterns that block concurrent development by multiple agents or developers" +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/previous-findings.md + - gh-aw-fragments/best-of-three-investigation.md + - gh-aw-fragments/scheduled-audit.md + - gh-aw-fragments/network-ecosystems.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: "" + title-prefix: + description: "Title prefix for created issues (e.g. '[autonomy-atomicity]')" + type: string + required: false + default: "[autonomy-atomicity]" + secrets: + COPILOT_GITHUB_TOKEN: + required: true + roles: [admin, maintainer, write] + bots: + - "${{ inputs.allowed-bot-users }}" +concurrency: + group: autonomy-atomicity-analyzer + 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: +strict: false +safe-outputs: + activation-comments: false + noop: + create-issue: + max: 1 + title-prefix: "${{ inputs.title-prefix }} " +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 Autonomy & Atomicity Analyzer — an expert in concurrent development workflows who identifies patterns that cause problems when multiple agents or developers work on the repository simultaneously. + +Your task is to analyze the codebase for autonomy and atomicity blockers — patterns that create contention, merge conflicts, or subtle breakage when parallel changes land. + +**The bar is high.** Only file an issue when you find a concrete, actionable blocker that a maintainer could refactor to improve parallel development. + +## 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 blockers** + - Scan the project structure and identify files with the highest import fan-in and fan-out. + - Look for arrays, objects, or switch statements that act as registries where every new feature must add an entry. + - Identify test files whose scope spans multiple unrelated features. + - Check for module-level mutable state (e.g., `let` declarations at module scope, mutable singletons). + - Review the store/state management layer for patterns that force all features into a single shared object. + +3. **Check for duplicates** + - Search open issues: `repo:{owner}/{repo} is:issue is:open in:title "${{ inputs.title-prefix }}"`. + - Review `/tmp/previous-findings.json` for issues already filed by this agent. + +### What to Look For + +1. **Global mutable state** — singleton stores, module-level variables, or shared caches that multiple features read/write without isolation. Flag cases where adding a new feature requires modifying the same global object or file that every other feature also touches. +2. **Manual routing or registration** — central switch statements, lookup tables, or config arrays where every new feature must add an entry to the same file. These are merge-conflict magnets. +3. **God files** — files that are imported by or import from a disproportionate number of other modules, creating a bottleneck that many concurrent changes must touch. +4. **Over-broad tests** — test files that assert on large snapshots, full-page renders, or integration scenarios covering multiple unrelated features in a single test. These break whenever any of the covered features change, even if the change is correct. +5. **Implicit ordering dependencies** — code that relies on import side effects, specific initialization order, or assumes a particular execution sequence without explicit dependency declaration. +6. **Shared configuration hotspots** — single config files where unrelated changes regularly collide. + +### What to Skip + +- Minor style issues or theoretical problems with no current impact +- Patterns that are already well-isolated or that the team has intentionally centralized +- Issues already tracked by an open issue + +### Quality Gate — When to Noop + +Call `noop` if: +- No concrete, actionable blocker is found. +- Every finding is theoretical with no evidence of actual contention. +- A similar issue is already open. + +"Autonomy Atomicity Analyzer skipped — no concrete concurrent development blockers found." + +### Issue Format + +**Issue title:** Brief summary of the blocker (e.g., "Central visualization registry is a merge-conflict hotspot") + +**Issue body:** + +> ## Autonomy / Atomicity Findings +> +> ### 1. [Brief description] +> **Category:** [Global state | Manual routing | God file | Over-broad test | Ordering dependency | Config hotspot] +> **File(s):** [paths] +> **Problem:** [What happens when two developers or agents change this area concurrently] +> **Suggested fix:** [Brief refactoring sketch] +> +> ### 2. [Next finding...] +> +> ## Suggested Actions +> - [ ] [Specific, actionable checkbox for each improvement] + +### Labeling + +- If the `autonomy-atomicity` label exists (check with `github-get_label`), include it in the `create_issue` call; otherwise, rely on the `${{ inputs.title-prefix }}` title prefix only. + +${{ inputs.additional-instructions }} diff --git a/.github/workflows/gh-aw-bug-exterminator.lock.yml b/.github/workflows/gh-aw-bug-exterminator.lock.yml index 2bc67f6b..bf36d865 100644 --- a/.github/workflows/gh-aw-bug-exterminator.lock.yml +++ b/.github/workflows/gh-aw-bug-exterminator.lock.yml @@ -37,7 +37,7 @@ # # inlined-imports: true # -# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"991407085650d1743069bebc1248a85ae740a054baeec5cc0fc20c6acc359adc"} +# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"45cf942b227f987fa2c177ada5793842c9c740a9a0240beeee6ad4cfa23f9fea"} name: "Gh Aw Bug Exterminator" "on": @@ -913,7 +913,9 @@ jobs: if (contributing) checklist.push(`Review the contributing guide (${contributing}) before opening or updating a PR.`); if (prTemplate) checklist.push(`Follow the PR template (${prTemplate}) for title, description, and validation notes.`); checklist.push('Confirm the requested task is fully completed and validated before creating or pushing PR changes.'); - return { status: 'ok', checklist, contributing_guide: contributing, pr_template: prTemplate }; + const result = { status: 'ok', checklist, contributing_guide: contributing, pr_template: prTemplate }; + console.log(JSON.stringify(result)); + return result; } module.exports = { execute }; GH_AW_SAFE_INPUTS_JS_READY-TO-MAKE-PR_EOF diff --git a/.github/workflows/gh-aw-code-duplication-fixer.lock.yml b/.github/workflows/gh-aw-code-duplication-fixer.lock.yml index bd85f7d3..898c6c5f 100644 --- a/.github/workflows/gh-aw-code-duplication-fixer.lock.yml +++ b/.github/workflows/gh-aw-code-duplication-fixer.lock.yml @@ -37,7 +37,7 @@ # # inlined-imports: true # -# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"1916aa7ab7cfae85db09043ecc595e92be869f27b28ac70db44958a5d0fe71f0"} +# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"c9fc297959faa74e43f0f19feb0aa061f4bfd52f5270de2aa7e445eae583b31e"} name: "Code Duplication Fixer" "on": @@ -915,7 +915,9 @@ jobs: if (contributing) checklist.push(`Review the contributing guide (${contributing}) before opening or updating a PR.`); if (prTemplate) checklist.push(`Follow the PR template (${prTemplate}) for title, description, and validation notes.`); checklist.push('Confirm the requested task is fully completed and validated before creating or pushing PR changes.'); - return { status: 'ok', checklist, contributing_guide: contributing, pr_template: prTemplate }; + const result = { status: 'ok', checklist, contributing_guide: contributing, pr_template: prTemplate }; + console.log(JSON.stringify(result)); + return result; } module.exports = { execute }; GH_AW_SAFE_INPUTS_JS_READY-TO-MAKE-PR_EOF diff --git a/.github/workflows/gh-aw-code-simplifier.lock.yml b/.github/workflows/gh-aw-code-simplifier.lock.yml index 09d04baf..de954ab4 100644 --- a/.github/workflows/gh-aw-code-simplifier.lock.yml +++ b/.github/workflows/gh-aw-code-simplifier.lock.yml @@ -37,7 +37,7 @@ # # inlined-imports: true # -# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"fccbdc4bde9b3be2ec7ad97e71411f0de4c25bf54d54339443e513116290b67f"} +# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"1f851ee8e8378d90735e9163608817728108b4f7d049c2ad35b8241978dedc80"} name: "Code Simplifier" "on": @@ -914,7 +914,9 @@ jobs: if (contributing) checklist.push(`Review the contributing guide (${contributing}) before opening or updating a PR.`); if (prTemplate) checklist.push(`Follow the PR template (${prTemplate}) for title, description, and validation notes.`); checklist.push('Confirm the requested task is fully completed and validated before creating or pushing PR changes.'); - return { status: 'ok', checklist, contributing_guide: contributing, pr_template: prTemplate }; + const result = { status: 'ok', checklist, contributing_guide: contributing, pr_template: prTemplate }; + console.log(JSON.stringify(result)); + return result; } module.exports = { execute }; GH_AW_SAFE_INPUTS_JS_READY-TO-MAKE-PR_EOF diff --git a/.github/workflows/gh-aw-deep-research.lock.yml b/.github/workflows/gh-aw-deep-research.lock.yml index f8bdf57d..0c6c3b1e 100644 --- a/.github/workflows/gh-aw-deep-research.lock.yml +++ b/.github/workflows/gh-aw-deep-research.lock.yml @@ -35,7 +35,7 @@ # # inlined-imports: true # -# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"b0c7fe8b87e88a90feb5b0f431531143fef4d241aaaba7e1ace607437e62c3f4"} +# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"27d2caa68b0f61eb756746772f601a036434d8212d4803cc5a4402fa769ea05a"} name: "Deep Research" "on": @@ -95,8 +95,11 @@ jobs: issues: write pull-requests: write outputs: + body: ${{ steps.sanitized.outputs.body }} comment_id: "" comment_repo: "" + text: ${{ steps.sanitized.outputs.text }} + title: ${{ steps.sanitized.outputs.title }} steps: - name: Setup Scripts uses: github/gh-aw/actions/setup@90ebf8057e8e005103b8d123732d2c64c30e9b27 # v0.50.4 @@ -128,6 +131,15 @@ jobs: setupGlobals(core, github, context, exec, io); const { main } = require('/opt/gh-aw/actions/check_workflow_timestamp_api.cjs'); await main(); + - name: Compute current body text + id: sanitized + 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/compute_text.cjs'); + await main(); - name: Create prompt with built-in context env: GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt @@ -269,7 +281,7 @@ jobs: - **Links**: Max 50 URLs per comment. - **HTML**: Only safe tags allowed (`details`, `summary`, `code`, `pre`, `blockquote`, `table`, `b`, `em`, `strong`, `h1`–`h6`, `hr`, `br`, `li`, `ol`, `ul`, `p`, `sub`, `sup`). Other tags are converted to parentheses. - **URLs**: Only HTTPS URLs to allowed domains. Non-HTTPS and non-allowed domains are redacted. - - **Bot triggers**: References like `fixes #123` or `closes #456` are neutralized to prevent unintended issue closures. + - **Bot triggers**: References like `fixes #123` or `closes #456` are neutralized to prevent unintended issue closures unless it's referencing the triggering issue. If you exceed 10 mentions or 50 links, the comment will be rejected. GH_AW_PROMPT_EOF @@ -1142,7 +1154,6 @@ jobs: permissions: contents: read issues: write - pull-requests: write outputs: noop_message: ${{ steps.noop.outputs.noop_message }} tools_reported: ${{ steps.missing_tool.outputs.tools_reported }} @@ -1276,7 +1287,6 @@ jobs: permissions: contents: read issues: write - pull-requests: write timeout-minutes: 15 env: GH_AW_ENGINE_ID: "gemini" diff --git a/.github/workflows/gh-aw-deep-research.md b/.github/workflows/gh-aw-deep-research.md index 123dc0d2..e3e02f85 100644 --- a/.github/workflows/gh-aw-deep-research.md +++ b/.github/workflows/gh-aw-deep-research.md @@ -84,7 +84,7 @@ Assist with deep research on ${{ github.repository }} from issue comments, then - **Repository**: ${{ github.repository }} - **Issue**: #${{ github.event.issue.number }} — ${{ github.event.issue.title }} -- **Request**: "${{ needs.activation.outputs.text }}" +- **Request**: "${{ steps.sanitized.outputs.text }}" ## Constraints diff --git a/.github/workflows/gh-aw-duplicate-issue-detector.lock.yml b/.github/workflows/gh-aw-duplicate-issue-detector.lock.yml index c1364769..79056e59 100644 --- a/.github/workflows/gh-aw-duplicate-issue-detector.lock.yml +++ b/.github/workflows/gh-aw-duplicate-issue-detector.lock.yml @@ -34,7 +34,7 @@ # # inlined-imports: true # -# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"b3addc3202658342f3d8e756b46197b1c2594a070de7e63553ec4e4e8fa76761"} +# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"94b141c19f85e61b3ae4e0b4149e3092a708d265685e74c0bab7e62170c41900"} name: "Duplicate Issue Detector" "on": @@ -274,7 +274,7 @@ jobs: - **Links**: Max 50 URLs per comment. - **HTML**: Only safe tags allowed (`details`, `summary`, `code`, `pre`, `blockquote`, `table`, `b`, `em`, `strong`, `h1`–`h6`, `hr`, `br`, `li`, `ol`, `ul`, `p`, `sub`, `sup`). Other tags are converted to parentheses. - **URLs**: Only HTTPS URLs to allowed domains. Non-HTTPS and non-allowed domains are redacted. - - **Bot triggers**: References like `fixes #123` or `closes #456` are neutralized to prevent unintended issue closures. + - **Bot triggers**: References like `fixes #123` or `closes #456` are neutralized to prevent unintended issue closures unless it's referencing the triggering issue. If you exceed 10 mentions or 50 links, the comment will be rejected. GH_AW_PROMPT_EOF diff --git a/.github/workflows/gh-aw-fragments/safe-output-add-comment-issue.md b/.github/workflows/gh-aw-fragments/safe-output-add-comment-issue.md index 9b486c07..64f25a6d 100644 --- a/.github/workflows/gh-aw-fragments/safe-output-add-comment-issue.md +++ b/.github/workflows/gh-aw-fragments/safe-output-add-comment-issue.md @@ -2,6 +2,7 @@ safe-outputs: add-comment: max: 1 + pull-requests: false issues: true discussions: false --- @@ -13,6 +14,6 @@ safe-outputs: - **Links**: Max 50 URLs per comment. - **HTML**: Only safe tags allowed (`details`, `summary`, `code`, `pre`, `blockquote`, `table`, `b`, `em`, `strong`, `h1`–`h6`, `hr`, `br`, `li`, `ol`, `ul`, `p`, `sub`, `sup`). Other tags are converted to parentheses. - **URLs**: Only HTTPS URLs to allowed domains. Non-HTTPS and non-allowed domains are redacted. -- **Bot triggers**: References like `fixes #123` or `closes #456` are neutralized to prevent unintended issue closures. +- **Bot triggers**: References like `fixes #123` or `closes #456` are neutralized to prevent unintended issue closures unless it's referencing the triggering issue. If you exceed 10 mentions or 50 links, the comment will be rejected. diff --git a/.github/workflows/gh-aw-fragments/safe-output-add-comment-pr.md b/.github/workflows/gh-aw-fragments/safe-output-add-comment-pr.md index 77e33e7c..3e695de4 100644 --- a/.github/workflows/gh-aw-fragments/safe-output-add-comment-pr.md +++ b/.github/workflows/gh-aw-fragments/safe-output-add-comment-pr.md @@ -2,6 +2,7 @@ safe-outputs: add-comment: max: 1 + issues: false pull-requests: true discussions: false --- diff --git a/.github/workflows/gh-aw-fragments/safe-output-create-pr.md b/.github/workflows/gh-aw-fragments/safe-output-create-pr.md index 61efec8b..7f4abe11 100644 --- a/.github/workflows/gh-aw-fragments/safe-output-create-pr.md +++ b/.github/workflows/gh-aw-fragments/safe-output-create-pr.md @@ -11,7 +11,9 @@ safe-inputs: if (contributing) checklist.push(`Review the contributing guide (${contributing}) before opening or updating a PR.`); if (prTemplate) checklist.push(`Follow the PR template (${prTemplate}) for title, description, and validation notes.`); checklist.push('Confirm the requested task is fully completed and validated before creating or pushing PR changes.'); - return { status: 'ok', checklist, contributing_guide: contributing, pr_template: prTemplate }; + const result = { status: 'ok', checklist, contributing_guide: contributing, pr_template: prTemplate }; + console.log(JSON.stringify(result)); + return result; safe-outputs: create-pull-request: draft: ${{ inputs.draft-prs }} diff --git a/.github/workflows/gh-aw-fragments/safe-output-push-to-pr.md b/.github/workflows/gh-aw-fragments/safe-output-push-to-pr.md index 6f5e8739..4c63410f 100644 --- a/.github/workflows/gh-aw-fragments/safe-output-push-to-pr.md +++ b/.github/workflows/gh-aw-fragments/safe-output-push-to-pr.md @@ -11,7 +11,9 @@ safe-inputs: if (contributing) checklist.push(`Review the contributing guide (${contributing}) before opening or updating a PR.`); if (prTemplate) checklist.push(`Follow the PR template (${prTemplate}) for title, description, and validation notes.`); checklist.push('Confirm the requested task is fully completed and validated before creating or pushing PR changes.'); - return { status: 'ok', checklist, contributing_guide: contributing, pr_template: prTemplate }; + const result = { status: 'ok', checklist, contributing_guide: contributing, pr_template: prTemplate }; + console.log(JSON.stringify(result)); + return result; safe-outputs: push-to-pull-request-branch: --- diff --git a/.github/workflows/gh-aw-framework-best-practices.lock.yml b/.github/workflows/gh-aw-framework-best-practices.lock.yml new file mode 100644 index 00000000..b72bf286 --- /dev/null +++ b/.github/workflows/gh-aw-framework-best-practices.lock.yml @@ -0,0 +1,1483 @@ +# +# ___ _ _ +# / _ \ | | (_) +# | |_| | __ _ ___ _ __ | |_ _ ___ +# | _ |/ _` |/ _ \ '_ \| __| |/ __| +# | | | | (_| | __/ | | | |_| | (__ +# \_| |_/\__, |\___|_| |_|\__|_|\___| +# __/ | +# _ _ |___/ +# | | | | / _| | +# | | | | ___ _ __ _ __| |_| | _____ ____ +# | |/\| |/ _ \ '__| |/ /| _| |/ _ \ \ /\ / / ___| +# \ /\ / (_) | | | | ( | | | | (_) \ 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/ +# +# Find places where library-native features could replace hand-rolled solutions +# +# Resolved workflow manifest: +# Imports: +# - gh-aw-fragments/best-of-three-investigation.md +# - 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/network-ecosystems.md +# - gh-aw-fragments/previous-findings.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":"1ed2241b597ef033c35f72553439ef8585648066c2ae7f0a0bfd72da00e1ff8a"} + +name: "Framework Best Practices" +"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 + title-prefix: + default: "[framework-best-practices]" + description: Title prefix for created issues (e.g. '[framework-best-practices]') + required: false + type: string + secrets: + COPILOT_GITHUB_TOKEN: + required: true + +permissions: {} + +concurrency: + cancel-in-progress: true + group: framework-best-practices + +run-name: "Framework Best Practices" + +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@90ebf8057e8e005103b8d123732d2c64c30e9b27 # v0.50.4 + 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-framework-best-practices.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_EXPR_BF503D80: ${{ inputs.title-prefix }} + 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_EOF + cat "/opt/gh-aw/prompts/xpia.md" + cat "/opt/gh-aw/prompts/temp_folder_prompt.md" + cat "/opt/gh-aw/prompts/markdown.md" + cat "/opt/gh-aw/prompts/safe_outputs_prompt.md" + cat << 'GH_AW_PROMPT_EOF' + + Tools: create_issue, missing_tool, missing_data + + + 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_EOF + cat << 'GH_AW_PROMPT_EOF' + ## 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_EOF + cat << 'GH_AW_PROMPT_EOF' + ## 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' + ## 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 submitting any output, re-read it 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. + - Be thorough, spend the time to investigate and verify. There is no rush. Do your best work. + GH_AW_PROMPT_EOF + cat << 'GH_AW_PROMPT_EOF' + ## 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' + ## 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' + ## 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' + ## Previous Findings + + Before filing a new issue, check `/tmp/previous-findings.json` for issues this agent has already filed. + + - Run `cat /tmp/previous-findings.json` to read the list of previously filed issue numbers and titles. + - If your finding closely matches an open or recently-closed issue in that list, call `noop` instead of filing a duplicate. + - Only file a new issue when the finding is genuinely distinct from all previous findings. + GH_AW_PROMPT_EOF + cat << 'GH_AW_PROMPT_EOF' + ### Best-of-Three Investigation + + For your initial investigation, use multiple sub-agents to explore the codebase and gather the best possible result. Give each sub-agent a unique instruction to explore a different starting point or angle — e.g., different starting points, different approaches, or different heuristics. + + Wait for all the sub-agents to complete. Do not proceed until every sub-agent has returned its result. + + Evaluate the candidates by comparing evidence quality, specificity, and actionability. Prefer candidates with concrete file paths, line numbers, and verifiable evidence over general observations. If most or all sub-agents recommend `noop`, that is a strong signal to `noop`. + + Select the single best candidate and proceed with it. Discard the others. If no candidate meets the quality gate, call `noop`. + GH_AW_PROMPT_EOF + cat << 'GH_AW_PROMPT_EOF' + 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. + + ## 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_EOF + cat << 'GH_AW_PROMPT_EOF' + You are the Framework & Library Best Practices Analyst — an expert in the libraries and frameworks used by this project who identifies opportunities to leverage built-in features instead of hand-rolled solutions. + + Your task is to analyze the codebase, identify the frameworks and libraries in use, and find places where the code could be simplified or improved by using library-native features. + + **The bar is high.** Most codebases make reasonable use of their dependencies; most runs should end with `noop`. Only file an issue when you find a concrete simplification. + + ## Report Assignment + + ### Data Gathering + + 1. **Discover the tech stack** + - Read `package.json`, `go.mod`, `pyproject.toml`, `Cargo.toml`, `pom.xml`, `Gemfile`, or equivalent to identify all dependencies and their versions. + - Read `README.md`, `CONTRIBUTING.md`, and any docs to understand the project's purpose and key technologies. + - Skim the directory structure and key source files to understand the architecture. + + 2. **Scan for library underuse** + - For each major dependency, understand what features it provides at the installed version. + - Search the codebase for patterns that reinvent or work around library features. + - Check configuration files for unnecessary complexity. + - Look for TODOs or workaround comments that reference library limitations that may have been resolved in the current version. + + 3. **Check for duplicates** + - Search open issues: `repo:{owner}/{repo} is:issue is:open in:title "__GH_AW_EXPR_BF503D80__"`. + - Review `/tmp/previous-findings.json` for issues already filed by this agent. + + ### What to Look For + + 1. **Reimplemented library features** — custom utility functions that duplicate what a library already provides (e.g., hand-rolled debounce when `lodash/debounce` is available, custom deep-clone when `structuredClone` or a library function exists). + 2. **State management anti-patterns** — using low-level primitives (e.g., `useState`/`useEffect`) for complex state that the project's state management library handles better; prop drilling through many levels when a store or context is available. + 3. **UI framework underuse** — building custom components (dialogs, tooltips, menus, form controls) when the UI library provides ready-made, accessible versions. + 4. **Build tool configuration** — config files that are overly complex or work around issues that newer versions of the tool have resolved natively. + 5. **Testing patterns** — manual mocking or test setup that testing libraries provide as built-in features. + 6. **Deprecated or legacy patterns** — using older API styles when the library has introduced newer, simpler alternatives. + 7. **Missing framework optimizations** — places where framework-native performance patterns could be applied following the framework's own guidance. + + ### What to Skip + + - Micro-optimizations with no observable impact + - Speculative performance improvements without evidence + - Cases where the custom implementation is intentionally different from the library version (e.g., different error handling, domain-specific logic) + - Findings already tracked by an open issue + + ### Quality Gate — When to Noop + + Call `noop` if: + - You cannot find a concrete simplification where the library feature exists, is stable, and would demonstrably reduce code complexity or improve behavior. + - Every finding is speculative, subjective, or already tracked. + - The codebase makes reasonable use of its dependencies. + + "Framework Best Practices skipped — no concrete library underuse found." + + ### Issue Format + + **Issue title:** Brief summary of the opportunity (e.g., "Replace custom debounce with lodash/debounce already in dependencies") + + **Issue body:** + + > ## Framework / Library Best Practices Findings + > + > ### 1. [Brief description] + > **Library:** [name and version from manifest] + > **Library feature:** [specific API or feature name] + > **Current code:** [file path(s) and brief description of what the code does instead] + > **Simplification:** [how using the library feature would reduce or improve the code] + > **Documentation:** [link to relevant library docs] + > + > ### 2. [Next finding...] + > + > ## Suggested Actions + > - [ ] [Specific, actionable checkbox for each improvement] + + ### Labeling + + - If the `framework-best-practices` label exists (check with `github-get_label`), include it in the `create_issue` call; otherwise, rely on the `__GH_AW_EXPR_BF503D80__` title prefix only. + + __GH_AW_EXPR_49B959F1__ + + GH_AW_PROMPT_EOF + } > "$GH_AW_PROMPT" + - 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_EXPR_49B959F1: ${{ inputs.additional-instructions }} + GH_AW_EXPR_BF503D80: ${{ inputs.title-prefix }} + 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_EXPR_BF503D80: ${{ inputs.title-prefix }} + 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 }} + 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_EXPR_BF503D80: process.env.GH_AW_EXPR_BF503D80, + 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 + } + }); + - 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 + 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: ghawframeworkbestpractices + outputs: + checkout_pr_success: ${{ steps.checkout-pr.outputs.checkout_pr_success || 'true' }} + detection_conclusion: ${{ steps.detection_conclusion.outputs.conclusion }} + detection_success: ${{ steps.detection_conclusion.outputs.success }} + 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@90ebf8057e8e005103b8d123732d2c64c30e9b27 # v0.50.4 + 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: + GH_TOKEN: ${{ github.token }} + TITLE_PREFIX: ${{ inputs.title-prefix }} + name: List previous findings + run: "set -euo pipefail\ngh issue list \\\n --repo \"$GITHUB_REPOSITORY\" \\\n --search \"in:title \\\"$TITLE_PREFIX\\\"\" \\\n --state all \\\n --limit 100 \\\n --json number,title,state \\\n > /tmp/previous-findings.json || { echo \"::warning::Failed to fetch previous findings — dedup will be skipped\"; echo \"[]\" > /tmp/previous-findings.json; }" + - 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]" + git config --global am.keepcr true + # 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.417", + workflow_name: "Framework Best Practices", + 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","clojure","cloud.elastic.co","containers","dart","defaults","dotnet","ela.st","elastic.co","elastic.dev","elixir","fonts","github","github-actions","go","haskell","java","kotlin","linux-distros","node","node-cdns","perl","php","playwright","public-code-search.fastmcp.app","python","ruby","rust","scala","swift","terraform","www.elastic.co","zig"], + firewall_enabled: true, + awf_version: "v0.23.0", + awmg_version: "v0.1.5", + 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.417 + - name: Install awf binary + run: bash /opt/gh-aw/actions/install_awf_binary.sh v0.23.0 + - 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.23.0 ghcr.io/github/gh-aw-firewall/api-proxy:0.23.0 ghcr.io/github/gh-aw-firewall/squid:0.23.0 ghcr.io/github/gh-aw-mcpg:v0.1.5 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":{"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 \"${{ inputs.title-prefix }} \".", + "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.5' + + 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 + # shellcheck disable=SC1003 + sudo -E awf --env-all --container-workdir "${GITHUB_WORKSPACE}" --allow-domains "*.docker.com,*.docker.io,*.githubusercontent.com,*.hackage.haskell.org,*.jsr.io,*.pythonhosted.org,*.rvm.io,*.vsblob.vsassets.io,adoptium.net,agents-md-generator.fastmcp.app,anaconda.org,api.adoptium.net,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.foojay.io,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.npms.io,api.nuget.org,api.rubygems.org,api.snapcraft.io,apt.llvm.org,apt.releases.hashicorp.com,archive.apache.org,archive.ubuntu.com,archlinux.org,artifacts.elastic.co,auth.docker.io,azure.archive.ubuntu.com,azuresearch-usnc.nuget.org,azuresearch-ussc.nuget.org,binstar.org,bitbucket.org,bootstrap.pypa.io,builds.dotnet.microsoft.com,builds.hex.pm,bun.sh,bundler.rubygems.org,cache.ruby-lang.org,cdn.azul.com,cdn.cocoapods.org,cdn.hex.pm,cdn.jsdelivr.net,cdn.playwright.dev,cdn.redhat.com,cdn.sheetjs.com,central.sonatype.com,ci.dot.net,clojars.org,cloud.elastic.co,cocoapods.org,code.jquery.com,codeload.github.com,conda.anaconda.org,conda.binstar.org,cpan.metacpan.org,cpan.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,data.jsdelivr.com,dc.services.visualstudio.com,deb.debian.org,deb.nodesource.com,debian.map.fastlydns.net,deno.land,dist.nuget.org,dl-cdn.alpinelinux.org,dl.bintray.com,dl.fedoraproject.org,dl.google.com,dl.k8s.io,dlcdn.apache.org,dot.net,dotnet.microsoft.com,dotnetcli.blob.core.windows.net,download.eclipse.org,download.fedoraproject.org,download.java.net,download.opensuse.org,download.oracle.com,download.swift.org,downloads.gradle-dn.com,downloads.haskell.org,ela.st,elastic.co,elastic.dev,esm.sh,fastly.hex.pm,files.pythonhosted.org,fonts.googleapis.com,fonts.gstatic.com,gcr.io,ge.jetbrains.com,gems.rubyforge.org,gems.rubyonrails.org,get-ghcup.haskell.org,get.pnpm.io,getcomposer.org,ghcr.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,gradle.org,haskell.org,hex.pm,host.docker.internal,index.crates.io,index.rubygems.org,jcenter.bintray.com,jdk.java.net,jitpack.io,json-schema.org,json.schemastore.org,jsr.io,keyring.debian.org,keyserver.ubuntu.com,kotlin.bintray.com,lfs.github.com,maven.apache.org,maven.google.com,maven.oracle.com,maven.pkg.github.com,mcr.microsoft.com,metacpan.org,mirror.archlinux.org,mirror.centos.org,mirrors.fedoraproject.org,nodejs.org,npm.pkg.github.com,npmjs.com,npmjs.org,nuget.org,nuget.pkg.github.com,nugetregistryv2prod.blob.core.windows.net,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,oneocsp.microsoft.com,packagecloud.io,packages.cloud.google.com,packages.debian.org,packages.jetbrains.team,packages.microsoft.com,packagist.org,pip.pypa.io,pkg.alpinelinux.org,pkg.go.dev,pkg.machengine.org,pkgs.dev.azure.com,pkgs.k8s.io,playwright.download.prss.microsoft.com,plugins-artifacts.gradle.org,plugins.gradle.org,ppa.launchpad.net,production.cloudflare.docker.com,productionresultssa0.blob.core.windows.net,productionresultssa1.blob.core.windows.net,productionresultssa10.blob.core.windows.net,productionresultssa11.blob.core.windows.net,productionresultssa12.blob.core.windows.net,productionresultssa13.blob.core.windows.net,productionresultssa14.blob.core.windows.net,productionresultssa15.blob.core.windows.net,productionresultssa16.blob.core.windows.net,productionresultssa17.blob.core.windows.net,productionresultssa18.blob.core.windows.net,productionresultssa19.blob.core.windows.net,productionresultssa2.blob.core.windows.net,productionresultssa3.blob.core.windows.net,productionresultssa4.blob.core.windows.net,productionresultssa5.blob.core.windows.net,productionresultssa6.blob.core.windows.net,productionresultssa7.blob.core.windows.net,productionresultssa8.blob.core.windows.net,productionresultssa9.blob.core.windows.net,proxy.golang.org,pub.dartlang.org,pub.dev,public-code-search.fastmcp.app,pypi.org,pypi.python.org,quay.io,raw.githubusercontent.com,registry.bower.io,registry.hub.docker.com,registry.npmjs.com,registry.npmjs.org,registry.terraform.io,registry.yarnpkg.com,releases.hashicorp.com,repo.anaconda.com,repo.clojars.org,repo.continuum.io,repo.gradle.org,repo.grails.org,repo.hex.pm,repo.maven.apache.org,repo.packagist.org,repo.scala-sbt.org,repo.spring.io,repo.typesafe.com,repo.yarnpkg.com,repo1.maven.org,rubygems.org,rubygems.pkg.github.com,s.symcb.com,s.symcd.com,scala-ci.typesafe.com,security.debian.org,security.ubuntu.com,services.gradle.org,sh.rustup.rs,skimdb.npmjs.com,static.crates.io,static.rust-lang.org,storage.googleapis.com,sum.golang.org,swift.org,telemetry.enterprise.githubcopilot.com,telemetry.vercel.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,vault.centos.org,www.cpan.org,www.elastic.co,www.java.com,www.microsoft.com,www.npmjs.com,www.npmjs.org,yarnpkg.com,yum.releases.hashicorp.com,ziglang.org" --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --enable-host-access --image-tag 0.23.0 --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]" + git config --global am.keepcr true + # 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: "*.docker.com,*.docker.io,*.githubusercontent.com,*.hackage.haskell.org,*.jsr.io,*.pythonhosted.org,*.rvm.io,*.vsblob.vsassets.io,adoptium.net,agents-md-generator.fastmcp.app,anaconda.org,api.adoptium.net,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.foojay.io,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.npms.io,api.nuget.org,api.rubygems.org,api.snapcraft.io,apt.llvm.org,apt.releases.hashicorp.com,archive.apache.org,archive.ubuntu.com,archlinux.org,artifacts.elastic.co,auth.docker.io,azure.archive.ubuntu.com,azuresearch-usnc.nuget.org,azuresearch-ussc.nuget.org,binstar.org,bitbucket.org,bootstrap.pypa.io,builds.dotnet.microsoft.com,builds.hex.pm,bun.sh,bundler.rubygems.org,cache.ruby-lang.org,cdn.azul.com,cdn.cocoapods.org,cdn.hex.pm,cdn.jsdelivr.net,cdn.playwright.dev,cdn.redhat.com,cdn.sheetjs.com,central.sonatype.com,ci.dot.net,clojars.org,cloud.elastic.co,cocoapods.org,code.jquery.com,codeload.github.com,conda.anaconda.org,conda.binstar.org,cpan.metacpan.org,cpan.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,data.jsdelivr.com,dc.services.visualstudio.com,deb.debian.org,deb.nodesource.com,debian.map.fastlydns.net,deno.land,dist.nuget.org,dl-cdn.alpinelinux.org,dl.bintray.com,dl.fedoraproject.org,dl.google.com,dl.k8s.io,dlcdn.apache.org,dot.net,dotnet.microsoft.com,dotnetcli.blob.core.windows.net,download.eclipse.org,download.fedoraproject.org,download.java.net,download.opensuse.org,download.oracle.com,download.swift.org,downloads.gradle-dn.com,downloads.haskell.org,ela.st,elastic.co,elastic.dev,esm.sh,fastly.hex.pm,files.pythonhosted.org,fonts.googleapis.com,fonts.gstatic.com,gcr.io,ge.jetbrains.com,gems.rubyforge.org,gems.rubyonrails.org,get-ghcup.haskell.org,get.pnpm.io,getcomposer.org,ghcr.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,gradle.org,haskell.org,hex.pm,host.docker.internal,index.crates.io,index.rubygems.org,jcenter.bintray.com,jdk.java.net,jitpack.io,json-schema.org,json.schemastore.org,jsr.io,keyring.debian.org,keyserver.ubuntu.com,kotlin.bintray.com,lfs.github.com,maven.apache.org,maven.google.com,maven.oracle.com,maven.pkg.github.com,mcr.microsoft.com,metacpan.org,mirror.archlinux.org,mirror.centos.org,mirrors.fedoraproject.org,nodejs.org,npm.pkg.github.com,npmjs.com,npmjs.org,nuget.org,nuget.pkg.github.com,nugetregistryv2prod.blob.core.windows.net,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,oneocsp.microsoft.com,packagecloud.io,packages.cloud.google.com,packages.debian.org,packages.jetbrains.team,packages.microsoft.com,packagist.org,pip.pypa.io,pkg.alpinelinux.org,pkg.go.dev,pkg.machengine.org,pkgs.dev.azure.com,pkgs.k8s.io,playwright.download.prss.microsoft.com,plugins-artifacts.gradle.org,plugins.gradle.org,ppa.launchpad.net,production.cloudflare.docker.com,productionresultssa0.blob.core.windows.net,productionresultssa1.blob.core.windows.net,productionresultssa10.blob.core.windows.net,productionresultssa11.blob.core.windows.net,productionresultssa12.blob.core.windows.net,productionresultssa13.blob.core.windows.net,productionresultssa14.blob.core.windows.net,productionresultssa15.blob.core.windows.net,productionresultssa16.blob.core.windows.net,productionresultssa17.blob.core.windows.net,productionresultssa18.blob.core.windows.net,productionresultssa19.blob.core.windows.net,productionresultssa2.blob.core.windows.net,productionresultssa3.blob.core.windows.net,productionresultssa4.blob.core.windows.net,productionresultssa5.blob.core.windows.net,productionresultssa6.blob.core.windows.net,productionresultssa7.blob.core.windows.net,productionresultssa8.blob.core.windows.net,productionresultssa9.blob.core.windows.net,proxy.golang.org,pub.dartlang.org,pub.dev,public-code-search.fastmcp.app,pypi.org,pypi.python.org,quay.io,raw.githubusercontent.com,registry.bower.io,registry.hub.docker.com,registry.npmjs.com,registry.npmjs.org,registry.terraform.io,registry.yarnpkg.com,releases.hashicorp.com,repo.anaconda.com,repo.clojars.org,repo.continuum.io,repo.gradle.org,repo.grails.org,repo.hex.pm,repo.maven.apache.org,repo.packagist.org,repo.scala-sbt.org,repo.spring.io,repo.typesafe.com,repo.yarnpkg.com,repo1.maven.org,rubygems.org,rubygems.pkg.github.com,s.symcb.com,s.symcd.com,scala-ci.typesafe.com,security.debian.org,security.ubuntu.com,services.gradle.org,sh.rustup.rs,skimdb.npmjs.com,static.crates.io,static.rust-lang.org,storage.googleapis.com,sum.golang.org,swift.org,telemetry.enterprise.githubcopilot.com,telemetry.vercel.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,vault.centos.org,www.cpan.org,www.elastic.co,www.java.com,www.microsoft.com,www.npmjs.com,www.npmjs.org,yarnpkg.com,yum.releases.hashicorp.com,ziglang.org" + 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 + # --- Threat Detection (inline) --- + - name: Check if detection needed + id: detection_guard + if: always() + env: + OUTPUT_TYPES: ${{ steps.collect_output.outputs.output_types }} + HAS_PATCH: ${{ steps.collect_output.outputs.has_patch }} + run: | + if [[ -n "$OUTPUT_TYPES" || "$HAS_PATCH" == "true" ]]; then + echo "run_detection=true" >> "$GITHUB_OUTPUT" + echo "Detection will run: output_types=$OUTPUT_TYPES, has_patch=$HAS_PATCH" + else + echo "run_detection=false" >> "$GITHUB_OUTPUT" + echo "Detection skipped: no agent outputs or patches to analyze" + fi + - name: Clear MCP configuration for detection + if: always() && steps.detection_guard.outputs.run_detection == 'true' + run: | + rm -f /tmp/gh-aw/mcp-config/mcp-servers.json + rm -f /home/runner/.copilot/mcp-config.json + rm -f "$GITHUB_WORKSPACE/.gemini/settings.json" + - name: Prepare threat detection files + if: always() && steps.detection_guard.outputs.run_detection == 'true' + run: | + mkdir -p /tmp/gh-aw/threat-detection/aw-prompts + cp /tmp/gh-aw/aw-prompts/prompt.txt /tmp/gh-aw/threat-detection/aw-prompts/prompt.txt 2>/dev/null || true + cp /tmp/gh-aw/agent_output.json /tmp/gh-aw/threat-detection/agent_output.json 2>/dev/null || true + for f in /tmp/gh-aw/aw-*.patch; do + [ -f "$f" ] && cp "$f" /tmp/gh-aw/threat-detection/ 2>/dev/null || true + done + echo "Prepared threat detection files:" + ls -la /tmp/gh-aw/threat-detection/ 2>/dev/null || true + - name: Setup threat detection + if: always() && steps.detection_guard.outputs.run_detection == 'true' + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + env: + WORKFLOW_NAME: "Framework Best Practices" + WORKFLOW_DESCRIPTION: "Find places where library-native features could replace hand-rolled solutions" + HAS_PATCH: ${{ steps.collect_output.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 + if: always() && steps.detection_guard.outputs.run_detection == 'true' + run: | + mkdir -p /tmp/gh-aw/threat-detection + touch /tmp/gh-aw/threat-detection/detection.log + - name: Execute GitHub Copilot CLI + if: always() && steps.detection_guard.outputs.run_detection == 'true' + id: detection_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 + # shellcheck disable=SC1003 + sudo -E awf --env-all --container-workdir "${GITHUB_WORKSPACE}" --allow-domains "api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,github.com,host.docker.internal,raw.githubusercontent.com,registry.npmjs.org,telemetry.enterprise.githubcopilot.com" --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --enable-host-access --image-tag 0.23.0 --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-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 "$(cat /tmp/gh-aw/aw-prompts/prompt.txt)"' 2>&1 | tee -a /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_detection_results + if: always() && steps.detection_guard.outputs.run_detection == 'true' + 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() && steps.detection_guard.outputs.run_detection == 'true' + uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 + with: + name: threat-detection.log + path: /tmp/gh-aw/threat-detection/detection.log + if-no-files-found: ignore + - name: Set detection conclusion + id: detection_conclusion + if: always() + env: + RUN_DETECTION: ${{ steps.detection_guard.outputs.run_detection }} + DETECTION_SUCCESS: ${{ steps.parse_detection_results.outputs.success }} + run: | + if [[ "$RUN_DETECTION" != "true" ]]; then + echo "conclusion=skipped" >> "$GITHUB_OUTPUT" + echo "success=true" >> "$GITHUB_OUTPUT" + echo "Detection was not needed, marking as skipped" + elif [[ "$DETECTION_SUCCESS" == "true" ]]; then + echo "conclusion=success" >> "$GITHUB_OUTPUT" + echo "success=true" >> "$GITHUB_OUTPUT" + echo "Detection passed successfully" + else + echo "conclusion=failure" >> "$GITHUB_OUTPUT" + echo "success=false" >> "$GITHUB_OUTPUT" + echo "Detection found issues" + fi + + conclusion: + needs: + - activation + - agent + - 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@90ebf8057e8e005103b8d123732d2c64c30e9b27 # v0.50.4 + 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: "Framework Best Practices" + 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: "Framework Best Practices" + 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: "Framework Best Practices" + 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-framework-best-practices" + 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.' }}\",\"activationComments\":\"false\"}" + 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: "Framework Best Practices" + 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(); + + pre_activation: + runs-on: ubuntu-slim + outputs: + activated: ${{ steps.check_membership.outputs.is_team_member == 'true' }} + matched_command: '' + steps: + - name: Setup Scripts + uses: github/gh-aw/actions/setup@90ebf8057e8e005103b8d123732d2c64c30e9b27 # v0.50.4 + 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 + if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (needs.agent.outputs.detection_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.' }}\",\"activationComments\":\"false\"}" + GH_AW_WORKFLOW_ID: "gh-aw-framework-best-practices" + GH_AW_WORKFLOW_NAME: "Framework Best Practices" + outputs: + code_push_failure_count: ${{ steps.process_safe_outputs.outputs.code_push_failure_count }} + code_push_failure_errors: ${{ steps.process_safe_outputs.outputs.code_push_failure_errors }} + 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@90ebf8057e8e005103b8d123732d2c64c30e9b27 # v0.50.4 + 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\":{\"max\":1,\"title_prefix\":\"${{ inputs.title-prefix }} \"},\"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-framework-best-practices.md b/.github/workflows/gh-aw-framework-best-practices.md new file mode 100644 index 00000000..a1832bae --- /dev/null +++ b/.github/workflows/gh-aw-framework-best-practices.md @@ -0,0 +1,162 @@ +--- +inlined-imports: true +name: "Framework Best Practices" +description: "Find places where library-native features could replace hand-rolled solutions" +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/previous-findings.md + - gh-aw-fragments/best-of-three-investigation.md + - gh-aw-fragments/scheduled-audit.md + - gh-aw-fragments/network-ecosystems.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: "" + title-prefix: + description: "Title prefix for created issues (e.g. '[framework-best-practices]')" + type: string + required: false + default: "[framework-best-practices]" + secrets: + COPILOT_GITHUB_TOKEN: + required: true + roles: [admin, maintainer, write] + bots: + - "${{ inputs.allowed-bot-users }}" +concurrency: + group: framework-best-practices + 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: +strict: false +safe-outputs: + activation-comments: false + noop: + create-issue: + max: 1 + title-prefix: "${{ inputs.title-prefix }} " +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 Framework & Library Best Practices Analyst — an expert in the libraries and frameworks used by this project who identifies opportunities to leverage built-in features instead of hand-rolled solutions. + +Your task is to analyze the codebase, identify the frameworks and libraries in use, and find places where the code could be simplified or improved by using library-native features. + +**The bar is high.** Most codebases make reasonable use of their dependencies; most runs should end with `noop`. Only file an issue when you find a concrete simplification. + +## Report Assignment + +### Data Gathering + +1. **Discover the tech stack** + - Read `package.json`, `go.mod`, `pyproject.toml`, `Cargo.toml`, `pom.xml`, `Gemfile`, or equivalent to identify all dependencies and their versions. + - Read `README.md`, `CONTRIBUTING.md`, and any docs to understand the project's purpose and key technologies. + - Skim the directory structure and key source files to understand the architecture. + +2. **Scan for library underuse** + - For each major dependency, understand what features it provides at the installed version. + - Search the codebase for patterns that reinvent or work around library features. + - Check configuration files for unnecessary complexity. + - Look for TODOs or workaround comments that reference library limitations that may have been resolved in the current version. + +3. **Check for duplicates** + - Search open issues: `repo:{owner}/{repo} is:issue is:open in:title "${{ inputs.title-prefix }}"`. + - Review `/tmp/previous-findings.json` for issues already filed by this agent. + +### What to Look For + +1. **Reimplemented library features** — custom utility functions that duplicate what a library already provides (e.g., hand-rolled debounce when `lodash/debounce` is available, custom deep-clone when `structuredClone` or a library function exists). +2. **State management anti-patterns** — using low-level primitives (e.g., `useState`/`useEffect`) for complex state that the project's state management library handles better; prop drilling through many levels when a store or context is available. +3. **UI framework underuse** — building custom components (dialogs, tooltips, menus, form controls) when the UI library provides ready-made, accessible versions. +4. **Build tool configuration** — config files that are overly complex or work around issues that newer versions of the tool have resolved natively. +5. **Testing patterns** — manual mocking or test setup that testing libraries provide as built-in features. +6. **Deprecated or legacy patterns** — using older API styles when the library has introduced newer, simpler alternatives. +7. **Missing framework optimizations** — places where framework-native performance patterns could be applied following the framework's own guidance. + +### What to Skip + +- Micro-optimizations with no observable impact +- Speculative performance improvements without evidence +- Cases where the custom implementation is intentionally different from the library version (e.g., different error handling, domain-specific logic) +- Findings already tracked by an open issue + +### Quality Gate — When to Noop + +Call `noop` if: +- You cannot find a concrete simplification where the library feature exists, is stable, and would demonstrably reduce code complexity or improve behavior. +- Every finding is speculative, subjective, or already tracked. +- The codebase makes reasonable use of its dependencies. + +"Framework Best Practices skipped — no concrete library underuse found." + +### Issue Format + +**Issue title:** Brief summary of the opportunity (e.g., "Replace custom debounce with lodash/debounce already in dependencies") + +**Issue body:** + +> ## Framework / Library Best Practices Findings +> +> ### 1. [Brief description] +> **Library:** [name and version from manifest] +> **Library feature:** [specific API or feature name] +> **Current code:** [file path(s) and brief description of what the code does instead] +> **Simplification:** [how using the library feature would reduce or improve the code] +> **Documentation:** [link to relevant library docs] +> +> ### 2. [Next finding...] +> +> ## Suggested Actions +> - [ ] [Specific, actionable checkbox for each improvement] + +### Labeling + +- If the `framework-best-practices` label exists (check with `github-get_label`), include it in the `create_issue` call; otherwise, rely on the `${{ inputs.title-prefix }}` title prefix only. + +${{ inputs.additional-instructions }} diff --git a/.github/workflows/gh-aw-information-architecture.lock.yml b/.github/workflows/gh-aw-information-architecture.lock.yml new file mode 100644 index 00000000..5f802cde --- /dev/null +++ b/.github/workflows/gh-aw-information-architecture.lock.yml @@ -0,0 +1,1481 @@ +# +# ___ _ _ +# / _ \ | | (_) +# | |_| | __ _ ___ _ __ | |_ _ ___ +# | _ |/ _` |/ _ \ '_ \| __| |/ __| +# | | | | (_| | __/ | | | |_| | (__ +# \_| |_/\__, |\___|_| |_|\__|_|\___| +# __/ | +# _ _ |___/ +# | | | | / _| | +# | | | | ___ _ __ _ __| |_| | _____ ____ +# | |/\| |/ _ \ '__| |/ /| _| |/ _ \ \ /\ / / ___| +# \ /\ / (_) | | | | ( | | | | (_) \ 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/ +# +# Audit the application's UI information architecture for navigation, placement, and consistency issues +# +# Resolved workflow manifest: +# Imports: +# - gh-aw-fragments/best-of-three-investigation.md +# - 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/network-ecosystems.md +# - gh-aw-fragments/previous-findings.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":"ac8f92c7b3122ba4140d78aa3b1eeee470d650a54e25a56ce4221609d710d721"} + +name: "Information Architecture" +"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 + title-prefix: + default: "[information-architecture]" + description: Title prefix for created issues (e.g. '[information-architecture]') + required: false + type: string + secrets: + COPILOT_GITHUB_TOKEN: + required: true + +permissions: {} + +concurrency: + cancel-in-progress: true + group: information-architecture + +run-name: "Information Architecture" + +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@90ebf8057e8e005103b8d123732d2c64c30e9b27 # v0.50.4 + 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-information-architecture.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_EXPR_BF503D80: ${{ inputs.title-prefix }} + 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_EOF + cat "/opt/gh-aw/prompts/xpia.md" + cat "/opt/gh-aw/prompts/temp_folder_prompt.md" + cat "/opt/gh-aw/prompts/markdown.md" + cat "/opt/gh-aw/prompts/safe_outputs_prompt.md" + cat << 'GH_AW_PROMPT_EOF' + + Tools: create_issue, missing_tool, missing_data + + + 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_EOF + cat << 'GH_AW_PROMPT_EOF' + ## 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_EOF + cat << 'GH_AW_PROMPT_EOF' + ## 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' + ## 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 submitting any output, re-read it 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. + - Be thorough, spend the time to investigate and verify. There is no rush. Do your best work. + GH_AW_PROMPT_EOF + cat << 'GH_AW_PROMPT_EOF' + ## 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' + ## 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' + ## 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' + ## Previous Findings + + Before filing a new issue, check `/tmp/previous-findings.json` for issues this agent has already filed. + + - Run `cat /tmp/previous-findings.json` to read the list of previously filed issue numbers and titles. + - If your finding closely matches an open or recently-closed issue in that list, call `noop` instead of filing a duplicate. + - Only file a new issue when the finding is genuinely distinct from all previous findings. + GH_AW_PROMPT_EOF + cat << 'GH_AW_PROMPT_EOF' + ### Best-of-Three Investigation + + For your initial investigation, use multiple sub-agents to explore the codebase and gather the best possible result. Give each sub-agent a unique instruction to explore a different starting point or angle — e.g., different starting points, different approaches, or different heuristics. + + Wait for all the sub-agents to complete. Do not proceed until every sub-agent has returned its result. + + Evaluate the candidates by comparing evidence quality, specificity, and actionability. Prefer candidates with concrete file paths, line numbers, and verifiable evidence over general observations. If most or all sub-agents recommend `noop`, that is a strong signal to `noop`. + + Select the single best candidate and proceed with it. Discard the others. If no candidate meets the quality gate, call `noop`. + GH_AW_PROMPT_EOF + cat << 'GH_AW_PROMPT_EOF' + 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. + + ## 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_EOF + cat << 'GH_AW_PROMPT_EOF' + You are the Information Architecture Analyst — a UX expert who evaluates whether the application's interface is logically organized, navigable, and consistent. + + Your task is to analyze the codebase and identify concrete information architecture problems — places where users would likely get confused, lost, or frustrated because controls, data, or navigation elements are in unexpected locations. + + **The bar is high.** Most UIs have minor rough edges that are not worth filing. Only file an issue when you find a concrete, user-impacting IA problem. + + ## Report Assignment + + ### Data Gathering + + 1. **Understand the product** + - Read `README.md` and any docs to understand the application's purpose, target users, and key flows. + - Identify the entry point component (e.g., `App.tsx`, `Layout.tsx`, `index.tsx`, or equivalent). + + 2. **Trace the component tree** + - Starting from the top-level App/Layout component, trace the navigation structure — how does a user move between features? + - For each major feature area, examine the component hierarchy and props to understand what controls are rendered and where. + - Compare similar features for layout consistency. + - Look at how the app handles edge cases: no data, loading states, errors, onboarding. + + 3. **Check for duplicates** + - Search open issues: `repo:{owner}/{repo} is:issue is:open in:title "__GH_AW_EXPR_BF503D80__"`. + - Review `/tmp/previous-findings.json` for issues already filed by this agent. + + ### What to Look For + + 1. **Navigation flow** — Are navigation elements (sidebar, tabs, breadcrumbs) consistent and logically ordered? Can users reach all major features from the main navigation? Are there dead ends or orphan views? + 2. **Button and action placement** — Are primary actions placed where users expect them? Are destructive actions visually distinct and appropriately guarded with confirmations? + 3. **Picker and selector placement** — Are pickers (date pickers, dropdowns, type selectors) positioned near the content they affect? Are there pickers in headers or toolbars that should be in context, or vice versa? + 4. **Data presentation** — Is data presented in the most appropriate format for its type? Are labels clear and consistent? + 5. **Progressive disclosure** — Are advanced options hidden behind expandable sections or secondary menus? Or is the UI overwhelming users with too many options at once? + 6. **Grouping and hierarchy** — Are related controls grouped together visually? Is there a clear visual hierarchy? + 7. **Consistency** — Do similar features use similar layouts? If one panel has controls in a toolbar, do other panels follow the same pattern? + 8. **Empty states and onboarding** — When there is no data, does the UI guide the user toward the next action? + + ### What to Skip + + - Subjective aesthetic preferences or minor spacing issues + - Problems that require user research to validate (no concrete evidence from the code) + - Issues already tracked by an open issue + + ### Quality Gate — When to Noop + + Call `noop` if: + - You cannot find a concrete, user-impacting IA problem supported by specific component paths. + - All findings are subjective style preferences. + - A similar issue is already open. + + "Information Architecture skipped — no concrete IA problem found." + + ### Issue Format + + **Issue title:** Brief summary of the IA problem (e.g., "Panel type selector is disconnected from the panel it configures") + + **Issue body:** + + > ## Information Architecture Findings + > + > ### 1. [Brief description] + > **Area:** [Navigation | Action placement | Picker placement | Data presentation | Disclosure | Grouping | Consistency | Empty states] + > **Component(s):** [file paths] + > **Problem:** [What the user experiences and why it is confusing] + > **Suggested improvement:** [Brief description of a better arrangement] + > + > ### 2. [Next finding...] + > + > ## Suggested Actions + > - [ ] [Specific, actionable checkbox for each improvement] + + ### Labeling + + - If the `information-architecture` label exists (check with `github-get_label`), include it in the `create_issue` call; otherwise, rely on the `__GH_AW_EXPR_BF503D80__` title prefix only. + + __GH_AW_EXPR_49B959F1__ + + GH_AW_PROMPT_EOF + } > "$GH_AW_PROMPT" + - 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_EXPR_49B959F1: ${{ inputs.additional-instructions }} + GH_AW_EXPR_BF503D80: ${{ inputs.title-prefix }} + 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_EXPR_BF503D80: ${{ inputs.title-prefix }} + 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 }} + 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_EXPR_BF503D80: process.env.GH_AW_EXPR_BF503D80, + 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 + } + }); + - 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 + 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: ghawinformationarchitecture + outputs: + checkout_pr_success: ${{ steps.checkout-pr.outputs.checkout_pr_success || 'true' }} + detection_conclusion: ${{ steps.detection_conclusion.outputs.conclusion }} + detection_success: ${{ steps.detection_conclusion.outputs.success }} + 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@90ebf8057e8e005103b8d123732d2c64c30e9b27 # v0.50.4 + 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: + GH_TOKEN: ${{ github.token }} + TITLE_PREFIX: ${{ inputs.title-prefix }} + name: List previous findings + run: "set -euo pipefail\ngh issue list \\\n --repo \"$GITHUB_REPOSITORY\" \\\n --search \"in:title \\\"$TITLE_PREFIX\\\"\" \\\n --state all \\\n --limit 100 \\\n --json number,title,state \\\n > /tmp/previous-findings.json || { echo \"::warning::Failed to fetch previous findings — dedup will be skipped\"; echo \"[]\" > /tmp/previous-findings.json; }" + - 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]" + git config --global am.keepcr true + # 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.417", + workflow_name: "Information Architecture", + 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","clojure","cloud.elastic.co","containers","dart","defaults","dotnet","ela.st","elastic.co","elastic.dev","elixir","fonts","github","github-actions","go","haskell","java","kotlin","linux-distros","node","node-cdns","perl","php","playwright","public-code-search.fastmcp.app","python","ruby","rust","scala","swift","terraform","www.elastic.co","zig"], + firewall_enabled: true, + awf_version: "v0.23.0", + awmg_version: "v0.1.5", + 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.417 + - name: Install awf binary + run: bash /opt/gh-aw/actions/install_awf_binary.sh v0.23.0 + - 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.23.0 ghcr.io/github/gh-aw-firewall/api-proxy:0.23.0 ghcr.io/github/gh-aw-firewall/squid:0.23.0 ghcr.io/github/gh-aw-mcpg:v0.1.5 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":{"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 \"${{ inputs.title-prefix }} \".", + "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.5' + + 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 + # shellcheck disable=SC1003 + sudo -E awf --env-all --container-workdir "${GITHUB_WORKSPACE}" --allow-domains "*.docker.com,*.docker.io,*.githubusercontent.com,*.hackage.haskell.org,*.jsr.io,*.pythonhosted.org,*.rvm.io,*.vsblob.vsassets.io,adoptium.net,agents-md-generator.fastmcp.app,anaconda.org,api.adoptium.net,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.foojay.io,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.npms.io,api.nuget.org,api.rubygems.org,api.snapcraft.io,apt.llvm.org,apt.releases.hashicorp.com,archive.apache.org,archive.ubuntu.com,archlinux.org,artifacts.elastic.co,auth.docker.io,azure.archive.ubuntu.com,azuresearch-usnc.nuget.org,azuresearch-ussc.nuget.org,binstar.org,bitbucket.org,bootstrap.pypa.io,builds.dotnet.microsoft.com,builds.hex.pm,bun.sh,bundler.rubygems.org,cache.ruby-lang.org,cdn.azul.com,cdn.cocoapods.org,cdn.hex.pm,cdn.jsdelivr.net,cdn.playwright.dev,cdn.redhat.com,cdn.sheetjs.com,central.sonatype.com,ci.dot.net,clojars.org,cloud.elastic.co,cocoapods.org,code.jquery.com,codeload.github.com,conda.anaconda.org,conda.binstar.org,cpan.metacpan.org,cpan.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,data.jsdelivr.com,dc.services.visualstudio.com,deb.debian.org,deb.nodesource.com,debian.map.fastlydns.net,deno.land,dist.nuget.org,dl-cdn.alpinelinux.org,dl.bintray.com,dl.fedoraproject.org,dl.google.com,dl.k8s.io,dlcdn.apache.org,dot.net,dotnet.microsoft.com,dotnetcli.blob.core.windows.net,download.eclipse.org,download.fedoraproject.org,download.java.net,download.opensuse.org,download.oracle.com,download.swift.org,downloads.gradle-dn.com,downloads.haskell.org,ela.st,elastic.co,elastic.dev,esm.sh,fastly.hex.pm,files.pythonhosted.org,fonts.googleapis.com,fonts.gstatic.com,gcr.io,ge.jetbrains.com,gems.rubyforge.org,gems.rubyonrails.org,get-ghcup.haskell.org,get.pnpm.io,getcomposer.org,ghcr.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,gradle.org,haskell.org,hex.pm,host.docker.internal,index.crates.io,index.rubygems.org,jcenter.bintray.com,jdk.java.net,jitpack.io,json-schema.org,json.schemastore.org,jsr.io,keyring.debian.org,keyserver.ubuntu.com,kotlin.bintray.com,lfs.github.com,maven.apache.org,maven.google.com,maven.oracle.com,maven.pkg.github.com,mcr.microsoft.com,metacpan.org,mirror.archlinux.org,mirror.centos.org,mirrors.fedoraproject.org,nodejs.org,npm.pkg.github.com,npmjs.com,npmjs.org,nuget.org,nuget.pkg.github.com,nugetregistryv2prod.blob.core.windows.net,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,oneocsp.microsoft.com,packagecloud.io,packages.cloud.google.com,packages.debian.org,packages.jetbrains.team,packages.microsoft.com,packagist.org,pip.pypa.io,pkg.alpinelinux.org,pkg.go.dev,pkg.machengine.org,pkgs.dev.azure.com,pkgs.k8s.io,playwright.download.prss.microsoft.com,plugins-artifacts.gradle.org,plugins.gradle.org,ppa.launchpad.net,production.cloudflare.docker.com,productionresultssa0.blob.core.windows.net,productionresultssa1.blob.core.windows.net,productionresultssa10.blob.core.windows.net,productionresultssa11.blob.core.windows.net,productionresultssa12.blob.core.windows.net,productionresultssa13.blob.core.windows.net,productionresultssa14.blob.core.windows.net,productionresultssa15.blob.core.windows.net,productionresultssa16.blob.core.windows.net,productionresultssa17.blob.core.windows.net,productionresultssa18.blob.core.windows.net,productionresultssa19.blob.core.windows.net,productionresultssa2.blob.core.windows.net,productionresultssa3.blob.core.windows.net,productionresultssa4.blob.core.windows.net,productionresultssa5.blob.core.windows.net,productionresultssa6.blob.core.windows.net,productionresultssa7.blob.core.windows.net,productionresultssa8.blob.core.windows.net,productionresultssa9.blob.core.windows.net,proxy.golang.org,pub.dartlang.org,pub.dev,public-code-search.fastmcp.app,pypi.org,pypi.python.org,quay.io,raw.githubusercontent.com,registry.bower.io,registry.hub.docker.com,registry.npmjs.com,registry.npmjs.org,registry.terraform.io,registry.yarnpkg.com,releases.hashicorp.com,repo.anaconda.com,repo.clojars.org,repo.continuum.io,repo.gradle.org,repo.grails.org,repo.hex.pm,repo.maven.apache.org,repo.packagist.org,repo.scala-sbt.org,repo.spring.io,repo.typesafe.com,repo.yarnpkg.com,repo1.maven.org,rubygems.org,rubygems.pkg.github.com,s.symcb.com,s.symcd.com,scala-ci.typesafe.com,security.debian.org,security.ubuntu.com,services.gradle.org,sh.rustup.rs,skimdb.npmjs.com,static.crates.io,static.rust-lang.org,storage.googleapis.com,sum.golang.org,swift.org,telemetry.enterprise.githubcopilot.com,telemetry.vercel.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,vault.centos.org,www.cpan.org,www.elastic.co,www.java.com,www.microsoft.com,www.npmjs.com,www.npmjs.org,yarnpkg.com,yum.releases.hashicorp.com,ziglang.org" --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --enable-host-access --image-tag 0.23.0 --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]" + git config --global am.keepcr true + # 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: "*.docker.com,*.docker.io,*.githubusercontent.com,*.hackage.haskell.org,*.jsr.io,*.pythonhosted.org,*.rvm.io,*.vsblob.vsassets.io,adoptium.net,agents-md-generator.fastmcp.app,anaconda.org,api.adoptium.net,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.foojay.io,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.npms.io,api.nuget.org,api.rubygems.org,api.snapcraft.io,apt.llvm.org,apt.releases.hashicorp.com,archive.apache.org,archive.ubuntu.com,archlinux.org,artifacts.elastic.co,auth.docker.io,azure.archive.ubuntu.com,azuresearch-usnc.nuget.org,azuresearch-ussc.nuget.org,binstar.org,bitbucket.org,bootstrap.pypa.io,builds.dotnet.microsoft.com,builds.hex.pm,bun.sh,bundler.rubygems.org,cache.ruby-lang.org,cdn.azul.com,cdn.cocoapods.org,cdn.hex.pm,cdn.jsdelivr.net,cdn.playwright.dev,cdn.redhat.com,cdn.sheetjs.com,central.sonatype.com,ci.dot.net,clojars.org,cloud.elastic.co,cocoapods.org,code.jquery.com,codeload.github.com,conda.anaconda.org,conda.binstar.org,cpan.metacpan.org,cpan.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,data.jsdelivr.com,dc.services.visualstudio.com,deb.debian.org,deb.nodesource.com,debian.map.fastlydns.net,deno.land,dist.nuget.org,dl-cdn.alpinelinux.org,dl.bintray.com,dl.fedoraproject.org,dl.google.com,dl.k8s.io,dlcdn.apache.org,dot.net,dotnet.microsoft.com,dotnetcli.blob.core.windows.net,download.eclipse.org,download.fedoraproject.org,download.java.net,download.opensuse.org,download.oracle.com,download.swift.org,downloads.gradle-dn.com,downloads.haskell.org,ela.st,elastic.co,elastic.dev,esm.sh,fastly.hex.pm,files.pythonhosted.org,fonts.googleapis.com,fonts.gstatic.com,gcr.io,ge.jetbrains.com,gems.rubyforge.org,gems.rubyonrails.org,get-ghcup.haskell.org,get.pnpm.io,getcomposer.org,ghcr.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,gradle.org,haskell.org,hex.pm,host.docker.internal,index.crates.io,index.rubygems.org,jcenter.bintray.com,jdk.java.net,jitpack.io,json-schema.org,json.schemastore.org,jsr.io,keyring.debian.org,keyserver.ubuntu.com,kotlin.bintray.com,lfs.github.com,maven.apache.org,maven.google.com,maven.oracle.com,maven.pkg.github.com,mcr.microsoft.com,metacpan.org,mirror.archlinux.org,mirror.centos.org,mirrors.fedoraproject.org,nodejs.org,npm.pkg.github.com,npmjs.com,npmjs.org,nuget.org,nuget.pkg.github.com,nugetregistryv2prod.blob.core.windows.net,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,oneocsp.microsoft.com,packagecloud.io,packages.cloud.google.com,packages.debian.org,packages.jetbrains.team,packages.microsoft.com,packagist.org,pip.pypa.io,pkg.alpinelinux.org,pkg.go.dev,pkg.machengine.org,pkgs.dev.azure.com,pkgs.k8s.io,playwright.download.prss.microsoft.com,plugins-artifacts.gradle.org,plugins.gradle.org,ppa.launchpad.net,production.cloudflare.docker.com,productionresultssa0.blob.core.windows.net,productionresultssa1.blob.core.windows.net,productionresultssa10.blob.core.windows.net,productionresultssa11.blob.core.windows.net,productionresultssa12.blob.core.windows.net,productionresultssa13.blob.core.windows.net,productionresultssa14.blob.core.windows.net,productionresultssa15.blob.core.windows.net,productionresultssa16.blob.core.windows.net,productionresultssa17.blob.core.windows.net,productionresultssa18.blob.core.windows.net,productionresultssa19.blob.core.windows.net,productionresultssa2.blob.core.windows.net,productionresultssa3.blob.core.windows.net,productionresultssa4.blob.core.windows.net,productionresultssa5.blob.core.windows.net,productionresultssa6.blob.core.windows.net,productionresultssa7.blob.core.windows.net,productionresultssa8.blob.core.windows.net,productionresultssa9.blob.core.windows.net,proxy.golang.org,pub.dartlang.org,pub.dev,public-code-search.fastmcp.app,pypi.org,pypi.python.org,quay.io,raw.githubusercontent.com,registry.bower.io,registry.hub.docker.com,registry.npmjs.com,registry.npmjs.org,registry.terraform.io,registry.yarnpkg.com,releases.hashicorp.com,repo.anaconda.com,repo.clojars.org,repo.continuum.io,repo.gradle.org,repo.grails.org,repo.hex.pm,repo.maven.apache.org,repo.packagist.org,repo.scala-sbt.org,repo.spring.io,repo.typesafe.com,repo.yarnpkg.com,repo1.maven.org,rubygems.org,rubygems.pkg.github.com,s.symcb.com,s.symcd.com,scala-ci.typesafe.com,security.debian.org,security.ubuntu.com,services.gradle.org,sh.rustup.rs,skimdb.npmjs.com,static.crates.io,static.rust-lang.org,storage.googleapis.com,sum.golang.org,swift.org,telemetry.enterprise.githubcopilot.com,telemetry.vercel.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,vault.centos.org,www.cpan.org,www.elastic.co,www.java.com,www.microsoft.com,www.npmjs.com,www.npmjs.org,yarnpkg.com,yum.releases.hashicorp.com,ziglang.org" + 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 + # --- Threat Detection (inline) --- + - name: Check if detection needed + id: detection_guard + if: always() + env: + OUTPUT_TYPES: ${{ steps.collect_output.outputs.output_types }} + HAS_PATCH: ${{ steps.collect_output.outputs.has_patch }} + run: | + if [[ -n "$OUTPUT_TYPES" || "$HAS_PATCH" == "true" ]]; then + echo "run_detection=true" >> "$GITHUB_OUTPUT" + echo "Detection will run: output_types=$OUTPUT_TYPES, has_patch=$HAS_PATCH" + else + echo "run_detection=false" >> "$GITHUB_OUTPUT" + echo "Detection skipped: no agent outputs or patches to analyze" + fi + - name: Clear MCP configuration for detection + if: always() && steps.detection_guard.outputs.run_detection == 'true' + run: | + rm -f /tmp/gh-aw/mcp-config/mcp-servers.json + rm -f /home/runner/.copilot/mcp-config.json + rm -f "$GITHUB_WORKSPACE/.gemini/settings.json" + - name: Prepare threat detection files + if: always() && steps.detection_guard.outputs.run_detection == 'true' + run: | + mkdir -p /tmp/gh-aw/threat-detection/aw-prompts + cp /tmp/gh-aw/aw-prompts/prompt.txt /tmp/gh-aw/threat-detection/aw-prompts/prompt.txt 2>/dev/null || true + cp /tmp/gh-aw/agent_output.json /tmp/gh-aw/threat-detection/agent_output.json 2>/dev/null || true + for f in /tmp/gh-aw/aw-*.patch; do + [ -f "$f" ] && cp "$f" /tmp/gh-aw/threat-detection/ 2>/dev/null || true + done + echo "Prepared threat detection files:" + ls -la /tmp/gh-aw/threat-detection/ 2>/dev/null || true + - name: Setup threat detection + if: always() && steps.detection_guard.outputs.run_detection == 'true' + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + env: + WORKFLOW_NAME: "Information Architecture" + WORKFLOW_DESCRIPTION: "Audit the application's UI information architecture for navigation, placement, and consistency issues" + HAS_PATCH: ${{ steps.collect_output.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 + if: always() && steps.detection_guard.outputs.run_detection == 'true' + run: | + mkdir -p /tmp/gh-aw/threat-detection + touch /tmp/gh-aw/threat-detection/detection.log + - name: Execute GitHub Copilot CLI + if: always() && steps.detection_guard.outputs.run_detection == 'true' + id: detection_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 + # shellcheck disable=SC1003 + sudo -E awf --env-all --container-workdir "${GITHUB_WORKSPACE}" --allow-domains "api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,github.com,host.docker.internal,raw.githubusercontent.com,registry.npmjs.org,telemetry.enterprise.githubcopilot.com" --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --enable-host-access --image-tag 0.23.0 --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-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 "$(cat /tmp/gh-aw/aw-prompts/prompt.txt)"' 2>&1 | tee -a /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_detection_results + if: always() && steps.detection_guard.outputs.run_detection == 'true' + 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() && steps.detection_guard.outputs.run_detection == 'true' + uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 + with: + name: threat-detection.log + path: /tmp/gh-aw/threat-detection/detection.log + if-no-files-found: ignore + - name: Set detection conclusion + id: detection_conclusion + if: always() + env: + RUN_DETECTION: ${{ steps.detection_guard.outputs.run_detection }} + DETECTION_SUCCESS: ${{ steps.parse_detection_results.outputs.success }} + run: | + if [[ "$RUN_DETECTION" != "true" ]]; then + echo "conclusion=skipped" >> "$GITHUB_OUTPUT" + echo "success=true" >> "$GITHUB_OUTPUT" + echo "Detection was not needed, marking as skipped" + elif [[ "$DETECTION_SUCCESS" == "true" ]]; then + echo "conclusion=success" >> "$GITHUB_OUTPUT" + echo "success=true" >> "$GITHUB_OUTPUT" + echo "Detection passed successfully" + else + echo "conclusion=failure" >> "$GITHUB_OUTPUT" + echo "success=false" >> "$GITHUB_OUTPUT" + echo "Detection found issues" + fi + + conclusion: + needs: + - activation + - agent + - 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@90ebf8057e8e005103b8d123732d2c64c30e9b27 # v0.50.4 + 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: "Information Architecture" + 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: "Information Architecture" + 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: "Information Architecture" + 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-information-architecture" + 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.' }}\",\"activationComments\":\"false\"}" + 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: "Information Architecture" + 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(); + + pre_activation: + runs-on: ubuntu-slim + outputs: + activated: ${{ steps.check_membership.outputs.is_team_member == 'true' }} + matched_command: '' + steps: + - name: Setup Scripts + uses: github/gh-aw/actions/setup@90ebf8057e8e005103b8d123732d2c64c30e9b27 # v0.50.4 + 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 + if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (needs.agent.outputs.detection_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.' }}\",\"activationComments\":\"false\"}" + GH_AW_WORKFLOW_ID: "gh-aw-information-architecture" + GH_AW_WORKFLOW_NAME: "Information Architecture" + outputs: + code_push_failure_count: ${{ steps.process_safe_outputs.outputs.code_push_failure_count }} + code_push_failure_errors: ${{ steps.process_safe_outputs.outputs.code_push_failure_errors }} + 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@90ebf8057e8e005103b8d123732d2c64c30e9b27 # v0.50.4 + 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\":{\"max\":1,\"title_prefix\":\"${{ inputs.title-prefix }} \"},\"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-information-architecture.md b/.github/workflows/gh-aw-information-architecture.md new file mode 100644 index 00000000..8ed002cb --- /dev/null +++ b/.github/workflows/gh-aw-information-architecture.md @@ -0,0 +1,160 @@ +--- +inlined-imports: true +name: "Information Architecture" +description: "Audit the application's UI information architecture for navigation, placement, and consistency 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/previous-findings.md + - gh-aw-fragments/best-of-three-investigation.md + - gh-aw-fragments/scheduled-audit.md + - gh-aw-fragments/network-ecosystems.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: "" + title-prefix: + description: "Title prefix for created issues (e.g. '[information-architecture]')" + type: string + required: false + default: "[information-architecture]" + secrets: + COPILOT_GITHUB_TOKEN: + required: true + roles: [admin, maintainer, write] + bots: + - "${{ inputs.allowed-bot-users }}" +concurrency: + group: information-architecture + 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: +strict: false +safe-outputs: + activation-comments: false + noop: + create-issue: + max: 1 + title-prefix: "${{ inputs.title-prefix }} " +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 Information Architecture Analyst — a UX expert who evaluates whether the application's interface is logically organized, navigable, and consistent. + +Your task is to analyze the codebase and identify concrete information architecture problems — places where users would likely get confused, lost, or frustrated because controls, data, or navigation elements are in unexpected locations. + +**The bar is high.** Most UIs have minor rough edges that are not worth filing. Only file an issue when you find a concrete, user-impacting IA problem. + +## Report Assignment + +### Data Gathering + +1. **Understand the product** + - Read `README.md` and any docs to understand the application's purpose, target users, and key flows. + - Identify the entry point component (e.g., `App.tsx`, `Layout.tsx`, `index.tsx`, or equivalent). + +2. **Trace the component tree** + - Starting from the top-level App/Layout component, trace the navigation structure — how does a user move between features? + - For each major feature area, examine the component hierarchy and props to understand what controls are rendered and where. + - Compare similar features for layout consistency. + - Look at how the app handles edge cases: no data, loading states, errors, onboarding. + +3. **Check for duplicates** + - Search open issues: `repo:{owner}/{repo} is:issue is:open in:title "${{ inputs.title-prefix }}"`. + - Review `/tmp/previous-findings.json` for issues already filed by this agent. + +### What to Look For + +1. **Navigation flow** — Are navigation elements (sidebar, tabs, breadcrumbs) consistent and logically ordered? Can users reach all major features from the main navigation? Are there dead ends or orphan views? +2. **Button and action placement** — Are primary actions placed where users expect them? Are destructive actions visually distinct and appropriately guarded with confirmations? +3. **Picker and selector placement** — Are pickers (date pickers, dropdowns, type selectors) positioned near the content they affect? Are there pickers in headers or toolbars that should be in context, or vice versa? +4. **Data presentation** — Is data presented in the most appropriate format for its type? Are labels clear and consistent? +5. **Progressive disclosure** — Are advanced options hidden behind expandable sections or secondary menus? Or is the UI overwhelming users with too many options at once? +6. **Grouping and hierarchy** — Are related controls grouped together visually? Is there a clear visual hierarchy? +7. **Consistency** — Do similar features use similar layouts? If one panel has controls in a toolbar, do other panels follow the same pattern? +8. **Empty states and onboarding** — When there is no data, does the UI guide the user toward the next action? + +### What to Skip + +- Subjective aesthetic preferences or minor spacing issues +- Problems that require user research to validate (no concrete evidence from the code) +- Issues already tracked by an open issue + +### Quality Gate — When to Noop + +Call `noop` if: +- You cannot find a concrete, user-impacting IA problem supported by specific component paths. +- All findings are subjective style preferences. +- A similar issue is already open. + +"Information Architecture skipped — no concrete IA problem found." + +### Issue Format + +**Issue title:** Brief summary of the IA problem (e.g., "Panel type selector is disconnected from the panel it configures") + +**Issue body:** + +> ## Information Architecture Findings +> +> ### 1. [Brief description] +> **Area:** [Navigation | Action placement | Picker placement | Data presentation | Disclosure | Grouping | Consistency | Empty states] +> **Component(s):** [file paths] +> **Problem:** [What the user experiences and why it is confusing] +> **Suggested improvement:** [Brief description of a better arrangement] +> +> ### 2. [Next finding...] +> +> ## Suggested Actions +> - [ ] [Specific, actionable checkbox for each improvement] + +### Labeling + +- If the `information-architecture` label exists (check with `github-get_label`), include it in the `create_issue` call; otherwise, rely on the `${{ inputs.title-prefix }}` title prefix only. + +${{ inputs.additional-instructions }} diff --git a/.github/workflows/gh-aw-issue-fixer.lock.yml b/.github/workflows/gh-aw-issue-fixer.lock.yml index 498f5f9c..90624561 100644 --- a/.github/workflows/gh-aw-issue-fixer.lock.yml +++ b/.github/workflows/gh-aw-issue-fixer.lock.yml @@ -38,7 +38,7 @@ # # inlined-imports: true # -# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"84c2298f214f819d06383811d74f8f02a3e7c9b053a00a5f4421cac33fd32476"} +# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"8b74b6fd69a0a375ce5dce34127bda9715081e16df190ab17204dc85529a7071"} name: "Issue Fixer" "on": @@ -283,7 +283,7 @@ jobs: - **Links**: Max 50 URLs per comment. - **HTML**: Only safe tags allowed (`details`, `summary`, `code`, `pre`, `blockquote`, `table`, `b`, `em`, `strong`, `h1`–`h6`, `hr`, `br`, `li`, `ol`, `ul`, `p`, `sub`, `sup`). Other tags are converted to parentheses. - **URLs**: Only HTTPS URLs to allowed domains. Non-HTTPS and non-allowed domains are redacted. - - **Bot triggers**: References like `fixes #123` or `closes #456` are neutralized to prevent unintended issue closures. + - **Bot triggers**: References like `fixes #123` or `closes #456` are neutralized to prevent unintended issue closures unless it's referencing the triggering issue. If you exceed 10 mentions or 50 links, the comment will be rejected. GH_AW_PROMPT_EOF @@ -962,7 +962,9 @@ jobs: if (contributing) checklist.push(`Review the contributing guide (${contributing}) before opening or updating a PR.`); if (prTemplate) checklist.push(`Follow the PR template (${prTemplate}) for title, description, and validation notes.`); checklist.push('Confirm the requested task is fully completed and validated before creating or pushing PR changes.'); - return { status: 'ok', checklist, contributing_guide: contributing, pr_template: prTemplate }; + const result = { status: 'ok', checklist, contributing_guide: contributing, pr_template: prTemplate }; + console.log(JSON.stringify(result)); + return result; } module.exports = { execute }; GH_AW_SAFE_INPUTS_JS_READY-TO-MAKE-PR_EOF diff --git a/.github/workflows/gh-aw-issue-triage.lock.yml b/.github/workflows/gh-aw-issue-triage.lock.yml index 4f87e438..40c32cf8 100644 --- a/.github/workflows/gh-aw-issue-triage.lock.yml +++ b/.github/workflows/gh-aw-issue-triage.lock.yml @@ -36,7 +36,7 @@ # # inlined-imports: true # -# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"9ff2f4232a4751065c9ba7cf743c3cf3e915dd437ebcf40c268cd6388f372351"} +# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"2d9bd8a6fb5b4dfbe599905904131888b4dec8b5e1052f12c3f3248ecddae85c"} name: "Issue Triage" "on": @@ -269,7 +269,7 @@ jobs: - **Links**: Max 50 URLs per comment. - **HTML**: Only safe tags allowed (`details`, `summary`, `code`, `pre`, `blockquote`, `table`, `b`, `em`, `strong`, `h1`–`h6`, `hr`, `br`, `li`, `ol`, `ul`, `p`, `sub`, `sup`). Other tags are converted to parentheses. - **URLs**: Only HTTPS URLs to allowed domains. Non-HTTPS and non-allowed domains are redacted. - - **Bot triggers**: References like `fixes #123` or `closes #456` are neutralized to prevent unintended issue closures. + - **Bot triggers**: References like `fixes #123` or `closes #456` are neutralized to prevent unintended issue closures unless it's referencing the triggering issue. If you exceed 10 mentions or 50 links, the comment will be rejected. GH_AW_PROMPT_EOF @@ -1220,7 +1220,6 @@ jobs: permissions: contents: read issues: write - pull-requests: write outputs: noop_message: ${{ steps.noop.outputs.noop_message }} tools_reported: ${{ steps.missing_tool.outputs.tools_reported }} @@ -1354,7 +1353,6 @@ jobs: permissions: contents: read issues: write - pull-requests: write timeout-minutes: 15 env: GH_AW_ENGINE_ID: "copilot" diff --git a/.github/workflows/gh-aw-mention-in-issue-no-sandbox.lock.yml b/.github/workflows/gh-aw-mention-in-issue-no-sandbox.lock.yml index 4ad89266..79c61b32 100644 --- a/.github/workflows/gh-aw-mention-in-issue-no-sandbox.lock.yml +++ b/.github/workflows/gh-aw-mention-in-issue-no-sandbox.lock.yml @@ -39,7 +39,7 @@ # # inlined-imports: true # -# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"f87b3714d0996c712a44a2b7e716ade7cb2ce66130602bb5ae489c76aaab7a19"} +# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"e62d5042c93258cdae2f85fcedfe70bed7af7ae450eac5358e44de328ff89b6e"} name: "Mention in Issue (no sandbox)" "on": @@ -104,8 +104,11 @@ jobs: issues: write pull-requests: write outputs: + body: ${{ steps.sanitized.outputs.body }} comment_id: "" comment_repo: "" + text: ${{ steps.sanitized.outputs.text }} + title: ${{ steps.sanitized.outputs.title }} steps: - name: Setup Scripts uses: github/gh-aw/actions/setup@90ebf8057e8e005103b8d123732d2c64c30e9b27 # v0.50.4 @@ -137,6 +140,15 @@ jobs: setupGlobals(core, github, context, exec, io); const { main } = require('/opt/gh-aw/actions/check_workflow_timestamp_api.cjs'); await main(); + - name: Compute current body text + id: sanitized + 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/compute_text.cjs'); + await main(); - name: Create prompt with built-in context env: GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt @@ -288,7 +300,7 @@ jobs: - **Links**: Max 50 URLs per comment. - **HTML**: Only safe tags allowed (`details`, `summary`, `code`, `pre`, `blockquote`, `table`, `b`, `em`, `strong`, `h1`–`h6`, `hr`, `br`, `li`, `ol`, `ul`, `p`, `sub`, `sup`). Other tags are converted to parentheses. - **URLs**: Only HTTPS URLs to allowed domains. Non-HTTPS and non-allowed domains are redacted. - - **Bot triggers**: References like `fixes #123` or `closes #456` are neutralized to prevent unintended issue closures. + - **Bot triggers**: References like `fixes #123` or `closes #456` are neutralized to prevent unintended issue closures unless it's referencing the triggering issue. If you exceed 10 mentions or 50 links, the comment will be rejected. GH_AW_PROMPT_EOF @@ -1037,7 +1049,9 @@ jobs: if (contributing) checklist.push(`Review the contributing guide (${contributing}) before opening or updating a PR.`); if (prTemplate) checklist.push(`Follow the PR template (${prTemplate}) for title, description, and validation notes.`); checklist.push('Confirm the requested task is fully completed and validated before creating or pushing PR changes.'); - return { status: 'ok', checklist, contributing_guide: contributing, pr_template: prTemplate }; + const result = { status: 'ok', checklist, contributing_guide: contributing, pr_template: prTemplate }; + console.log(JSON.stringify(result)); + return result; } module.exports = { execute }; GH_AW_SAFE_INPUTS_JS_READY-TO-MAKE-PR_EOF diff --git a/.github/workflows/gh-aw-mention-in-issue-no-sandbox.md b/.github/workflows/gh-aw-mention-in-issue-no-sandbox.md index 527f9df9..e8de6b88 100644 --- a/.github/workflows/gh-aw-mention-in-issue-no-sandbox.md +++ b/.github/workflows/gh-aw-mention-in-issue-no-sandbox.md @@ -95,7 +95,7 @@ Assist with issues on ${{ github.repository }} — answer questions, debug probl - **Repository**: ${{ github.repository }} - **Issue**: #${{ github.event.issue.number }} — ${{ github.event.issue.title }} -- **Request**: "${{ needs.activation.outputs.text }}" +- **Request**: "${{ steps.sanitized.outputs.text }}" ## Constraints diff --git a/.github/workflows/gh-aw-mention-in-issue.lock.yml b/.github/workflows/gh-aw-mention-in-issue.lock.yml index cb35348b..4e858b2e 100644 --- a/.github/workflows/gh-aw-mention-in-issue.lock.yml +++ b/.github/workflows/gh-aw-mention-in-issue.lock.yml @@ -39,7 +39,7 @@ # # inlined-imports: true # -# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"c0f6f707d5624e09aaec266cecddac40eb80c05ef638557db04e59d0943d6422"} +# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"eab038274f5694415a6f9dbe07ac5b42fac4aa4c956851029207d68a435498c6"} name: "Mention in Issue" "on": @@ -104,8 +104,11 @@ jobs: issues: write pull-requests: write outputs: + body: ${{ steps.sanitized.outputs.body }} comment_id: "" comment_repo: "" + text: ${{ steps.sanitized.outputs.text }} + title: ${{ steps.sanitized.outputs.title }} steps: - name: Setup Scripts uses: github/gh-aw/actions/setup@90ebf8057e8e005103b8d123732d2c64c30e9b27 # v0.50.4 @@ -137,6 +140,15 @@ jobs: setupGlobals(core, github, context, exec, io); const { main } = require('/opt/gh-aw/actions/check_workflow_timestamp_api.cjs'); await main(); + - name: Compute current body text + id: sanitized + 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/compute_text.cjs'); + await main(); - name: Create prompt with built-in context env: GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt @@ -288,7 +300,7 @@ jobs: - **Links**: Max 50 URLs per comment. - **HTML**: Only safe tags allowed (`details`, `summary`, `code`, `pre`, `blockquote`, `table`, `b`, `em`, `strong`, `h1`–`h6`, `hr`, `br`, `li`, `ol`, `ul`, `p`, `sub`, `sup`). Other tags are converted to parentheses. - **URLs**: Only HTTPS URLs to allowed domains. Non-HTTPS and non-allowed domains are redacted. - - **Bot triggers**: References like `fixes #123` or `closes #456` are neutralized to prevent unintended issue closures. + - **Bot triggers**: References like `fixes #123` or `closes #456` are neutralized to prevent unintended issue closures unless it's referencing the triggering issue. If you exceed 10 mentions or 50 links, the comment will be rejected. GH_AW_PROMPT_EOF @@ -1041,7 +1053,9 @@ jobs: if (contributing) checklist.push(`Review the contributing guide (${contributing}) before opening or updating a PR.`); if (prTemplate) checklist.push(`Follow the PR template (${prTemplate}) for title, description, and validation notes.`); checklist.push('Confirm the requested task is fully completed and validated before creating or pushing PR changes.'); - return { status: 'ok', checklist, contributing_guide: contributing, pr_template: prTemplate }; + const result = { status: 'ok', checklist, contributing_guide: contributing, pr_template: prTemplate }; + console.log(JSON.stringify(result)); + return result; } module.exports = { execute }; GH_AW_SAFE_INPUTS_JS_READY-TO-MAKE-PR_EOF diff --git a/.github/workflows/gh-aw-mention-in-issue.md b/.github/workflows/gh-aw-mention-in-issue.md index b9a4ba6f..86859241 100644 --- a/.github/workflows/gh-aw-mention-in-issue.md +++ b/.github/workflows/gh-aw-mention-in-issue.md @@ -92,7 +92,7 @@ Assist with issues on ${{ github.repository }} — answer questions, debug probl - **Repository**: ${{ github.repository }} - **Issue**: #${{ github.event.issue.number }} — ${{ github.event.issue.title }} -- **Request**: "${{ needs.activation.outputs.text }}" +- **Request**: "${{ steps.sanitized.outputs.text }}" ## Constraints diff --git a/.github/workflows/gh-aw-mention-in-pr-by-id.lock.yml b/.github/workflows/gh-aw-mention-in-pr-by-id.lock.yml index f21c1ae2..c6913b86 100644 --- a/.github/workflows/gh-aw-mention-in-pr-by-id.lock.yml +++ b/.github/workflows/gh-aw-mention-in-pr-by-id.lock.yml @@ -42,7 +42,7 @@ # # inlined-imports: true # -# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"06af32bebfd0daa2d21eda9bcd8a91059c3fcf4e413862749a62b79d4fdcc8b9"} +# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"ab13f9afdf485aa303c7bddb1fb8b017ef295d7ecbaf4a6f721f2c8cf2ebff78"} name: "Mention in PR by ID" "on": @@ -1210,7 +1210,9 @@ jobs: if (contributing) checklist.push(`Review the contributing guide (${contributing}) before opening or updating a PR.`); if (prTemplate) checklist.push(`Follow the PR template (${prTemplate}) for title, description, and validation notes.`); checklist.push('Confirm the requested task is fully completed and validated before creating or pushing PR changes.'); - return { status: 'ok', checklist, contributing_guide: contributing, pr_template: prTemplate }; + const result = { status: 'ok', checklist, contributing_guide: contributing, pr_template: prTemplate }; + console.log(JSON.stringify(result)); + return result; } module.exports = { execute }; GH_AW_SAFE_INPUTS_JS_READY-TO-MAKE-PR_EOF diff --git a/.github/workflows/gh-aw-mention-in-pr-no-sandbox.lock.yml b/.github/workflows/gh-aw-mention-in-pr-no-sandbox.lock.yml index ff7fdfa2..3311610e 100644 --- a/.github/workflows/gh-aw-mention-in-pr-no-sandbox.lock.yml +++ b/.github/workflows/gh-aw-mention-in-pr-no-sandbox.lock.yml @@ -42,7 +42,7 @@ # # inlined-imports: true # -# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"cfd467196fde808dd59cfc6b1e6f5151a06ddaa798cb82c78eda994bd9ab9bc1"} +# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"e3419020c0872c77806a0dafad62ed921afb0f4112135764a1f7953f61061d33"} name: "Mention in PR (no sandbox)" "on": @@ -112,8 +112,11 @@ jobs: issues: write pull-requests: write outputs: + body: ${{ steps.sanitized.outputs.body }} comment_id: "" comment_repo: "" + text: ${{ steps.sanitized.outputs.text }} + title: ${{ steps.sanitized.outputs.title }} steps: - name: Setup Scripts uses: github/gh-aw/actions/setup@90ebf8057e8e005103b8d123732d2c64c30e9b27 # v0.50.4 @@ -145,6 +148,15 @@ jobs: setupGlobals(core, github, context, exec, io); const { main } = require('/opt/gh-aw/actions/check_workflow_timestamp_api.cjs'); await main(); + - name: Compute current body text + id: sanitized + 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/compute_text.cjs'); + await main(); - name: Create prompt with built-in context env: GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt @@ -1247,7 +1259,9 @@ jobs: if (contributing) checklist.push(`Review the contributing guide (${contributing}) before opening or updating a PR.`); if (prTemplate) checklist.push(`Follow the PR template (${prTemplate}) for title, description, and validation notes.`); checklist.push('Confirm the requested task is fully completed and validated before creating or pushing PR changes.'); - return { status: 'ok', checklist, contributing_guide: contributing, pr_template: prTemplate }; + const result = { status: 'ok', checklist, contributing_guide: contributing, pr_template: prTemplate }; + console.log(JSON.stringify(result)); + return result; } module.exports = { execute }; GH_AW_SAFE_INPUTS_JS_READY-TO-MAKE-PR_EOF @@ -1544,7 +1558,6 @@ jobs: runs-on: ubuntu-slim permissions: contents: write - issues: write pull-requests: write outputs: noop_message: ${{ steps.noop.outputs.noop_message }} @@ -1682,7 +1695,6 @@ jobs: runs-on: ubuntu-slim permissions: contents: write - issues: write pull-requests: write timeout-minutes: 15 env: diff --git a/.github/workflows/gh-aw-mention-in-pr-no-sandbox.md b/.github/workflows/gh-aw-mention-in-pr-no-sandbox.md index 680e905f..98e6c110 100644 --- a/.github/workflows/gh-aw-mention-in-pr-no-sandbox.md +++ b/.github/workflows/gh-aw-mention-in-pr-no-sandbox.md @@ -112,7 +112,7 @@ Assist with pull requests on ${{ github.repository }} — review code, fix issue - **Repository**: ${{ github.repository }} - **PR**: #${{ github.event.issue.number }} — ${{ github.event.issue.title }} -- **Request**: "${{ needs.activation.outputs.text }}" +- **Request**: "${{ steps.sanitized.outputs.text }}" ## Constraints diff --git a/.github/workflows/gh-aw-mention-in-pr.lock.yml b/.github/workflows/gh-aw-mention-in-pr.lock.yml index 3b42ec48..6821a48e 100644 --- a/.github/workflows/gh-aw-mention-in-pr.lock.yml +++ b/.github/workflows/gh-aw-mention-in-pr.lock.yml @@ -42,7 +42,7 @@ # # inlined-imports: true # -# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"65af10438116e8740859a4256620f3b98845b86f57bd479d1b8fbb32c7062611"} +# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"e528be4cf028fd8ce8bd43491752116e4120a662d6c020e6354188155601efce"} name: "Mention in PR" "on": @@ -1265,7 +1265,9 @@ jobs: if (contributing) checklist.push(`Review the contributing guide (${contributing}) before opening or updating a PR.`); if (prTemplate) checklist.push(`Follow the PR template (${prTemplate}) for title, description, and validation notes.`); checklist.push('Confirm the requested task is fully completed and validated before creating or pushing PR changes.'); - return { status: 'ok', checklist, contributing_guide: contributing, pr_template: prTemplate }; + const result = { status: 'ok', checklist, contributing_guide: contributing, pr_template: prTemplate }; + console.log(JSON.stringify(result)); + return result; } module.exports = { execute }; GH_AW_SAFE_INPUTS_JS_READY-TO-MAKE-PR_EOF @@ -1689,7 +1691,6 @@ jobs: runs-on: ubuntu-slim permissions: contents: write - issues: write pull-requests: write outputs: noop_message: ${{ steps.noop.outputs.noop_message }} @@ -1827,7 +1828,6 @@ jobs: runs-on: ubuntu-slim permissions: contents: write - issues: write pull-requests: write timeout-minutes: 15 env: diff --git a/.github/workflows/gh-aw-mention-in-pr.md b/.github/workflows/gh-aw-mention-in-pr.md index d577f596..cb391ec9 100644 --- a/.github/workflows/gh-aw-mention-in-pr.md +++ b/.github/workflows/gh-aw-mention-in-pr.md @@ -119,7 +119,7 @@ Assist with pull requests on ${{ github.repository }} — review code, fix issue - **Repository**: ${{ github.repository }} - **PR**: #${{ inputs.target-pr-number || github.event.issue.number }} — ${{ github.event.issue.title }} -- **Request**: "${{ inputs.prompt || needs.activation.outputs.text }}" +- **Request**: "${{ inputs.prompt || steps.sanitized.outputs.text }}" ## Constraints diff --git a/.github/workflows/gh-aw-newbie-contributor-fixer.lock.yml b/.github/workflows/gh-aw-newbie-contributor-fixer.lock.yml index 14f5d5a9..5d1eb292 100644 --- a/.github/workflows/gh-aw-newbie-contributor-fixer.lock.yml +++ b/.github/workflows/gh-aw-newbie-contributor-fixer.lock.yml @@ -37,7 +37,7 @@ # # inlined-imports: true # -# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"0739f317a7297098c1911d9a9402c6fc8071bb254541b9d0a526aeba042541fe"} +# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"a313bd464d565689b8f72b806e49d9d3a259e96a55aa233b25c74e54c7e4bedb"} name: "Newbie Contributor Fixer" "on": @@ -916,7 +916,9 @@ jobs: if (contributing) checklist.push(`Review the contributing guide (${contributing}) before opening or updating a PR.`); if (prTemplate) checklist.push(`Follow the PR template (${prTemplate}) for title, description, and validation notes.`); checklist.push('Confirm the requested task is fully completed and validated before creating or pushing PR changes.'); - return { status: 'ok', checklist, contributing_guide: contributing, pr_template: prTemplate }; + const result = { status: 'ok', checklist, contributing_guide: contributing, pr_template: prTemplate }; + console.log(JSON.stringify(result)); + return result; } module.exports = { execute }; GH_AW_SAFE_INPUTS_JS_READY-TO-MAKE-PR_EOF diff --git a/.github/workflows/gh-aw-plan.lock.yml b/.github/workflows/gh-aw-plan.lock.yml index 4bb48d64..f607b5a7 100644 --- a/.github/workflows/gh-aw-plan.lock.yml +++ b/.github/workflows/gh-aw-plan.lock.yml @@ -37,7 +37,7 @@ # # inlined-imports: true # -# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"b9d49660709023dac48817f15274ee0069e898cfc2815ca8355ebffbe802ed4d"} +# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"be3eb110a7075dfaefb199f5396824f73a40a55b356b05da39c8fee3cfbe04c5"} name: "Plan" "on": @@ -102,8 +102,11 @@ jobs: issues: write pull-requests: write outputs: + body: ${{ steps.sanitized.outputs.body }} comment_id: "" comment_repo: "" + text: ${{ steps.sanitized.outputs.text }} + title: ${{ steps.sanitized.outputs.title }} steps: - name: Setup Scripts uses: github/gh-aw/actions/setup@90ebf8057e8e005103b8d123732d2c64c30e9b27 # v0.50.4 @@ -135,6 +138,15 @@ jobs: setupGlobals(core, github, context, exec, io); const { main } = require('/opt/gh-aw/actions/check_workflow_timestamp_api.cjs'); await main(); + - name: Compute current body text + id: sanitized + 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/compute_text.cjs'); + await main(); - name: Create prompt with built-in context env: GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt @@ -276,7 +288,7 @@ jobs: - **Links**: Max 50 URLs per comment. - **HTML**: Only safe tags allowed (`details`, `summary`, `code`, `pre`, `blockquote`, `table`, `b`, `em`, `strong`, `h1`–`h6`, `hr`, `br`, `li`, `ol`, `ul`, `p`, `sub`, `sup`). Other tags are converted to parentheses. - **URLs**: Only HTTPS URLs to allowed domains. Non-HTTPS and non-allowed domains are redacted. - - **Bot triggers**: References like `fixes #123` or `closes #456` are neutralized to prevent unintended issue closures. + - **Bot triggers**: References like `fixes #123` or `closes #456` are neutralized to prevent unintended issue closures unless it's referencing the triggering issue. If you exceed 10 mentions or 50 links, the comment will be rejected. GH_AW_PROMPT_EOF @@ -1256,7 +1268,6 @@ jobs: permissions: contents: read issues: write - pull-requests: write outputs: noop_message: ${{ steps.noop.outputs.noop_message }} tools_reported: ${{ steps.missing_tool.outputs.tools_reported }} @@ -1390,7 +1401,6 @@ jobs: permissions: contents: read issues: write - pull-requests: write timeout-minutes: 15 env: GH_AW_ENGINE_ID: "copilot" diff --git a/.github/workflows/gh-aw-plan.md b/.github/workflows/gh-aw-plan.md index ede212f7..ab83e852 100644 --- a/.github/workflows/gh-aw-plan.md +++ b/.github/workflows/gh-aw-plan.md @@ -92,7 +92,7 @@ Assist with implementation planning on ${{ github.repository }} from issue comme - **Repository**: ${{ github.repository }} - **Issue**: #${{ github.event.issue.number }} — ${{ github.event.issue.title }} -- **Request**: "${{ needs.activation.outputs.text }}" +- **Request**: "${{ steps.sanitized.outputs.text }}" ## Constraints diff --git a/.github/workflows/gh-aw-pr-actions-detective.lock.yml b/.github/workflows/gh-aw-pr-actions-detective.lock.yml index 877bf106..6a843706 100644 --- a/.github/workflows/gh-aw-pr-actions-detective.lock.yml +++ b/.github/workflows/gh-aw-pr-actions-detective.lock.yml @@ -36,7 +36,7 @@ # # inlined-imports: true # -# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"13be3d21cd1f4e6255034e93334a3f9cd60640d39576e00c1ca20face8423926"} +# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"63534bda77999d6aea61353f5e9015a218d38f769cce0d8316961ad0f0864346"} name: "PR Actions Detective" "on": @@ -1166,7 +1166,6 @@ jobs: runs-on: ubuntu-slim permissions: contents: read - issues: write pull-requests: write outputs: noop_message: ${{ steps.noop.outputs.noop_message }} @@ -1283,7 +1282,6 @@ jobs: runs-on: ubuntu-slim permissions: contents: read - issues: write pull-requests: write timeout-minutes: 15 env: diff --git a/.github/workflows/gh-aw-pr-actions-fixer.lock.yml b/.github/workflows/gh-aw-pr-actions-fixer.lock.yml index 83a92d72..4fdb8bc3 100644 --- a/.github/workflows/gh-aw-pr-actions-fixer.lock.yml +++ b/.github/workflows/gh-aw-pr-actions-fixer.lock.yml @@ -37,7 +37,7 @@ # # inlined-imports: true # -# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"d7684a25cf5031d4317d1a5d063ae908476c7eda0fd3d9eb8adc648858adf9c5"} +# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"f985cb01e1a0c39f8cdb91d9203f120a3aabdd3eec81f658eae9973e3a504748"} name: "PR Actions Fixer" "on": @@ -929,7 +929,9 @@ jobs: if (contributing) checklist.push(`Review the contributing guide (${contributing}) before opening or updating a PR.`); if (prTemplate) checklist.push(`Follow the PR template (${prTemplate}) for title, description, and validation notes.`); checklist.push('Confirm the requested task is fully completed and validated before creating or pushing PR changes.'); - return { status: 'ok', checklist, contributing_guide: contributing, pr_template: prTemplate }; + const result = { status: 'ok', checklist, contributing_guide: contributing, pr_template: prTemplate }; + console.log(JSON.stringify(result)); + return result; } module.exports = { execute }; GH_AW_SAFE_INPUTS_JS_READY-TO-MAKE-PR_EOF @@ -1353,7 +1355,6 @@ jobs: runs-on: ubuntu-slim permissions: contents: write - issues: write pull-requests: write outputs: noop_message: ${{ steps.noop.outputs.noop_message }} @@ -1474,7 +1475,6 @@ jobs: runs-on: ubuntu-slim permissions: contents: write - issues: write pull-requests: write timeout-minutes: 15 env: diff --git a/.github/workflows/gh-aw-pr-buildkite-detective.lock.yml b/.github/workflows/gh-aw-pr-buildkite-detective.lock.yml index 48ab8107..9b515fa7 100644 --- a/.github/workflows/gh-aw-pr-buildkite-detective.lock.yml +++ b/.github/workflows/gh-aw-pr-buildkite-detective.lock.yml @@ -36,7 +36,7 @@ # # inlined-imports: true # -# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"15ce6c43e6db63bf35be21effd835f32b43e74896da77eaf23e984049468c0de"} +# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"ea98d152cecc4ba17969adf6b63c8ea83b5436d04902f073f336cf31bb05bd4c"} name: "PR Buildkite Detective" "on": @@ -1241,7 +1241,6 @@ jobs: runs-on: ubuntu-slim permissions: contents: read - issues: write pull-requests: write outputs: noop_message: ${{ steps.noop.outputs.noop_message }} @@ -1358,7 +1357,6 @@ jobs: runs-on: ubuntu-slim permissions: contents: read - issues: write pull-requests: write timeout-minutes: 15 env: diff --git a/.github/workflows/gh-aw-pr-ci-detective.lock.yml b/.github/workflows/gh-aw-pr-ci-detective.lock.yml index ceea8ead..3cdf59c9 100644 --- a/.github/workflows/gh-aw-pr-ci-detective.lock.yml +++ b/.github/workflows/gh-aw-pr-ci-detective.lock.yml @@ -41,7 +41,7 @@ # # inlined-imports: true # -# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"13be3d21cd1f4e6255034e93334a3f9cd60640d39576e00c1ca20face8423926"} +# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"63534bda77999d6aea61353f5e9015a218d38f769cce0d8316961ad0f0864346"} name: "PR Actions Detective" "on": @@ -1171,7 +1171,6 @@ jobs: runs-on: ubuntu-slim permissions: contents: read - issues: write pull-requests: write outputs: noop_message: ${{ steps.noop.outputs.noop_message }} @@ -1288,7 +1287,6 @@ jobs: runs-on: ubuntu-slim permissions: contents: read - issues: write pull-requests: write timeout-minutes: 15 env: diff --git a/.github/workflows/gh-aw-pr-review-addresser.lock.yml b/.github/workflows/gh-aw-pr-review-addresser.lock.yml index 5242eb17..c6c9e44a 100644 --- a/.github/workflows/gh-aw-pr-review-addresser.lock.yml +++ b/.github/workflows/gh-aw-pr-review-addresser.lock.yml @@ -39,7 +39,7 @@ # # inlined-imports: true # -# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"bd76e673bffb563eb8a2f1f66f34cb2f81aaec3d04ead551ce88086a4284a2d4"} +# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"9b2418b1915aa2f4b9ae98da4ff5d8476ef6504441bda833e4f0019aedc92832"} name: "PR Review Addresser" "on": @@ -1023,7 +1023,9 @@ jobs: if (contributing) checklist.push(`Review the contributing guide (${contributing}) before opening or updating a PR.`); if (prTemplate) checklist.push(`Follow the PR template (${prTemplate}) for title, description, and validation notes.`); checklist.push('Confirm the requested task is fully completed and validated before creating or pushing PR changes.'); - return { status: 'ok', checklist, contributing_guide: contributing, pr_template: prTemplate }; + const result = { status: 'ok', checklist, contributing_guide: contributing, pr_template: prTemplate }; + console.log(JSON.stringify(result)); + return result; } module.exports = { execute }; GH_AW_SAFE_INPUTS_JS_READY-TO-MAKE-PR_EOF @@ -1447,7 +1449,6 @@ jobs: runs-on: ubuntu-slim permissions: contents: write - issues: write pull-requests: write outputs: noop_message: ${{ steps.noop.outputs.noop_message }} @@ -1568,7 +1569,6 @@ jobs: runs-on: ubuntu-slim permissions: contents: write - issues: write pull-requests: write timeout-minutes: 15 env: diff --git a/.github/workflows/gh-aw-product-manager-impersonator.lock.yml b/.github/workflows/gh-aw-product-manager-impersonator.lock.yml index 8a391b78..2e81c7cb 100644 --- a/.github/workflows/gh-aw-product-manager-impersonator.lock.yml +++ b/.github/workflows/gh-aw-product-manager-impersonator.lock.yml @@ -39,7 +39,7 @@ # # inlined-imports: true # -# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"9a1ff65537dfbd445b36543d1b04a904ea6fb253e2ba66a46c02f43d37ffdab2"} +# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"cd15f3aa9b738182a9b0d46b3f9b25cf7fe95153d0c7f0ca0a7048791173e102"} name: "Product Manager Impersonator" "on": @@ -61,6 +61,11 @@ name: "Product Manager Impersonator" description: Allowlisted bot actor usernames (comma-separated) required: false type: string + idea-size: + default: small + description: "Size framing for the idea: 'small' (iterative, quick wins) or 'medium' (1-2 sprint scope)" + required: false + type: string messages-footer: default: "" description: Footer appended to all agent comments and reviews @@ -71,6 +76,11 @@ name: "Product Manager Impersonator" description: AI model to use required: false type: string + persona: + default: "" + description: Optional persona description that sets the perspective for idea generation (e.g., 'a seasoned SRE who lives in logs and traces'). When empty, uses a generic product thinker perspective. + required: false + type: string setup-commands: default: "" description: Shell commands to run before the agent starts (dependency install, build, etc.) @@ -89,7 +99,7 @@ permissions: {} concurrency: cancel-in-progress: true - group: product-manager-impersonator + group: product-manager-impersonator-${{ inputs.title-prefix }} run-name: "Product Manager Impersonator" @@ -139,6 +149,7 @@ jobs: 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_EXPR_7369865F: ${{ inputs.idea-size }} GH_AW_EXPR_BF503D80: ${{ inputs.title-prefix }} GH_AW_GITHUB_ACTOR: ${{ github.actor }} GH_AW_GITHUB_EVENT_COMMENT_ID: ${{ github.event.comment.id }} @@ -148,6 +159,7 @@ jobs: GH_AW_GITHUB_REPOSITORY: ${{ github.repository }} GH_AW_GITHUB_RUN_ID: ${{ github.run_id }} GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }} + GH_AW_INPUTS_PERSONA: ${{ inputs.persona }} run: | bash /opt/gh-aw/actions/create_prompt_first.sh { @@ -364,8 +376,13 @@ jobs: GH_AW_PROMPT_EOF cat << 'GH_AW_PROMPT_EOF' + **Persona:** `__GH_AW_INPUTS_PERSONA__` + **Idea size:** `__GH_AW_EXPR_7369865F__` + 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. + If `persona` above is set (not empty), adopt that persona fully — bring its domain knowledge, professional pain points, and perspective to every idea you propose. For example, if the persona is "a seasoned SRE who lives in logs, metrics, and distributed traces", think like an SRE and propose features that address observability workflows. + Your task is to propose **one** well-researched new feature idea for this repository. ## Report Assignment @@ -375,6 +392,7 @@ jobs: 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. + - If a persona is set, identify which aspects of the project's domain are most relevant to that persona's perspective. 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. @@ -383,18 +401,23 @@ 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 reports: `repo:{owner}/{repo} is:issue in:title "__GH_AW_EXPR_BF503D80__"`. + - Review `/tmp/previous-findings.json` for issues already filed by this agent. - 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. + - **Customer-aligned**: A real user or customer could plausibly request this feature. If a persona is set, frame the need from that persona's perspective. 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. + **Size guidance based on `idea-size`:** + - If `idea-size` is `small`: Scope the idea as a quick iterative win — something a single developer could implement in a day or two. Not a one-liner, but not a sprint-level commitment. + - If `idea-size` is `medium`: Scope the idea for roughly 1–2 sprints of engineering effort. Clearly scoped — not a full redesign, but meaningful enough that a team would need to plan it. + ### Noop If you cannot find a genuinely useful, non-duplicate idea that meets all the criteria above, call `noop` with: @@ -406,14 +429,16 @@ jobs: **Issue title:** Short, punchy feature name - **Issue body:** + **Issue body — use the format matching the `idea-size`:** - > ## 💡 Feature Idea + **For `small` ideas:** + + > ## Feature Idea > > **Summary:** One-sentence summary of the idea. > > ## Why a Customer Would Want This - > [Explain the user need and who benefits] + > [Explain the user need and who benefits. If a persona is set, frame from that perspective.] > > ## Rough Implementation Sketch > - [2–4 bullet points describing the approach] @@ -425,6 +450,31 @@ jobs: > ## Evidence > - [Links to files, issues, or PRs that support the idea] + **For `medium` ideas:** + + > ## Feature Idea + > + > **Summary:** One-sentence summary of the idea. + > + > ## Why a Customer Would Want This + > [Explain the user need and who benefits. If a persona is set, frame from that perspective.] + > + > ## Rough Implementation Sketch + > - [3–6 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] + > + > ## Estimated Effort + > [e.g., "~1 sprint", "~2 sprints"] + > + > ## Risks and Open Questions + > - [Any notable risks, unknowns, or dependencies] + > + > ## Evidence + > - [Links to files, issues, or PRs that support the idea] + ### Labeling - If the `product-manager-impersonator` label exists (check with `github-get_label`), include it in the `create_issue` call; otherwise, rely on the `__GH_AW_EXPR_BF503D80__` title prefix only. @@ -438,6 +488,8 @@ jobs: env: GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt GH_AW_EXPR_49B959F1: ${{ inputs.additional-instructions }} + GH_AW_EXPR_7369865F: ${{ inputs.idea-size }} + GH_AW_INPUTS_PERSONA: ${{ inputs.persona }} GH_AW_EXPR_BF503D80: ${{ inputs.title-prefix }} with: script: | @@ -450,6 +502,7 @@ jobs: env: GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt GH_AW_EXPR_49B959F1: ${{ inputs.additional-instructions }} + GH_AW_EXPR_7369865F: ${{ inputs.idea-size }} GH_AW_EXPR_BF503D80: ${{ inputs.title-prefix }} GH_AW_GITHUB_ACTOR: ${{ github.actor }} GH_AW_GITHUB_EVENT_COMMENT_ID: ${{ github.event.comment.id }} @@ -459,6 +512,7 @@ jobs: GH_AW_GITHUB_REPOSITORY: ${{ github.repository }} GH_AW_GITHUB_RUN_ID: ${{ github.run_id }} GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }} + GH_AW_INPUTS_PERSONA: ${{ inputs.persona }} GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_ACTIVATED: ${{ needs.pre_activation.outputs.activated }} with: script: | @@ -472,6 +526,7 @@ jobs: file: process.env.GH_AW_PROMPT, substitutions: { GH_AW_EXPR_49B959F1: process.env.GH_AW_EXPR_49B959F1, + GH_AW_EXPR_7369865F: process.env.GH_AW_EXPR_7369865F, GH_AW_EXPR_BF503D80: process.env.GH_AW_EXPR_BF503D80, GH_AW_GITHUB_ACTOR: process.env.GH_AW_GITHUB_ACTOR, GH_AW_GITHUB_EVENT_COMMENT_ID: process.env.GH_AW_GITHUB_EVENT_COMMENT_ID, @@ -481,6 +536,7 @@ jobs: 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_INPUTS_PERSONA: process.env.GH_AW_INPUTS_PERSONA, GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_ACTIVATED: process.env.GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_ACTIVATED } }); diff --git a/.github/workflows/gh-aw-product-manager-impersonator.md b/.github/workflows/gh-aw-product-manager-impersonator.md index b15d9239..7beb4e58 100644 --- a/.github/workflows/gh-aw-product-manager-impersonator.md +++ b/.github/workflows/gh-aw-product-manager-impersonator.md @@ -25,6 +25,16 @@ on: type: string required: false default: "gpt-5.3-codex" + persona: + description: "Optional persona description that sets the perspective for idea generation (e.g., 'a seasoned SRE who lives in logs and traces'). When empty, uses a generic product thinker perspective." + type: string + required: false + default: "" + idea-size: + description: "Size framing for the idea: 'small' (iterative, quick wins) or 'medium' (1-2 sprint scope)" + type: string + required: false + default: "small" additional-instructions: description: "Repo-specific instructions appended to the agent prompt" type: string @@ -57,7 +67,7 @@ on: bots: - "${{ inputs.allowed-bot-users }}" concurrency: - group: product-manager-impersonator + group: product-manager-impersonator-${{ inputs.title-prefix }} cancel-in-progress: true permissions: contents: read @@ -84,8 +94,13 @@ steps: run: eval "$SETUP_COMMANDS" --- +**Persona:** `${{ inputs.persona }}` +**Idea size:** `${{ inputs.idea-size }}` + 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. +If `persona` above is set (not empty), adopt that persona fully — bring its domain knowledge, professional pain points, and perspective to every idea you propose. For example, if the persona is "a seasoned SRE who lives in logs, metrics, and distributed traces", think like an SRE and propose features that address observability workflows. + Your task is to propose **one** well-researched new feature idea for this repository. ## Report Assignment @@ -95,6 +110,7 @@ Your task is to propose **one** well-researched new feature idea for this reposi 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. + - If a persona is set, identify which aspects of the project's domain are most relevant to that persona's perspective. 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. @@ -103,18 +119,23 @@ 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 reports: `repo:{owner}/{repo} is:issue in:title "${{ inputs.title-prefix }}"`. + - Review `/tmp/previous-findings.json` for issues already filed by this agent. - 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. +- **Customer-aligned**: A real user or customer could plausibly request this feature. If a persona is set, frame the need from that persona's perspective. 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. +**Size guidance based on `idea-size`:** +- If `idea-size` is `small`: Scope the idea as a quick iterative win — something a single developer could implement in a day or two. Not a one-liner, but not a sprint-level commitment. +- If `idea-size` is `medium`: Scope the idea for roughly 1–2 sprints of engineering effort. Clearly scoped — not a full redesign, but meaningful enough that a team would need to plan it. + ### Noop If you cannot find a genuinely useful, non-duplicate idea that meets all the criteria above, call `noop` with: @@ -126,14 +147,16 @@ If you cannot find a genuinely useful, non-duplicate idea that meets all the cri **Issue title:** Short, punchy feature name -**Issue body:** +**Issue body — use the format matching the `idea-size`:** + +**For `small` ideas:** -> ## 💡 Feature Idea +> ## Feature Idea > > **Summary:** One-sentence summary of the idea. > > ## Why a Customer Would Want This -> [Explain the user need and who benefits] +> [Explain the user need and who benefits. If a persona is set, frame from that perspective.] > > ## Rough Implementation Sketch > - [2–4 bullet points describing the approach] @@ -145,6 +168,31 @@ If you cannot find a genuinely useful, non-duplicate idea that meets all the cri > ## Evidence > - [Links to files, issues, or PRs that support the idea] +**For `medium` ideas:** + +> ## Feature Idea +> +> **Summary:** One-sentence summary of the idea. +> +> ## Why a Customer Would Want This +> [Explain the user need and who benefits. If a persona is set, frame from that perspective.] +> +> ## Rough Implementation Sketch +> - [3–6 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] +> +> ## Estimated Effort +> [e.g., "~1 sprint", "~2 sprints"] +> +> ## Risks and Open Questions +> - [Any notable risks, unknowns, or dependencies] +> +> ## Evidence +> - [Links to files, issues, or PRs that support the idea] + ### Labeling - If the `product-manager-impersonator` label exists (check with `github-get_label`), include it in the `create_issue` call; otherwise, rely on the `${{ inputs.title-prefix }}` title prefix only. diff --git a/.github/workflows/gh-aw-release-update.lock.yml b/.github/workflows/gh-aw-release-update.lock.yml index 6435b55c..22c8e813 100644 --- a/.github/workflows/gh-aw-release-update.lock.yml +++ b/.github/workflows/gh-aw-release-update.lock.yml @@ -36,7 +36,7 @@ # # inlined-imports: true # -# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"827f89b7f5a80bdea850fd395211b792d19bb67b4b3525f1e1284962dcb88c72"} +# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"b67d3b9f175abb92080e3b14c0c68aa1746a7ea20d75670b70fc23fef1304cbb"} name: "Release Update Check" "on": @@ -884,7 +884,9 @@ jobs: if (contributing) checklist.push(`Review the contributing guide (${contributing}) before opening or updating a PR.`); if (prTemplate) checklist.push(`Follow the PR template (${prTemplate}) for title, description, and validation notes.`); checklist.push('Confirm the requested task is fully completed and validated before creating or pushing PR changes.'); - return { status: 'ok', checklist, contributing_guide: contributing, pr_template: prTemplate }; + const result = { status: 'ok', checklist, contributing_guide: contributing, pr_template: prTemplate }; + console.log(JSON.stringify(result)); + return result; } module.exports = { execute }; GH_AW_SAFE_INPUTS_JS_READY-TO-MAKE-PR_EOF diff --git a/.github/workflows/gh-aw-scheduled-fix.lock.yml b/.github/workflows/gh-aw-scheduled-fix.lock.yml index 5ffb825a..a31825c8 100644 --- a/.github/workflows/gh-aw-scheduled-fix.lock.yml +++ b/.github/workflows/gh-aw-scheduled-fix.lock.yml @@ -37,7 +37,7 @@ # # inlined-imports: true # -# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"283c05e2524390ee44f1998e68fe2e89e9f5f102d0bb078e8a0a8b0fc71066fe"} +# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"154f672a99f85027c1616145f6e00a6ac8b448146e7d7643a063867bd8ee7604"} name: "Scheduled Fix" "on": @@ -939,7 +939,9 @@ jobs: if (contributing) checklist.push(`Review the contributing guide (${contributing}) before opening or updating a PR.`); if (prTemplate) checklist.push(`Follow the PR template (${prTemplate}) for title, description, and validation notes.`); checklist.push('Confirm the requested task is fully completed and validated before creating or pushing PR changes.'); - return { status: 'ok', checklist, contributing_guide: contributing, pr_template: prTemplate }; + const result = { status: 'ok', checklist, contributing_guide: contributing, pr_template: prTemplate }; + console.log(JSON.stringify(result)); + return result; } module.exports = { execute }; GH_AW_SAFE_INPUTS_JS_READY-TO-MAKE-PR_EOF diff --git a/.github/workflows/gh-aw-small-problem-fixer.lock.yml b/.github/workflows/gh-aw-small-problem-fixer.lock.yml index 269a8834..61c48614 100644 --- a/.github/workflows/gh-aw-small-problem-fixer.lock.yml +++ b/.github/workflows/gh-aw-small-problem-fixer.lock.yml @@ -37,7 +37,7 @@ # # inlined-imports: true # -# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"e092ff28edc39fa1f25befee51bc0924487ec9fe61756c5f9e63e9c8992affae"} +# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"5e03acc344c30e36c9a1dce6a565bfc64c074b037d29b9c501110d57cbefb8c5"} name: "Small Problem Fixer" "on": @@ -274,7 +274,7 @@ jobs: - **Links**: Max 50 URLs per comment. - **HTML**: Only safe tags allowed (`details`, `summary`, `code`, `pre`, `blockquote`, `table`, `b`, `em`, `strong`, `h1`–`h6`, `hr`, `br`, `li`, `ol`, `ul`, `p`, `sub`, `sup`). Other tags are converted to parentheses. - **URLs**: Only HTTPS URLs to allowed domains. Non-HTTPS and non-allowed domains are redacted. - - **Bot triggers**: References like `fixes #123` or `closes #456` are neutralized to prevent unintended issue closures. + - **Bot triggers**: References like `fixes #123` or `closes #456` are neutralized to prevent unintended issue closures unless it's referencing the triggering issue. If you exceed 10 mentions or 50 links, the comment will be rejected. GH_AW_PROMPT_EOF @@ -967,7 +967,9 @@ jobs: if (contributing) checklist.push(`Review the contributing guide (${contributing}) before opening or updating a PR.`); if (prTemplate) checklist.push(`Follow the PR template (${prTemplate}) for title, description, and validation notes.`); checklist.push('Confirm the requested task is fully completed and validated before creating or pushing PR changes.'); - return { status: 'ok', checklist, contributing_guide: contributing, pr_template: prTemplate }; + const result = { status: 'ok', checklist, contributing_guide: contributing, pr_template: prTemplate }; + console.log(JSON.stringify(result)); + return result; } module.exports = { execute }; GH_AW_SAFE_INPUTS_JS_READY-TO-MAKE-PR_EOF diff --git a/.github/workflows/gh-aw-test-improvement.lock.yml b/.github/workflows/gh-aw-test-improvement.lock.yml index a1d67faf..be15c05b 100644 --- a/.github/workflows/gh-aw-test-improvement.lock.yml +++ b/.github/workflows/gh-aw-test-improvement.lock.yml @@ -41,7 +41,7 @@ # # inlined-imports: true # -# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"0cb0e71f5f360f41d4858c9db3ca1aa5c20d667d07d3204f5c50947d71e43a0b"} +# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"6ef72d1d56c561e01f84ccfcc3cd5910ff72093b3c9771e73f1c86bb9415f3aa"} name: "Test Improver" "on": @@ -927,7 +927,9 @@ jobs: if (contributing) checklist.push(`Review the contributing guide (${contributing}) before opening or updating a PR.`); if (prTemplate) checklist.push(`Follow the PR template (${prTemplate}) for title, description, and validation notes.`); checklist.push('Confirm the requested task is fully completed and validated before creating or pushing PR changes.'); - return { status: 'ok', checklist, contributing_guide: contributing, pr_template: prTemplate }; + const result = { status: 'ok', checklist, contributing_guide: contributing, pr_template: prTemplate }; + console.log(JSON.stringify(result)); + return result; } module.exports = { execute }; GH_AW_SAFE_INPUTS_JS_READY-TO-MAKE-PR_EOF diff --git a/.github/workflows/gh-aw-test-improver.lock.yml b/.github/workflows/gh-aw-test-improver.lock.yml index 6f54c8a9..c8c77089 100644 --- a/.github/workflows/gh-aw-test-improver.lock.yml +++ b/.github/workflows/gh-aw-test-improver.lock.yml @@ -36,7 +36,7 @@ # # inlined-imports: true # -# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"0cb0e71f5f360f41d4858c9db3ca1aa5c20d667d07d3204f5c50947d71e43a0b"} +# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"6ef72d1d56c561e01f84ccfcc3cd5910ff72093b3c9771e73f1c86bb9415f3aa"} name: "Test Improver" "on": @@ -922,7 +922,9 @@ jobs: if (contributing) checklist.push(`Review the contributing guide (${contributing}) before opening or updating a PR.`); if (prTemplate) checklist.push(`Follow the PR template (${prTemplate}) for title, description, and validation notes.`); checklist.push('Confirm the requested task is fully completed and validated before creating or pushing PR changes.'); - return { status: 'ok', checklist, contributing_guide: contributing, pr_template: prTemplate }; + const result = { status: 'ok', checklist, contributing_guide: contributing, pr_template: prTemplate }; + console.log(JSON.stringify(result)); + return result; } module.exports = { execute }; GH_AW_SAFE_INPUTS_JS_READY-TO-MAKE-PR_EOF diff --git a/.github/workflows/gh-aw-text-beautifier.lock.yml b/.github/workflows/gh-aw-text-beautifier.lock.yml index 139a275e..4d4135b8 100644 --- a/.github/workflows/gh-aw-text-beautifier.lock.yml +++ b/.github/workflows/gh-aw-text-beautifier.lock.yml @@ -38,7 +38,7 @@ # # inlined-imports: true # -# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"074493ba72bde72df5c7239557613e11e0caefe45f2e4efd4c605aca5f6015a0"} +# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"a84d576ef9fe7b8f6ee3f14265c08db439edbdb171c63a4df7284d82b0a5dc6c"} name: "Text Beautifier" "on": @@ -924,7 +924,9 @@ jobs: if (contributing) checklist.push(`Review the contributing guide (${contributing}) before opening or updating a PR.`); if (prTemplate) checklist.push(`Follow the PR template (${prTemplate}) for title, description, and validation notes.`); checklist.push('Confirm the requested task is fully completed and validated before creating or pushing PR changes.'); - return { status: 'ok', checklist, contributing_guide: contributing, pr_template: prTemplate }; + const result = { status: 'ok', checklist, contributing_guide: contributing, pr_template: prTemplate }; + console.log(JSON.stringify(result)); + return result; } module.exports = { execute }; GH_AW_SAFE_INPUTS_JS_READY-TO-MAKE-PR_EOF diff --git a/.github/workflows/trigger-autonomy-atomicity-analyzer.yml b/.github/workflows/trigger-autonomy-atomicity-analyzer.yml new file mode 100644 index 00000000..a6efe0f8 --- /dev/null +++ b/.github/workflows/trigger-autonomy-atomicity-analyzer.yml @@ -0,0 +1,18 @@ +# This file is auto-generated by scripts/dogfood.sh. Do not edit directly. +# Edit gh-agent-workflows/autonomy-atomicity-analyzer/example.yml and run 'make compile' to regenerate. +name: Trigger Autonomy Atomicity Analyzer +on: + schedule: + - cron: "0 16 * * 1-5" + workflow_dispatch: + +permissions: + contents: read + issues: write + pull-requests: read + +jobs: + run: + uses: ./.github/workflows/gh-aw-autonomy-atomicity-analyzer.lock.yml + secrets: + COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} diff --git a/.github/workflows/trigger-framework-best-practices.yml b/.github/workflows/trigger-framework-best-practices.yml new file mode 100644 index 00000000..c48df73b --- /dev/null +++ b/.github/workflows/trigger-framework-best-practices.yml @@ -0,0 +1,18 @@ +# This file is auto-generated by scripts/dogfood.sh. Do not edit directly. +# Edit gh-agent-workflows/framework-best-practices/example.yml and run 'make compile' to regenerate. +name: Trigger Framework Best Practices +on: + schedule: + - cron: "0 13 * * 1-5" + workflow_dispatch: + +permissions: + contents: read + issues: write + pull-requests: read + +jobs: + run: + uses: ./.github/workflows/gh-aw-framework-best-practices.lock.yml + secrets: + COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} diff --git a/.github/workflows/trigger-information-architecture.yml b/.github/workflows/trigger-information-architecture.yml new file mode 100644 index 00000000..e4a1b65b --- /dev/null +++ b/.github/workflows/trigger-information-architecture.yml @@ -0,0 +1,18 @@ +# This file is auto-generated by scripts/dogfood.sh. Do not edit directly. +# Edit gh-agent-workflows/information-architecture/example.yml and run 'make compile' to regenerate. +name: Trigger Information Architecture +on: + schedule: + - cron: "0 17 * * 1-5" + workflow_dispatch: + +permissions: + contents: read + issues: write + pull-requests: read + +jobs: + run: + uses: ./.github/workflows/gh-aw-information-architecture.lock.yml + secrets: + COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} diff --git a/docs/blog/posts/a-day-in-the-factory.md b/docs/blog/posts/a-day-in-the-factory.md index e386c0e2..d17c2a41 100644 --- a/docs/blog/posts/a-day-in-the-factory.md +++ b/docs/blog/posts/a-day-in-the-factory.md @@ -8,11 +8,11 @@ categories: # A Day in the Factory -What does it look like when a repo runs the full Elastic AI Software Factory? We deployed the framework on our playground repository -- combining the named workflows that ship with ai-github-actions and a set of custom [Scheduled Audit](../../workflows/gh-agent-workflows/scheduled-audit.md) configurations (Ideas Man agents, Playwright smoke testers, and domain-specific analyzers). The result is over 30 agents running on a daily schedule, and from the outside it can look like chaos. But there is a rhythm to it. +What does it look like when a repo runs the full Elastic AI Software Factory? We deployed the framework on our playground repository -- combining the named workflows that ship with ai-github-actions and a set of custom [Scheduled Audit](../../workflows/gh-agent-workflows/scheduled-audit.md) configurations (Ideas Man agents and Playwright smoke testers). The result is over 30 agents running on a daily schedule, and from the outside it can look like chaos. But there is a rhythm to it. -This is the story of a Monday in that deployment, told hour by hour. All times are UTC. Some agents below are named workflows from the framework (Bug Hunter, PR Review, etc.). Others are custom configurations we built on the Scheduled Audit base (marked with *custom* in the schedule table). Your deployment will look different -- the point is the pattern, not the specific lineup. +This is the story of a Monday in that deployment, told hour by hour. All times are UTC. Some agents below are named workflows from the framework (Bug Hunter, PR Review, etc.). Others are custom configurations we built on the Scheduled Audit base (marked with *custom* in the schedule table). A few — like Framework Best Practices, Autonomy Atomicity Analyzer, and Information Architecture — started as custom configurations and graduated to named workflows. Your deployment will look different -- the point is the pattern, not the specific lineup. The event-driven agents are always listening in the background, but the scheduled crew punches in at 9 AM sharp. @@ -60,11 +60,11 @@ All times UTC, weekdays unless noted. | 10:00 AM | Smoke Connection Dialog *(custom)*, Medium Ideas Man *(custom)*, Product Manager Impersonator, Text Auditor | | 11:00 AM | Smoke Auth Tab Switch *(custom)*, Security Ideas Man *(custom)*, Bug Hunter | | 12:00 PM | Smoke Connect Button Enablement *(custom)*, Observability Ideas Man *(custom)*, Code Duplication Detector | -| 1:00 PM | Smoke Reset Visibility *(custom)*, Vector Search Ideas Man *(custom)*, Framework Best Practices *(custom)* | +| 1:00 PM | Smoke Reset Visibility *(custom)*, Vector Search Ideas Man *(custom)*, Framework Best Practices | | 2:00 PM | Flaky Test Investigator, Performance Profiler, Breaking Change Detector | | 3:00 PM | Code Simplifier, Refactor Opportunist, Docs Patrol | -| 4:00 PM | Newbie Contributor Patrol, Autonomy Atomicity Analyzer *(custom)*, Stale Issues | -| 5:00 PM | Information Architecture *(custom)*, UX Design Patrol, Small Problem Fixer, Test Improver *(weekly)* | +| 4:00 PM | Newbie Contributor Patrol, Autonomy Atomicity Analyzer, Stale Issues | +| 5:00 PM | Information Architecture, UX Design Patrol, Small Problem Fixer, Test Improver *(weekly)* | **Event-driven (anytime):** PR Review, PR Actions Detective, Branch Actions Detective, Issue Triage, Duplicate Issue Detector, Update PR Body diff --git a/docs/blog/posts/meet-the-idea-machines.md b/docs/blog/posts/meet-the-idea-machines.md index 0ceb5a63..6713392d 100644 --- a/docs/blog/posts/meet-the-idea-machines.md +++ b/docs/blog/posts/meet-the-idea-machines.md @@ -12,7 +12,7 @@ What if your repo generated its own feature backlog every morning? Not vague "we -The Idea Machines don't ship as named workflows in the ai-github-actions framework. They're custom configurations we built on top of the [Scheduled Audit](../../workflows/gh-agent-workflows/scheduled-audit.md) base workflow using `additional-instructions` to define each agent's persona and domain focus. We're showing them here because they demonstrate one of the most powerful patterns in the factory: take a generic base workflow, give it a personality, and let it run. +The Idea Machines are all instances of the [Product Manager Impersonator](../../workflows/gh-agent-workflows/product-manager-impersonator.md) workflow, configured with different `persona` and `idea-size` inputs. You run the same workflow multiple times in a single trigger file — each job gets its own persona, scope, and title prefix. Here's what we built for our playground repo. You can build your own set for any domain. @@ -54,6 +54,6 @@ The result is a self-generating feature backlog that represents perspectives you ## Build Your Own -Every Ideas Man agent is a [Scheduled Audit](../../workflows/gh-agent-workflows/scheduled-audit.md) workflow with a custom `additional-instructions` prompt. You're not limited to these five personas. Need a "Data Pipeline Ideas Man" or a "Mobile UX Ideas Man"? Copy the Scheduled Audit example, write your persona prompt, set a cron schedule, and you're running. +Every Ideas Man agent is a [Product Manager Impersonator](../../workflows/gh-agent-workflows/product-manager-impersonator.md) job with its own `persona`, `idea-size`, and `title-prefix`. You're not limited to these five personas. Need a "Data Pipeline Ideas Man" or a "Mobile UX Ideas Man"? Add another job to your trigger file with a new persona prompt and you're running. See the [Product Manager Impersonator README](../../workflows/gh-agent-workflows/product-manager-impersonator.md) for a multi-persona example. See the [workflow docs](../../workflows/gh-agent-workflows.md) for setup instructions and base workflow details. If you're new to the factory, start with the [welcome post](welcome-to-the-factory.md) for the full picture. diff --git a/docs/blog/posts/meet-the-quality-crew.md b/docs/blog/posts/meet-the-quality-crew.md index 7a10b9a1..843b1ab5 100644 --- a/docs/blog/posts/meet-the-quality-crew.md +++ b/docs/blog/posts/meet-the-quality-crew.md @@ -48,13 +48,13 @@ The Refactor Opportunist runs on a weekday schedule, scanning for functions that User-facing strings deserve the same care as code. The Text Auditor scans for grammar issues, unclear phrasing, and inconsistent terminology across all user-visible text. The Text Beautifier creates PRs to fix what the Auditor finds. Same detector/fixer pattern, applied to language instead of logic. -## Custom Quality Agents +## [Framework Best Practices](../../workflows/gh-agent-workflows/framework-best-practices.md) and [Autonomy Atomicity Analyzer](../../workflows/gh-agent-workflows/autonomy-atomicity-analyzer.md) -The base workflows make it straightforward to build your own quality agents. In our playground repo we run two custom [Scheduled Audit](../../workflows/gh-agent-workflows/scheduled-audit.md) configurations that sit at the proactive end of the spectrum: a **Framework Best Practices** agent that checks whether you're using your libraries the way they were designed, and an **Autonomy Atomicity Analyzer** that finds structural patterns (god files, merge-conflict magnets, over-broad tests) that cause problems when multiple developers work in parallel. These aren't named workflows in the framework -- they're examples of what you can build with `additional-instructions`. +These two agents sit at the proactive end of the quality spectrum. [Framework Best Practices](../../workflows/gh-agent-workflows/framework-best-practices.md) reads your dependency manifest, discovers your tech stack, and scans for patterns that reinvent or work around library features — custom utilities that duplicate what a framework already provides, deprecated API styles, and missing optimizations. [Autonomy Atomicity Analyzer](../../workflows/gh-agent-workflows/autonomy-atomicity-analyzer.md) finds structural patterns that cause problems when multiple developers or agents work in parallel: god files with disproportionate fan-in, merge-conflict magnets like manual routing registries, over-broad tests that break on any change, and shared configuration hotspots. Both run on a weekday schedule and stay silent when there's nothing to report. ## The Quality Spectrum -Step back and look at this squad as a progression. Bug Hunter sits at the reactive end: find real bugs hurting users right now. Flaky Test Investigator moves upstream: find test infrastructure problems before they erode confidence. Code Duplication Detector shifts to structural issues: find patterns that will cause bugs eventually. Refactor Opportunist and Code Simplifier work at the architecture level: improve code so bugs are harder to introduce. And with custom audit agents, you can push even further into proactive territory -- preventing entire categories of problems by getting the design right. +Step back and look at this squad as a progression. Bug Hunter sits at the reactive end: find real bugs hurting users right now. Flaky Test Investigator moves upstream: find test infrastructure problems before they erode confidence. Code Duplication Detector shifts to structural issues: find patterns that will cause bugs eventually. Refactor Opportunist and Code Simplifier work at the architecture level: improve code so bugs are harder to introduce. And Framework Best Practices and Autonomy Atomicity Analyzer push even further into proactive territory -- preventing entire categories of problems by getting the design right. Reactive to proactive. No single agent covers the whole spectrum, but together the Quality Crew covers every stage from "something is broken" to "let's make sure it never breaks." diff --git a/docs/blog/posts/meet-the-watchdogs.md b/docs/blog/posts/meet-the-watchdogs.md index 26092b9f..ec8350fe 100644 --- a/docs/blog/posts/meet-the-watchdogs.md +++ b/docs/blog/posts/meet-the-watchdogs.md @@ -30,9 +30,9 @@ This one runs on a weekly schedule and does something a little meta: it keeps th Running on a weekday schedule, the UX Design Patrol reviews UI components for design consistency, accessibility compliance, and adherence to established UX patterns. It catches the kind of drift that happens when multiple developers build features independently — slightly different button styles, inconsistent spacing, missing ARIA labels. Design systems help, but they do not enforce themselves. This agent does. -## Custom Watchdog: Information Architecture +## [Information Architecture](../../workflows/gh-agent-workflows/information-architecture.md) -In our playground repo we also run an **Information Architecture** agent -- a custom [Scheduled Audit](../../workflows/gh-agent-workflows/scheduled-audit.md) configuration that evaluates whether the application's interface is logically organized, navigable, and consistent. It checks navigation flow, button placement, data presentation patterns, progressive disclosure, and empty states. This isn't a named workflow in the framework -- it's an example of what you can build with `additional-instructions` when your repo needs a domain-specific watchdog. +The Information Architecture agent evaluates whether the application's interface is logically organized, navigable, and consistent. It traces the component tree from the top-level layout, examining navigation structure, action placement, data presentation patterns, progressive disclosure, and empty states. It only files an issue when it finds a concrete, user-impacting IA problem — something a real user would likely get confused or frustrated by. Like the other watchdogs, most runs end with `noop`. ## [Downstream Health](../../workflows/gh-agent-workflows/downstream-health.md) @@ -40,7 +40,7 @@ Running on a daily schedule, the Downstream Health agent monitors the overall qu ## How They Work Together -The watchdogs are not independent sentries -- they overlap intentionally. The Breaking Change Detector catches API-level regressions. The Performance Profiler catches runtime regressions. The UX Design Patrol catches visual and consistency drift. The Release Update Check keeps the tooling current so the other agents are always running the latest checks. And Downstream Health ties it all together with a broad quality signal across the repositories that depend on us. Custom watchdogs like Information Architecture extend coverage into domains specific to your project. +The watchdogs are not independent sentries -- they overlap intentionally. The Breaking Change Detector catches API-level regressions. The Performance Profiler catches runtime regressions. The UX Design Patrol catches visual and consistency drift. The Release Update Check keeps the tooling current so the other agents are always running the latest checks. And Downstream Health ties it all together with a broad quality signal across the repositories that depend on us. Information Architecture extends coverage into the domain of UI structure and navigation. None of these agents replace human judgment. They surface the things humans would eventually notice — just weeks or months earlier, when fixing them is still cheap. diff --git a/docs/blog/posts/welcome-to-the-factory.md b/docs/blog/posts/welcome-to-the-factory.md index 524bf76a..49a88bad 100644 --- a/docs/blog/posts/welcome-to-the-factory.md +++ b/docs/blog/posts/welcome-to-the-factory.md @@ -56,13 +56,13 @@ We've organized the agents into squads based on what they do. Each squad has its **[The Issue Squad](meet-the-issue-squad.md)** — Issue Triage, Duplicate Issue Detector, Stale Issues, Plan, and Deep Research. A new issue lands and within seconds it's labeled, prioritized, and checked against every existing issue for duplicates. Deep Research is the one agent that breaks the mold — it uses Google Gemini instead of Copilot for extended investigation. -**[The Quality Crew](meet-the-quality-crew.md)** — Bug Hunter, Bug Exterminator, Flaky Test Investigator, Code Duplication Detector, Refactor Opportunist, Text Auditor, and more. They form a spectrum from "find bugs" (reactive) to "prevent bugs" (proactive architecture analysis). Bug Hunter has the highest quality bar in the factory — mandatory local reproduction, concrete failure scenarios, evidence-based findings. +**[The Quality Crew](meet-the-quality-crew.md)** — Bug Hunter, Bug Exterminator, Flaky Test Investigator, Code Duplication Detector, Refactor Opportunist, Text Auditor, Framework Best Practices, Autonomy Atomicity Analyzer, and more. They form a spectrum from "find bugs" (reactive) to "prevent bugs" (proactive architecture analysis). Bug Hunter has the highest quality bar in the factory — mandatory local reproduction, concrete failure scenarios, evidence-based findings. -**[The Idea Machines](meet-the-idea-machines.md)** — Custom audit agents we built using the Scheduled Audit base workflow, each thinking from a different persona. An example of what you can build when you give a generic workflow a personality and a schedule. +**[The Idea Machines](meet-the-idea-machines.md)** — Product Manager Impersonator configured with different personas, each thinking from a different domain. An SRE, a security analyst, a search engineer — all generating feature ideas daily. **[The Smoke Testers](meet-the-smoke-testers.md)** — Custom audit agents that run Playwright tests every weekday morning. Another example of the base workflow pattern — silence unless something breaks. -**[The Watchdogs](meet-the-watchdogs.md)** — Breaking Change Detector, Performance Profiler, UX Design Patrol, and Release Update Check. They guard the things developers forget to check — undocumented API changes, performance regressions, design drift. +**[The Watchdogs](meet-the-watchdogs.md)** — Breaking Change Detector, Performance Profiler, UX Design Patrol, Information Architecture, and Release Update Check. They guard the things developers forget to check — undocumented API changes, performance regressions, design drift, and navigation inconsistencies. **[The Docs Patrol](meet-the-docs-patrol.md)** — Docs Patrol and Docs PR Review. Code changes. Docs don't. These agents make sure they stay in sync, scanning both internal README files and published Elastic documentation for staleness. diff --git a/docs/index.md b/docs/index.md index 512cd628..85732d18 100644 --- a/docs/index.md +++ b/docs/index.md @@ -37,7 +37,7 @@ We built a fleet of specialized AI agents that review PRs, hunt bugs, triage iss --- - Custom audit agents that generate daily feature proposals from different personas. See what you can build with the base workflows. + Product Manager Impersonator, configured with different personas. Daily feature proposals from an iterative thinker, an SRE, a security analyst, and more. - **[The Issue Squad](blog/posts/meet-the-issue-squad.md)** @@ -49,7 +49,7 @@ We built a fleet of specialized AI agents that review PRs, hunt bugs, triage iss --- - Breaking Change Detector, Performance Profiler, UX Design Patrol. They guard the things developers forget to check. + Breaking Change Detector, Performance Profiler, UX Design Patrol, Information Architecture. They guard the things developers forget to check. diff --git a/docs/workflows/gh-agent-workflows.md b/docs/workflows/gh-agent-workflows.md index e54f79a4..1039ea5b 100644 --- a/docs/workflows/gh-agent-workflows.md +++ b/docs/workflows/gh-agent-workflows.md @@ -85,11 +85,15 @@ Many scheduled workflows follow a **detector / fixer** pattern: the detector fin | Workflow | Trigger | Description | | --- | --- | --- | | [Agent Suggestions](gh-agent-workflows/agent-suggestions.md) | Weekly schedule | Suggest new agent workflows based on repo and downstream needs | +| [Autonomy Atomicity Analyzer](gh-agent-workflows/autonomy-atomicity-analyzer.md) | Weekday schedule | Find patterns that block concurrent development by multiple agents or developers | | [Breaking Change Detector](gh-agent-workflows/breaking-change-detector.md) | Weekday schedule | Detect undocumented public breaking changes | | [Code Simplifier](gh-agent-workflows/code-simplifier.md) | Weekday schedule | Simplify overcomplicated code with high-confidence refactors | | [Downstream Health](gh-agent-workflows/downstream-health.md) | Daily schedule | Monitor downstream repo quality | | [Flaky Test Investigator](gh-agent-workflows/flaky-test-investigator.md) | Weekday schedule + failed CI runs | Identify repeated flaky failures and file root-cause-first triage reports | +| [Framework Best Practices](gh-agent-workflows/framework-best-practices.md) | Weekday schedule | Find where library-native features could replace hand-rolled solutions | +| [Information Architecture](gh-agent-workflows/information-architecture.md) | Weekday schedule | Audit UI information architecture for navigation, placement, and consistency | | [Performance Profiler](gh-agent-workflows/performance-profiler.md) | Weekday schedule | Profile performance hotspots | +| [Product Manager Impersonator](gh-agent-workflows/product-manager-impersonator.md) | Weekday schedule | Propose feature ideas from a configurable persona and scope | | [Project Summary](gh-agent-workflows/project-summary.md) | Daily schedule | Summarize recent activity and priorities | | [Release Update Check](gh-agent-workflows/release-update.md) | Weekly schedule | Open a PR updating pinned ai-github-actions workflow SHAs and suggest workflow changes | | [Small Problem Fixer](gh-agent-workflows/small-problem-fixer.md) | Weekday schedule | Fix small, related issues and open a focused PR | diff --git a/gh-agent-workflows/autonomy-atomicity-analyzer/README.md b/gh-agent-workflows/autonomy-atomicity-analyzer/README.md new file mode 100644 index 00000000..63e7f7f2 --- /dev/null +++ b/gh-agent-workflows/autonomy-atomicity-analyzer/README.md @@ -0,0 +1,36 @@ +# Autonomy Atomicity Analyzer + +Find patterns that block concurrent development by multiple agents or developers. + +## How it works + +Scans the project structure for autonomy and atomicity blockers: global mutable state that forces serial edits, manual routing registries that are merge-conflict magnets, god files with disproportionate import fan-in/fan-out, over-broad tests that break on any change, implicit ordering dependencies, and shared configuration hotspots. Only files an issue when a concrete, actionable blocker 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/autonomy-atomicity-analyzer/example.yml \ + -o .github/workflows/autonomy-atomicity-analyzer.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 an autonomy/atomicity blocker report (max 1) diff --git a/gh-agent-workflows/autonomy-atomicity-analyzer/example.yml b/gh-agent-workflows/autonomy-atomicity-analyzer/example.yml new file mode 100644 index 00000000..e0d4636c --- /dev/null +++ b/gh-agent-workflows/autonomy-atomicity-analyzer/example.yml @@ -0,0 +1,16 @@ +name: Autonomy Atomicity Analyzer +on: + schedule: + - cron: "0 16 * * 1-5" + workflow_dispatch: + +permissions: + contents: read + issues: write + pull-requests: read + +jobs: + run: + uses: elastic/ai-github-actions/.github/workflows/gh-aw-autonomy-atomicity-analyzer.lock.yml@v0 + secrets: + COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} diff --git a/gh-agent-workflows/framework-best-practices/README.md b/gh-agent-workflows/framework-best-practices/README.md new file mode 100644 index 00000000..1faec4c1 --- /dev/null +++ b/gh-agent-workflows/framework-best-practices/README.md @@ -0,0 +1,36 @@ +# Framework Best Practices + +Find places where library-native features could replace hand-rolled solutions. + +## How it works + +Reads the project's dependency manifest (`package.json`, `go.mod`, `pyproject.toml`, etc.) to discover the tech stack, then scans the codebase for patterns that reinvent or work around library features — custom utilities that duplicate what a library already provides, state management anti-patterns, UI framework underuse, deprecated API styles, and missing framework optimizations. Only files an issue when a concrete simplification 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/framework-best-practices/example.yml \ + -o .github/workflows/framework-best-practices.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 framework best practices report (max 1) diff --git a/gh-agent-workflows/framework-best-practices/example.yml b/gh-agent-workflows/framework-best-practices/example.yml new file mode 100644 index 00000000..1d311a78 --- /dev/null +++ b/gh-agent-workflows/framework-best-practices/example.yml @@ -0,0 +1,16 @@ +name: Framework Best Practices +on: + schedule: + - cron: "0 13 * * 1-5" + workflow_dispatch: + +permissions: + contents: read + issues: write + pull-requests: read + +jobs: + run: + uses: elastic/ai-github-actions/.github/workflows/gh-aw-framework-best-practices.lock.yml@v0 + secrets: + COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} diff --git a/gh-agent-workflows/information-architecture/README.md b/gh-agent-workflows/information-architecture/README.md new file mode 100644 index 00000000..0e0d789b --- /dev/null +++ b/gh-agent-workflows/information-architecture/README.md @@ -0,0 +1,36 @@ +# Information Architecture + +Audit the application's UI information architecture for navigation, placement, and consistency issues. + +## How it works + +Traces the component tree from the top-level App/Layout component, examining navigation structure, action placement, picker positioning, data presentation, progressive disclosure, grouping, consistency, and empty states. Only files an issue when a concrete, user-impacting IA problem is found — something a real user would likely get confused or frustrated by; 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/information-architecture/example.yml \ + -o .github/workflows/information-architecture.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 an information architecture report (max 1) diff --git a/gh-agent-workflows/information-architecture/example.yml b/gh-agent-workflows/information-architecture/example.yml new file mode 100644 index 00000000..7d1dee6c --- /dev/null +++ b/gh-agent-workflows/information-architecture/example.yml @@ -0,0 +1,16 @@ +name: Information Architecture +on: + schedule: + - cron: "0 17 * * 1-5" + workflow_dispatch: + +permissions: + contents: read + issues: write + pull-requests: read + +jobs: + run: + uses: elastic/ai-github-actions/.github/workflows/gh-aw-information-architecture.lock.yml@v0 + secrets: + COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} diff --git a/gh-agent-workflows/product-manager-impersonator/README.md b/gh-agent-workflows/product-manager-impersonator/README.md index 6b3b25fd..b0210160 100644 --- a/gh-agent-workflows/product-manager-impersonator/README.md +++ b/gh-agent-workflows/product-manager-impersonator/README.md @@ -1,11 +1,13 @@ # Product Manager Impersonator -Propose well-researched new feature ideas as GitHub issues. +Propose well-researched new feature ideas as GitHub issues from a configurable persona and scope. ## 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`. +Use the `persona` input to adopt a domain-specific perspective (e.g., SRE, security analyst, search engineer) and the `idea-size` input to control whether the idea is scoped as a quick win or a multi-sprint effort. + ## Quick Install ```bash @@ -27,10 +29,57 @@ See [example.yml](example.yml) for the full workflow file. | Input | Description | Required | Default | | --- | --- | --- | --- | +| `persona` | Persona description for domain-specific ideas (e.g., `a seasoned SRE who lives in logs and traces`) | No | `""` | +| `idea-size` | Scope framing: `small` (quick iterative win) or `medium` (1–2 sprint effort) | No | `"small"` | | `additional-instructions` | Repo-specific instructions appended to the agent prompt | No | `""` | | `setup-commands` | Shell commands run before the agent starts | No | `""` | +| `title-prefix` | Title prefix for created issues | No | `"[product-manager-impersonator]"` | | `allowed-bot-users` | Allowlisted bot actor usernames (comma-separated) | No | `github-actions[bot]` | +## Example: Running Multiple Personas + +You can run the same workflow multiple times with different personas and title prefixes to get ideas from different perspectives: + +```yaml +name: Ideas +on: + schedule: + - cron: "0 9 * * 1-5" + workflow_dispatch: + +permissions: + contents: read + issues: write + pull-requests: read + +jobs: + iterative-idea: + uses: elastic/ai-github-actions/.github/workflows/gh-aw-product-manager-impersonator.lock.yml@v0 + with: + idea-size: "small" + title-prefix: "[idea]" + secrets: + COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} + + sre-idea: + uses: elastic/ai-github-actions/.github/workflows/gh-aw-product-manager-impersonator.lock.yml@v0 + with: + persona: "a seasoned SRE and platform engineer who lives in logs, metrics, and distributed traces" + idea-size: "small" + title-prefix: "[observability idea]" + secrets: + COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} + + security-idea: + uses: elastic/ai-github-actions/.github/workflows/gh-aw-product-manager-impersonator.lock.yml@v0 + with: + persona: "a seasoned threat-hunter and SOC engineer who lives in dashboards, detection rules, and XDR alert queues" + idea-size: "medium" + title-prefix: "[security idea]" + secrets: + COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} +``` + ## Safe Outputs -- `create-issue` — file a feature idea (max 1, auto-closes older reports) +- `create-issue` — file a feature idea (max 1 per run)