# GitHub Agentic Workflows — Full Corpus > Full content of the agent instruction files for GitHub Agentic Workflows (gh-aw). > This file is intended for AI agents and LLMs that need the complete instruction material. --- description: How to configure action and container image substitutions in aw.json for private-cloud and air-gapped enterprise environments. --- # Action and Container Substitutions Use `action_pins` and `container_pins` in `.github/workflows/aw.json` to redirect compiled action and container image references to internal mirrors — for private-cloud or air-gapped runners where public registries are unreachable. These are repository-level settings in `aw.json`, not workflow frontmatter, so one file controls all redirects across every workflow. ## Action substitutions (`action_pins`) `action_pins` maps `owner/repo@ref` source keys to replacement `owner/repo@ref` values. Applied before the pin-resolution pipeline (cache → GitHub API → embedded pins), so the full chain operates on the mapped target. ```json title=".github/workflows/aw.json" { "action_pins": { "actions/checkout@v4": "acme-corp/checkout-mirror@v4", "actions/setup-node@v4": "acme-corp/setup-node-mirror@v4" } } ``` **Key requirements:** - Keys and values must use format `owner/repo@ref` (validated at schema load time). - Map each source version individually — no wildcard or prefix matching. - The replacement target must itself be resolvable by the pin machinery (dynamic lookup, embedded pins, or local cache); otherwise resolution fails. ## Container substitutions (`container_pins`) `container_pins` maps source container image references (e.g. `ghcr.io/owner/image:tag`) to replacement targets. Applied before digest-pin resolution, so a mirrored image can replace the public source. Each value is an object with separate `image` (ref name) and `digest` (SHA-256) fields, validated independently: ```json title=".github/workflows/aw.json" { "container_pins": { "ghcr.io/github/gh-aw-firewall:0.27.22": { "image": "registry.acme.com/gh-aw-firewall:0.27.22", "digest": "sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" }, "node:lts-alpine": { "image": "registry.acme.com/node:lts-alpine", "digest": "sha256:abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789" } } } ``` **Key requirements:** - Keys are source image references as they appear in compiled workflows (e.g. `image:tag`, `registry/image:tag`). Digest-pinned source keys are not supported. - `image` must be a valid reference without a digest component (e.g. `registry.acme.com/image:tag`). - `digest` must be a full SHA-256 digest in `sha256:<64 lowercase hex chars>` form. Both keys may be set in the same `aw.json`. ## Notes - Substitutions apply at compile time and are baked into the generated `.lock.yml` files. - One console message per mapped key is logged at compile time. - Re-run `gh aw compile` after modifying `aw.json`. - See [Self-Hosted Runners](/gh-aw/reference/self-hosted-runners/#action-and-container-substitutions-awjson) for full docs. --- description: Choose and configure agent runtimes for GitHub Agentic Workflows. disable-model-invocation: true --- # Agent Runtime Instructions Use these instructions when creating or updating workflows that mention Docker, gVisor, Docker sbx, Cloud Hypervisor, ARC DinD, self-hosted runners, or `sandbox.agent.runtime-install`. ## Runtime fields - Omit `sandbox.agent.runtime` for the default Docker agent runtime. - Set `sandbox.agent.runtime: gvisor` only when the runner has a local Docker daemon and can install or already has `runsc`. - Set `sandbox.agent.runtime: docker-sbx` only when the runner supports KVM-backed microVMs. - Set `sandbox.agent.runtime: cloud-hypervisor` only for the preview microVM runtime on a GitHub-hosted Ubuntu x86_64 runner with `/dev/kvm`; prefer `docker-sbx` or `gvisor` when those host constraints are not guaranteed. - Do not set `sandbox.agent.runtime: docker`; Docker is selected by omitting the field. - Do not set `sandbox.agent.runtime: sbx`; `sbx` is not a valid `sandbox.agent.runtime` value. - Set `runner.topology: arc-dind` for ARC or equivalent Kubernetes runners that use a Docker-in-Docker sidecar. This is a runner topology, not an agent runtime. ## Compatibility - Do not combine `runner.topology: arc-dind` with `sandbox.agent.runtime: gvisor`, `sandbox.agent.runtime: docker-sbx`, or `sandbox.agent.runtime: cloud-hypervisor`. - ARC DinD workflows must be rootless: do not add `sudo`, `apt-get install`, or other host package bootstrap steps. - Docker sbx requires KVM and normally does not work on ARC DinD because the sbx daemon must run on the runner host. - Cloud Hypervisor requires `RUNNER_ENVIRONMENT=github-hosted`, Ubuntu Linux x86_64, and `/dev/kvm`; it is not supported on self-hosted or ARC DinD runners. ## `runtime-install` - `sandbox.agent.runtime-install` defaults to `true` for gVisor and Docker sbx provisioning. - Set `runtime-install: false` only when the runner image or pod is pre-provisioned with the runtime and required daemon or policy. - When any imported workflow sets `runtime-install: false`, false wins during import merging. - With `runtime-install: false`, gh-aw skips generated runtime checks and setup, so the runner must already satisfy those prerequisites. ## gVisor guidance - gVisor uses `runsc` for the agent container while AWF infrastructure containers continue to use Docker. - The generated gVisor installer may use host `sudo`; the compiler derives that from `runtime: gvisor`. There is no `sandbox.agent.sudo` field. - Use gVisor when stronger kernel isolation is needed and the workload is compatible with gVisor syscall behavior. ## Docker sbx guidance - Docker sbx runs the agent in a KVM-backed microVM and requires a KVM-capable Linux runner. - With runtime installation enabled, gh-aw installs `docker-sbx`, adjusts `/dev/kvm`, starts the sbx daemon, authenticates CLIs, pulls the template, and runs a smoke test. The compiler derives the required host privileges from `runtime: docker-sbx`. - Docker sbx requires both `DOCKER_USERNAME` and `DOCKER_PAT` Actions secrets. `DOCKER_PAT` must be a Docker Hub personal access token that can authenticate Docker Hub pulls for the sandbox template. - `DOCKER_USERNAME` and `DOCKER_PAT` remain required even with `runtime-install: false`, because compiled workflows refresh sbx credentials immediately before agent execution. - Do not use Docker sbx for workflows triggered from untrusted forks unless the trigger and credential model safely provide those secrets. ## Cloud Hypervisor guidance (preview) - Preview scope is narrow: GitHub-hosted runners only, Ubuntu Linux x86_64 only, and `/dev/kvm` must be present. - The compiler emits host preflight and release-asset provisioning steps that download and checksum-verify the pinned Cloud Hypervisor binary, `virtiofsd`, kernel, rootfs, and supervisor from the `gh-aw-firewall` release before AWF starts, and grants only the runner user scoped read/write access to `/dev/kvm`. - AWF launches with the host privileges required to create the VM but keeps strict network isolation; the guest defaults to 2 vCPUs and 4096 MiB, and its trusted topology attachment is limited to the MCP gateway on TCP 8080 (no CLI proxy). - Not supported under Cloud Hypervisor: `tools.github.mode: gh-proxy`, the `integrity-reactions` feature, `sandbox.agent.allow-host-ports`, GitHub Actions `services:` with published ports, and `enclaves:` configuration. - Do not recommend this runtime for self-hosted, non-Ubuntu, or non-x86_64 runners; use `docker-sbx` or `gvisor` instead. ## ARC DinD guidance - Use `runner.topology: arc-dind` when `DOCKER_HOST` points to a DinD sidecar such as `tcp://localhost:2375` or `tcp://dind:2375`. - Ensure the runner container and DinD sidecar share `/home/runner/_work`. - Use a daemon-visible tool cache path such as `/tmp/gh-aw/tool-cache`, not `/opt/hostedtoolcache`. - If the Docker socket is bind-mounted at a nonstandard path, set `GH_AW_DOCKER_SOCK_PATH`. Set `GH_AW_DOCKER_SOCK_GID` only when group detection with `stat` fails. --- name: agentic-chat description: AI assistant for creating clear, actionable task descriptions for GitHub Copilot coding agent --- # Agentic Task Description Assistant Help users create task descriptions for GitHub Copilot coding agent that work with gh-aw. ## Required Knowledge Load from gh-aw: 1. **Workflows Instructions**: https://raw.githubusercontent.com/github/gh-aw/main/.github/aw/github-agentic-workflows.md 2. **Dictation Instructions**: https://raw.githubusercontent.com/github/gh-aw/main/DICTATION.md ## Core Principles ### 1. Neutral Technical Tone - Direct language; no marketing adjectives ("great", "easy", "powerful") ### 2. Specification Only - **DO NOT generate code** — pseudo-code only - Describe WHAT, not HOW; include acceptance criteria ### 3. Problem Decomposition Each step: what to do, inputs/outputs, constraints. ### 4. Task Description Format ```markdown # create a github agentic workflow that: [specific task goal] ## Objective [Clear statement of what needs to be accomplished] ## Context [Background information and current state] ## Requirements [Specific requirements and constraints] ## Steps - [Step 1] - [Step 2] - [Step 3] ## Constraints - [Constraint 1] - [Constraint 2] ``` ## Pseudo-Code Guidelines **Allowed**: ``` IF condition THEN perform action ELSE perform alternative action END IF FOR EACH item IN collection process item END FOR ``` **Not Allowed**: - Actual code in any programming language (Python, JavaScript, Go, etc.) - Specific library or framework calls - Implementation-specific syntax ## Output Format Wrap the final task description in **5 backticks** for copy/paste: `````markdown [Your complete task description here] ````` **Important**: Title must start with "create a github agentic workflow that:" to trigger instruction loading. ## Interaction Guidelines 1. **Clarify**: outcome, context (repo, issue numbers), constraints, tools (GitHub API, web search, file editing). 2. **Validate**: summarize before creating the spec. 3. **Iterate** on feedback. Stay spec, not implementation. 4. **Cite** loaded instruction files when relevant. 5. **Summarize updates** rather than re-reading full markdown. ## Terminology Use gh-aw terms (see dictation instructions): - "agentic" (not "agent-ick"/"agent-tick") - "workflow" (not "work flow") - "frontmatter" (not "front matter") - "gh-aw" (not "ghaw"/"G H A W") - Hyphenated: "safe-outputs", "cache-memory", "max-turns" ## Do Not - Over-specify — balance clarity with flexibility - Ignore user questions — clarify first **Final Step**: Compile in strict mode and fix errors/warnings before returning. --- description: agentic-workflows MCP server tool reference for workflows that call status, logs, audit, or compile --- # agentic-workflows MCP Server Tools **⚠️ CRITICAL**: `status`, `logs`, `audit`, and `compile` are MCP server tools — NOT shell commands. Do NOT run `gh aw` directly. If the MCP server fails, give up. ## Tools ### `status` Verify MCP server configuration and list all workflows. No required parameters. ### `logs` Download workflow run logs to `/tmp/gh-aw/aw-mcp/logs/`. | Parameter | Description | |---|---| | `workflow_name` | Filter to a specific workflow (leave empty for all) | | `count` | Number of runs (default: 100) | | `start_date` | Filter runs after this date — `YYYY-MM-DD` or relative like `-1d`, `-7d`, `-30d` | | `end_date` | Filter runs before this date | | `engine` | Filter by AI engine: `copilot`, `claude`, `codex` | | `branch` | Filter by branch name | | `firewall` / `no_firewall` | Filter by firewall status | | `filtered_integrity` | Only runs with DIFC integrity-filtered events in gateway logs | | `after_run_id` / `before_run_id` | Paginate by run database ID | If a gateway timeout or token budget guardrail cuts the call short, the response sets `partial: true` and includes `after_run_id`/`before_run_id` — reissue `logs` with that parameter to fetch the rest. ### `audit` Inspect a specific run in detail (missing tools, safe outputs, metrics). | Parameter | Description | |---|---| | `run_id_or_url` | Run ID or run/job URL (including step anchors), as string or number | ### `compile` Recompile workflow `.md` files into `.lock.yml` files. **MCP equivalent of**: `gh aw compile` --- description: Guidance for generating compact ASCII charts that render cleanly in GitHub markdown surfaces. --- # ASCII CHART MAKER Make charts for GitHub issue markdown: easy to read, compact, stable on desktop + mobile, inside a fenced code block. Think monospace grid, fixed width. ## RULES - ALWAYS fenced code block; ALWAYS spaces, NEVER tabs - NEVER ANSI color or escape codes - Width under 80 chars; prefer height under 12 rows - KEEP labels short; optimize for glance reading Bad: `API latency over time for production workloads` — Good: `API Lat` ## BEST GLYPHS Use first: ```text █ ▇ ▆ ▅ ▄ ▃ ▂ ▁ │ ─ ┌ ┐ └ ┘ ``` Fallback: `# * - |`. Use carefully: `╭ ╮ ╰ ╯`. Avoid unless needed: `⣀ ⣄ ⣤ ⣶ ⣿` (braille breaks on some mobile/browser/font combos). ## BEST CHART TYPES ### Sparkline (best overall) ```text CPU ▁▂▃▄▅▆▇█ ``` ### Bars ```text API ████████ DB ████ Cache ██████ ``` ### Table + Trend (best for dashboards) ```text Svc P95 Trend API 84ms ▁▂▃▄▅▆█ DB 12ms ▁▁▂▂▃▄▅ Cache 4ms ▁▁▁▁▂▂▃ ``` ## ALIGNMENT Pad labels to equal width. Good: ```text API ███████ Worker ████ Cache █████████ ``` Bad: ```text API ███████ Worker ████ Cache █████████ ``` ## SCALING - Normalize bars to width; clamp outliers so one spike doesn't dominate. - Prefer trend shape over exact precision — humans read shape fast. ## MOBILE GitHub mobile is narrow. Target 40-60 cols ideal, 80 max. Never make giant wide graphs. ## GOLDEN RULE Make a graph a human understands in 2 seconds. Priority: readability > alignment > compactness > pretty > precision. --- description: Guidance for designing campaign-style agentic workflows with measurable goals, pacing controls, and safe output constraints. --- # Campaign Workflows Coordinated, time-bounded pushes with measurable outcomes, including **KPI workflows** (measure and improve a metric over time). ## Design principles ### Minimum viable campaign spec 1. **Goal**: measurable criteria (metric, source, target, deadline). 2. **Cadence**: schedule + optional `workflow_dispatch`. 3. **Stop condition**: define "goal met"; report + stop early. 4. **Outputs**: comment, issue, PR vs stdout/stderr only. 5. **Scope**: single-repo or cross-repo. 6. **Constraints**: per-run caps (max PRs, issues, runtime). ### Composable building blocks - **Agentic (default)**: judgment, synthesis, ambiguous decisions. - **Deterministic core**: precise, repeatable, validatable. - **Hybrid**: deterministic prep in `steps:`, agentic prompt for decisions. - **Metrics + memory**: `cache-memory` (optionally `repo-memory`) for cross-run goal tracking. ### Pacing levers - **Cadence**: prefer fuzzy `schedule:` (weekdays for daily) to spread runs. - **No overlap**: workflow-level `concurrency:`. - **Global throughput**: share `concurrency.group` across campaigns. - **Hard deadline**: `on.stop-after` for date/time or relative window. - **Output caps**: `safe-outputs.*.max` (e.g., max 1 PR per run; max 1–3 comments). - **Rate limiting**: round-robin + cache-memory (one component per run) for large scopes. - **Goal-aware early exit**: deterministic pre-check, stop when goal met. **Minimal pacing example:** ```yaml --- on: schedule: weekly stop-after: "+30d" concurrency: group: "campaign-weekly-ci-kpi" cancel-in-progress: false permissions: content: read issues: read tools: cache-memory: true safe-outputs: create-pull-request: max: 1 add-comment: max: 1 noop: --- ``` ### Goal-aware early exit Deterministic pre-check; exit early when goal met, still report. ```markdown --- on: workflow_dispatch: permissions: read-all tools: cache-memory: true steps: - name: Precompute goal status run: | echo '{"goal_met": true, "metric": "coverage", "value": 82, "target": 80}' > /tmp/gh-aw/agent/goal_status.json safe-outputs: add-comment: max: 1 noop: --- # Goal-aware run Read `/tmp/gh-aw/agent/goal_status.json`. If `goal_met` is true: post a short summary (3–5 bullets) and stop. Otherwise: proceed with the plan, then end with a summary and learnings. ``` ### KPI workflows (measure + improve) Output a **metric** and **interpretation**. Make KPI computation deterministic. - Compute KPI in `steps:`, write JSON (e.g., `/tmp/gh-aw/agent/kpi.json`). - Agent reads JSON, decides report-only vs follow-up, ends with short summary. **Inputs:** - `workflow_dispatch` inputs for user parameters; normalize via `steps:` into JSON. - `mcp-scripts:` for constrained, auditable access to privileged data (not human input). **Minimum viable KPI spec:** - `kpi.name` + `kpi.definition` (formula) - `kpi.source` (command, GitHub API read, file parse) - `kpi.target` (threshold + timeframe) - `kpi.scope` (branch, directory, package set) - `kpi.publish_to` (comment/issue/discussion) + "update existing?" **Standard deterministic payload:** ```json { "kpi": "ci_success_rate", "value": 0.92, "target": 0.95, "window": "last_30_runs", "goal_met": false, "notes": "2 failures were flaky tests" } ``` ### Cross-repo coordination - `safe-outputs.dispatch-workflow` is same-repo by default; cross-repo needs `target-repo` plus `allowed-repos` allowlist and a token with `actions: write` on the target. - For org-wide/multi-org, use a coordinator sending `repository_dispatch` to each target. - Requires PAT or GitHub App token with access to every dispatched repo. - Prefer fine-grained PAT scoped to specific repos with `Actions: Read & Write`. - Keep permissions minimal, lock down inputs. --- description: Full trending-analysis patterns, best practices, and reporting guidance for chart workflows. --- # Charts with Trending ## Option C: Charts with Trending (Full Guide) Use when you need full trending analysis with cache-memory persistence. ### Frontmatter ```yaml imports: - shared/python-dataviz.md - shared/trends.md tools: cache-memory: key: charts-trending-${{ github.workflow }}-${{ github.run_id }} safe-outputs: upload-asset: max: 3 allowed-exts: [.png, .jpg, .jpeg, .svg] ``` ### Agent Instructions **Cache-Memory Organization**: ``` /tmp/gh-aw/cache-memory/ ├── trending/ │ ├── / │ │ ├── history.jsonl # Time-series data (JSON Lines format) │ │ ├── metadata.json # Data schema and descriptions │ │ └── last_updated.txt # Timestamp of last update │ └── index.json # Index of all tracked metrics ``` **Load Historical Data**: ```bash if [ -f /tmp/gh-aw/cache-memory/trending/issues/history.jsonl ]; then echo "Loading historical data..." cp /tmp/gh-aw/cache-memory/trending/issues/history.jsonl /tmp/gh-aw/python/data/ else echo "No historical data found. Starting fresh." mkdir -p /tmp/gh-aw/cache-memory/trending/issues fi ``` **Append New Data**: ```python import json from datetime import datetime data_point = { "timestamp": datetime.now().isoformat(), "metric": "issue_count", "value": 42, "metadata": {"source": "github_api"} } with open('/tmp/gh-aw/cache-memory/trending/issues/history.jsonl', 'a') as f: f.write(json.dumps(data_point) + '\n') ``` **Load History into DataFrame**: ```python import pandas as pd, json, os history_file = '/tmp/gh-aw/cache-memory/trending/issues/history.jsonl' if os.path.exists(history_file): df = pd.read_json(history_file, lines=True) df['timestamp'] = pd.to_datetime(df['timestamp']) df = df.sort_values('timestamp') else: df = pd.DataFrame() ``` ### Trending Analysis Patterns **Pattern 1: Daily Metrics Tracking** — append today's data (see "Append New Data" above), then `daily_stats = df.groupby('date').sum()` and plot with `daily_stats.plot(ax=ax, marker='o', linewidth=2)`. See the Complete Example below for the full script. **Pattern 2: Moving Averages and Smoothing** ```python df['rolling_avg'] = df['value'].rolling(window=7, min_periods=1).mean() fig, ax = plt.subplots(figsize=(12, 7), dpi=300) ax.plot(df['date'], df['value'], label='Actual', alpha=0.5, marker='o') ax.plot(df['date'], df['rolling_avg'], label='7-day Average', linewidth=2.5) ax.fill_between(df['date'], df['value'], df['rolling_avg'], alpha=0.2) ``` **Pattern 3: Comparative Trends** ```python fig, ax = plt.subplots(figsize=(14, 8), dpi=300) for metric in ['metric_a', 'metric_b', 'metric_c']: metric_data = df[df['metric'] == metric] ax.plot(metric_data['timestamp'], metric_data['value'], marker='o', label=metric, linewidth=2) ax.set_title('Comparative Metrics Trends', fontsize=16, fontweight='bold') ax.legend(loc='best', fontsize=12) ax.grid(True, alpha=0.3) plt.xticks(rotation=45) ``` **Data Retention (90 days)**: ```python from datetime import timedelta cutoff_date = datetime.now() - timedelta(days=90) df = df[df['timestamp'] >= cutoff_date] df.to_json('/tmp/gh-aw/cache-memory/trending/history.jsonl', orient='records', lines=True) ``` **Complete Trending Example**: ```python #!/usr/bin/env python3 import pandas as pd, matplotlib.pyplot as plt, seaborn as sns, json, os from datetime import datetime, timedelta CACHE_DIR = '/tmp/gh-aw/cache-memory/trending' METRIC_NAME = 'github_activity' HISTORY_FILE = f'{CACHE_DIR}/{METRIC_NAME}/history.jsonl' CHARTS_DIR = '/tmp/gh-aw/python/charts' os.makedirs(f'{CACHE_DIR}/{METRIC_NAME}', exist_ok=True) os.makedirs(CHARTS_DIR, exist_ok=True) today_data = { "timestamp": datetime.now().isoformat(), "issues_opened": 8, "prs_merged": 12, "commits": 45, "contributors": 6 } with open(HISTORY_FILE, 'a') as f: f.write(json.dumps(today_data) + '\n') df = pd.read_json(HISTORY_FILE, lines=True) df['date'] = pd.to_datetime(df['timestamp']).dt.date df = df.sort_values('timestamp') daily_stats = df.groupby('date').sum() sns.set_style("whitegrid") sns.set_palette("husl") fig, axes = plt.subplots(2, 2, figsize=(16, 12), dpi=300) fig.suptitle('GitHub Activity Trends', fontsize=18, fontweight='bold') axes[0, 0].plot(daily_stats.index, daily_stats['issues_opened'], marker='o', linewidth=2, color='#FF6B6B') axes[0, 0].set_title('Issues Opened', fontsize=14) axes[0, 0].grid(True, alpha=0.3) axes[0, 1].plot(daily_stats.index, daily_stats['prs_merged'], marker='s', linewidth=2, color='#4ECDC4') axes[0, 1].set_title('PRs Merged', fontsize=14) axes[0, 1].grid(True, alpha=0.3) axes[1, 0].plot(daily_stats.index, daily_stats['commits'], marker='^', linewidth=2, color='#45B7D1') axes[1, 0].set_title('Commits', fontsize=14) axes[1, 0].grid(True, alpha=0.3) axes[1, 1].plot(daily_stats.index, daily_stats['contributors'], marker='D', linewidth=2, color='#FFA07A') axes[1, 1].set_title('Active Contributors', fontsize=14) axes[1, 1].grid(True, alpha=0.3) plt.tight_layout() plt.savefig(f'{CHARTS_DIR}/activity_trends.png', dpi=300, bbox_inches='tight', facecolor='white') print(f"✅ Trend chart generated with {len(df)} data points") ``` --- ## Trends Visualization Best Practices Temporal and moving-average charts use the Pattern 3 / Pattern 2 code above. Growth rates: ```python fig, ax = plt.subplots(figsize=(10, 6), dpi=300) growth_data.plot(kind='bar', ax=ax, color=sns.color_palette("husl")) ax.set_title('Growth Rates by Period', fontsize=16, fontweight='bold') ax.axhline(y=0, color='black', linestyle='-', linewidth=0.8) ax.set_ylabel('Growth %', fontsize=12) ``` ### Data Preparation ```python # Time-based indexing data['date'] = pd.to_datetime(data['date']) data.set_index('date', inplace=True) data = data.sort_index() # Resampling weekly_data = data.resample('W').mean() data['rolling_mean'] = data['value'].rolling(window=7).mean() # Growth calculations data['pct_change'] = data['value'].pct_change() * 100 data['yoy_growth'] = data['value'].pct_change(periods=365) * 100 ``` ### Color Palettes - **Sequential**: `sns.color_palette("viridis", n_colors=5)` - **Diverging**: `sns.color_palette("RdYlGn", n_colors=7)` - **Multiple series**: `sns.color_palette("husl", n_colors=8)` - **Categorical**: `sns.color_palette("Set2", n_colors=6)` ### Annotation ```python max_idx = data['value'].idxmax() max_val = data['value'].max() ax.annotate(f'Peak: {max_val:.2f}', xy=(max_idx, max_val), xytext=(10, 20), textcoords='offset points', arrowprops=dict(arrowstyle='->', color='red'), fontsize=10, fontweight='bold') ``` --- ## Embedding Charts in Reports 1. Save chart to `/tmp/gh-aw/python/charts/` 2. Upload via `upload asset` tool → raw GitHub URL 3. Embed: `![Chart description](URL_FROM_UPLOAD_ASSET)` Assets are published to an orphaned git branch and become URL-addressable after workflow completion. Example report: ```markdown ## 📈 Trending Analysis ![Activity Trends](URL_FROM_UPLOAD_ASSET) Analysis shows: - Issues opened: Up 15% from last week - PR velocity: Stable at 12 PRs/day - Active contributors: Growing trend (+20% this month) **Data**: {count} points | **Range**: {start} to {end} ``` --- ## Session Analysis Chart Pattern For Copilot coding agent session data, generate two charts: **Chart 1: Session Completion Trends** — multi-line: successful (green), failed/abandoned (red), completion rate % (secondary y-axis). X: last 30 days. Save as `/tmp/gh-aw/python/charts/session_completion_trends.png`. **Chart 2: Session Duration & Efficiency** — avg duration (line), median (line), sessions with loops (bar overlay). X: last 30 days. Y: minutes. Save as `/tmp/gh-aw/python/charts/session_duration_trends.png`. **Data files**: - `session_completion.csv` — date, successful, failed, completion_rate - `session_duration.csv` — date, avg_duration_min, median_duration_min, loop_count If fewer than 7 days of data, use bar charts instead of line charts and note the limited range. --- --- description: Guidance for adding Python data visualization to agentic workflows with compact setup patterns and links to the full trending guide. --- # Python Data Visualization in Agentic Workflows ## Choosing a Shared Workflow | Import | Best for | |---|---| | `shared/trending-charts-simple.md` | Quick setup with cache-memory-backed trend charts | | `shared/python-dataviz.md` | One-off charts from current-run data | | `shared/charts-with-trending.md` | Full trending analysis with richer historical guidance | Default to `shared/trending-charts-simple.md` for new charting workflows. If the shared files are not present locally, import them with: ```bash gh aw add githubnext/agentics/python-dataviz ``` ## Option A: Trending Charts (Simple) Use when you need trend charts with cache-memory persistence and minimal configuration. ```yaml tools: cache-memory: key: trending-data-${{ github.workflow }}-${{ github.run_id }} bash: - "*" network: allowed: - defaults - python steps: - name: Setup Python environment run: | mkdir -p /tmp/gh-aw/python/{data,charts,artifacts} # Use /tmp/gh-aw/python/venv — keeps the venv out of /tmp/gh-aw/agent/ (the artifact upload path) if [ ! -d /tmp/gh-aw/python/venv ]; then python3 -m venv /tmp/gh-aw/python/venv fi echo "/tmp/gh-aw/python/venv/bin" >> "$GITHUB_PATH" /tmp/gh-aw/python/venv/bin/pip install --quiet numpy pandas matplotlib seaborn scipy safe-outputs: upload-asset: max: 3 allowed-exts: [.png, .jpg, .jpeg, .svg] ``` Agent guidance: - write data to `/tmp/gh-aw/python/data/` - write charts to `/tmp/gh-aw/python/charts/` - append history to `/tmp/gh-aw/cache-memory/trending//history.jsonl` - use ISO 8601 timestamps - generate charts at 300 DPI with clear labels ## Option B: Current-Run Charts Only Use when the workflow needs charts from current data without historical tracking. ```yaml tools: cache-memory: true bash: - "*" network: allowed: - defaults - python safe-outputs: upload-asset: max: 3 allowed-exts: [.png, .jpg, .jpeg, .svg] steps: - name: Setup Python environment run: | mkdir -p /tmp/gh-aw/python/{data,charts,artifacts} # Use /tmp/gh-aw/python/venv — keeps the venv out of /tmp/gh-aw/agent/ (the artifact upload path) if [ ! -d /tmp/gh-aw/python/venv ]; then python3 -m venv /tmp/gh-aw/python/venv fi echo "/tmp/gh-aw/python/venv/bin" >> "$GITHUB_PATH" /tmp/gh-aw/python/venv/bin/pip install --quiet numpy pandas matplotlib seaborn scipy ``` Rules: - never inline dataset values directly in Python code - store input data in files and load with pandas - keep reusable helpers in cache-memory when that improves later runs - save chart images under `/tmp/gh-aw/python/charts/` ## Full Trending Guide Load [charts-trending.md](charts-trending.md) only when you need: - detailed historical-data layouts - moving averages, comparative trends, and retention patterns - reporting templates with embedded chart assets - session-analysis chart patterns --- description: Complete reference for gh aw CLI commands and their MCP tool equivalents for restricted environments --- # gh aw CLI Commands Reference ## CLI vs MCP Tool — When to Use Each | Environment | Use | |---|---| | **Local development** (terminal with `gh` auth) | `gh aw ` CLI | | **GitHub Copilot Cloud** (coding agent, Copilot Chat) | `agentic-workflows` MCP tool | | **GitHub Actions workflow step** | `gh aw ` after installing `github/gh-aw/actions/setup-cli` | | **CI runner without gh auth** | `agentic-workflows` MCP tool | > [!NOTE] > **agentic-workflows MCP tool availability** > > The MCP tool is available when `agentic-workflows:` is added to a workflow's `tools:` section. In Copilot Chat / Copilot coding agent, it is pre-configured and always available. > > In a GitHub Actions workflow step, install the CLI first: > ```yaml > - uses: github/gh-aw/actions/setup-cli@ > - run: gh aw compile > ``` --- ## Command Reference ### `gh aw init` Initialize a repository for agentic workflows. ```bash gh aw init # Initialize with defaults (non-interactive) gh aw init --engine claude # Skip Copilot-specific artifacts gh aw init --no-mcp # Skip MCP server integration (Copilot engine) gh aw init --no-agent # Skip custom agent creation (Copilot engine) ``` Creates `.github/skills/agentic-workflows/SKILL.md`. With the Copilot engine (default), also creates the custom agent (`.github/agents/agentic-workflows.md`) and enables MCP server integration — use `--no-mcp`/`--no-agent` to skip either. Non-Copilot engines skip both Copilot-specific artifacts automatically. **MCP equivalent**: Not available — run from a local terminal or use the `upgrade` tool for updates. --- ### `gh aw compile` Compile workflow `.md` files into GitHub Actions `.lock.yml` files. ```bash gh aw compile # Compile all workflows gh aw compile # Compile a specific workflow gh aw compile --strict # Compile with strict mode validation gh aw compile --validate # Validate without emitting lock files gh aw compile --fail-fast # Stop at first error gh aw compile --purge # Remove orphaned .lock.yml files gh aw compile --approve # Approve new secrets / action changes ``` **MCP equivalent**: `compile` tool --- ### `gh aw run` > [!IMPORTANT] > **Always prefer `gh aw run` over `gh workflow run .lock.yml`** — it handles workflow resolution by short name, validates inputs, and enables correct run-tracking with `gh aw audit` and `gh aw logs`. Trigger a workflow on demand using `workflow_dispatch`. ```bash gh aw run # Interactive mode — pick workflow and fill inputs gh aw run # Run by short name gh aw run .md # Alternative: explicit .md extension gh aw run --ref main # Run on a specific branch/tag/SHA gh aw run --repeat 3 # Run 4 times total (1 + 3 repeats) gh aw run --raw-field key=value # Pass a specific input ``` **MCP equivalent**: Not available. Fallback: use the GitHub MCP server's `create_workflow_dispatch` with `workflow_id: .lock.yml`. --- ### `gh aw logs` Download and analyze workflow execution logs. ```bash gh aw logs # Logs for all agentic workflows gh aw logs # Logs for a specific workflow gh aw logs --json # JSON output for programmatic use gh aw logs --engine copilot # Filter by engine gh aw logs -c 10 # Last 10 runs gh aw logs --start-date -1w # Last week's runs gh aw logs --start-date 2024-01-01 --end-date 2024-01-31 gh aw logs -o ./workflow-logs # Save to directory gh aw logs --repo owner/repo # Query logs in another repository gh aw logs --ignore-workflow-runs 123,456 # Exclude specific run IDs from results ``` **MCP equivalent**: `logs` tool --- ### `gh aw audit` Investigate a specific workflow run in detail (missing tools, safe outputs, metrics). ```bash gh aw audit # Audit a single run gh aw audit --json # JSON output gh aw audit # Diff two runs (regression detection) gh aw audit --json # Multi-run diff ``` **MCP equivalent**: `audit` tool (single run) / `audit-diff` tool (multi-run comparison) --- ### `gh aw status` Show the status of all agentic workflows in the repository. ```bash gh aw status gh aw status --repo owner/repo # Query status in another repository ``` **MCP equivalent**: `status` tool --- ### `gh aw checks` Show check run results for a workflow run. ```bash gh aw checks ``` **MCP equivalent**: `checks` tool --- ### `gh aw experiments` Inspect experiment state tracked in `experiments/*` branches. Default behavior matches `experiments list`; use `experiments analyze` for per-workflow statistics. All subcommands accept `--repo/-r` and `--json/-j`. ```bash gh aw experiments # List experiment workflow branches gh aw experiments list --json # List all experiments as JSON gh aw experiments analyze # Analyze one experiment workflow gh aw experiments analyze --repo owner/repo # Analyze in another repository ``` **MCP equivalent**: Not available — run from a local terminal. --- ### `gh aw fix` Apply automatic codemods to fix deprecated fields in workflow files. ```bash gh aw fix # Preview changes (dry run) gh aw fix --write # Apply changes ``` **MCP equivalent**: `fix` tool --- ### `gh aw format` Apply all available codemods and normalize workflow frontmatter (two-space indentation, deterministic field ordering, comments and Markdown body preserved). ```bash gh aw format # Format all workflows in .github/workflows gh aw format # Format a specific workflow gh aw format --dir custom/workflows # Format workflows in a custom directory ``` **MCP equivalent**: Not available — run from a local terminal. --- ### `gh aw upgrade` Upgrade the repository's agentic workflows configuration to the latest gh-aw version. ```bash gh aw upgrade # Upgrade agent files + codemods + compile gh aw upgrade -v # Verbose output gh aw upgrade --no-fix # Skip codemods and compilation gh aw upgrade --create-pull-request # Open a PR with the upgrade changes (alias: --pr) gh aw upgrade --org my-org # Preview upgrade PRs across an organization gh aw upgrade --org my-org --repos '*-service' # Limit org mode to matching repos gh aw upgrade --org my-org --create-issue # Open issues in org repos with agentic workflows (requires --org) ``` **MCP equivalent**: `upgrade` tool --- ### `gh aw add` Add a new shared workflow component as an import. ```bash gh aw add ``` **MCP equivalent**: `add` tool --- ### `gh aw update` Update imported shared workflow components. ```bash gh aw update # Update all workflows from source gh aw update # Update a specific workflow gh aw update --major # Allow major version updates gh aw update --create-pull-request # Update and open a PR (alias: --pr) gh aw update --repo owner/repo # Update workflows in another repository (isolated shallow checkout) gh aw update --cool-down 3d # Custom cooldown before applying pending releases ``` **MCP equivalent**: `update` tool --- ### `gh aw deploy` Deploy workflows to a target repository (chains update, add, compile --purge, opens a PR). `--repo` is required. ```bash gh aw deploy ... --repo owner/repo # Deploy listed workflows gh aw deploy githubnext/agentics/ci-doctor --repo o/r # Deploy a shared workflow gh aw deploy ./local-workflow.md --repo owner/repo # Deploy a local workflow gh aw deploy --repo owner/repo --force # Overwrite without confirmation ``` **MCP equivalent**: Not available — run from a local terminal or invoke the CLI inside a workflow step with `github/gh-aw/actions/setup-cli`. --- ### `gh aw env` Manage compiler default variables (`GH_AW_DEFAULT_*`) as repo/org/enterprise GitHub Actions variables. YAML file uses lowercase `default_*` keys. `null` deletes the variable; any non-null string sets it (`""` = set-to-empty, not delete). ```bash gh aw env get [file] # Download defaults to file.yml (default name) gh aw env get --scope org --org myorg # Org-scope export gh aw env update file.yml --scope repo # Apply with interactive confirmation gh aw env update file.yml --scope ent --enterprise myent --yes # Skip confirmation gh aw env update file.yml --scope repo --dry-run # Preview without applying ``` Example file: ```yaml default_max_ai_credits: "1000" default_max_turn_cache_misses: "5" default_detection_max_ai_credits: "400" default_max_turns: "12" default_model_copilot: "gpt-5-mini" default_model_codex: null # delete this variable ``` Recognized keys include `default_max_ai_credits`, `default_max_turn_cache_misses`, `default_detection_max_ai_credits`, `default_max_daily_ai_credits`, `default_timeout_minutes`, `default_agent_job_timeout_minutes`, `default_detection_job_timeout_minutes`, `default_max_turns`, `default_detection_model`, `default_utc`, `default_model_copilot`, `default_model_claude`, `default_model_codex`. The compiler resolves model selection as `GH_AW_MODEL_*` → `GH_AW_DEFAULT_MODEL_*` → built-in engine fallback. **MCP equivalent**: Not available — run from a local terminal. --- ### `gh aw mcp inspect` Inspect and analyze MCP server configurations in workflows. ```bash gh aw mcp inspect gh aw mcp inspect --inspector # Launch web-based inspector UI gh aw mcp list # List workflows with MCP servers ``` **MCP equivalent**: `mcp-inspect` tool --- ### `gh aw json-schema` Generate the JSON Schema for `audit`, `logs` JSON output, or cached logs JSONL items. ```bash gh aw json-schema audit gh aw json-schema logs gh aw json-schema logs-jsonl ``` **MCP equivalent**: Not available — run from a local terminal. --- ## MCP Tool ↔ CLI Quick Reference | CLI command | MCP tool | |---|---| | `gh aw status` | `status` | | `gh aw compile` | `compile` | | `gh aw run` | *(use GitHub MCP `create_workflow_dispatch`)* | | `gh aw logs` | `logs` | | `gh aw audit` | `audit` | | `gh aw audit ` | `audit-diff` | | `gh aw checks` | `checks` | | `gh aw experiments` | *(local only)* | | `gh aw mcp inspect` | `mcp-inspect` | | `gh aw add` | `add` | | `gh aw update` | `update` | | `gh aw fix` | `fix` | | `gh aw format` | *(local only)* | | `gh aw upgrade` | `upgrade` | | `gh aw deploy` | *(local only)* | | `gh aw env` | *(local only)* | | `gh aw init` | *(local only)* | | `gh aw json-schema` | *(local only)* | # Blocked gh-aw versions The following releases are blocked by `.github/aw/compat.json` and fail during workflow activation. | Versions | Reason | | --- | --- | | `v0.82.8` through `v0.85.3` | Affected by [GHSA-8h78-hpm7-29gg](https://github.com/github/gh-aw/security/advisories/GHSA-8h78-hpm7-29gg). `v0.85.4` is the first unaffected release. | ## Remediation Upgrade to [`v0.85.4`](https://github.com/github/gh-aw/releases/tag/v0.85.4) or later, verify the installed version, then regenerate and review the repository's compiled workflows: ```bash gh extension upgrade gh-aw gh aw version gh aw upgrade git diff -- .github/workflows ``` Confirm that `gh aw version` reports `v0.85.4` or later and commit the regenerated `.lock.yml` files. Blocking the affected compiler versions prevents their workflows from activating but does not regenerate existing workflow artifacts. See [Upgrading Workflows](https://github.com/github/gh-aw/blob/main/docs/src/content/docs/guides/working-with-workflows.mdx#upgrading-workflows) for the supported upgrade process. ## Temporary mitigations No advisory-supported temporary mitigation could be verified. Upgrade and regenerate compiled workflows as described above. --- description: Guide for configuring new declarative agentic engines — engine definition fields, auth wiring, behavior blocks, and validation. --- # Configure a New Agentic Engine Use this guide when adding or updating a declarative engine definition in a repository that uses the `gh aw` extension. Do not assume that the gh-aw source repository, its build system, or its Go packages are available. ## Prefer shared agentic workflow definitions For CLI-style engines, create a repository-scoped definition in `.github/workflows/shared/.md`. Import it from a workflow that sets `engine.id: `. Use GitHub to inspect the shared [OpenCode](https://github.com/github/gh-aw/blob/main/.github/workflows/shared/opencode.md), [Goose](https://github.com/github/gh-aw/blob/main/.github/workflows/shared/goose.md), [Aider](https://github.com/github/gh-aw/blob/main/.github/workflows/shared/aider.md), [Cursor](https://github.com/github/gh-aw/blob/main/.github/workflows/shared/cursor.md), and [Kiro](https://github.com/github/gh-aw/blob/main/.github/workflows/shared/kiro.md) definitions as patterns. - express the engine entirely through frontmatter-defined `engine.behaviors` - keep install, config, execution, MCP, manifest, and capability metadata in the engine markdown file - keep engine-specific adapters and harnesses with the shared definition - stop and report the missing declarative capability when the runtime cannot be expressed by the supported schema; do not modify gh-aw internals from the consuming repository ## Gather the engine contract first Do not begin from a generic engine template. Use GitHub access to inspect the CLI's repository, documentation, release notes, package manifests, configuration examples, and pinned release source. Answer every item below before editing files. ### LLM endpoint and model contract 1. Identify how the CLI accepts its LLM endpoint: environment variable, command flag, or config key. 2. Determine whether the endpoint is OpenAI-compatible, Anthropic-native, or another protocol, including any required path such as `/v1`. 3. Record the workflow-facing model syntax, normally `provider/model`, and the exact syntax passed to the CLI. Document any provider-prefix removal, replacement, or other model transformation. 4. Determine whether the CLI runs on the host or inside the AWF agent container. Do not copy a host URL into a container configuration or hard-code an `api-proxy` port or container IP. 5. Identify which configured provider must be selected at runtime and how to report an actionable error when the provider or model is unavailable. ### MCP contract 1. Determine whether the CLI has native MCP support. If it does not, set `engine.mcp: false` and rely on the compiler's proxy-backed tools. 2. If MCP is supported, identify the accepted transports, config path, root object name, server entry schema, and support for authorization headers. 3. Compare the native schema with the gateway's `{ "mcpServers": ... }` output. If they differ, generate the native config with `behaviors.mcp.config-adapter`. 4. Determine whether the CLI loads that config directly or requires a harness to translate servers into command-line flags or a runtime config overlay. 5. Determine whether CLI-mounted servers must be filtered and whether gateway URLs must use the host or container domain. 6. Treat generated MCP configuration as sensitive when it contains gateway authorization headers; create it with owner-only permissions. ### Installation, config, and execution contract 1. Choose a stable engine `id` and display name. Set `runtime-id` only when reusing a documented runtime adapter. 2. Identify the install source, package manager, package name, binary name, pinned version, and verification command. 3. Identify the config path and format, such as JSON, JSONC, YAML, or TOML. Determine whether gh-aw creates, replaces, or merges the file; do not use a JSON merge strategy for syntax that is only valid as JSONC. 4. Identify the non-interactive execution command, fixed arguments, prompt delivery mechanism, exit-code behavior, and any required environment variables. 5. List every engine-owned config file and directory in `behaviors.manifest`. 6. Identify required secrets and whether they use universal provider routing or engine-specific auth. Do not implement the engine until each contract is known. If the available GitHub documentation and pinned source disagree, use the pinned release behavior and record the limitation in the shared definition. ## Choose the declarative mechanism | Requirement | Mechanism | |---|---| | Shared provider credentials and environment | `secret-strategy: universal-llm-consumer` and `execution.provider-env-mode: universal-llm-consumer` | | Model passed through an environment variable | `execution.model-env-var` | | `provider/model` must be rewritten for the CLI | `execution.model-env-provider-prefix`, or a harness for more complex transformations | | Static engine configuration | `behaviors.config-file` with the correct path, content, and merge strategy | | Gateway MCP output already matches the CLI | `behaviors.mcp.config-path` and an execution MCP config binding | | Gateway MCP output needs another schema | `behaviors.mcp.config-adapter` | | MCP servers must become CLI flags or a runtime overlay | `execution.mcp-config-env-var` and `behaviors.harness-script` | | Runtime endpoint discovery or custom invocation | `behaviors.harness-script` using `awf_reflect.cjs` | | No native MCP client | `engine.mcp: false` | | CLI emits logs the built-in parsers cannot normalize | `behaviors.log-parser` | Use a `config-adapter` only to transform generated MCP configuration. Use a `harness-script` when endpoint selection, model transformation, prompt delivery, or CLI invocation requires runtime logic. ## Resolve LLM endpoints at runtime Do not hard-code proxy ports or addresses in new shared engine definitions. Add a harness and resolve the configured endpoint from `/reflect` at execution time. Prefer the versioned helper beside the generated harness: ```javascript const { fetchAWFReflect, resolveProviderEndpointFromReflect, } = require("./awf_reflect.cjs"); ``` The harness must: 1. check `AWF_REFLECT_ENABLED` before using the AWF endpoint 2. call `fetchAWFReflect()` and require a successful response 3. select the requested provider from `GH_AW_LLM_PROVIDER` 4. use only an endpoint with `configured: true` 5. map the resolved URL into the CLI's documented environment variable, flag, or config key 6. transform and validate the selected model using the discovered provider's syntax 7. read the prompt from `GH_AW_PROMPT`, spawn the CLI without shell interpolation, and preserve its exit status 8. fail with an actionable message when endpoint or model resolution is impossible Use `resolveProviderEndpointFromReflect()` when the CLI accepts a base URL. Use `resolveOpenAICompatibleEndpointFromReflect()` when it needs an OpenAI-compatible host and request path separately, as in the shared Goose harness. Use `resolveMultiProviderFromReflect()` only when the CLI consumes a generated multi-provider catalog. Parse `/reflect` directly only when the shared helpers cannot represent the engine's contract. `AWF_REFLECT_ENABLED=1` only indicates that reflection is available; it does not configure the CLI. The harness must fetch and apply the result. When AWF is disabled, preserve the CLI's documented environment-based fallback or fail clearly if the engine cannot run without reflection. See [LLM API Endpoint Discovery](llms.md) for the response shape and model-discovery behavior. ## Generate MCP configuration only when needed When the gateway output already matches the CLI's native schema, point `behaviors.mcp.config-path` at the native config path and bind it through `execution.mcp-config-env-var` or `execution.mcp-config-flag`. When the schemas differ, add a `config-adapter` that reads the gateway environment, filters CLI-mounted servers, preserves supported authorization headers, rewrites the gateway domain for the engine's execution context, and writes the native format with owner-only permissions. When the CLI requires MCP servers as flags or cannot represent all gateway fields in its static config, add that translation to the execution harness. Read the generated path from the configured MCP environment variable, pass arguments as an array to the spawned process, and use a temporary runtime overlay for fields such as HTTP headers that cannot be represented safely as flags. Do not interpolate generated MCP values into a shell command. The shared Goose definition demonstrates both a config adapter and runtime harness. ## Engine definition shape ```aw wrap engine: id: auggie display-name: Auggie experimental: true auth: - role: session secret: AUGMENT_SESSION_AUTH behaviors: supported-env-var-keys: - AUGMENT_SESSION_AUTH installation: package-manager: npm package-name: "@augmentcode/auggie" version: "1.0.0" step-name: Install Auggie binary-name: auggie include-node-setup: true config-file: path: .auggie.json step-name: Write Auggie Config content: '{"sandbox":"workspace-write"}' merge-strategy: json-merge execution: command-name: auggie args: [run] step-name: Execute Auggie CLI model-env-var: AUGGIE_MODEL mcp-config-env-var: AUGGIE_MCP_CONFIG write-timestamp: true ``` ## Field guide - `engine.id` is the public identifier used by workflow authors in `engine: `. - `version` sets the default CLI version applied when a workflow references this engine without specifying `engine.version`; distinct from `behaviors.installation.version`, which pins the version actually installed on the runner. - `display-name` and `description` should be human-readable because they surface in validation and docs. - `runtime-id` is only needed when the definition reuses a different registered runtime adapter. - `experimental: true` should be set for engines that are not yet considered stable. - `provider` and `models` describe provider defaults and supported model metadata. - `auth` declares engine-specific secret bindings forwarded into the runtime environment. - `behaviors.capabilities` advertises runtime support such as `max-turns`, `tools-allowlist`, or `native-agent-file`. - `behaviors.manifest` lists engine-owned files and path prefixes that affect runtime behavior. - `behaviors.installation` defines CLI installation and optional verification steps. - `behaviors.config-file` writes engine config before execution; use `json-merge` when the file must merge with rendered MCP content. - `behaviors.execution` defines the command, fixed args, model binding, MCP binding, and timestamp behavior. - `behaviors.mcp.config-path` points to the file where rendered MCP configuration should be written. - `behaviors.log-parser` supplies a JavaScript `parseLog(logContent)` function (not exported directly — a shared wrapper handles exports and bootstrap) run in the post-agent log-parsing step. It must return `{markdown, logEntries, mcpFailures, maxTurnsHit}` so behavior-defined engines produce normalized events files like built-in engine parsers. - `behaviors.plugins` (experimental) opts the engine into top-level `plugins:` (Agent Plugins) support; omit it to make `plugins:` a compile-time error for this engine. Set `directory` (folder the engine CLI scans for staged plugins, workspace- or home-relative) and/or `command-name`/`install-args` (CLI invoked as ` `) — see the shared Cursor and Kiro engine definitions for examples. ## Auth and provider rules - prefer `secret-strategy: universal-llm-consumer` when the engine can reuse shared provider/model routing - pair that with `execution.provider-env-mode: universal-llm-consumer` when the CLI expects provider env vars - use `engine.auth` only for engine-specific secrets that must be injected directly into the CLI runtime - keep `supported-env-var-keys` aligned with the env var names the CLI actually accepts - do not hard-code credential values in the shared definition or generated configuration ## Validation loop 1. add or update `.github/workflows/shared/.md` 2. import it from a minimal workflow that exercises the selected provider, model syntax, MCP mode, and prompt delivery 3. compile that workflow in strict mode with the installed extension 4. inspect the generated `.lock.yml` and verify the installation, config, MCP adapter, harness, model, and prompt wiring 5. repeat until compilation succeeds without engine-related warnings: ```bash gh aw compile --strict ``` ## Anti-patterns - do not require a gh-aw source checkout, Go changes, or repository-internal build commands - do not scatter install metadata, CLI args, or config-file templates across consuming workflows - do not attempt to create a built-in engine when a shared agentic workflow definition can express the contract - do not hard-code LLM proxy ports, container IPs, or a single provider endpoint when `/reflect` can resolve the selected provider - do not claim MCP support until the generated gateway configuration matches the CLI's accepted schema and transport - do not omit manifest files for engine-owned config that changes runtime behavior - do not use a mismatched `runtime-id` unless an existing runtime adapter is intentionally being reused --- description: GitHub context expression variables and Handlebars-style template conditionals ({{#if}}) for agentic workflows. --- ## GitHub Context Expression Interpolation **For security reasons, only specific expressions are allowed.** ### Allowed Context Variables - **`${{ github.event.after }}`** - SHA of the most recent commit after the push - **`${{ github.event.before }}`** - SHA of the most recent commit before the push - **`${{ github.event.check_run.id }}`** - ID of the check run - **`${{ github.event.check_suite.id }}`** - ID of the check suite - **`${{ github.event.comment.id }}`** - ID of the comment - **`${{ github.event.deployment.id }}`** - ID of the deployment - **`${{ github.event.deployment_status.id }}`** - ID of the deployment status - **`${{ github.event.head_commit.id }}`** - ID of the head commit - **`${{ github.event.installation.id }}`** - ID of the GitHub App installation - **`${{ github.event.issue.number }}`** - Issue number - **`${{ github.event.issue.state }}`** - State of the issue (open/closed) - **`${{ github.event.issue.title }}`** - Title of the issue - **`${{ github.event.label.id }}`** - ID of the label - **`${{ github.event.milestone.id }}`** - ID of the milestone - **`${{ github.event.milestone.number }}`** - Number of the milestone - **`${{ github.event.organization.id }}`** - ID of the organization - **`${{ github.event.page.id }}`** - ID of the GitHub Pages page - **`${{ github.event.project.id }}`** - ID of the project - **`${{ github.event.project_card.id }}`** - ID of the project card - **`${{ github.event.project_column.id }}`** - ID of the project column - **`${{ github.event.pull_request.number }}`** - Pull request number - **`${{ github.event.pull_request.state }}`** - State of the pull request (open/closed) - **`${{ github.event.pull_request.title }}`** - Title of the pull request - **`${{ github.event.pull_request.head.sha }}`** - SHA of the PR head commit - **`${{ github.event.pull_request.base.sha }}`** - SHA of the PR base commit - **`${{ github.event.discussion.number }}`** - Discussion number - **`${{ github.event.discussion.title }}`** - Title of the discussion - **`${{ github.event.discussion.category.name }}`** - Category name of the discussion - **`${{ github.event.release.assets[0].id }}`** - ID of the first release asset - **`${{ github.event.release.id }}`** - ID of the release - **`${{ github.event.release.name }}`** - Name of the release - **`${{ github.event.release.tag_name }}`** - Tag name of the release - **`${{ github.event.repository.id }}`** - ID of the repository - **`${{ github.event.repository.default_branch }}`** - Default branch of the repository - **`${{ github.event.review.id }}`** - ID of the review - **`${{ github.event.review_comment.id }}`** - ID of the review comment - **`${{ github.event.sender.id }}`** - ID of the user who triggered the event - **`${{ github.event.deployment.environment }}`** - Deployment environment name - **`${{ github.event.workflow_job.id }}`** - ID of the workflow job - **`${{ github.event.workflow_job.run_id }}`** - Run ID of the workflow job - **`${{ github.event.workflow_run.id }}`** - ID of the workflow run - **`${{ github.event.workflow_run.number }}`** - Number of the workflow run - **`${{ github.event.workflow_run.conclusion }}`** - Conclusion of the workflow run - **`${{ github.event.workflow_run.status }}`** - Status of the workflow run - **`${{ github.event.workflow_run.event }}`** - Event that triggered the workflow run - **`${{ github.event.workflow_run.html_url }}`** - HTML URL of the workflow run - **`${{ github.event.workflow_run.head_sha }}`** - Head SHA of the workflow run - **`${{ github.event.workflow_run.run_number }}`** - Run number of the workflow run - **`${{ github.actor }}`** - Username of the person who initiated the workflow - **`${{ github.event_name }}`** - Name of the event that triggered the workflow - **`${{ github.job }}`** - Job ID of the current workflow run - **`${{ github.repository }}`** - Repository name in "owner/name" format - **`${{ github.repository_owner }}`** - Owner of the repository (organization or user) - **`${{ github.run_id }}`** - Unique ID of the workflow run - **`${{ github.run_number }}`** - Number of the workflow run - **`${{ github.server_url }}`** - Base URL of the server, e.g. - **`${{ github.workflow }}`** - Name of the workflow - **`${{ github.workspace }}`** - The default working directory on the runner for steps #### Special Pattern Expressions - **`${{ needs.* }}`** - Any outputs from previous jobs (e.g., `${{ needs.pre_activation.outputs.activated }}`, or `${{ needs.activation.outputs.label_command }}` for the triggering label when using a `label_command` trigger). The activation job cannot reference its own outputs—only jobs after activation can. - **`${{ steps.* }}`** - Any outputs from previous steps (e.g., `${{ steps.my-step.outputs.result }}`) - **`${{ github.event.inputs.* }}`** - Any workflow inputs when triggered by workflow_dispatch (e.g., `${{ github.event.inputs.environment }}`) All other expressions are disallowed. ### Sanitized Context Text (`steps.sanitized.outputs.text`) **RECOMMENDED**: Prefer `${{ steps.sanitized.outputs.text }}` over individual `github.event` fields for issue/PR content. Auto-populated per triggering event: - **Issues / Pull Requests**: `title + "\n\n" + body` - **Issue Comments / PR Review Comments**: `comment.body` - **PR Reviews**: `review.body` - **Other events**: Empty string **Security Benefits:** - **@mention neutralization**: converts `@user` to `` `@user` `` - **Bot trigger protection**: converts `fixes #123` to `` `fixes #123` `` - **XML tag safety**: converts XML tags to parentheses to prevent injection - **URI filtering**: only allows HTTPS URIs from trusted domains; others become "(redacted)" - **Content limits**: truncates to 0.5MB / 65k lines max - **Control character removal**: strips ANSI escape sequences and non-printable characters ### Security Validation Expression safety is validated at compile time. Unauthorized expressions cause compilation to fail with an error listing them. ### Example Usage ```markdown # Valid — prefer sanitized text Analyze issue #${{ github.event.issue.number }} in repository ${{ github.repository }}. The issue content is: "${{ steps.sanitized.outputs.text }}" # Valid — individual fields (less secure) Created by ${{ github.actor }} with title: "${{ github.event.issue.title }}" Deploy to environment: "${{ github.event.inputs.environment }}" # Invalid (compile errors) # ${{ secrets.GITHUB_TOKEN }} # ${{ env.MY_VAR }} # ${{ toJson(github.workflow) }} ``` ## Prompt Template Conditionals (`{{#if}}`) Conditional blocks resolved **at runtime, before the agent sees the prompt** — the agent only sees the final resolved text. ### Syntax ``` {{#if }} ...true branch content... {{#else}} ...false branch content (optional)... {{#endif}} ``` - **`{{#if }}`** — content included only when truthy - **`{{#else}}`** — optional false-branch separator - **`{{#endif}}`** — closes block (**preferred** closing tag) - **`{{/if}}`** — alternate closing tag (also supported) Block form (tag on its own line) is recommended for readability. ### Supported Conditions | Form | Example | Truthy when | |---|---|---| | Bare value | `{{#if experiments.flag }}` | value is non-empty and not `"false"` | | Equality | `{{#if experiments.style == "concise" }}` | value equals the quoted string | | Inequality | `{{#if experiments.style != "verbose" }}` | value does not equal the quoted string | | Strict equality | `{{#if experiments.style === "concise" }}` | value strictly equals the quoted string | | Strict inequality | `{{#if experiments.style !== "verbose" }}` | value strictly differs from the quoted string | ### Example: Conditional Without Else ```markdown {{#if experiments.skill_hint == "enabled" }} Check `skills/` and `.github/skills/` for relevant `SKILL.md` files and apply their guidance. {{#endif}} ``` ### Example: Conditional With Else ```markdown {{#if experiments.output_style == "concise" }} Write a maximum of 5 bullet points. Each bullet is one sentence. {{#else}} Write a structured report with sections for new features, bug fixes, and refactors. Include a one-paragraph executive summary at the top. {{#endif}} ``` ### Integration with Experiments When `experiments:` is set in frontmatter, the selected variant is substituted into `{{#if experiments. == "..." }}` conditions before rendering. See [A/B Testing Experiments](../aw/experiments.md). ### Notes - **Fenced code blocks are preserved** — `{{#if}}` tags inside `` ``` `` blocks appear verbatim. - **No nested conditionals** — inner tags become literal text. - **Tags are stripped before the agent runs** — never visible in the final prompt. --- description: Detailed trigger and escalation guidance referenced by create-agentic-workflow.md section 2. --- ## Reporting and digest guidance For recurring reports, audits, and stakeholder digests, set these create-specific defaults: - default to `create-issue`; use `create-discussion` only when the requester explicitly wants threaded discussion - use `add-comment` only when updating an existing issue or pull request instead of creating a new report destination - add `workflow_dispatch` when manual reruns, backfills, or preview runs should be possible For the recurring-report window, grouping dimensions, deduplication key, `close-older-issues` lifecycle, and empty-window/missing-metadata `noop` rules, follow the canonical defaults in [report.md](report.md). Use [workflow-patterns.md](workflow-patterns.md) for the digest/incident skeletons. ## Persona-oriented scenario map Base persona-to-trigger/tool/output facts are canonical in the [Persona-to-Pattern Quick Matrix](github-agentic-workflows.md#persona-to-pattern-quick-matrix); the table below adds only the prompt-authoring detail that matrix omits. | Persona or scenario | Trigger and scope | Typical tools and outputs | Required prompt details | |---|---|---|---| | Program Manager or information-worker digest | `schedule` plus `workflow_dispatch` for previews, reruns, and backfills | `github` (`gh-proxy`); `create-issue` by default | Define the report window, grouping dimensions, deduplication key, and `noop` behavior for empty windows | | Designer or design-governance review | `pull_request` with `paths:` scoped to UI, design-token, copy, or asset files | `github` (`gh-proxy`); optional `playwright`; `add-comment` on the PR | State the review rubric (for example accessibility, token consistency, asset policy), and call `noop` when scoped files are unchanged | | Legal / compliance / documentation-policy review | `pull_request` with scoped `paths:` or `schedule` for recurring audits | `github` (`gh-proxy`); `add-comment` for findings; `create-issue` only for violations needing follow-up | Classify findings against the policy, search for existing open issues before escalating, and call `noop` when there is no in-scope change or violation | ## Milestone slip / dependency-escalation trigger decision Coordination-style requests (for example "tell me when a milestone is slipping" or "flag blocked cross-team dependencies") are often ambiguous between a recurring digest and an event-driven alert. Use this decision order: 1. **Default to `schedule` (+ `workflow_dispatch`)** when the request is about ongoing visibility into milestone health or dependency status over time (a digest), not a single triggering event. Follow the [Recurring Digest Defaults](report.md#recurring-digest-defaults) for window, grouping, and dedup key. 2. **Use `issues` (`types: [labeled, milestoned, demilestoned]`)** only when the requester explicitly wants an immediate reaction to a specific state change (for example the moment an issue is relabeled `blocked` or moved off a milestone), not a periodic summary. 3. **Combine both** only when the requester explicitly asks for both an immediate alert and a periodic rollup; keep them as two distinct trigger blocks (or two workflows) rather than one ambiguous trigger, so each has its own dedup key. | Signal in the request | Trigger | Grouping dimension | Dedup key example | |---|---|---|---| | "weekly/daily view of milestones at risk" | `schedule` + `workflow_dispatch` | milestone, owning team | `milestone-risk::` | | "let me know the moment a milestone slips" | `issues` (`milestoned`/`demilestoned`) or `workflow_run` if computed by CI | milestone | `milestone-slip::` | | "flag blocked dependencies across teams" (ongoing) | `schedule` + `workflow_dispatch` | dependency, blocking team, severity | `dependency-escalation::` | Call `noop` when the window has no slipped milestones or newly blocked dependencies, and search for an existing open issue with the same dedup key before creating a new one. ## Backend review guidance For backend-focused PR automation (schema migrations and API compatibility): - scope `pull_request.paths` to backend contract indicators instead of whole-repo review - instruct the agent to classify changes as additive, backward-compatible, or breaking, then report only actionable risks - include explicit `noop` criteria when no migration/API contract files changed ## PR analyzer escalation guidance For PR-triggered automation that must decide between commenting, creating an issue, or doing nothing: | Condition | Action | |---|---| | Findings affect only this PR (style, quality, risk) | `add-comment` on the PR | | Finding is a cross-cutting or team-wide concern requiring follow-up beyond this PR | `create-issue` | | No findings, or only docs/metadata changed outside scoped `paths:` | `noop` | Rules: - prefer `add-comment` over `create-issue` for PR-local findings; issues outlive the PR and create noise - before creating an issue, search for an existing open issue covering the same concern (use a stable title prefix or label to avoid duplicates) - if a matching open issue already exists, add a linked `add-comment` on the PR referencing it instead of opening a duplicate issue - call `noop` explicitly whenever no actionable finding exists — do not comment with "no issues found" text ## Incident dedup-key templates (`workflow_run` and `deployment_status`) For incident workflows, define one stable dedup key before creating output and search for an open issue containing that key. Use and adapt these templates: ```text # workflow_run incident key incident:workflow_run:::: example: incident:workflow_run:CI:lint:eslint-error:2026-07-05 # deployment_status incident key incident:deployment_status:::: example: incident:deployment_status:production:vercel:build-timeout:2026-07-05 ``` Template rules: - keep `` stable (normalized failing step, error class, or provider error code) - use `` based on the selected reporting window (for example `2026-07-05` or `2026-W27`) - create a new issue only when no open issue matches the same key - call `noop` when the event is non-terminal, recovered, or already represented by an open issue with the same key ## Compliance review guidance For dependency-license compliance and policy review on PRs: - scope `pull_request.paths` to dependency manifest files (for example `package.json`, `go.mod`, `requirements.txt`, `Cargo.toml`, `pyproject.toml`, `composer.json`) - classify each new dependency by license tier using the project's configured policy (the example tiers below represent a common MIT-compatible policy; adjust for your project): **allowed** (MIT, Apache-2.0, BSD, ISC), **needs-review** (unknown, dual-licensed, weak-copyleft), **blocked** (strong-copyleft such as GPL/AGPL, proprietary, or licenses incompatible with your project's license) - publish per-tier findings with `add-comment` listing each dependency, its version, and detected license - escalate to `create-issue` only when a **blocked** dependency was added or a policy violation requires team-wide follow-up beyond this PR - before creating a new issue, search for an existing open issue with a stable key (for example `license-violation + dependency-name + version`) to avoid duplicates; if found, link to it from the PR comment instead - call `noop` when no new dependencies were added or all additions are confirmed in the allowed tier **Compliance escalation decision table:** | Finding | Action | |---|---| | No dependency manifest files changed | `noop` immediately | | All new dependencies in allowed tier | `noop` (or brief `add-comment` confirmation when the workflow prompt explicitly requests a confirmation comment) | | Dependencies in needs-review tier | `add-comment` listing them with license details and requesting maintainer confirmation | | Blocked dependency added | `add-comment` flagging the violation + `create-issue` for team-wide record (skip `create-issue` if a matching open issue already exists) | ### Scheduled compliance-policy audit example Monthly (or otherwise recurring) audits of policy/disclosure files use `schedule` instead of `pull_request`, since there is no single triggering PR event to react to: ```yaml on: schedule: - cron: "0 9 1 * *" # first of the month workflow_dispatch: permissions: contents: read issues: write safe-outputs: create-issue: close-older-issues: true ``` Prompt guidance: - Check for the presence and freshness of required policy/disclosure files (for example `SECURITY.md`, `CODE_OF_CONDUCT.md`, `LICENSE`, a responsible-disclosure contact) against the project's compliance checklist. - Reporting window: one calendar month; dedup key example `compliance-audit:` (for example `compliance-audit:2026-08`). - Group findings by policy area (security disclosure, licensing, code of conduct) rather than by file. - Escalate with `create-issue` only when a required file is missing, stale (for example no update in over a year), or contains a broken disclosure contact; use `close-older-issues: true` so each month's audit supersedes the prior one. - Call `noop` when every required policy/disclosure file is present and current. ## Coverage-analysis guidance For workflows that read, analyze, or comment on test coverage (PR comments, trend tracking, coverage gates): - **Prefer existing artifacts**: check for a coverage artifact from the current or parent CI run before recomputing; use `actions: read` via `gh-proxy` to list and download artifacts. - **Prefer PR signals**: read existing check run annotations or coverage diff comments before fetching raw data; only recompute when no artifact or annotation is available. - **Explicit fallback**: when no artifact exists, document the fallback computation step in the workflow prompt; never invent coverage values. - call `noop` when no coverage data can be retrieved or computed and there is no meaningful output to report. See [test-coverage.md](test-coverage.md) for the full coverage data strategy. --- description: Design and create new agentic workflows using GitHub Agentic Workflows (gh-aw) — unified interview-first experience with concise guidance on triggers, tools, and security. disable-model-invocation: true --- # GitHub Agentic Workflow Designer & Creator Design and create new workflow files under `.github/workflows/` using the installed `gh aw` CLI. ## Load These References First - [designer.md](designer.md) - [intent.md](intent.md) for the outcome definition, PromptPex eval derivation, and operational-value inference - [github-agentic-workflows.md](github-agentic-workflows.md) - [workflow-editing.md](workflow-editing.md) - [workflow-constraints.md](workflow-constraints.md) - [workflow-patterns.md](workflow-patterns.md) - [safe-outputs.md](safe-outputs.md) - [syntax.md](syntax.md) - [mcp-clis.md](mcp-clis.md) Load these topic files only when relevant: - [maintainer.md](maintainer.md) for recurring repository maintenance, backlog triage, owned-PR upkeep, or long-term code health - [campaign.md](campaign.md) for campaign, KPI, pacing, cadence, or `stop-after` - [experiments.md](experiments.md) for experiments, A/B tests, variants, or prompt comparisons - [visual-regression.md](visual-regression.md) for screenshot comparison workflows - [deployment-status.md](deployment-status.md) for external deployment monitoring - [charts.md](charts.md) for chart-generation workflows - [report.md](report.md) for reporting output structure and recurring report lifecycle - [release-workflow.md](release-workflow.md) for release workflows that build, test, publish a GitHub release, and generate release highlights - [linter-workflows.md](linter-workflows.md) for mining, refining, or applying custom linter rules - [agent-runtime-instructions.md](agent-runtime-instructions.md) when choosing or debugging Docker, gVisor, Docker sbx, ARC DinD, self-hosted runners, or `sandbox.agent.runtime-install` - [skills.md](skills.md) when the user asks for specific skills or agent plugins ## Skills and Plugins When the user requests specific skills or agent plugins, declare them in the built-in top-level `skills:` and `plugins:` frontmatter fields — gh-aw installs them before the agent runs. Never generate on-the-fly installation (`steps:` running `gh skill install`, `copilot plugin install`, `npx`, `curl`, or `git clone`) and never instruct the agent to install a skill or plugin from the prompt body. See [skills.md](skills.md). ## Modes ### Interactive mode When the user has not already stated an automation goal, start with exactly: > What do you want to automate today? When the request already states a goal, infer its intent and ask only for information that is still needed. Then follow a progressive interview — ask one question at a time, advance only when the current phase is clear: 1. **Goal and intent** — confirm the workflow name, description, and a concise outcome-oriented `intent:`. Derive activation, required-effect, no-op, success, and uncertainty conditions before choosing implementation; see [intent.md](intent.md). 2. **Repository survey and intent mining** — only for maintenance or underspecified automation requests, inspect bounded repository evidence using [maintainer.md](maintainer.md). Summarize observed signals, propose evidence-backed candidate intents, then select and augment one before choosing a portfolio or cadence. 3. **Architecture and trigger** — compare feasible architectures against the augmented intent's coverage, timeliness, attention cost, safety, boundedness, determinism, state, complexity, and evidence. Then ask "When should this run?" and map the selected architecture to an `on:` block. For scheduled workflows that create issues or pull requests, also choose how previous results are handled using [Choose the previous-result strategy](#choose-the-previous-result-strategy). 4. **Scope** — ask what it reads and what it creates or updates; map to `permissions:`, `tools:`, and `safe-outputs:`. 5. **Data strategy** — ask whether GitHub data should be pre-fetched with `gh` + `jq` (DataOps default); map to `steps:`. 6. **Guardrails** — ask whether it should block, advise, or silently log; guide toward `noop` and safe-output behavior. 7. **Context & network** — ask about external APIs, MCP servers, and required secrets; map to `network.allowed` and `env:`. 8. **Engine** — preserve explicit engine hints. With no engine preference or engine-specific requirement, omit `engine:` and let the configured default apply. If an explicit model requirement forces engine selection, try Copilot first. 9. **Confirmation** — present a structured summary before generating: ```text Proposed workflow: - Name: - Trigger: - Engine: - Tools: - Safe outputs: - Network: - Integrations/Auth: - Repository signals: - Initial maintenance portfolio: - Intent: ``` Ask: **"Ready to generate, or want to adjust anything?"** Skip phases when the answer is already clear from earlier statements. Apply progressive disclosure: at most 5 questions before presenting the confirmation summary; then ask "anything else?" if needed. Detect done signals (`that's it`, `looks good`, `generate it`) and proceed to generation. For detailed trigger/safe-output/network/tool decision heuristics and integration auth setup patterns, load [designer-mappings.md](designer-mappings.md). For token-optimization defaults, load [designer.md](designer.md). ### Issue-form mode When triggered from a workflow-creation issue form, read the form fields and generate the workflow without further conversation. ## Conversation Rules - Keep the conversation short and iterative. - Translate user intent into workflow structure. - When the user asks for exploration, evaluation, or scenario design rather than file creation, stay in ad hoc evaluation mode. - In ad hoc evaluation mode, do not create `.github/workflows/*.md`. - Do not overwhelm the user with long option dumps unless they ask. - If the request exceeds the single-job model, explain the constraint and recommend traditional GitHub Actions. ## Ad Hoc Evaluation Mode Use this mode for exploratory testing, persona walkthroughs, and "what workflow would you create for this scenario?" requests. - Do not create or edit workflow files. - Return a compact recommendation covering trigger, any scoped `paths:` filters for file-event triggers, read tools, safe outputs, permissions, and explicit `noop` criteria. - For recurring reports or digests, always include the report window, grouping dimensions, and deduplication key. See [triggers.md](triggers.md) for key-format examples. - Exit ad hoc evaluation mode only when the user explicitly asks to create, implement, or write the workflow file. - End by offering to turn the recommendation into `.github/workflows/.md` if the user wants to proceed. ### Invocation Surface Ad hoc evaluation is reached by addressing the `agentic-workflows` custom agent directly in conversation (chat prompt, issue comment, or PR comment) — it is **not** a CLI flag or MCP tool parameter. The `gh aw` CLI and MCP tools (`compile`, `audit`, `status`, `update`, etc.) only manage existing workflow files and do not accept a `prompt`/`scenario`/`query` parameter; passing one will fail with an "Unknown parameter" error. Use the example prompt below instead of trying to script evaluation through a tool call. ### Single-Scenario Evaluation Example > agentic-workflows evaluate this scenario without creating files: Information Worker — weekly summary of stale documentation files not updated in the last 90 days Return a single recommendation table using the same fields as the multi-scenario example below (trigger, scope, read tools, safe outputs, permissions, noop condition). Only create `.github/workflows/.md` if the user then explicitly asks to proceed. ### Multi-Scenario Evaluation Example To compare multiple persona or task slices in a single request, use the following prompt format: > agentic-workflows evaluate these scenarios without creating files: > 1. Information Worker — weekly digest of open issues and PRs assigned to me > 2. Product Manager — recurring backlog triage report sorted by staleness > 3. Backend Engineer — API contract diff review on every pull request Expected comparison output: return one combined table with one row per scenario (not a separate table per scenario), so the trigger/tool/safe-output choices can be compared side by side. Use the scenario's persona/task label as the row key and cover these columns: | Scenario | Trigger | Scope | Read tools | Safe outputs | Permissions | Noop condition | |---|---|---|---|---|---|---| | Information Worker — weekly digest | `schedule` + `workflow_dispatch` | 7-day window, grouped by assignee | `github` (`gh-proxy`, default toolset) | `create-issue` with `close-older-issues: true` | `contents: read`, `issues: write` | window has no assigned issues/PRs | | Product Manager — backlog triage | `schedule` + `workflow_dispatch` | recurring window, grouped by staleness bucket | `github` (`gh-proxy`, default toolset) | `create-issue` with `close-older-issues: true` | `contents: read`, `issues: write` | no items cross the staleness threshold | | Backend Engineer — API contract review | `pull_request` with `paths:` scoped to API/schema files | per-PR, no window | `github` (`gh-proxy`, default toolset) | `add-comment` on the PR | `contents: read`, `pull-requests: write` | no API contract files changed in the PR | This is the same invocation surface as [Single-Scenario Evaluation Example](#single-scenario-evaluation-example) above — reached only by addressing the `agentic-workflows` custom agent directly in conversation, never via a CLI/MCP tool parameter. After the comparison table, call out any scenario that shares a trigger or write path with another (for example two digests that could share a schedule) before offering to generate files. ### Failure Classification When evaluating scenarios, classify any failure before stopping: | Failure type | Symptom | Action | |---|---|---| | Transient issue | Network error, timeout, or quota exceeded | Retry once; if it persists, record `invocation_unavailable` and continue with partial results | | Unsupported command | Unknown subcommand or unrecognized option | Record `command_not_supported`, document the gap, and fall back to providing the recommendation directly from local gh-aw guidance | | Product gap | Invocation succeeds but returns no workflow-design guidance | Record `response_unavailable`, note the scenario, and surface it as a missing capability rather than treating it as an error | ## Design Checklist ### 1. Pick the workflow ID - Derive kebab-case from the workflow name. - Before creating the file, check whether `.github/workflows/.md` already exists. - If it exists, choose a more specific ID instead of overwriting. ### 2. Derive architecture, then choose the trigger Use the smallest trigger that satisfies the augmented intent. Treat the mappings below as implementation options, not direct substitutions for intent reasoning. See the [Decision Matrix](triggers.md#decision-matrix) in triggers.md for the base trigger-to-use-case mapping. | Scenario | Trigger and default output | Details | |---|---|---| | Recurring reports and stakeholder digests | `schedule` (+ `workflow_dispatch` for reruns), usually `create-issue` | [Reporting/digest guidance](create-agentic-workflow-trigger-details.md#reporting-and-digest-guidance) | | Persona-oriented requests (PM, design governance, compliance policy) | `pull_request` with scoped `paths:` when the request is framed around changed files (`tokens/**`, `**/*tokens*.json`, `**/theme/**`, `policy/**`, `compliance/**`, `controls/**`, `docs/policies/**`); `schedule` (+ `workflow_dispatch`) for recurring audits | [Persona scenario map](create-agentic-workflow-trigger-details.md#persona-oriented-scenario-map) | | Backend schema/API review | `pull_request` with backend contract `paths:` and `add-comment` | [Backend review guidance](create-agentic-workflow-trigger-details.md#backend-review-guidance) | | PR analyzers deciding comment vs issue vs noop | `pull_request` + escalation logic | [PR analyzer escalation](create-agentic-workflow-trigger-details.md#pr-analyzer-escalation-guidance) | | Incident workflows | `workflow_run` / `deployment_status` with `create-issue` dedup | [Incident dedup-key templates](create-agentic-workflow-trigger-details.md#incident-dedup-key-templates-workflow_run-and-deployment_status) | | CI regressions tied to a pull request | `workflow_run` with PR-comment escalation; repository-wide or unowned failures use deduplicated `create-issue` | Keep the visible output attached to the affected PR when one is known; use an issue when no single owner can be identified | | Dependency-license and policy compliance | `pull_request` with manifest `paths:` | [Compliance review guidance](create-agentic-workflow-trigger-details.md#compliance-review-guidance) | | Coverage analysis | `pull_request` or CI-linked triggers with explicit fallback | [Coverage-analysis guidance](create-agentic-workflow-trigger-details.md#coverage-analysis-guidance) | Use [triggers.md](triggers.md), [workflow-patterns.md](workflow-patterns.md), and [create-agentic-workflow-trigger-details.md](create-agentic-workflow-trigger-details.md) for detailed trigger-selection patterns. #### Choose the previous-result strategy For every daily or scheduled workflow that creates issues or pull requests, choose the strategy that best matches the workflow's goal: - **Wait for the previous result** when only one active result should exist. Configure `on.skip-if-match` to skip the entire agent execution while the issue or pull request created by an earlier run remains open. The workflow resumes after that item is closed or merged. - **Replace previous results** when the newest result supersedes older reports. For issues, configure `safe-outputs.create-issue.close-older-issues: true` and use `close-older-key` when an explicit matching key is needed. - **Keep previous results** when each run should produce a distinct item or preserve a history of work. Instruct the agent to search for and review existing issues or pull requests before acting, then select a materially different scope so it does not repeat previous work. Treat those existing items as the workflow's memory. Do not default every scheduled workflow to the same strategy. Base the choice on whether the workflow needs a single active item, a latest-only result, or a continuing series of distinct results, and include the selected behavior in the generated workflow. ### 3. Keep permissions read-only See [workflow-constraints.md](workflow-constraints.md) for the read-only security posture. Specific to workflow creation: - Do not grant `issues: write`, `pull-requests: write`, or `contents: write` to the agent job. - When targeting the Copilot coding agent, recommend `permissions: { copilot-requests: write }` so Copilot can authenticate with `${{ github.token }}`. - If the user asks for direct writes, explain why the safe-output pattern is required. ### 4. Select tools - `bash` and `edit` are enabled by default in sandboxed workflows; do not add them unless you are restricting them. - For GitHub reads, prefer `tools.github.mode: gh-proxy` and instruct the agent to use `gh` commands. - For non-GitHub MCP servers, prefer `tools.cli-proxy: true` and instruct the agent to use the mounted `mcp-clis` commands. - Combined configuration example for GitHub reads plus non-GitHub MCP CLI access: ```yaml tools: github: mode: gh-proxy toolsets: [default] cli-proxy: true ``` Omit `cli-proxy: true` when the workflow only needs GitHub reads. - Suggest `playwright` for browser automation. - Suggest dedicated topic files rather than embedding long tutorials in the prompt. ### 5. Infer network access from repository files Do not ask for the ecosystem if it can be inferred from the repository. See [network.md#inferring-ecosystem-from-repository-files](network.md#inferring-ecosystem-from-repository-files) for the manifest-to-ecosystem mapping. Never use `network: defaults` alone for workflows that build, test, or install packages. ### 6. Configure safe outputs Map write behavior to `safe-outputs:`. Common mappings: - create issues → `create-issue` - add comments → `add-comment` - create PRs → `create-pull-request` - add labels → `add-labels` - attach downloadable files → `upload-artifact` - publish embeddable assets → `upload-asset` Rules: - always restrict `create-pull-request.allowed-files` - prefer the dedicated safe output instead of shelling out to `gh` for the same mutation - include `noop` guidance in the prompt so successful no-op runs are explicit - when using `create-issue`, instruct the agent to provide a meaningful body (20-65000 characters; avoid placeholder-only text) ### 7. Decide who can trigger the workflow - Default behavior is team-only triggering. - For community-facing issue triage or other public entrypoints, recommend `roles: all`. ### 8. Add cost-aware triage and context flow - For high-volume inputs, apply the [High-Volume Triage and Escalation Pattern](workflow-patterns.md#high-volume-triage-and-escalation-pattern): cheap triage first, `noop`/safe output for known/duplicate/stale/low-value cases, frontier reasoning reserved for ambiguous/high-value cases, and context pulled on demand. - Use deterministic `steps:` plus compact files under `/tmp/gh-aw/` when large data must be preprocessed. See also: [subagents.md](subagents.md) and [token-optimization.md](token-optimization.md). ### 9. Omit unnecessary defaults Avoid adding fields just to restate defaults. Usually omit: - `engine: copilot` - unrestricted `bash` - `edit` - `timeout-minutes:` unless a custom timeout is needed ## Prompt Requirements The markdown body should: - state the canonical intent clearly - determine applicability using its activation conditions and required evidence - produce the required effects only when the evidence supports them - reference the triggering context explicitly - name the allowed safe outputs when write actions are expected - instruct the agent to call `noop` with a short reason when an inverse/no-op condition applies, including duplicates or insufficient evidence - stay concise and task-focused When `evals:` are appropriate, derive separate positive and adversarial scenario fixtures from required effects and inverse/no-op conditions as described in [intent.md](intent.md). Each BinEval run receives one fixture; phrase questions for that fixture, or explicitly return `UNKNOWN` when a shared question's scenario is not provided rather than mixing mutually exclusive assertions. When the workflow generates reports or markdown output, follow [report.md#report-style-and-structure](report.md#report-style-and-structure) and [report.md#workflow-run-references](report.md#workflow-run-references). ## Issue-Form Mode Procedure When processing a workflow-creation issue form: 1. extract the workflow name, description, and additional context 2. derive and persist a canonical intent, then augment it before implementation choices 3. derive a unique workflow ID and select an architecture, trigger, tools, network access, and safe outputs from the augmented intent 4. create exactly one workflow markdown file 5. compile it with `gh aw compile ` 6. include the generated `.lock.yml` in the PR ## Recommended Workflow Skeleton ```markdown --- emoji: 🏷️ description: intent: on: issues: types: [opened] permissions: contents: read issues: read tools: github: mode: gh-proxy toolsets: [default] cli-proxy: true safe-outputs: add-comment: --- # ## Task ## Safe Outputs - Use the configured safe outputs for visible actions. - Use `noop` with a short explanation when no action is required. ``` ## PR-Report Checklist Before finalizing any `pull_request`-triggered reporting workflow, verify: - [ ] **Permissions**: `contents: read` + `pull-requests: read` in the agent job; no write permissions - [ ] **Safe outputs**: `add-comment` for inline findings; `create-issue` for incidents needing follow-up - [ ] **Network**: infer ecosystem from repository lock files; never use `defaults` alone when packages are installed - [ ] **`noop` required**: prompt instructs the agent to call `noop` with a brief explanation when no issues are found ## Generated Workflow Quality Checklist Before finalizing any newly generated workflow, verify: - [ ] **Trigger fit**: trigger matches user intent and event granularity (for example `pull_request`, `workflow_run`, `deployment_status`, `schedule`, `slash_command`) - [ ] **Maintenance baseline**: recurring maintenance strategies are derived from a bounded repository survey, with observed signals separated from recommendations - [ ] **Tool fit**: enabled tools are the minimal set needed for reads/analysis (prefer `gh-proxy`; add `playwright`/`cache-memory` only when required) - [ ] **Safe outputs**: all visible writes route through `safe-outputs:` and include `noop` for explicit no-op outcomes - [ ] **Permissions**: agent job remains read-only; no direct write scopes granted - [ ] **Network**: access is inferred from repository ecosystem and avoids `network: defaults` alone for install/build/test workflows - [ ] **Prompt clarity**: prompt is concise, context-aware, and clearly states expected outputs and stop/no-op behavior ## Generated Workflow Scoping Checklist Before finalizing any newly generated workflow, verify: - [ ] **Paths scope**: include `paths:`/`paths-ignore:` when the automation should ignore unrelated files (for backend reviews, include migration/schema/API contract globs; for design governance, include design-token/theme globs like `tokens/**` and `**/theme/**`; for compliance policy reviews, include policy/control docs like `policy/**`, `compliance/**`, `controls/**`, `docs/policies/**`) - [ ] **Labels scope**: define required labels (for example `label_command` names or PR/issue label filters) when label-based routing is expected - [ ] **Workflow-name scope**: for `workflow_run`, explicitly set `workflows:` to named targets and gate conclusions via `if:` on `${{ github.event.workflow_run.conclusion }}` (for incident triage, prefer failure-only outcomes) - [ ] **Date-window scope**: for reporting/triage, state the exact window (for example `last 24h`, `since previous run`, `current week`) - [ ] **Safe-output write contract**: name which safe output is used for each outcome and when `noop` is required instead of a write ## Multi-Repository Requests For cross-repository workflows, first determine whether the question is **finite and bounded**: - If the answer requires arbitrary source-code extraction, full file contents, or other unbounded access: - enable the GitHub toolsets needed to read external repositories - configure cross-repo authentication in `safe-outputs:` - tell the agent to set `target-repo` - explain that the workflow still cannot wait for external workflows or create multi-job orchestration Use [workflow-patterns.md](workflow-patterns.md) for the compact cross-repo pattern. ## Final Steps 1. create `.github/workflows/.md` 2. compile with `gh aw compile ` 3. fix all compile errors 4. create a PR with the workflow file and `.lock.yml` ## Guidelines - create exactly one workflow `.md` file as the primary deliverable - keep prompts short, specific, and imperative - prefer dedicated reference files over repeating large explanations inline - always compile before finishing - keep responses concise after the workflow is created --- name: create-shared-agentic-workflow description: Create shared agentic workflow components that wrap MCP servers using secure, reusable patterns. disable-model-invocation: true --- # Shared Agentic Workflow Designer Create reusable shared workflow components under `.github/workflows/shared/`. ## Load These References First - [github-agentic-workflows.md](github-agentic-workflows.md) - [workflow-constraints.md](workflow-constraints.md) - [shared-safe-jobs.md](shared-safe-jobs.md) - [safe-outputs.md](safe-outputs.md) Load these only when relevant: - [campaign.md](campaign.md) - [experiments.md](experiments.md) ## Core Rules - prefer `container:`-based MCP servers - pin versions when practical - allow only read-only tools by default - move writes to built-in safe outputs or custom safe-output jobs - keep documentation in XML comments in the markdown body, not in frontmatter comments ## Ask First Start by asking what MCP server or shared component the user wants to integrate. Then gather: - the server name - the documentation URL or repository - required secrets - any expected write operations ## File Shape Shared components are markdown files with frontmatter and an optional markdown body. ```yaml --- mcp-servers: server-name: container: "registry/image" version: "tag" env: API_KEY: "${{ secrets.API_KEY }}" allowed: - read_tool --- ``` ## MCP Design Flow 1. research the server from the provided docs 2. prefer an official container image when available 3. identify required args, env vars, and mounts 4. create `.github/workflows/shared/-mcp.md` 5. list required secrets clearly for the user 6. inspect available tools with `gh aw mcp inspect` 7. allow only the read-only tools by default 8. document excluded write tools and route them to safe outputs when needed ## Secret Guidance When secrets are required, explicitly list: - the secret name - what it is used for - where the user must configure it in GitHub Actions ## Tool Allowlist Guidance - use `allowed:` with a specific list whenever possible - exclude write tools from shared read-oriented components - if writes are needed, describe the companion safe-output pattern rather than broadening MCP permissions ## Custom Write Behavior When a component needs post-agent mutation logic: - create a safe-output job - follow [shared-safe-jobs.md](shared-safe-jobs.md) - keep the schema explicit and typed ## Validation Loop Use this loop until the component is valid: ```bash gh aw compile --strict gh aw mcp inspect --server -v ``` Iterate on: - image name and version - env vars and secrets - Docker args and mounts - allowed tools ## Guidelines - keep one shared file focused on one MCP server or one reusable concern - prefer containers over raw commands for production use - keep write access out of the shared component unless it is explicitly implemented as a safe-output job - keep the generated instructions concise --- description: Debug and refine agentic workflows using gh-aw CLI tools and focused run-log analysis. disable-model-invocation: true --- # GitHub Agentic Workflow Debugger Help users investigate failing or underperforming workflows in this repository. ## Load These References First - [github-agentic-workflows.md](github-agentic-workflows.md) - [workflow-editing.md](workflow-editing.md) - [safe-outputs.md](safe-outputs.md) - [syntax.md](syntax.md) Load these only when relevant: - [campaign.md](campaign.md) - [experiments.md](experiments.md) - [agent-runtime-instructions.md](agent-runtime-instructions.md) for Docker, gVisor, Docker sbx, ARC DinD, or `sandbox.agent.runtime-install` failures ## Available Commands ```bash gh aw status gh aw compile gh aw logs --json gh aw audit --json gh aw run ``` If `gh aw` is unavailable or unauthenticated in a workflow environment, use the matching `agentic-workflows` tools instead. ## Start the Conversation Ask for one of these inputs: - a workflow name - a workflow run URL - a request to list workflows with `gh aw status` ## Fast Path: Run URL Provided If the user gives a GitHub Actions run URL: 1. extract the run ID 2. run `gh aw audit --json` 3. analyze the audit result before asking additional questions ## Two Debug Modes ### 1. Analyze existing logs Use when the user wants to inspect past runs. ```bash gh aw logs --json ``` Focus on: - failures and warnings - token usage - missing tool reports - execution time - repeated failure patterns ### 2. Run and audit now Use when the user wants to reproduce the issue. 1. verify the workflow supports `workflow_dispatch` 2. run `gh aw run ` 3. poll `gh aw audit --json` until the run reaches a terminal state 4. inspect the downloaded artifacts ## What to Inspect in Audits ### Missing tools Check for: - tools the agent tried to call but could not access - name mismatches such as wrong prefixes or wrong underscore/hyphen forms - safe outputs that were referenced in the prompt but not configured in frontmatter Common fixes: - correct the tool name in the prompt - enable the required tool or safe output - move a write action from shell/GitHub tool usage to `safe-outputs:` ### Key artifacts Inspect these when available: - `run_summary.json` - `agent-stdio.log` - `safe_outputs.jsonl` - token-usage artifacts under the firewall audit logs ## Diagnostic Checklist - permissions and authentication failures - missing or misconfigured tools - GitHub MCP DIFC source policy without a matching `safeoutputs` write-sink policy - network allowlist problems - prompt ambiguity or lack of context - timeout pressure - unnecessary token consumption - expensive model invoked on events that cheap triage could resolve - expensive model reading large raw logs or payloads that should be queried on demand - orchestrator context bloated by raw worker/tool output instead of compact summaries - unbounded sub-agent fan-out or recursive delegation - safe-output validation failures ## Workflow-Internal Use of `gh aw` When a generated workflow itself runs `gh aw logs` or `gh aw audit`: - add `permissions: actions: read` - install the CLI first with `github/gh-aw/actions/setup-cli` - do not place the `gh aw` command before the install step ## Fix-and-Validate Loop When you suggest a fix: 1. point to the exact frontmatter or prompt section 2. explain the reason briefly 3. validate with `gh aw compile ` and inspect the generated lock file for both source and sink guard policies when GitHub MCP and safe outputs are used 4. suggest another run only after the workflow compiles When token cost is part of the issue, compare before/after runs with `gh aw audit` and inspect `aic`, input/output tokens, and cache read/write tokens. Treat quality regressions as failures even when token usage drops. ## Final Response Rules End with: - the root cause or most likely cause - the concrete fix - the validation command - whether the user should run the workflow again Keep it concise and actionable. --- description: Instructions for fixing Dependabot PRs that update dependencies in generated workflow manifest files disable-model-invocation: true --- You are specialized in **fixing Dependabot PRs for GitHub Agentic Workflows dependency manifests**. Read the ENTIRE content of this file carefully before proceeding. Follow the instructions precisely. # Fixing Dependabot PRs for Agentic Workflow Dependencies > [!WARNING] > **Never directly merge Dependabot PRs that modify generated files** such as `.github/workflows/package.json`, `.github/workflows/requirements.txt`, or `.github/workflows/go.mod`. These files are generated by the `gh aw` compiler and any direct changes will be overwritten on the next compilation. ## Background The `gh aw compile --dependabot` command scans all agentic workflow files (`.github/workflows/*.md`) for runtime tool dependencies and generates manifest files: | Manifest | Ecosystem | Full Path | |----------|-----------|-----------| | `package.json` / `package-lock.json` | npm | `.github/workflows/package.json` / `.github/workflows/package-lock.json` | | `requirements.txt` | pip | `.github/workflows/requirements.txt` | | `go.mod` | Go | `.github/workflows/go.mod` | When Dependabot opens PRs to update these dependencies, the fix must be applied to the **source `.md` workflow files**, not the generated manifests. ## Fix Strategy: Bundle Multiple PRs Rather than fixing Dependabot PRs one by one, **bundle all pending fixes into a single commit**: 1. **Find all open Dependabot PRs** targeting the generated manifest files 2. **Identify the source `.md` files** for each dependency 3. **Apply all version updates** to the `.md` files in one pass 4. **Regenerate the manifests** with a single `gh aw compile --dependabot` 5. **Commit and push** — Dependabot will auto-close the resolved PRs ## Step-by-Step Instructions ### 1. List Open Dependabot PRs Use GitHub tools to list all open Dependabot PRs: ```bash gh pr list --author "app/dependabot" --state open ``` Filter for PRs affecting generated workflow manifests (title contains `Bump` or similar, files include `.github/workflows/package.json`, `.github/workflows/requirements.txt`, or `.github/workflows/go.mod`). ### 2. Identify Source `.md` Files For each outdated dependency, find which workflow files reference it: ```bash # For npm packages (e.g., @playwright/test) grep -r "@playwright/test" .github/workflows/*.md .github/workflows/shared/ # For pip packages (e.g., requests) grep -r "requests==" .github/workflows/*.md # For Go packages grep -r "golang.org/x/tools" .github/workflows/*.md ``` ### 3. Update Versions in `.md` Files Edit the workflow files to use the updated dependency versions: ```bash # Example: Update @playwright/test from 1.41.0 to 1.42.0 # Find: npx @playwright/test@1.41.0 # Replace: npx @playwright/test@1.42.0 ``` For **MCP server transitive dependencies**, update the shared MCP config: ```bash # Locate the shared MCP configuration grep -r "@sentry/mcp-server" .github/workflows/shared/ # Update the version in the args array: # args: ["@sentry/mcp-server@0.27.0"] → args: ["@sentry/mcp-server@0.29.0"] ``` ### 4. Regenerate Manifests After updating all `.md` files, regenerate the manifests: ```bash gh aw compile --dependabot ``` This updates `.github/workflows/package.json`, `.github/workflows/requirements.txt`, and `.github/workflows/go.mod` from the updated `.md` file versions. If `.github/workflows/package-lock.json` also needs updating: ```bash cd .github/workflows && npm install --package-lock-only && cd - ``` ### 5. Verify and Commit ```bash # Review the changes git diff .github/workflows/ # Stage and commit all dependency updates together git add .github/workflows/ .github/aw/ git commit -m "chore: bundle dependabot dependency updates" git push ``` Dependabot will automatically close all PRs whose dependency versions now match the committed versions. ## Bundling Decision Guide **Bundle multiple PRs when:** - ✅ Multiple Dependabot PRs target the same ecosystem (npm, pip, Go) - ✅ PRs affect different workflows but update the same package - ✅ All updates are minor or patch version bumps (low breaking-change risk) **Handle separately when:** - ⚠️ A PR involves a **major version bump** with potential breaking changes - ⚠️ Different teams own different workflows with separate review requirements ## Troubleshooting | Issue | Solution | |-------|----------| | `.github/workflows/package-lock.json` not updated | Run `cd .github/workflows && npm install --package-lock-only` after compilation | | Dependency not found in `.md` files | Check shared MCP configs in `.github/workflows/shared/` | | Compilation fails after version update | Check if the new version has breaking API changes | | Dependabot PR not auto-closing | Verify the exact version strings match; check for pre-release suffixes | ## Dismissed Dependabot Alerts and VEX When a Dependabot security alert is dismissed with a substantive security reason (`not_used`, `inaccurate`, or `tolerable_risk`), consider generating a [VEX (Vulnerability Exploitability eXchange)](https://openvex.dev/) statement to record the assessment as a machine-readable OpenVEX v0.2.0 document in `.vex/.json`. Alerts dismissed as `no_bandwidth` do not represent a security decision and should not produce a VEX statement. Learn about the OpenVEX format, purl construction, and dismissal-to-justification mappings from [openvex.dev](https://openvex.dev/) before generating statements. ## Related Documentation - [Dependabot Support](/gh-aw/reference/dependabot/) — Full reference for `gh aw compile --dependabot` - [OpenVEX Specification](https://openvex.dev/) — VEX standard for vulnerability exploitability exchange - Local copy: @.github/aw/github-agentic-workflows.md --- description: Reference pattern for monitoring external deployment failures using the deployment_status trigger and creating incident issues automatically. --- # Deployment Status Monitoring Consult this file when creating an agentic workflow that responds to external deployment failures from services like Heroku, Vercel, Railway, or Fly.io that post deployment status back to GitHub. ## Trigger and Frontmatter Use the `deployment_status` trigger with an `if:` condition to filter to failed deployments only: ```yaml on: deployment_status: if: ${{ github.event.deployment_status.state == 'failure' }} permissions: contents: read issues: read deployments: read tools: github: toolsets: [default] safe-outputs: create-issue: expires: 1d title-prefix: "[Deployment Failure] " close-older-issues: true noop: ``` ## Available Event Context The following expressions are available in the prompt body: | Expression | Description | |---|---| | `${{ github.event.deployment.environment }}` | Target environment (e.g. `production`) | | `${{ github.event.deployment_status.state }}` | Status (`failure`, `success`, `error`, etc.) | | `${{ github.event.deployment_status.target_url }}` | URL to the external service deployment logs | | `${{ github.event.deployment_status.description }}` | Human-readable error message from the service | | `${{ github.event.deployment.ref }}` | Branch or tag that was deployed | | `${{ github.event.deployment.sha }}` | Commit SHA that was deployed | | `${{ github.event.deployment.creator.login }}` | GitHub user who triggered the deployment | ## Agent Instructions Pattern ```markdown A deployment to **${{ github.event.deployment.environment }}** has failed. 1. **Verify the failure**: Confirm `${{ github.event.deployment_status.state }}` is `failure`. If not, call `noop` and stop. 2. **Gather context**: Review ref (`${{ github.event.deployment.ref }}`), SHA (`${{ github.event.deployment.sha }}`), and error description (`${{ github.event.deployment_status.description }}`). 3. **Check for duplicates**: Search open issues with the `[Deployment Failure]` title prefix. 4. **Create an incident issue** if none exists, including environment, ref/SHA, deployment URL, error details, and suggested next steps. Use `noop` if the deployment did not fail or a duplicate issue already exists. ``` ## Safe External Log Linking When including `${{ github.event.deployment_status.target_url }}` in outputs: - treat the URL as untrusted external input and include it as a plain link (never as executable shell input; avoid patterns like `$(...)` or piping it directly into `curl` commands) - prefer a short label such as `External deployment logs` instead of echoing long raw URLs inline - include key incident context (environment, ref, SHA, description) in the issue body so triage does not depend on external link availability - if `target_url` is empty or malformed, continue triage with in-event fields and call out that no external logs URL was provided ## When to Use `deployment_status` vs `workflow_run` - **`deployment_status`**: External services (Heroku, Vercel, Railway, Fly.io) that integrate with the GitHub Deployments API — they post a deployment status event back to GitHub when a deploy finishes. - **`workflow_run`**: In-repo GitHub Actions pipelines — use when reacting to the success or failure of another Actions workflow in the same repository. --- description: Quick reference mappings from user requirements to agentic workflow triggers, outputs, tools, and guardrails. --- # Designer Decision Heuristics Quick-reference mapping tables for `.github/aw/designer.md`. Load this file during Phase 2–7 of the interview when translating user answers into workflow syntax. ## Trigger Mapping | User says... | Maps to | |---|---| | "when someone opens a PR" | `on: pull_request:` with `types: [opened]` | | "when a PR is updated" | `on: pull_request:` with `types: [opened, synchronize]` | | "every morning", "daily" | fuzzy schedule shorthand `on: schedule: daily on weekdays` (compiler expands to cron) | | "every Monday", "weekly" | fuzzy schedule shorthand `on: schedule: weekly` (compiler expands to cron) | | "when I say /review" | `on: slash_command:` with `name: review` (or requested command) | | "when an issue is labeled bug" | `on: issues:` with `types: [labeled]` and label filter guidance | | "run when label ai-review is added" | `on: label_command:` with `name`/`names`, optional event scoping, and label-as-command semantics | | "run on PRs from forks" | `on: pull_request:` plus explicit `forks:` allowlist and fork security guardrails | | "sometimes automatic, sometimes manual" | semi-active pattern: combine `schedule`/event triggers with `workflow_dispatch` | | "manually", "on demand" | `on: workflow_dispatch:` | | "maintain this repository long term" | survey the repository first, then choose a bounded `schedule` plus optional `workflow_dispatch` | | "when a deployment fails" | `on: deployment_status:` | | "when another workflow finishes" | `on: workflow_run:` | ## Safe Output Mapping | User says... | Maps to | |---|---| | "post a comment" | `add-comment` | | "create an issue" | `create-issue` | | "update issue title/body" | `update-issue` | | "create a Jira issue" | `jira-create-issue` | | "update Jira issue ENG-123" | `jira-update-issue` | | "comment on Jira issue ENG-123" | `jira-add-comment` | | "add a Jira label" | `jira-add-label` | | "create a Linear issue" | `linear-create-issue` (experimental) | | "update Linear issue" | `linear-update-issue` (experimental) | | "comment on Linear issue" | `linear-add-comment` (experimental) | | "create an Azure DevOps work item" | `ado-create-work-item` (experimental) | | "update an Azure DevOps work item" | `ado-update-work-item` (experimental) | | "comment/assign/link Azure DevOps work items" | `ado-comment-on-work-item`, `ado-assign-work-item`, `ado-link-work-items` (experimental) | | "close the issue" | `close-issue` | | "assign someone", "remove assignment" | `assign-to-user`, `unassign-from-user` | | "set issue type/field/milestone" | `set-issue-type`, `set-issue-field`, `assign-milestone` | | "open a PR", "submit changes" | `create-pull-request` | | "update PR description/title" | `update-pull-request` | | "close the PR", "merge the PR" | `close-pull-request`, `merge-pull-request` | | "mark PR ready" | `mark-pull-request-as-ready-for-review` | | "sync PR branch with base" | `update-pull-request` with `update-branch: true` | | "commit a fix to the PR branch" | `push-to-pull-request-branch` | | "approve / request changes" | `submit-pull-request-review` | | "dismiss a PR review" | `dismiss-pull-request-review` | | "inline review comment", "reply to review thread" | `create-pull-request-review-comment`, `reply-to-pull-request-review-comment`, `resolve-pull-request-review-thread` | | "start or edit discussion", "close discussion" | `create-discussion`, `update-discussion`, `close-discussion` | | "request reviewer", "hide comment" | `add-reviewer`, `hide-comment` | | "create/update project", "project status update" | `create-project`, `update-project`, `create-project-status-update` | | "update release", "upload release asset" | `update-release`, `upload-asset` | | "trigger another workflow", "dispatch to workflow", "run another workflow" | `dispatch-workflow` | | "create/auto-fix code scan alert" | `create-code-scanning-alert`, `autofix-code-scanning-alert` | | "start an agent session", "assign to an agent" | `create-agent-session`, `assign-to-agent` | | "store persistent memory comment" | `comment-memory` | | "store durable repository memory", "persist memory in the repository" | `repo-memory` | | "link a sub-issue" | `link-sub-issue` | | "add labels", "remove labels" | `add-labels`, `remove-labels` | | "replace a label with another" | `replace-label` | | "log completion message", "signal no action needed" | `noop` (auto-enabled; no declaration required in most workflows) | | "track when tools are missing", "create issues for missing tools" | `missing-tool` (auto-enabled; configure `create-issue: true` to file tracking issues) | | "track when data is unavailable", "create issues for missing data" | `missing-data` (auto-enabled; configure `create-issue: true` to file tracking issues) | | "flag when agent can't finish", "report infrastructure failure" | `report-incomplete` (auto-enabled; configure `create-issue: true` to track failures) | | "surface analysis on the commit/PR checks UI" | `create-check-run` | | "upload a file as a run artifact" | `upload-artifact` | | "nothing visible", "just analyze" | no write safe outputs required (noop is still called automatically) | ## Network Mapping | User says... | Maps to | |---|---| | "calls an external API" | ask for exact FQDN/wildcard, then add to `network.allowed` | | "reads GitHub data / clones repos" | include `github` in `network.allowed` | | "uses GitHub Actions artifacts or cache" | include `github-actions` in `network.allowed` | | "installs npm packages" | include `node` in `network.allowed` | | "runs pip install" | include `python` in `network.allowed` | | "builds Go code" | include `go` in `network.allowed` | | "installs gems / uses Bundler" | include `ruby` in `network.allowed` | | "runs cargo build" | include `rust` in `network.allowed` | | "uses NuGet / .NET restore" | include `dotnet` in `network.allowed` | | "builds with Maven / Gradle" | include `java` in `network.allowed` | | "uses Docker / pulls container images / pushes to GHCR" | include `containers` in `network.allowed` | | "runs Playwright browser tests" | include `playwright` in `network.allowed` | | "runs apt install / yum / apk" | include `linux-distros` in `network.allowed` | | "uses Terraform / HashiCorp registry" | include `terraform` in `network.allowed` | | "connects to localhost / loopback / local services" | include `local` in `network.allowed` | | "no external access" | `network.allowed: [defaults]` (or `[]` if explicitly zero network) | For less common ecosystems (Swift, PHP, Dart, Haskell, Perl, fonts, Deno, Elixir, Bazel, Clojure, Julia, Kotlin, Lua, node CDNs, OCaml, PowerShell, R, Scala, Zig, dev-tools, Chrome, LaTeX, Lean, python-native) and the full list of **invalid shorthands** (`npm`, `pypi`, `docker`, etc. — see `.github/aw/network.md#invalid-shorthands`), consult `.github/aw/network.md` before generating. ## Tool Mapping | User says... | Maps to | |---|---| | "read GitHub issues/PRs/workflows" | `tools.github` with `mode: gh-proxy` and minimal `toolsets` | | "use full MCP server/tool definitions" | `tools.github` with `mode: local` | | "use other MCP servers but keep token cost down" | `tools.cli-proxy: true` (hybrid CLI-proxy mode) | | "edit files" | `edit` tool (default unless restricted) | | "run commands/tests" | `bash` tool (default unless restricted) | | "browse web pages/docs" | `web-fetch` and/or `web-search` | | "test UI flows" | `playwright` | ## Pattern Heuristics | User says... | Recommended named pattern | |---|---| | "triage issues automatically" | `IssueOps` | | "run on /commands with human approval loops" | `ChatOps` | | "run every weekday and keep improving" | `DailyOps` | | "monitor workflow failures and trends" | `MonitorOps` | | "process a big backlog in chunks" | `BatchOps` | | "run manually with input parameters" | `DispatchOps` | | "keep advancing a feature one chunk at a time" | `Feature Grower` | | "apply a label-based workflow" | `LabelOps` | | "operate across multiple repositories" | `MultiRepoOps` | | "coordinate multiple sub-agents" | `Orchestration` | | "manage project board items" | `ProjectOps` | | "research, plan, and assign issues" | `ResearchPlanAssignOps` | | "self-correcting / retry on failure" | `CorrectionOps` | | "run in a side/fork repo" | `SideRepoOps` | | "write a spec before implementing" | `SpecOps` | | "A/B test workflow variants" | `TrialOps` | | "process items from a queue" | `WorkQueueOps` | | "deterministic, no LLM needed" | `DeterministicOps` | | "manage from a central repo" | `CentralRepoOps` | | "track work via GitHub Projects" | `Monitoring with Projects` | ## Integration Auth Mapping When the user names a third-party service or MCP server: 1. Confirm whether native tool, MCP server, or safe-output job is the right integration path. 2. Look up the integration's auth requirements and required scopes before finalizing the design. 3. Provide a concrete setup checklist with: - required GitHub Actions secrets (names to create) - workflow env variables that consume those secrets - minimum token scopes/permissions needed Output format to use: ```text Integration auth setup: - : - Secrets to create: , - Workflow env vars: =${{ secrets. }} - Required scopes/permissions: ``` Never suggest committing plaintext tokens. ## Data Strategy Mapping | User says... | Maps to | |---|---| | "analyze PRs", "review issues", "check status" | add `steps:` that pre-fetch with `gh` + `jq` | | "read the diff", "look at changed files" | add `steps:` using `gh pr diff` or `gh pr view --json files` | | "search for patterns across repos" | add `steps:` using `gh search` + `jq` filters | | "just respond to a comment" | no pre-fetch needed (event payload is enough) | | "process each item individually" | suggest sub-agent pattern with `model: small` | | "weekly digest", "compliance report", "license review", "policy audit" | pre-fetch with `gh` + `jq` into `/tmp/gh-aw/data/`; point prompt to those files | --- description: Structured interview playbook for turning user goals into complete, runnable agentic workflow specifications. --- # Workflow Designer Use this skill to run a structured interview with users who know their goal but not the workflow syntax yet, then generate one complete workflow `.md` file. ## When to Use This Skill - Use `.github/aw/designer.md` to discover and confirm requirements. - Use `.github/aw/create-agentic-workflow.md` once requirements are clear and ready for implementation. - Use `.github/aw/agentic-chat.md` when the user wants a specification/pseudo-code instead of a runnable workflow file. - Load `.github/aw/maintainer.md` when the goal is recurring repository maintenance, backlog reduction, owned-PR upkeep, or long-term code health. ## Interview Framework Ask one question at a time. Move to the next phase only after the current phase is clear. ### Phase 1: Goal Ask: **"What do you want to automate?"** Capture: - Workflow name (kebab-case candidate) - Brief description - Optional emoji ### Phase 1a: Intent Before selecting a trigger or implementation, load [intent.md](intent.md) and derive the concise canonical outcome and transient IntentSpec. Use it to derive PromptPex eval and inverse-eval scenarios and, when needed, operational value. Confirm the outcome when it is ambiguous and persist it later as `intent:`. For explicit, narrow requests, keep this step lightweight. ### Phase 1b: Repository Survey and Intent Mining For maintenance or broad automation requests, run the bounded survey in [maintainer.md#survey-the-repository-before-choosing-a-strategy](maintainer.md#survey-the-repository-before-choosing-a-strategy). Record examined sources, observed signals, and confidence; if evidence is insufficient, stop and ask the user rather than inventing a portfolio. Separate observed signals from inferred strategy, derive evidence-backed candidate intents, and present competing candidates when none clearly dominates before selecting and augmenting one. Ask only about policy choices that cannot be inferred. ### Phase 2: Trigger Ask: **"When should this run?"** Follow up only if needed: - Which event type(s)? - Any filters (labels, branches, commands)? - Scheduled cadence (daily/weekly/hourly)? Compare candidate architectures against the IntentSpec, then map the selected one to the `on:` block. ### Phase 3: Scope (Read/Write) Ask: - **"What should it read?"** (issues, PRs, code, discussions, CI data) - **"What should it create or update?"** (comments, issues, PRs, labels) Map to: - `permissions:` (keep read-only for agent job) - `tools:` - `safe-outputs:` ### Phase 4: Data Strategy Ask: - **"What data does the agent need to make decisions?"** - Follow up: **"Can we pre-fetch and aggregate that data with shell commands so the agent only reads compact JSON?"** Capture: - Whether `steps:` should pre-fetch GitHub data with `gh` + `jq` - Output paths under `/tmp/gh-aw/data/` - Whether batch work should use sub-agents Map to: - `steps:` - Prompt references to pre-computed file paths ### Phase 5: Guardrails Ask: **"Should it block merging, just advise, or silently log?"** Capture: - Visibility expectations (comment, issue, no visible output) - No-op behavior expectation Guide toward safe output behavior and explicit `noop` instructions. ### Phase 6: Context & Network Ask: **"Does it need external APIs, web access, package installs, or MCP servers?"** Follow up: - **"Any third-party services or MCP servers to include (for example Slack, Jira, Datadog, custom internal MCP)?"** - **"Are you deploying on GitHub.com, GHEC with custom endpoints, or GHES?"** - For each integration, identify required auth from source docs and map it to GitHub Actions secrets + workflow env variables. - Ask for exact external domains (FQDN/wildcard). Map to: - `network.allowed` - Optional MCP/GitHub tool usage in `tools:` - `secrets:` / `env:` wiring for integration tokens - GHES/GHEC settings such as `engine.api-target` and `aw.json` `ghes: true` (when applicable) ### Phase 7: Engine (optional) Ask **"Any AI engine preference?"** only when the request contains ambiguous engine-specific hints. Omit `engine:` and let the configured default apply unless there's an explicit preference or a requirement the default can't satisfy — then map to `engine:`, trying Copilot first. ### Phase 7b: Skills, Plugins, LSP & Evals (optional) Ask only when relevant: **"Does the agent need extra domain knowledge, agent plugins, language-server code intelligence, or automated success checks?"** Map to: - `skills:` — pinned external skills (`owner/repo/skill@sha`) or local paths (`.github/skills/`) when the agent needs domain knowledge (see `.github/aw/skills.md`) - `plugins:` — pinned agent plugins (`owner/repo[/path]@ref`) when the user names specific plugins; experimental and unsupported by `gemini`/`pi` (see `.github/aw/skills.md`) - `lsp:` — language servers for code intelligence; **experimental** and only valid with `engine: copilot` (see `.github/aw/lsp.md`) - `evals:` — binary YES/NO questions checking whether the run met its goals; requires `safe-outputs:` so `agent_output.json` exists (see `.github/aw/evals.md`) gh-aw installs `skills:` and `plugins:` entries before the agent runs. Never emit install steps or prompt instructions that fetch skills or plugins on the fly. ### Phase 8: Confirmation Present a structured summary and ask for approval before generation. ## Decision Heuristics Load `.github/aw/designer-mappings.md` for the full trigger, safe-output, network, tool, pattern, integration-auth, and data-strategy mapping tables used to translate interview answers (Phases 2–7) into workflow syntax. ## Token Optimization Defaults Apply these defaults unless the user explicitly asks otherwise: 1. Use DataOps by default for GitHub reads: pre-fetch/aggregate with `gh` + `jq` in `steps:`, store compact JSON in `/tmp/gh-aw/data/`, and point the prompt to those files (see `.github/aw/token-optimization.md` for details). 2. Keep tool surface minimal: default to `tools.github.mode: gh-proxy`, include only required toolsets, and prefer `bash` + `gh` for simple reads. 3. For batch workloads, split items into compact data and suggest sub-agent processing with `model: small`. 4. Keep prompts compact: concise imperative instructions, explicit file paths, single-line `noop` guidance, and stable instructions before dynamic content. ## Progressive Disclosure Rules 1. Never dump all options at once; ask one targeted question at a time. 2. Skip questions when answers are inferable from prior user statements. 3. Offer smart defaults and request confirmation instead of over-questioning. 4. Ask at most 5 questions before presenting a summary; then ask "anything else?" if needed. 5. Detect done signals (`that's it`, `looks good`, `generate it`) and proceed to generation. ## Confirmation Format Use this exact structure: ```text 📋 Proposed workflow: - Name: - Trigger: - Engine: - Tools: - Safe outputs: - Network: - Integrations/Auth: - Deployment: - Intent: ``` Then ask: **"Ready to generate, or want to adjust anything?"** ## Generation Template After confirmation, generate one workflow file using the same skeleton style as `.github/aw/create-agentic-workflow.md`. ```markdown --- emoji: description: intent: on: permissions: contents: read issues: read pull-requests: read tools: github: mode: gh-proxy toolsets: [default] steps: - name: run: | mkdir -p /tmp/gh-aw/data safe-outputs: network: allowed: - defaults - skills: - — only if domain knowledge is needed> plugins: - lsp: : # optional, engine: copilot only (experimental) command: fileExtensions: ".": evals: - id: # optional, requires safe-outputs question: --- # ## Task Objective: Determine applicability from the activation conditions and required context. Produce the required effects only when the evidence threshold is met. If a no-op condition applies, including insufficient evidence or a duplicate, call `noop` with a short reason and take no visible write action. If `steps:` includes pre-fetch commands, read the resulting `/tmp/gh-aw/data/*.json` files instead of broad live re-fetches. ## Safe Outputs - Use configured safe outputs for all visible write actions. - Call `noop` with a short reason when no action is needed. ``` ## Validation Checklist Before final output, run this internal self-check: - [ ] Agent job permissions remain read-only (writes only via safe outputs) - [ ] `safe-outputs:` covers every write action mentioned in prompt/instructions - [ ] Network access is scoped; avoid blanket wildcard entries - [ ] Trigger matches the user's intended activation event - [ ] `intent:` is a concise outcome, and the selected architecture follows the augmented IntentSpec - [ ] Prompt instructs agent to call `noop` when no action is needed - [ ] Prompt states applicability, required effects, and inverse/no-op conditions - [ ] Unnecessary defaults are omitted (for example `engine: copilot`) - [ ] If reading GitHub data, `steps:` pre-fetches compact JSON (DataOps) - [ ] `tools.github.mode` is `gh-proxy` unless broader MCP toolsets are explicitly needed - [ ] Only required toolsets are listed (avoid blanket toolset lists) - [ ] Prompt references specific pre-computed file paths - [ ] For batch processing (>5 items), sub-agent pattern is suggested - [ ] Network entries use valid ecosystem identifiers (no `npm`/`pypi`/`docker`-style invalid shorthands) - [ ] `skills:` entries are pinned (`owner/repo/skill@sha`) or local paths, and only added when domain knowledge is needed - [ ] `plugins:` entries are pinned (`owner/repo[/path]@ref`) and only added when the user asked for specific agent plugins - [ ] Skills and plugins are declared in frontmatter — no on-the-fly install steps or prompt-driven installation - [ ] `lsp:` is only used with `engine: copilot` (experimental; omit otherwise) - [ ] `evals:` questions are binary YES/NO and `safe-outputs:` is declared so `agent_output.json` exists - [ ] Evals, when used, cover both an intent-required effect and a counter-case through separate scenario fixtures or scenario-aware questions; do not require mutually exclusive outcomes from one run - [ ] For each third-party service/MCP integration, required secrets/env vars are listed - [ ] Auth guidance includes least-privilege token scope recommendations - [ ] For GHEC/GHES deployments, `engine.api-target` and GHES compatibility guidance are included when needed ## References (load only when needed) - `.github/aw/designer-mappings.md` (trigger, safe-output, network, tool, pattern, integration-auth, and data-strategy mapping tables) - `.github/aw/syntax.md` (index → `.github/aw/syntax-core.md`, `.github/aw/syntax-agentic.md`, `.github/aw/syntax-tools-imports.md`) - `.github/aw/safe-outputs.md` (index → `.github/aw/safe-outputs-content.md`, `.github/aw/safe-outputs-management.md`, `.github/aw/safe-outputs-automation.md`, `.github/aw/safe-outputs-runtime.md`) - `.github/aw/network.md` - `.github/aw/patterns.md` - `.github/aw/subagents.md` - `.github/aw/token-optimization.md` - `.github/aw/triggers.md` - `.github/aw/create-agentic-workflow.md` - `.github/aw/skills.md` - `.github/aw/lsp.md` - `.github/aw/evals.md` - `.github/aw/intent.md` Outside the repo, use `https://github.com/github/gh-aw/blob/main/` for any of the above. --- description: Private-preview GitHub Drives memory backend — experimental, gated, do not configure unless explicitly enrolled. --- # Drive Memory (Private Preview) Use these instructions only when a repository has been explicitly enrolled in the [GitHub Drives preview](https://github.com/actions/gh-drives-preview). Do not recommend or configure `drive-memory` otherwise — prefer [`cache-memory` or `repo-memory`](memory.md). ## What it is - `tools.drive-memory` mounts a persistent GitHub Drive into the agent at `/tmp/gh-aw/drive-memory/` (or `/tmp/gh-aw/drive-memory-{id}/` for a named entry in a multi-drive array). - Backed by an experimental service, not general `cache-memory`/`repo-memory`. GitHub Drives allows only one active writer per drive; overlapping runs writing the same drive can contend for the writer lease. - The compiler checks out each drive before the agent runs and commits validated changes afterward. With threat detection enabled, it stages drive contents as an artifact and a separate `update_drive_memory` job publishes them only after detection succeeds and the drive hasn't changed since checkout. ## Configuration ```yaml tools: drive-memory: true # default drive, default config ``` ```yaml tools: drive-memory: drive-name: my-drive # optional, defaults to "default" description: "..." # optional, shown in agent prompt disk-size: 100M # number + K/M/G/T suffix; ignored for existing drives prefetch: false # optional, eagerly fetch existing contents restore-only: false # optional, mount without committing changes allowed-extensions: [".json"] # optional validation: script: | // Node.js body; globals: fs, path, memoryRoot, memoryId, memoryKind timeout-minutes: 1 ``` Multiple named drives (array form, each needs `id`): ```yaml tools: drive-memory: - id: notes drive-name: agent-notes - id: cache drive-name: agent-cache restore-only: true ``` ## Compiler effects - Grants the generated job `contents: read`, `id-token: write`, and the required `drives` permission. - Adds a `push_drive_memory` (or threat-detection-gated `update_drive_memory`) job analogous to `push_repo_memory` for `repo-memory`. ## Limitations - GitHub-hosted `ubuntu-latest` only; not supported inside job containers. - Upstream actions have no versioned release — gh-aw pins the preview `main` commit. - Do not store secrets in drive memory. --- description: Private-repository enclaves (preview) — finite-disclosure access to approved private repos via the MCP gateway. --- # Private Repository Enclaves Use these instructions when a workflow needs bounded, auditable access to a private repository other than the one the workflow runs in. ## What it is - The top-level `enclaves:` array (1-2 entries) enables finite-disclosure access to approved private repositories through the compiler-launched MCP gateway. - Each entry is either a **script enclave** (`script:` + `repos:`) registering `enclave_run_script`, or an **agent enclave** (`agent:` + static `repos:` or dynamic `dynamic:`) registering `enclave_run_agent`. - Omit `enclaves:` entirely to disable the feature — this is the default. - This is a preview feature gated on `github/gh-aw-firewall#6992`; an older pinned AWF version will not provide the enclave server. ## Prerequisites - Enclaves require AWF network isolation, which every supported `sandbox.agent.runtime` profile provides, so the compiler launches the MCP gateway in bridge mode and AWF can attach it to the isolated topology. - Each `repos:` entry needs `repo:` (`owner/name`) and `sensitivity:` (`public`, `trusted`, `internal`, `confidential`, or `sealed`). - Choose `trusted` only for repositories whose content is approved for unrestricted return to the primary agent without confidentiality accounting, and where the enclave may return free-form strings in a declared response schema. Do not select it merely to obtain string output. All other sensitivities are finite-schema-only; do not recommend free-form string schemas for them. ## Example ```yaml sandbox: agent: id: awf enclaves: - script: repos: - repo: octo-org/private-service sensitivity: confidential timeout: 45 - agent: model: gpt-5 repos: - repo: octo-org/private-service sensitivity: confidential timeout: 180 ``` ## Rules - Each enclave type (`script`, `agent`) can appear at most once. - If the same repository appears in both entries, its `sensitivity` must match — the information budget is shared across executor types. - AWF fixes the script enclave's network and interpreter, and the agent enclave's network, internally; do not attempt to override these in workflow frontmatter. - A fresh masked capability is generated per workflow run and passed only to the MCP gateway and AWF, never to the primary agent environment. - `timeout:` per enclave entry is capped at 4,740 seconds (AWF reserves the final 60 seconds of its 4,800-second finite-disclosure bucket for cleanup). The gateway itself enforces a 4,860-second tool timeout (4,800s AWF bucket + 60s transport allowance) — treat this as an enforcement bound, not a wall-clock guarantee. ## Agent GitHub tool configuration Prefer this configuration shape for new workflows: ```yaml sandbox: mcp: version: v0.4.17 enclaves: - agent: model: gpt-5 tools: github: allowed: [list_issues, issue_read] allowed-repos: [octo-org/private-service] min-integrity: none repos: - repo: octo-org/private-service sensitivity: confidential ``` - `allowed` is required and currently supports only `list_issues` and `issue_read`. - `allowed-repos` is optional. When omitted, the enclave identity inherits all repositories declared in the enclave's `repos:` list. When set, each entry must also appear in that list. - `min-integrity` is optional and defaults to `approved`. - Unsupported tools and out-of-scope repositories fail closed at compile time. - GraphQL, search, writes, and all other GitHub tools remain denied. - Minimum versions are AWF `v0.28.9` and mcpg `v0.4.15`; trusted repositories additionally require AWF `v0.28.14`. ## Dynamic agent repository policies Use `dynamic:` on agent entries when the primary agent should select one admitted repository at invocation time without enumerating every repository in frontmatter: ```yaml sandbox: agent: id: awf version: v0.28.14 mcp: version: v0.4.19 enclaves: - agent: model: gpt-5 max-task-bytes: 4096 max-model-requests: 8 max-model-tokens: 1024 dynamic: allowed-owners: [octo-org] sensitivity: confidential github-policy: github-repository-read-v1 max-repositories: 4 quotas: max-invocations: 8 max-output-bytes: 32768 max-execution-seconds: 900 audit-labels: [dynamic-enclave] expires-at: "2026-09-06T00:32:00Z" timeout: 120 memory-limit: 512m cpu-limit: "1" pids-limit: 128 tmpfs-limit: 64m max-output-bytes: 8192 max-invocations: 8 ``` - Dynamic mode is agent-only; scripts remain static seed-backed and must declare `repos`. - Each entry declares either non-empty static `repos` or `dynamic`, never both. - Declare `allowed-owners` or `allowed-repositories` using the ADR 0001 canonical lowercase ASCII selector form. The compiler does not trim, case-fold, URL-decode, or otherwise normalize dynamic selectors. - `github-policy` must be `github-repository-read-v1`, the closed policy containing only `list_issues` and `issue_read`. - Dynamic entries require fixed sensitivity, finite resource limits, total quotas, audit labels, an absolute `expires-at` timestamp, AWF `v0.28.14` or newer, and mcpg `v0.4.19` or newer. `expires-at` is an upper bound; the compiler resolves the effective envelope expiry at workflow setup time as `min(expires-at, job-start + workflow timeout)`. Each delegated identity remains independently bounded by its configured `max_identity_ttl`. - The compiler emits the dynamic policy envelope and starts mcpg's `github-repository-delegation-v1` controller, then hands AWF a host-private delegation control endpoint. The delegation-control capability is AWF-only and is excluded from primary and enclave agent environments. ## Deprecated legacy profile The legacy profile remains supported during migration: ```yaml enclaves: - agent: model: gpt-5 github: cli: issues-read-v1 repos: - repo: octo-org/private-service sensitivity: confidential ``` - `enclaves[].agent.github.cli: issues-read-v1` is deprecated. Migrate to `enclaves[].agent.tools.github`. - `issues-read-v1` permits only the `list_issues` and `issue_read` GitHub MCP tools. GraphQL, search, writes, and all other GitHub tools fail closed. - V1 allows at most one repository whose sensitivity is neither `public` nor `trusted` in the agent entry; `trusted` is public-equivalent for this limit. - `trusted` repositories are public-equivalent for this limit, so multiple `trusted` and `public` repositories are allowed. - The compiler generates separate primary and enclave identities for one shared mcpg gateway. The enclave identity is restricted to the GitHub server, those two tools, and the union of repositories declared in its trusted entry. - AWF privately stages the enclave identity and connects the enclave directly to `/mcp/github`; the enclave has no `gh` executable or GitHub token. - The primary agent receives neither the enclave identity nor the gateway configuration. - Minimum versions are AWF `v0.28.9` and mcpg `v0.4.15`; trusted repositories additionally require AWF `v0.28.14`. For a trusted repository, an `enclave_run_agent` response schema may contain strings while remaining structured and strict: ```json { "type": "object", "fields": { "should_dispatch": { "type": "boolean" }, "title": { "type": "string" }, "problem": { "type": "string" }, "root_cause": { "type": "string" }, "proposed_solution": { "type": "string" } } } ``` Responses must conform exactly to the declared schema: fields are required, extra properties are rejected, floats, `$ref`, recursion, regex schemas, and untagged unions are unsupported. Output remains subject to AWF's configured limit and the global 8 KiB ceiling. See also: [agent-runtime-instructions.md](agent-runtime-instructions.md) for `sandbox.agent` fields, and [network.md](network.md) for network isolation defaults. --- description: Guide for adding BinEval-style binary evaluations to agentic workflows — syntax, intent-derived question methodology, and anti-patterns. --- # BinEval Evaluations in Agentic Workflows Use `evals:` with `safe-outputs` to judge whether an agent achieved its intended outcome. Each eval is a binary YES/NO question about observable agent output. --- ## Basic Syntax ### Shorthand — plain list > **Prerequisite:** Declare `safe-outputs:` with `evals:`. ```yaml --- on: issues: types: [opened] engine: copilot safe-outputs: add-comment: evals: - id: response_provided question: Does the agent output confirm that a response was written? - id: no_unrelated_files question: Does the agent output show that only the expected files were modified? --- Implement the requested change described in ${{ github.event.issue.body }}. ``` Each entry requires: - `id` — unique, non-empty identifier for the question. - `question` — the binary question the LLM judge will answer YES or NO. ### Extended form — with model and runs-on overrides ```yaml evals: questions: - id: compiles question: Does the generated code compile without errors? - id: tests_pass question: Do all existing tests still pass according to the agent output? - id: scoped_change question: Does the agent output show that only the expected files were modified? model: small # model for all questions runs-on: ubuntu-latest ``` **Fields:** - `questions:` — list of question objects (required in extended form, ≥ 1 entry). - `model:` — LLM model for all questions. Use a model alias (`small`, `gpt-4o`) or a full model ID. - `runs-on:` — optional runner override. --- ## Decomposing a Task into Binary Questions BinEval questions must be answerable with a strict YES or NO by an LLM reading the agent's output alone. Follow this process: ### 1 — State the goal One sentence describing a successful run: > "The agent should update the CHANGELOG and bump the version number without touching unrelated files." ### 2 — Identify observable properties Break the goal into properties a judge can verify from `agent_output.json`: | Property | Observable signal | |---|---| | CHANGELOG updated | Agent output mentions or contains CHANGELOG edits | | Version bumped | A version number appears changed in the diff or agent summary | | No unrelated files changed | Agent output does not list changes outside CHANGELOG and version files | ### 3 — Write falsifiable YES/NO questions One property per question, YES when the property holds, referencing observable evidence in the agent output — not intent or effort. ```yaml evals: - id: changelog_updated question: Does the agent output confirm that CHANGELOG was updated? - id: version_bumped question: Does the agent output confirm that the version number was incremented? - id: no_unrelated_files question: Does the agent output show that only CHANGELOG and version files were modified? ``` ### 4 — Assign question cost Prefer `model: small` (the default) for factual checks. Set `model` at the `evals:` level for reasoning-heavy questions: ```yaml evals: questions: - id: changelog_updated question: Does the agent output confirm that CHANGELOG was updated? - id: design_sound question: Is the agent's proposed design consistent with established patterns described in the agent output? model: gpt-4o # nuanced questions; override default small model ``` ### PromptPex intent and counter-intent scenarios When a workflow has an `intent:`, load [intent.md](intent.md). Derive a positive scenario from each required effect and a counter-intent scenario from each inverse/no-op condition. Write an observable, scenario-specific question for each: ```yaml evals: - id: actionable_case question: Does the agent output show that the novel, actionable case received the configured visible result? - id: duplicate_noop question: Does the agent output show that the already-tracked case produced no visible write action? - id: uncertainty_noop question: Does the agent output show that insufficient evidence produced no visible write action? ``` Do not combine mutually exclusive scenarios into one question list. If a question is shared, state its applicability and return `UNKNOWN` when its scenario was not provided—not `NO`. ### Good question checklist - ✅ Answerable from the agent output alone — no external calls needed. - ✅ Exactly one binary claim per question. - ✅ Uses YES = success convention consistently. - ✅ Avoids subjective terms ("good", "well-written") unless the question explicitly bounds them ("according to the coding style guide"). --- ## Anti-Patterns - ❌ **Compound questions** — "Did the agent update CHANGELOG and bump the version?" splits into two questions. A single NO is ambiguous. - ❌ **Unobservable questions** — "Did the agent try its best?" cannot be answered from output text. - ❌ **Duplicate IDs** — `id` must be unique within a workflow; the compiler rejects duplicates. - ❌ **Empty questions** — both `id` and `question` must be non-empty strings. - ❌ **Using a frontier model for all questions** — factual checks are cheap on small models; save larger models for reasoning-heavy questions. - ❌ **Questions that require external evidence** — questions must be answerable from agent output alone. --- description: Guide for setting up A/B testing experiments in agentic workflows — syntax, design principles, dimensions to test, how to measure results, and anti-patterns. --- # A/B Testing Experiments in Agentic Workflows --- ## How Experiments Work Per run: 1. **Restore** — activation job loads experiment state from configured storage (git branch default, or Actions cache). 2. **Pick** — `pick_experiment.cjs` picks the variant with the lowest invocation count (ties broken by array order). 3. **Save** — updated counter written back. 4. **Upload** — state uploaded as workflow artifact `experiment` (30-day retention). 5. **Inject** — variant available as `${{ experiments. }}` and in `{{#if experiments. }}` blocks. **Key properties**: - Every run gets one variant per experiment; no sampling. - Assignment persists across runs automatically. - Multiple experiments run simultaneously, each independently balanced. --- ## Basic Syntax ```yaml --- on: schedule: daily on weekdays engine: copilot experiments: prompt_style: [concise, detailed] --- {{#if experiments.prompt_style == "concise" }} Summarise the findings in ≤ 5 bullets. {{#else}} Provide a detailed analysis with reasoning for each finding. {{#endif}} ``` ### Naming Rules - Names must match `[a-zA-Z_][a-zA-Z0-9_]*`. Use `lowercase_with_underscores`. - Non-matching names are silently skipped at compile time. ### Variant Rules - At least **2 variants** required. - Plain strings, lowercase descriptive (`concise`, `detailed`, `step_by_step`). - ~10 variants practical max — sample size per variant grows fast beyond that. --- ## Object Form (Weighted Variants and Date Gating) Object form supports non-uniform weights, date gating, and governance metadata: ```yaml experiments: prompt_style: variants: [concise, detailed, step_by_step] weight: [2, 1, 1] # 50% concise, 25% detailed, 25% step_by_step description: "Verbosity A/B test" metric: "ai_credits" hypothesis: "H0: no change in ai_credits. H1: concise reduces by >=15%" guardrail_metrics: - name: success_rate threshold: ">=0.95" - name: empty_output_rate direction: min threshold: 0.0 issue: "42" start_date: "2026-05-01" end_date: "2026-06-01" ``` **Fields:** - `variants:` — array of variant strings (required, ≥ 2 entries). - `weight:` — non-negative integers, same length as `variants`. Enables weighted-random selection. `[2, 1, 1]` = 50/25/25. All zeros → always returns control (first variant). Omit for round-robin. - `start_date:` / `end_date:` — ISO-8601 `YYYY-MM-DD`. Outside this window, control variant is returned and counters do not increment. - `description:`, `metric:`, `issue:`, `hypothesis:` — governance metadata (no runtime effect). - `guardrail_metrics:` — array; once minimum samples and supported observations are available for every mandatory guardrail, any failure produces a deterministic core decision of `REJECT`. Each entry: - `name` (required) — metric identifier. - `threshold` (required) — comparison string (`">=0.95"`, `"==0"`) or bare number paired with `direction`. - `direction` (optional, `"min"`/`"max"`) — lower-better vs higher-better. With bare numeric `threshold`: `min` → metric ≤ threshold; `max` → metric ≥ threshold. Bare-array and object forms can be mixed in the same `experiments:` map. --- ## Storage Configuration ```yaml experiments: storage: repo # or: cache prompt_style: [concise, detailed] ``` | Value | Behaviour | When to use | |---|---|---| | `repo` (**default**) | Commits `state.json` to branch `experiments/{sanitizedWorkflowID}` (hyphens stripped, e.g. `my-workflow` → `experiments/myworkflow`). Adds a `push_experiments_state` job; needs `contents: write`. Durable. | Recommended for all experiments. | | `cache` | GitHub Actions cache. No extra job/permission. May evict after 7 days of inactivity. | Use only when `contents: write` cannot be granted. | > The branch is created automatically on first run as an orphan containing `state.json` and `assignments.json`. --- ## Referencing the Active Variant Two forms, both resolved before the agent sees the prompt: ### 1 — Conditional blocks (most common) ```markdown {{#if experiments.tone == "formal" }} Use formal, professional language throughout the report. {{#else}} Use a friendly, conversational tone. {{#endif}} ``` ### 2 — Direct interpolation ```markdown Use `${{ experiments.tone }}` tone when writing the issue body. ``` --- ## Designing a Good Experiment 1. **One dimension** per experiment. 2. **Falsifiable hypothesis**. 3. **Primary metric** measurable from workflow run data (artifacts, outputs, duration, tokens). Prefer `eval:` / `evals.` when success is best measured as a YES/NO question. 4. **Pair the experiment with an eval.** Add at least one `evals:` question that checks whether the assigned variant's intended effect actually shows up in the output (e.g., "does the report follow the STE writing rules?"), and reference it from `metric` or `secondary_metrics` as `eval:`. Purely quantitative metrics (token count, duration, engagement score) don't verify *why* an effect happened — the paired eval does. 5. **Guardrail metrics** — things that must not degrade. Use `direction: min` + bare number for lower-is-better rates, or `">=0.95"` for higher-is-better. 6. **Sample size estimate** per variant. Prefer high-frequency workflows for faster significance. --- ## Dimensions Worth Experimenting On ### Prompt Design ```yaml experiments: prompt_style: [concise, detailed] reasoning_depth: [shallow, deep] output_format: [bullets, prose, table, ste] tone: [formal, casual] ``` Use `{{#if experiments.prompt_style == "concise" }}` blocks to swap prompt instructions. Always compare against a specific variant value. > ⚠️ **Never write** the internal env-var form `__GH_AW_EXPERIMENTS__PROMPT_STYLE___detailed`. The compiler expands `experiments.` references automatically. **Typical metrics**: output quality, AI credits, success rate, output length. When `metric` references `eval:` or `evals.`, declare that eval question under `evals:`. `gh aw experiments analyze` will then show both the metric question text and observed eval YES/NO/UNKNOWN results. `ste` (Simplified Technical English) is a text-style variant worth testing alongside `bullets`/`prose`/`table`. It constrains the prompt to a small set of writing rules — short sentences (≤20 words), one instruction or fact per sentence, active voice, present tense, familiar vocabulary, and spelled-out acronyms on first use — to test whether simplified phrasing improves readability, engagement, or token efficiency versus richer prose/table formats. ### Engine & Model ```yaml experiments: engine_variant: [copilot, claude] ``` > ⚠️ **Engine experiments require separate compiled files**: the `engine:` key cannot be switched mid-run from a single file. Use two parallel workflow files and compare run metrics. **Typical metrics**: run cost (tokens), duration, completion rate, error rate. ### Tool Configuration ```yaml experiments: tool_scope: [narrow, broad] ``` ```markdown {{#if experiments.tool_scope == "narrow" }} Only use the `issues` and `pull_requests` toolsets. {{#else}} Use any available GitHub MCP tools. {{#endif}} ``` **Typical metrics**: number of tool calls, run duration, output accuracy. ### Skill Usage ```yaml experiments: skill_hint: [enabled, disabled] ``` ```markdown {{#if experiments.skill_hint == "enabled" }} Check `skills/` and `.github/skills/` for relevant `SKILL.md` files and apply their guidance. {{#endif}} ``` **Typical metrics**: output quality, context token consumption, run duration. ### Timeout & Pacing ```yaml experiments: timeout: [short, long] ``` Pair with a conditional step, or use two compiled files with different `timeout-minutes:`. --- ## Minimal Working Example ```markdown --- description: Daily PR summary — A/B test concise vs. detailed output on: schedule: daily on weekdays engine: copilot permissions: pull-requests: read tools: github: toolsets: [pull_requests] safe-outputs: create-discussion: title-prefix: "[pr-summary] " close-older-discussions: true timeout-minutes: 15 experiments: output_style: [concise, detailed] --- Summarise the pull requests merged in ${{ github.repository }} today. {{#if experiments.output_style == "concise" }} Write a maximum of 5 bullet points. Each bullet is one sentence. {{#else}} Write a structured report with sections for: new features, bug fixes, refactors, and documentation changes. Include a one-paragraph executive summary at the top. {{#endif}} Include links to each PR. Use ${{ github.server_url }}/${{ github.repository }}/pull/ format. ``` Compile and deploy: ```bash gh aw compile pr-summary ``` First run picks `concise` (count 0), second picks `detailed`, alternating until one variant wins. --- ## Multiple Simultaneous Experiments Independent assignment, all three injected into the prompt: ```yaml experiments: prompt_style: [concise, detailed] emoji_density: [heavy, minimal] skill_hint: [enabled, disabled] ``` > ⚠️ **Interaction effects** — limit to 2–3 simultaneous experiments unless you can run factorial analysis. --- ## Lifecycle of an Experiment 1. **Design** — hypothesis, dimension, primary + guardrail metrics. 2. **Instrument** — add `experiments:` and `{{#if experiments. == "" }}` blocks. Never use `__GH_AW_EXPERIMENTS__*`. 3. **Compile** — `gh aw compile `. 4. **Run** — check activation job step summary for variant assignment. 5. **Analyse** — once min sample size reached, compare distributions; for eval-backed metrics, use `gh aw experiments analyze ` to inspect the resolved question and current eval outcomes. 6. **Conclude** — rewrite baseline to winning variant, remove `experiments:`, recompile. ## Continual Experiment Ramps `continual:` is experimental. It provides deterministic control/candidate assignment with a runtime-managed traffic ramp. The first variant is the control and the second is the candidate. Existing experiments without this block keep their current behavior. ```yaml experiments: optimize_tool_use: variants: [control, candidate] metric: eval:quality min_samples: 20 continual: seed: tool-use-v1 ramp: [10, 25, 50] ``` Assignment occurs in the activation job before agent execution. It hashes the seed, experiment name, repository, workflow, and run ID. The activation job advances the ramp after each `min_samples` candidate assignments and stores the current stage on the experiment branch, leaving the workflow source immutable. Each decision logs the stage, assignment counts, active weights, and selected variant. The ramp only changes candidate traffic; it does not evaluate outcomes or promote a winner. Use the existing experiment analysis commands and metrics to decide whether to stop the experiment or make a variant permanent. --- ## Anti-Patterns - ❌ **Multiple dimensions in one experiment** — can't attribute the improvement. - ❌ **Removing `experiments:` before sample size reached** — resets state, invalidates counts. - ❌ **Interpreting early results** (<~20 runs/variant) — chance variation dominates. - ❌ **Experiments as feature flags** — use `features:` for deterministic switches. - ❌ **Engine experiments in one file** — `engine:` cannot switch mid-run; use two parallel files. - ❌ **Conditional frontmatter imports** — keep imports security-stable and use `{{#if experiments. }}` with `{{#runtime-import? path}}` (optional form, not promoted to unconditional lock-file macros) for prompt experiments instead. - ❌ **Nesting `{{#if experiments. }}` inside `{{#runtime-import? }}`** — evaluation order is brittle across import boundaries. Prefer explicit branching in the main workflow prompt or separate workflow files per variant. - ❌ **Writing the internal env-var form** `__GH_AW_EXPERIMENTS__*` — implementation detail, may change. --- description: GitHub Agentic Workflows applyTo: ".github/workflows/*.md,.github/workflows/**/*.md" --- # GitHub Agentic Workflows ## Persona-to-Pattern Quick Matrix Persona-lens view of the same facts as the canonical [Decision Matrix](triggers.md#decision-matrix) in triggers.md; update both when a trigger/tool/output mapping changes. | Persona | Preferred trigger and scope | Typical read tools | Typical write path | Explicit `noop` rule | |---|---|---|---|---| | Backend Engineer | `pull_request` with `paths:` scoped to migrations, schema, and API contracts | `github` (`gh-proxy`) | `add-comment` for PR-local findings; `create-issue` only for cross-cutting incidents | `noop` when no backend contract files changed | | Frontend Developer | `pull_request` with `paths:` scoped to UI, design-token, and asset files | `github` (`gh-proxy`), optional `playwright`, optional `cache-memory` for baselines | `add-comment` | `noop` when no UI/token files changed or no actionable visual/token issues were found | | DevOps Engineer | `workflow_run` for GitHub Actions failures, `deployment_status` for external deployment failures | `github` (`gh-proxy`) with `actions: read` or `deployments: read` | `create-issue` with stable dedup key | `noop` when status is non-terminal, self-recovered, or an open incident already exists for the same dedup key | | Program Manager | `schedule` (+ `workflow_dispatch` for previews and backfills) | `github` (`gh-proxy`) | `create-issue` with `close-older-issues: true` for recurring digests | `noop` when the reporting window contains no qualifying updates | | Designer | `pull_request` with `paths:` scoped to UI, design-token, copy, and asset files | `github` (`gh-proxy`); optional `playwright` for visual checks | `add-comment` on the PR | `noop` when scoped paths are unchanged or no actionable design/token issue is found | | Legal / Compliance | `pull_request` with `paths:` scoped to dependency manifests or policy docs for PR reviews; `schedule` for recurring audits | `github` (`gh-proxy`) | `add-comment` for findings; `create-issue` only for violations requiring team-wide follow-up | `noop` when no in-scope files changed or all findings are in the allowed tier; always search for an existing open issue before escalating | ## Persona-to-Toolset Matrix | Persona | Default toolset is enough when... | Name optional tools when... | |---|---|---| | Program Manager | Digest/report uses GitHub data only (`tools.github.toolsets: [default]`) | Add `cache-memory` only when trend baselines/deltas must persist across runs | | Designer | PR review is metadata/content-aware via GitHub reads only | Add `playwright` for screenshot/visual checks; add `cache-memory` when baselines or snapshot history are required | | Legal / Compliance | Policy/dependency review is repo-state and metadata driven | Add `cache-memory` when recurring audits need prior-run evidence/comparison state | ## File Format Agentic workflows are markdown files with YAML frontmatter. ```markdown --- emoji: 🧠 name: My Workflow description: Short description on: issues: types: [opened] permissions: contents: read actions: read strict: true network: allowed: [defaults, github] tools: github: mode: gh-proxy toolsets: [default] safe-outputs: add-comment: --- # Workflow Title Natural language instructions for the AI agent. ``` ## Recompilation Rule See [workflow-editing.md](workflow-editing.md) for when `gh aw compile` is required. ## Core Rules - Set `strict: true` for production workflows. - Limit `bash` access to what the workflow actually needs. - For visual regression workflows, explicitly name the baseline source (for example `cache-memory` key, artifact, or branch path). See [visual-regression.md](visual-regression.md). See [workflow-constraints.md](workflow-constraints.md) for the security posture (read-only job, safe-outputs routing, gh-proxy/cli-proxy, network constraints, sanitized text), safer-alternatives pattern, and common risk areas. ## Repository-Specific Instructions Use `@.github/aw/instructions.md` as the canonical repository-local overlay for workflow authoring standards. - This file is optional and repository-owned. - Installed gh-aw agents should load and apply it automatically when present. - Precedence: apply upstream defaults first, then apply repository overlay rules; when they conflict, repository overlay rules win. ## Trigger Selection Use the smallest trigger that matches the requested automation. See the [Decision Matrix](triggers.md#decision-matrix) in triggers.md for the canonical trigger-to-use-case mapping, and [workflow-constraints.md](workflow-constraints.md) for the security posture. ## Ad Hoc Scenario Evaluation Installed gh-aw agents should support scenario evaluation requests that do not create workflow files. - Treat prompts such as `agentic-workflows evaluate this scenario without creating files` as ad hoc evaluation mode. - For explicit research/evaluation requests, invoke with wording such as `agentic-workflows evaluate this scenario without creating files` or `agentic-workflows research this workflow pattern and return recommendations only`. - Return a compact design recommendation covering trigger, scope, tools, permissions, safe outputs, `noop` behavior, and any report window / grouping / deduplication requirements. - Offer to turn the recommendation into `.github/workflows/.md` only if the user asks to proceed. ### Supported Invocation Surface Ad hoc scenario evaluation is a **conversation-mode capability** of the installed `agentic-workflows` custom agent, not a CLI flag or MCP tool parameter — no `gh aw` CLI/MCP command accepts a freeform `prompt`/`scenario`/`query` parameter. See [Invocation Surface](create-agentic-workflow.md#ad-hoc-evaluation-mode) in create-agentic-workflow.md for the full explanation and recovery steps if a tool call returns `Unknown parameter`. ### Program Manager digest example ```yaml on: schedule: - cron: "0 9 * * 1" # weekly, Monday 09:00 workflow_dispatch: permissions: contents: read issues: write tools: github: mode: gh-proxy toolsets: [default] safe-outputs: create-issue: close-older-issues: true ``` - Reporting window: 7 days, ending at run time; use `workflow_dispatch` for previews, reruns, or backfills of a prior window. - Grouping dimensions: group items by owning team or repository, then by status (in-progress, blocked, at-risk). - Dedup key example: `pm-digest:` (for example `pm-digest:2026-W33`); combine with `close-older-issues: true` so each run supersedes the previous digest issue instead of accumulating duplicates. - Call `noop` when the reporting window has no qualifying updates. ### Non-technical persona examples Trigger and write-path are the same as the [Persona-to-Pattern Quick Matrix](#persona-to-pattern-quick-matrix) above. For ad hoc evaluation, also gather: | Persona | Key prompt details | |---|---| | Program Manager | Report window, grouping dimensions, stable dedup key, and `noop` for empty windows | | Designer | Review rubric (accessibility, token consistency, asset policy); `noop` when scoped files unchanged | | Legal / Compliance | Classify against policy tiers; dedup before escalating; `noop` when no in-scope change or violation | ## PR Checks with Linked References When a PR analysis requires verifying or attaching a linked artifact (design doc, policy link, architecture decision record, or approval), follow this compact pattern: 1. **Read the linked reference** from the PR body or comments (for example, a URL, a markdown link, or an ADR reference token like `ADR-NN`) using `gh pr view`. 2. **Validate the link** — confirm the document exists and is accessible before assessing compliance. 3. **Classify the result**: - Link present and satisfies requirement → `add-comment` with a ✅ summary - Link present but does not satisfy requirement → `add-comment` flagging the specific gap - Link missing → `add-comment` requesting it, or `create-issue` if policy requires a blocking escalation 4. **Call `noop`** when the PR is not in scope (for example `paths:` guard excludes all changed files). Permissions: `pull-requests: read` only; all writes route through `add-comment` safe output. For the full dependency-license/compliance review pattern (paths scoping, license-tier classification, escalation table), see [Compliance review guidance](create-agentic-workflow-trigger-details.md#compliance-review-guidance). ## Reference Files | Topic | File | |---|---| | Editing and recompilation rules | [workflow-editing.md](workflow-editing.md) | | Architectural and security constraints | [workflow-constraints.md](workflow-constraints.md) | | Common design patterns | [workflow-patterns.md](workflow-patterns.md) | | Frontmatter schema index | [syntax.md](syntax.md) | | Safe outputs index | [safe-outputs.md](safe-outputs.md) | | Trigger patterns | [triggers.md](triggers.md) | | Context expressions and `{{#if}}` templates | [context.md](context.md) | | Declarative engine configuration | [configure-agentic-engine.md](configure-agentic-engine.md) | | Agent runtime selection (Docker, gVisor, Docker sbx, Cloud Hypervisor, ARC DinD) | [agent-runtime-instructions.md](agent-runtime-instructions.md) | | Private-repository enclaves (preview) | [enclaves.md](enclaves.md) | | CLI commands and MCP equivalents | [cli-commands.md](cli-commands.md) | | Network configuration | [network.md](network.md) | | Memory and persistence | [memory.md](memory.md) | | Drive memory (private preview) | [drive-memory.md](drive-memory.md) | | Imports and shared components | [reuse.md](reuse.md) | | Sub-agents | [subagents.md](subagents.md) | | Skills | [skills.md](skills.md) | | Token cost optimization | [token-optimization.md](token-optimization.md) | | GitHub MCP server configuration | [github-mcp-server.md](github-mcp-server.md) | | GitHub MCP server per-toolset tool reference | [github-mcp-server-tools.md](github-mcp-server-tools.md) | | GitHub MCP server pagination limits | [github-mcp-server-pagination.md](github-mcp-server-pagination.md) | | Compiler-generated jobs, credentials, and job graph | [jobs.md](jobs.md) | | Campaign and KPI patterns | [campaign.md](campaign.md) | | Experiments and A/B testing | [experiments.md](experiments.md) | | Charts and Python data visualization | [charts.md](charts.md) | | LLM API endpoint discovery | [llms.md](llms.md) | ## Compile Commands ```bash gh aw compile gh aw compile gh aw compile --purge gh aw compile --strict ``` --- description: Pagination guidance for GitHub MCP tools to stay within token limits while retrieving complete result sets. --- # GitHub MCP Server — Pagination See [github-mcp-server.md](github-mcp-server.md) for toolset and tool reference. MCP tool responses have a **25,000 token limit**. Fetching large result sets without pagination causes the response to be truncated or rejected, forcing costly retry turns. ## `perPage` Defaults by Item Type | Item type | Recommended `perPage` | |-----------|----------------------| | PRs with diffs / issues with comments (detailed) | 10–20 | | Simple list operations (commits, branches, labels) | 50–100 | | Exploratory / schema-discovery queries | 1–5 | Always pass an explicit `perPage` value. Do **not** rely on server defaults. ## Tool-Specific Guidance **Pull Requests** - `list_pull_requests` — use `perPage: 10`, `sort: updated`, `direction: desc` - `pull_request_read` with `method: get_files` — use `perPage: 30` - Fetch diff and comments **separately** when full detail is needed **Issues** - `list_issues` — `perPage: 20` - `issue_read` with `method: get_comments` — `perPage: 20` **Search** - `search_issues`, `search_pull_requests`, `search_code` — `perPage: 10` - `search_repositories` exploratory calls — `perPage: 3–5`; increase only after narrowing the query ## Pagination Loop (when all pages are needed) ``` page 1 → check total_count or has_next_page → fetch page 2, 3, … until done ``` Process results incrementally rather than accumulating all pages in memory. ## Known Tool Quirks Two built-in GitHub MCP tools ignore standard pagination parameters: - **`list_label`** — uses a hardcoded GraphQL `labels(first: 100)` query; `perPage` is silently ignored. Use the `shared/github-mcp-pagination-wrappers.md` wrapper instead. - **`list_workflows`** — uses snake_case `per_page` (inconsistent with every other list tool). Use the `shared/github-mcp-pagination-wrappers.md` wrapper for consistent camelCase `perPage` support. One built-in GitHub MCP tool ignores a search qualifier: - **`search_repositories` with `repo:`** — the `repo:owner/name` qualifier is silently ignored; results are ranked by star count and will return unrelated high-star repositories. Use `org:`, `user:`, `topic:`, or `stars:` to scope repository searches. To resolve a specific repository, use a `repos`-toolset call with explicit `owner` and `repo` parameters (e.g. `get_file_contents`) instead. ## Oversized-Response Errors If you encounter errors like: - `MCP tool "list_pull_requests" response (75897 tokens) exceeds maximum allowed tokens (25000)` - `Response too large for tool [tool_name]` add `perPage: 10` (or smaller) and retry. --- description: Toolset-by-toolset reference for GitHub MCP server tools, including purposes and key parameters. --- # GitHub MCP Server — Tools by Toolset Full tool reference for each toolset. See [github-mcp-server.md](github-mcp-server.md) for overview, configuration, and recommended defaults. ### context **Description**: Team-awareness helpers for GitHub org membership. Workflow metadata is injected separately as `` whenever the GitHub tool is configured. | Tool | Purpose | Key Parameters | |------|---------|----------------| | `get_me` | Get details of the authenticated user | ⚠️ Do not use for workflow identity; read `` instead | | `get_team_members` | List members of a GitHub team | `org`, `team_slug` | | `get_teams` | List teams the authenticated user belongs to | `org` | --- ### code_quality **Description**: Code quality findings | Tool | Purpose | Key Parameters | |------|---------|----------------| | `get_code_quality_finding` | Get details of a specific code quality finding | `owner`, `repo`, `alert_number` | --- ### copilot **Description**: GitHub Copilot assignment, review, and coding agent tools | Tool | Purpose | Key Parameters | |------|---------|----------------| | `assign_copilot_to_issue` | Assign GitHub Copilot to an issue | `owner`, `repo`, `issue_number` | | `create_pull_request_with_copilot` | Ask Copilot to create a pull request | `owner`, `repo`, `issue_number` | | `request_copilot_review` | Request a Copilot review on a pull request | `owner`, `repo`, `pullNumber` | --- ### copilot_issue_intents **Description**: Opt-in Copilot issue assignment tools with intent metadata | Tool | Purpose | Key Parameters | |------|---------|----------------| | `assign_copilot_to_issue_with_intent` | Assign Copilot to an issue with intent metadata | `owner`, `repo`, `issue_number`, `rationale`, `confidence`, `is_suggestion` | --- ### copilot_spaces **Description**: GitHub Copilot Spaces (remote-only) > **Note**: Remote-only toolset — only available when using the GitHub MCP server in remote mode (`https://api.githubcopilot.com/mcp/`). Not available with the local `gh mcp` mode. | Tool | Purpose | Key Parameters | |------|---------|----------------| | `get_copilot_space` | Get details of a specific Copilot Space | `owner`, `name` | | `list_copilot_spaces` | List Copilot Spaces for a user or organization | `owner` | --- ### repos **Description**: Repository operations | Tool | Purpose | Key Parameters | |------|---------|----------------| | `create_branch` | Create a new branch | `owner`, `repo`, `branch`, `from_branch` | | `create_or_update_file` | Create or update a file in a repository | `owner`, `repo`, `path`, `content`, `message`, `branch` | | `create_repository` | Create a new GitHub repository | `name`, `description`, `private`, `auto_init` | | `delete_file` | Delete a file from a repository | `owner`, `repo`, `path`, `message`, `sha`, `branch` | | `fork_repository` | Fork a repository | `owner`, `repo`, `organization` | | `get_commit` | Get details of a specific commit | `owner`, `repo`, `sha` | | `get_file_blame` | Get line-by-line blame information for a file | `owner`, `repo`, `path`, `ref` | | `get_file_contents` | Read file or directory contents | `owner`, `repo`, `path`, `ref` | | `get_latest_release` | Get the latest release for a repository | `owner`, `repo` | | `get_release_by_tag` | Get a release by its tag name | `owner`, `repo`, `tag` | | `get_tag` | Get details of a specific tag | `owner`, `repo`, `tag` | | `list_branches` | List branches in a repository | `owner`, `repo`, `page`, `per_page` | | `list_commits` | List commits in a repository | `owner`, `repo`, `sha`, `path`, `page` | | `list_releases` | List all releases for a repository | `owner`, `repo`, `page`, `per_page` | | `list_repository_collaborators` | List collaborators of a repository | `owner`, `repo`, `affiliation`, `page`, `per_page` | | `list_tags` | List tags in a repository | `owner`, `repo`, `page`, `per_page` | | `search_code` | Search code across repositories | `query`, `page`, `per_page` | | `search_commits` | Search commits across GitHub | `query`, `page`, `per_page` | | `search_repositories` | Search for repositories | `query`, `page`, `per_page` | | `push_files` | Push multiple files in a single commit | `owner`, `repo`, `branch`, `files`, `message` | > **`search_repositories` known limitation — `repo:` qualifier is ignored**: The `repo:owner/name` qualifier has no effect in `search_repositories` queries. Instead of scoping results to the named repository, the API ranks by star count and may return a completely unrelated high-star repository as the top hit (e.g. querying `repo:github/gh-aw` may return `github/gitignore`). **Do not use `repo:` with `search_repositories`.** > > - To check whether a specific repository exists or to fetch its metadata, use `get_file_contents` (with explicit `owner` and `repo`) or any other `repos`-toolset call that takes `owner`/`repo` directly. > - To discover repositories in a scope, use supported qualifiers such as `org:`, `user:`, `topic:`, `language:`, or `stars:`. --- ### git **Description**: Git API operations (tree, refs) | Tool | Purpose | Key Parameters | |------|---------|----------------| | `get_repository_tree` | Get the file tree of a repository | `owner`, `repo`, `sha`, `recursive` | --- ### github_support_docs_search **Description**: GitHub support documentation search (remote-only) > **Note**: Remote-only toolset — only available when using the GitHub MCP server in remote mode (`https://api.githubcopilot.com/mcp/`). Not available with the local `gh mcp` mode. | Tool | Purpose | Key Parameters | |------|---------|----------------| | `github_support_docs_search` | Search GitHub support documentation | `query` | --- ### issues **Description**: Issue management > **Note**: `find_duplicate`, `issue_dependency_read`, and `issue_dependency_write` require their upstream feature flags to be enabled, independently of toolset selection. | Tool | Purpose | Key Parameters | |------|---------|----------------| | `add_issue_comment` | Add a comment to an issue | `owner`, `repo`, `issue_number`, `body` | | `find_duplicate` | Find likely duplicate issues for an existing issue | `owner`, `repo`, `issue_number`, `confidence_threshold` | | `get_label` | Get details of a specific label | `owner`, `repo`, `name` | | `issue_dependency_read` | Read an issue's dependency relationships | `owner`, `repo`, `issue_number` | | `issue_dependency_write` | Add or remove issue dependencies | `owner`, `repo`, `issue_number` | | `issue_read` | Read issue details and comments | `owner`, `repo`, `issue_number` | | `issue_write` | Create or update an issue | `owner`, `repo`, `title`, `body`, `labels`, `assignees` | | `list_issue_fields` | List available issue fields for a repository | `owner`, `repo` | | `list_issue_types` | List available issue types for a repository | `owner`, `repo` | | `list_issues` | List issues in a repository | `owner`, `repo`, `state`, `labels`, `page` | | `search_issues` | Search issues across GitHub | `query`, `page`, `per_page` | | `semantic_issue_similarity_search` | Find GitHub issues semantically similar to a given issue | `owner`, `repo`, `issue_number` | | `semantic_issues_search` | Search issues using natural language queries | `query`, `owner`, `repo` | | `sub_issue_write` | Create or manage sub-issues | `owner`, `repo`, `issue_number` | --- ### pull_requests **Description**: Pull request operations | Tool | Purpose | Key Parameters | |------|---------|----------------| | `add_comment_to_pending_review` | Add a comment to a pending PR review | `owner`, `repo`, `pull_number`, `review_id` | | `add_reply_to_pull_request_comment` | Reply to a PR review comment | `owner`, `repo`, `pull_number`, `comment_id`, `body` | | `create_pull_request` | Create a new pull request | `owner`, `repo`, `title`, `body`, `head`, `base` | | `list_pull_requests` | List pull requests in a repository | `owner`, `repo`, `state`, `head`, `base` | | `merge_pull_request` | Merge a pull request | `owner`, `repo`, `pull_number`, `merge_method` | | `pull_request_read` | Read PR details, reviews, and comments | `owner`, `repo`, `pull_number` | | `pull_request_review_write` | Create or submit a PR review | `owner`, `repo`, `pull_number`, `event`, `body` | | `search_pull_requests` | Search pull requests across GitHub | `query`, `page`, `per_page` | | `update_pull_request` | Update PR title, body, or state | `owner`, `repo`, `pull_number`, `title`, `body` | | `update_pull_request_branch` | Update PR branch with latest base | `owner`, `repo`, `pull_number` | --- ### actions **Description**: GitHub Actions workflows | Tool | Purpose | Key Parameters | |------|---------|----------------| | `actions_get` | Get details of a specific workflow run | `owner`, `repo`, `run_id` | | `actions_list` | List GitHub Actions workflows and runs | `owner`, `repo`, `method`, `resource_id`, `per_page`, `page` | | `actions_run_trigger` | Trigger a workflow run | `owner`, `repo`, `workflow_id`, `ref`, `inputs` | | `get_job_logs` | Download logs for a specific workflow job | `owner`, `repo`, `job_id` | --- ### code_security **Description**: Code scanning alerts | Tool | Purpose | Key Parameters | |------|---------|----------------| | `get_code_scanning_alert` | Get details of a specific code scanning alert | `owner`, `repo`, `alert_number` | | `list_code_scanning_alerts` | List code scanning alerts for a repository | `owner`, `repo`, `state`, `severity` | When calling `list_code_scanning_alerts` in workflow prompts/templates, always bound requests with `state: open` and `severity: critical,high`. --- ### dependabot **Description**: Dependabot alerts | Tool | Purpose | Key Parameters | |------|---------|----------------| | `get_dependabot_alert` | Get details of a specific Dependabot alert | `owner`, `repo`, `alert_number` | | `list_dependabot_alerts` | List Dependabot alerts for a repository | `owner`, `repo`, `state`, `severity` | --- ### discussions **Description**: GitHub Discussions | Tool | Purpose | Key Parameters | |------|---------|----------------| | `get_discussion` | Get details of a specific discussion | `owner`, `repo`, `discussion_number` | | `get_discussion_comments` | Get comments for a specific discussion | `owner`, `repo`, `discussion_number` | | `list_discussion_categories` | List discussion categories for a repository | `owner`, `repo` | | `list_discussions` | List discussions in a repository | `owner`, `repo`, `category_id` | --- ### gists **Description**: Gist operations | Tool | Purpose | Key Parameters | |------|---------|----------------| | `create_gist` | Create a new gist | `description`, `files`, `public` | | `get_gist` | Get a specific gist by ID | `gist_id` | | `list_gists` | List gists for a user | `username`, `page`, `per_page` | | `update_gist` | Update an existing gist | `gist_id`, `description`, `files` | --- ### labels **Description**: Label management | Tool | Purpose | Key Parameters | |------|---------|----------------| | `get_label` | Get details of a specific label | `owner`, `repo`, `name` | | `label_write` | Create or update a label | `owner`, `repo`, `name`, `color`, `description` | | `list_label` | List labels in a repository | `owner`, `repo`, `page`, `per_page` | --- ### notifications **Description**: Notification management | Tool | Purpose | Key Parameters | |------|---------|----------------| | `dismiss_notification` | Dismiss a specific notification | `notification_id` | | `get_notification_details` | Get details of a specific notification | `notification_id` | | `list_notifications` | List user notifications | `all`, `participating`, `page` | | `manage_notification_subscription` | Manage notification subscription for a thread | `thread_id`, `subscribed` | | `manage_repository_notification_subscription` | Manage notifications for a repository | `owner`, `repo`, `subscribed` | | `mark_all_notifications_read` | Mark all notifications as read | `last_read_at` | --- ### orgs **Description**: Organization operations | Tool | Purpose | Key Parameters | |------|---------|----------------| | `search_orgs` | Search GitHub organizations | `query`, `page`, `per_page` | --- ### projects **Description**: GitHub Projects (requires PAT — not supported by GITHUB_TOKEN) | Tool | Purpose | Key Parameters | |------|---------|----------------| | `projects_get` | Get details of a specific project | `owner`, `project_number` | | `projects_list` | List GitHub Projects for a user or organization | `owner`, `per_page` | | `projects_write` | Create or update project items/fields | `owner`, `project_number` | --- ### secret_protection **Description**: Secret scanning | Tool | Purpose | Key Parameters | |------|---------|----------------| | `get_secret_scanning_alert` | Get details of a specific secret scanning alert | `owner`, `repo`, `alert_number` | | `list_secret_scanning_alerts` | List secret scanning alerts for a repository | `owner`, `repo`, `state` | | `run_secret_scanning` | Scan file contents or diffs for exposed secrets | `content` | --- ### security_advisories **Description**: Security advisories | Tool | Purpose | Key Parameters | |------|---------|----------------| | `check_dependency_vulnerabilities` | Check dependencies against known vulnerabilities in the GitHub Advisory Database | `owner`, `repo`, `dependencies` | | `get_global_security_advisory` | Get a specific global security advisory | `ghsa_id` | | `list_global_security_advisories` | List advisories from the GitHub Advisory Database | `type`, `severity`, `ecosystem` | | `list_org_repository_security_advisories` | List security advisories for all repos in an org | `org`, `state` | | `list_repository_security_advisories` | List security advisories for a specific repository | `owner`, `repo`, `state` | --- ### stargazers **Description**: Repository stars | Tool | Purpose | Key Parameters | |------|---------|----------------| | `list_starred_repositories` | List repositories starred by a user | `username`, `page`, `per_page` | | `star_repository` | Star a repository | `owner`, `repo` | | `unstar_repository` | Unstar a repository | `owner`, `repo` | --- ### users **Description**: User information | Tool | Purpose | Key Parameters | |------|---------|----------------| | `search_users` | Search GitHub users | `query`, `page`, `per_page` | --- description: Overview and practical guidance for configuring and using GitHub MCP server toolsets in agentic workflows. --- # GitHub MCP Server Instructions **Source**: [github/github-mcp-server](https://github.com/github/github-mcp-server/tree/main/pkg/github) **Mapping File**: [pkg/workflow/data/github_toolsets_permissions.json](https://github.com/github/gh-aw/blob/main/pkg/workflow/data/github_toolsets_permissions.json) **Last Updated**: 2026-08-16 ## Overview The GitHub MCP server provides tools to interact with GitHub APIs through the Model Context Protocol (MCP). It operates in two modes: - **Remote mode**: Connects to GitHub's hosted MCP endpoint (`https://api.githubcopilot.com/mcp/`) - **Local mode**: Runs `gh mcp` (GitHub CLI) as a local subprocess ### Authentication **Remote mode**: Uses a Bearer token in the Authorization header: ``` Authorization: Bearer ``` **Read-only mode**: Add the `X-MCP-Readonly: true` header to restrict to read operations only: ``` X-MCP-Readonly: true ``` **Local mode**: Uses the GitHub CLI's existing authentication (`gh auth login`). ## Configuration ### In Agentic Workflows ```yaml tools: github: toolsets: [default] # or specific toolsets # Optional: GitHub App authentication github-app: client-id: ${{ vars.APP_ID }} private-key: ${{ secrets.APP_PRIVATE_KEY }} ``` > ⚠️ **Do NOT use `mode: remote`** in GitHub Actions workflows. Remote mode does not work with the GitHub Actions token (`GITHUB_TOKEN`) — it requires a special PAT or GitHub App token with MCP access. The default `mode: local` (Docker-based) works with `GITHUB_TOKEN` and should always be used. > > GitHub App authentication only scopes the token. It does not replace DIFC guard policy labels. When safe outputs are enabled, compile the workflow and confirm the lock file includes both `mcp_servers.github.guard-policies.allow-only` and `mcp_servers.safeoutputs.guard-policies.write-sink`. ### Toolset Options - `[default]` — Recommended defaults: `context`, `repos`, `issues`, `pull_requests` - `[all]` — Enable all toolsets - Specific toolsets: `[repos, issues, pull_requests, discussions]` - Extend defaults: `[default, discussions, actions]` ## Recommended Default Toolsets The following toolsets are recommended as defaults for typical agentic workflows: When the GitHub tool is configured, gh-aw injects a separate `` prompt block with workflow identity metadata. That injected block is independent of toolset selection, so enable `context` for its team-awareness tools, not to obtain workflow identity. | Toolset | Rationale | |---------|-----------| | `context` | Team-awareness helpers (`get_teams`, `get_team_members`) — enable when workflows need org or team membership lookups | | `repos` | Core repository operations (read files, list commits/branches) — most workflows need file access | | `issues` | Issue management (read, comment, create) — common in CI/CD and automation workflows | | `pull_requests` | PR operations (read, create, review) — critical for code review and merge automation | **Enable explicitly when needed** (not in defaults): | Toolset | When to Enable | |---------|---------------| | `actions` | Workflow introspection, triggering runs | | `code_quality` | Code quality finding lookups | | `code_security` | Code scanning alert management | | `copilot` | Copilot assignment, PR creation, and review requests | | `copilot_issue_intents` | Intent-aware Copilot issue assignment | | `copilot_spaces` | GitHub Copilot Spaces (remote mode only) | | `dependabot` | Dependency vulnerability management | | `discussions` | Community discussion workflows | | `gists` | Gist creation and management | | `git` | Git API operations (tree, refs) | | `github_support_docs_search` | GitHub support documentation search (remote mode only) | | `labels` | Label management automation | | `notifications` | Notification processing agents | | `orgs` | Organization search operations | | `projects` | GitHub Projects automation (requires PAT) | | `secret_protection` | Secret scanning alert management | | `security_advisories` | Advisory database queries | | `stargazers` | Star/unstar repository operations | | `users` | User search operations | ## Tools by Toolset See [github-mcp-server-tools.md](github-mcp-server-tools.md) for the full per-toolset tool reference (parameters, known quirks like the `search_repositories` `repo:` limitation). --- ## Pagination MCP tool responses have a **25,000 token limit**; always pass an explicit `perPage`. See [github-mcp-server-pagination.md](github-mcp-server-pagination.md) for per-tool `perPage` defaults, the pagination loop pattern, known tool quirks (`list_label`, `list_workflows`, `search_repositories` with `repo:`), and oversized-response recovery. --- ## Best Practices ### Toolset Selection 1. **Start with defaults** (`context`, `repos`, `issues`, `pull_requests`) for most workflows 2. **Add toolsets incrementally** based on actual needs rather than enabling `all` 3. **Security toolsets** (`code_security`, `dependabot`, `secret_protection`, `security_advisories`) require `security-events` permission 4. **Write operations** require appropriate GitHub token permissions (see `write_permissions` in the JSON mapping) 5. **Projects toolset** requires a PAT (Personal Access Token) — `GITHUB_TOKEN` lacks the required `project` scope ### Permission Requirements Most toolsets work with the default `GITHUB_TOKEN` in GitHub Actions. Exceptions: - `projects` — Requires a PAT with `project` scope - `security_advisories` (write) — Requires `security-events: write` permission - `actions` (write for `actions_run_trigger`) — Requires `actions: write` permission --- description: Repository-specific overlay rules that refine default gh-aw guidance for workflow authoring and validation. --- # Repository Instructions Overlay for gh-aw Agents This optional file defines repository-local workflow authoring standards for installed gh-aw agents. ## Scope These rules apply when creating, editing, reviewing, and upgrading agentic workflow files. ## Precedence Apply upstream/default gh-aw instructions first, then apply this overlay. If a rule conflicts, this repository overlay takes precedence. ## Repository Rules Add your repository-specific standards here, for example: - **CRITICAL INVARIANT:** After **any** modification to agentic workflow markdown files (`.github/workflows/*.md`), you **must** run a one-shot `gh aw compile` before stopping. Agents must not use `--watch`, because watch mode does not terminate automatically. - Required shared include(s) for new workflows - Standard frontmatter defaults - Frontmatter ordering/style conventions - Security or policy constraints specific to this repository - For workflows that will be enforced by repository or organization pull request rulesets, keep workflow/job names stable for required checks and use `inlined-imports: true` when imports are present - When documenting or recommending Copilot authentication, state that `permissions: { copilot-requests: write }` uses `${{ github.token }}` for inference and does not require a PAT or `COPILOT_GITHUB_TOKEN` secret - When you need prior art for workflow design, shared components, tool configuration, or safe-output patterns, use GitHub APIs or `gh` to inspect `https://github.com/gm3dmo/the-power` before inventing a new pattern - When authoring or reasoning about an `operational-value` grader, use the `operational value designer` skill (`/operational-value-designer`) to infer operational value from the target agentic workflow before finalizing the grader contract --- description: Design-time guidance for deriving an outcome-oriented workflow intent and using it to select, implement, and evaluate an agentic workflow. --- # Intent-Driven Workflow Design Start every workflow design by extracting a concise, implementation-independent outcome. Persist that canonical outcome in the top-level `intent:` frontmatter field; use the richer analysis below only while designing the workflow. ```yaml intent: Reduce maintainer effort spent identifying recurring actionable CI regressions without generating duplicate work. ``` An **intent** is the repository outcome that a workflow should attain for a defined actor and subject. It describes why the workflow exists, not its trigger, tool, schedule, output volume, or write action. It must remain valid if the implementation changes from an immediate issue to a weekly digest. ## Derive an IntentSpec Before selecting implementation details, derive this transient model: ```text IntentSpec - intent: concise canonical outcome - actors and subject: who benefits and what is affected - activation conditions: facts that make the intent relevant - required context: evidence needed to make a decision - required effects: observable results that satisfy the outcome - noop conditions: inverse cases that must not create attention or writes - success conditions: how the design avoids attention cost while producing value - uncertainties: policy or evidence gaps that need a conservative default or clarification ``` Do not serialize this structure in workflow frontmatter. The `intent:` value is the only persisted part. Do not duplicate executable configuration such as `on:`, `tools:`, `permissions:`, `safe-outputs:`, or schedules in it. For an explicit, narrow request, infer the obvious intent and keep this pass lightweight. For an underspecified request or one asking what to automate, collect bounded repository evidence first, then propose evidence-backed candidate intents with their evidence, feasibility, expected value, risk, and uncertainties. Do not perform a broad survey when it cannot materially change a clear request. ## Design from the IntentSpec Use the model to derive implementation rather than mapping the request directly to a trigger: 1. Compare plausible architectures against intent coverage, timeliness, attention cost, safety, boundedness, determinism, state requirements, implementation complexity, and available evidence. 2. Select the trigger, schedule, data collection, tools, permissions, safe outputs, and deduplication strategy that satisfy the selected architecture. 3. Put the activation conditions, required effects, evidence threshold, and no-op conditions in the prompt body. Require `noop` when a counter-case applies or evidence is insufficient. 4. Make duplicate detection, filters, output caps, and previous-result strategy enforce the same conditions where configuration can do so. For example, an intent to surface actionable CI regressions can require completed relevant CI, actionable and novel evidence, and sufficient diagnostics. Known flakes, infrastructure failures, already-tracked regressions, closed pull requests, and insufficient evidence are counter-cases. An immediate incident, PR comment, daily digest, and weekly trend report are alternative architectures; choose the one that best meets the intent without unnecessary attention cost. ## Apply PromptPex to Derive Evals PromptPex treats the prompt as a behavioral specification and expands each intent condition into a concrete scenario. Use the IntentSpec to generate both sides of the behavior: 1. For each activation condition and required effect, create a positive fixture in which the workflow should produce an observable result. Derive an eval that returns `YES` only when the output demonstrates that result. 2. Invert each activation condition, required effect, and evidence threshold to find counter-intent cases such as irrelevant, duplicate, benign, stale, or insufficiently evidenced input. 3. Create an inverse fixture for each meaningful counter-case. Derive an inverse eval that returns `YES` only when the output demonstrates the intended no-op, bounded investigation, or other safe behavior. 4. Check that the positive and inverse fixtures jointly cover the intent without prescribing the implementation. Create representative positive and adversarial scenario fixtures from required effects and no-op conditions. A BinEval run evaluates one provided scenario and one `agent_output.json`; do not combine mutually exclusive scenarios into one unconditional question list. For each fixture, use a separate scenario-specific eval question about the observable agent output: - a novel, sufficiently evidenced actionable case produces the intended visible result; - a duplicate or known benign case produces no visible write; - an uncertain case investigates when appropriate but does not write. Keep eval questions binary and output-observable. If a shared eval suite must accept different scenarios, make applicability explicit and treat a scenario that was not provided as `UNKNOWN`, not as a failure. Do not ask a judge whether the intent itself is good or whether the agent made sufficient effort. See [evals.md](evals.md) for BinEval syntax and question constraints. ## Infer Operational Value from Intent Operational value is the degree to which the workflow's intended repository outcome is attained for the opportunity assigned to a run, demonstrated by accepted repository evidence. Infer it from the IntentSpec rather than from execution quality, output volume, or the agent's own assessment: 1. Turn the actors, subject, and activation conditions into a stable per-run opportunity. 2. Turn the required effects and success conditions into accepted repository evidence and one direct attainment metric in `[0,1]`. 3. Turn no-op conditions into the zero rule, and uncertainties into explicit missing-evidence behavior. 4. Define when evidence matures and which repositories and matching rules are accepted. Evals and operational value answer different questions. PromptPex evals test whether output follows the intended behavior for representative scenarios; operational value measures whether the intended repository outcome was attained for a real run. When adding an `operational-value` grader, use the `operational-value-designer` skill to freeze the evidence and metric contract. ## Infer Trace Graders from Intent Select graders that test a concrete risk to achieving the intent; do not enable metrics merely because they are available. Start with the known builtin graders: use `tool-success-rate` and `tool-failure-count` when reliable collection is required; `retries`, `loops`, `execution-step-count`, and `execution-duration` when boundedness or timely escalation matters; `working-set-rebuild-factor` and `context-growth` when repeated context is an attention or cost risk; `trajectory-efficiency` when unnecessary tool churn is a concern; and `artifact-production` only when producing the intended artifacts is itself useful diagnostic evidence. Then inspect the implemented fragments in [`shared/graders/`](../workflows/shared/graders/README.md). Use `policy-near-miss` for explicit guard or no-op requirements, and `skill-constraint-coverage` when a harness/skill declares behavioral requirements that should be exercised. Use `exploration-error` when failure may stem from insufficient search, and `exploitation-error` when the agent had enough information but failed to use it. For intents that require efficient investigation rather than repeated exploration, consider `state-revisit-probability-rep`, `recurrence-rate`, `recurrence-determinism`, `recurrence-laminarity`, or `recurrence-trapping-time`. For intents where varied, non-repetitive investigation is relevant, consider `event-entropy-rate` or `lempel-ziv-trajectory-complexity`. Use `tool-output-consumption-rate` when tool outputs going unused by later actions is a risk. Import only the applicable implemented fragments and ensure their documented trace prerequisites are available. These trace graders diagnose execution behavior; they do not replace scenario evals or the operational-value attainment metric. ## Preserve Intent on Updates Read the existing `intent:` before changing an existing workflow. Preserve it for an implementation-only change, including a trigger or output-channel redesign. Reconsider and update it only when the request materially expands, contracts, or otherwise changes the outcome. When it changes, re-derive conditions, architecture, prompt behavior, and evals. --- description: Maps every compiler-generated job to its purpose, dependencies, and GitHub token or GitHub App configuration so agents grant credentials only to the job that needs them. --- # Compiler-generated jobs Generated job IDs are reserved. Built-in job configuration may add `setup-steps`, `pre-steps`, `needs`, `if`, and — for `agent` and `detection` only — `timeout-minutes`; it cannot replace compiler-managed permissions or authentication. ## Job timeouts The generated `agent` and `detection` jobs carry their own `timeout-minutes`, resolved independently from the top-level `timeout-minutes` that bounds the `agentic_execution` step. Generated job timeout overrides must be positive integer literals. | Timeout | Frontmatter override | Built-in default | |---|---|---| | `agent` job (all steps) | `jobs.agent.timeout-minutes` (positive integer) | 60 minutes | | `detection` job and its execution step | `jobs.detection.timeout-minutes` (positive integer) | 10 minutes | | `agentic_execution` step | top-level `timeout-minutes` | 20 minutes | The step default is never used as the agent job budget. When top-level `timeout-minutes` is an explicit literal larger than the built-in agent job default, the agent job default is raised to that value so an explicit step budget is not truncated by the implicit job budget. ```yaml timeout-minutes: 25 # agentic_execution step jobs: agent: timeout-minutes: 90 detection: timeout-minutes: 30 ``` Other generated jobs are not bounded by these values; `safe-outputs.timeout-minutes` covers the safe-outputs job. ## Credential configuration Configure credentials on the consuming feature: | Jobs | Token | GitHub App | |---|---|---| | `pre_activation`, `activation` | `on.github-token` | `on.github-app` | | `agent` | `tools.github.github-token: ${{ secrets.MY_TOKEN }}` | `tools.github.github-app` | | `safe_outputs`, `upload_assets`, `upload_code_scanning_sarif`, `call-*` | `safe-outputs.github-token` or handler `github-token` | `safe-outputs.github-app` or handler `github-app` | | Maintenance | Generated workflow `GITHUB_TOKEN` permissions or maintenance configuration | — | Use secret expressions for custom tokens and private keys. Grant least privilege. Keep `agent` and `detection` read-only; use safe outputs for writes. `permissions: { copilot-requests: write }` permits Copilot inference through `${{ github.token }}` without a PAT or `COPILOT_GITHUB_TOKEN`. ## Workflow job graph | Job | Created when | Needs | Notes | |---|---|---|---| | `pre_activation` | Trigger validation, role/skip checks, or `on.github-app` | — | Trigger-time reactions, comments, and queries. | | `activation` | Most workflows | `pre_activation` if present | Activation-only credential use. | | `agent` | Every workflow | `activation` if present | GitHub tool access; read-only. | | `detection` | Safe-output threat detection | `agent`, `activation` | Read-only; no credential configuration. | | `safe_outputs` | Built-in output, script, action, or job | `agent`, `activation`, `detection` if present, `unlock` if `lock-for-agent`, plus any explicit `safe-outputs.needs` jobs | Approved writes. | | `upload_assets` | Release-asset output | `safe_outputs`, `activation` | Inherits safe-output authentication; release permissions only. | | `upload_code_scanning_sarif` | Code-scanning output | `safe_outputs` | Inherits safe-output authentication; `security-events: write`. | | `unlock` | `lock-for-agent` | `activation`, `agent`, `detection` if present | Workflow-token lock cleanup; do not grant agent writes. | | `evals` | `evals` | `agent` | No custom credential; runs alongside safe outputs. | | `conclusion` | Compiler-generated conclusion | All generated and custom jobs | No custom credential; aggregates results and usage. | | `push_repo_memory` | Repository-backed memory | After threat detection | Framework-managed repository credential. | | `update_cache_memory` | Cache memory | After threat detection | Framework-managed repository credential. | | `push_experiments_state` | Repository-backed experiments | After threat detection | Framework-managed repository credential. | | `push_evals_state` | Persisted eval state | After threat detection | Framework-managed repository credential. | | `call-` | `safe-outputs.call-workflow` worker | — | Configure the called workflow input through the worker's `github-token` or `github-app`. | ## Maintenance workflow jobs `agentics-maintenance.yml` uses its `GITHUB_TOKEN` with explicit job permissions. Do not configure these jobs in agentic-workflow frontmatter. | Jobs | Purpose | |---|---| | `close-expired-discussions`, `close-expired-issues`, `close-expired-pull-requests` | Close expired items. | | `cleanup-cache-memory` | Remove stale cache-memory entries. | | `run_operation`, `update_pull_request_branches`, `apply_safe_outputs` | Run selected maintenance operations. | | `create_labels`, `label_disable_agentic_workflow`, `label_apply_safe_outputs` | Manage labels. | | `activity_report`, `forecast_report` | Produce reports. | | `close_agentic_workflows_issues`, `validate_workflows`, `compile-workflows`, `secret-validation` | Maintain workflow configuration. | ## Compatibility aliases `pre-activation` and `safe-outputs` are reserved compatibility aliases for `pre_activation` and `safe_outputs`. The compiler emits the underscore forms; use those forms in `needs` and built-in job configuration. --- description: Design evidence-driven workflows that mine, refine, and apply custom linter rules without overfitting or creating unbounded remediation work. --- # Linter Workflow Guidance Use this guidance for any language or static-analysis framework. Treat mining, refinement, and application as a feedback loop; they may be separate workflows. ## Mine Rules From Repository Evidence Search a bounded recent window and retain source links. Prefer evidence in this order: 1. repeated fixes in merged commits and pull requests 2. recurring review comments and resolved discussion threads 3. repeated failures or corrections in Copilot coding agent sessions 4. issues, discussions, and CI diagnostics 5. confirmed occurrences from structural or semantic code scans Corroborate a candidate with independent events or multiple concrete occurrences. A single preference, speculative smell, or isolated mistake is insufficient. Normalize each candidate to: - the unsafe or undesirable pattern - the consequence and mechanical correction - evidence references and occurrence count - affected languages, paths, and constructs - likely false-positive cases Use deterministic pre-steps to fetch, trim, and normalize large histories into `/tmp/gh-aw/agent/`. Give the agent compact evidence, not raw repositories of logs. Persist only candidate identifiers and outcomes in `cache-memory` or `repo-memory`. ## Select One High-Signal Rule Before selection, compare candidates with: - existing custom rules and prior proposals - enabled standard or third-party linters - recently rejected or reverted rules Prefer a narrow rule with a clear diagnostic, a mechanical fix, stable syntax or semantics, and low false-positive risk. Reject candidates that are stylistic only, duplicate existing coverage, depend on intent unavailable to static analysis, or combine unrelated patterns. Select at most one new rule per run. If no candidate clears the quality bar, emit `noop`. ## Implement and Validate Follow the repository's existing rule layout, registration, naming, suppression, and test conventions. Keep implementation changes scoped to the rule, its registration, configuration, and tests. Tests must cover: - representative positive cases from the mined evidence - nearby valid code that must not trigger - relevant edge, aliasing, scope, or type-resolution cases - suppression and autofix behavior when supported Run the rule's targeted tests, build the linter, then run the configured ruleset against its target codebase. A new rule must not leave unexplained diagnostics. Open one focused draft pull request with the evidence, intended invariant, known limitations, and validation results; otherwise emit `noop`. ## Refine Existing Rules Mine rule diagnostics, suppressions, CI failures, review feedback, reverted fixes, and follow-up commits. Classify each problem as: - false positive - false negative - unclear diagnostic - unsafe or incomplete autofix - missing suppression or configuration behavior - performance regression Make the smallest change that addresses one evidenced class. Add a regression test before changing detection behavior. Do not broaden a rule merely to increase match counts; precision takes priority over coverage. ## Apply Rules Run the linter deterministically before the agent starts and save compact diagnostics. If clean, emit `noop`. When findings exist: 1. group them by root cause, then by subsystem when useful 2. bound each run to a small number of independent groups 3. search open and recently closed work before creating anything 4. create or update one authoritative issue per group 5. include affected paths, representative diagnostics, expected outcome, and the exact validation command 6. assign agents only for new, execution-ready work Do not create separate work items for count changes or path slices of the same backlog. Feed fix outcomes, review comments, and validation failures back into refinement. ## Workflow Guardrails - Keep repository access read-only in the agent job; use safe outputs for writes. - Restrict write outputs to the rule's intended paths and fall back to an issue for protected files. - Bound history windows, candidates, remediation groups, and agent assignments. - Use persistent memory for compact deduplication state and cursors, not large transcripts. - End with exactly one terminal safe output such as a pull request, issue/report, or `noop`. - Do not finish while delegated agents are still running. --- description: Discover LLM API endpoints, ports, and available model names inside the AWF agent container using the api-proxy /reflect endpoint. --- # LLM API Endpoint Discovery The AWF api-proxy sidecar exposes a `/reflect` endpoint listing every configured LLM provider, its port, and available models. Use it to configure any tool that needs OpenAI/Anthropic access inside the agent container. > ⚠️ Only reachable from **inside the AWF agent container** — not from the runner host. ## Quick Start ```bash # Discover all configured providers and their models curl -sf http://api-proxy:10000/reflect | jq '.endpoints[] | select(.configured)' ``` ## Provider Ports | Provider | Port | Base URL | Credentials env var | |---|---|---|---| | `openai` / `codex` | 10000 | `http://api-proxy:10000/v1` | `OPENAI_API_KEY` | | `anthropic` | 10001 | `http://api-proxy:10001/v1` (or no `/v1` for native SDK) | `ANTHROPIC_API_KEY` | | `copilot` | 10002 | `http://api-proxy:10002/v1` | `COPILOT_GITHUB_TOKEN` | | `gemini` | 10003 | `http://api-proxy:10003/v1` | `GEMINI_API_KEY` | All ports use the OpenAI-compatible API format. The api-proxy injects auth headers automatically — **do not pass raw API keys** to these URLs. ## /reflect Response ```json { "endpoints": [ { "provider": "openai", "port": 10000, "configured": true, "models": ["gpt-4o", "o1-mini"], "models_url": "http://api-proxy:10000/v1/models" }, { "provider": "anthropic", "port": 10001, "configured": true, "models": ["claude-sonnet-4-5"], "models_url": "http://api-proxy:10001/v1/models" }, { "provider": "copilot", "port": 10002, "configured": true, "models": null, "models_url": "http://api-proxy:10002/models" }, { "provider": "gemini", "port": 10003, "configured": false, "models": null, "models_url": null } ], "models_fetch_complete": true } ``` Only use endpoints where `configured: true`. `models` may be `null` when the proxy hasn't finished fetching; use `models_url` to fetch on demand. ## Configure Tools ### OpenAI-compatible SDK (any provider) ```bash # Use Copilot as the OpenAI backend export OPENAI_BASE_URL="http://api-proxy:10002/v1" export OPENAI_API_KEY="$COPILOT_GITHUB_TOKEN" ``` ### Anthropic SDK ```bash export ANTHROPIC_BASE_URL="http://api-proxy:10001" export ANTHROPIC_API_KEY="$ANTHROPIC_API_KEY" ``` ### Dynamic resolution from /reflect ```bash PROVIDER=anthropic PORT=$(curl -sf http://api-proxy:10000/reflect \ | jq -r --arg p "$PROVIDER" '.endpoints[] | select(.provider == $p and .configured) | .port') export ANTHROPIC_BASE_URL="http://api-proxy:${PORT}" ``` ## List Available Models ```bash # OpenAI / Anthropic / Copilot format → { data: [{id}] } curl -sf http://api-proxy:10000/reflect \ | jq -r '.endpoints[] | select(.provider == "openai" and .configured) | .models_url' \ | xargs curl -sf | jq '[.data[].id]' # Gemini format → { models: [{name: "models/gemini-..."}] } curl -sf http://api-proxy:10003/v1/models | jq '[.models[].name | ltrimstr("models/")]' ``` ## See Also - [network.md](network.md) — egress domain configuration - [syntax.md](syntax.md) — `engine:` and top-level `model:` frontmatter --- description: Loop-engineering workflow patterns and implementation guidance for gh-aw workflows. --- # Loop Engineering Patterns Use as a playbook for long-running iterative workflows. ## What “loop engineering” means A loop workflow repeatedly: 1) selects one work item, 2) makes one bounded improvement step, 3) verifies with concrete evidence, 4) preserves accepted progress, 5) records durable state for the next run. Design for reliability across repeated runs, merges, CI failures, and human steering. ## Shared architecture across Autoloop, Goal, and Crane ### 1) Single-item scheduler Select one item per run (Autoloop: one program, Goal: one goal issue, Crane: one migration). Bounds run cost, preserves round-robin fairness. ### 2) Canonical long-running branch + single PR Each item owns one stable branch and one draft PR (`autoloop/`, `goal/-`, `crane/`). Accumulate accepted commits on that same PR over time. ### 3) Ratcheting acceptance Accept a change only when it improves the tracked metric (or advances the contract) and passes CI/verification gates. On failure, discard the change but still record the run. ### 4) Durable state in repo-memory Persist state as markdown in a dedicated memory branch (`memory/autoloop`, `memory/goal`, `memory/crane`). Keep it machine-readable and human-editable. ### 5) Human control-plane issue Each item has one canonical issue with: a durable status comment sentinel (``), one per-run log comment, human steering directives. ### 6) Explicit no-progress and pause semantics When blocked or stuck, pause with a concrete reason. Do not retry forever. ## Pattern inventory ### Pattern A — Item selection and fairness Use a deterministic pre-step scheduler that writes a compact selection artifact (e.g. `/tmp/gh-aw/autoloop.json`; match the file name to your workflow) with: selected item, deferred items, due/not-due flags, existing PR/branch metadata. Do not discover candidates ad hoc in-prompt. ### Pattern B — Canonical branch invariants Branch names must be deterministic and suffix-free. Always use ahead/behind logic against default branch: - `ahead=0, behind>0`: fast-forward/reset branch to default, - `ahead>0, behind>0`: merge default into branch, - else: checkout as-is. When a force-push is required, use `--force-with-lease` (not `--force`). Keep canonical branches single-writer (the workflow) to minimize push conflicts. ### Pattern C — One PR per item Never create multiple active PRs for the same item. Resolve in order: 1) scheduler-provided `existing_pr`, 2) state-file PR fallback, 3) create exactly one PR if none exists. ### Pattern D — Improve → push → gate → accept Three-phase accept path: 1) metric/contract improvement check, 2) push and wait for CI/checks, 3) accept only on green. Avoids sandbox-only false positives. ### Pattern E — CI fix loop with circuit breakers When CI fails after an improved change: collect failing jobs and error signatures, attempt bounded fix retries, stop on repeated identical signature, pause with structured reason (`ci-fix-exhausted`, `stuck`, `ci-timeout`). ### Pattern F — Structured state file Keep a stable state layout with: machine-state table (iteration count, last run, best metric, pause/completion fields), current focus/checkpoint, lessons learned, foreclosed avenues/blockers, iteration history (newest first). ### Pattern G — Setup guard and safety rails Use sentinel-based configuration checks before first real run (Autoloop: ``, Crane: ``). If unconfigured, create/refresh setup issue and skip execution. ### Pattern H — Direction-aware metrics Support both directions: `higher` is better (default), `lower` is better. Use direction in: improvement test, signed delta reporting, target-metric completion check. ### Pattern I — Completion by evidence, not intent Completion requires explicit evidence gates. Goal enforces issue-defined completion contracts; Crane separates reaching target metric from deterministic completion-gate pass; Autoloop supports target-metric completion with explicit label transition. Never mark complete on belief alone. ### Pattern J — Unified run reporting On every run (accepted/rejected/error/blocked): update durable status comment, append per-run summary comment, include run URL, checkpoint, evidence, result, next step. Creates an auditable run narrative. ## Comparative notes by project | Project | Primary loop unit | Unique strength | Key reusable pattern | |---|---|---|---| | Autoloop | Program | General metric-driven optimization with rich iteration memory | Improvement ratchet + CI-gated accept/reject | | Goal | Goal-labeled issue | Contract-first execution and definition-quality gating | “Needs action” path before implementation | | Crane | Migration | Milestone plan + strategy selection (`in-place` vs `greenfield`) | iteration 0 planning commit and migration-specific completion gate | ## Implementation blueprint for new loop workflows in gh-aw Implement in this order: 1. **Define the loop unit** (issue/program/migration/task). 2. **Add scheduler pre-step** that selects one item and emits JSON context. 3. **Define canonical branch and single-PR invariant**. 4. **Add durable state schema** in repo-memory. 5. **Implement run phases**: read state → choose checkpoint → change → verify. 6. **Add accept/reject logic** with direction-aware metric handling. 7. **Gate acceptance on CI/check health**. 8. **Add bounded fix loop** with failure-signature no-progress guard. 9. **Implement completion semantics** with explicit evidence gate. 10. **Add status + per-run issue comments** for observability. 11. **Add pause/recovery policy** for blocked or repeated failures. 12. **Document command-mode overrides** (slash command steering). ## Minimal loop run-state model Conceptual states: `active`, `accepted`, `rejected`, `error`, `needs_action`, `blocked`, `paused`, `completed`. Transitions must be deterministic and evidence-backed. ## Common failure modes to avoid - Branch name drift (suffixes/hashes/run IDs) - Multiple PRs per item - Marking completion without deterministic evidence - Repeating the same failed CI signature without pause - Losing long-term context by storing state only in ephemeral run logs - Unbounded scope growth per iteration ## Practical guidance for prompt authors For loop prompts, explicitly require: one checkpoint per run, smallest useful change, explicit evidence command output, explicit `noop`/blocked behavior, state updates every run, strict branch/PR invariants. Keep prompts short. Move durable policy to state + structured workflow rules. ## Reusable checklist - [ ] One selected item per run - [ ] Canonical branch name with no suffix - [ ] Single draft PR per item - [ ] Durable state file updated every run - [ ] Improvement criterion defined (direction-aware) - [ ] Acceptance gated on CI/checks - [ ] Fix-loop retry cap and signature-based stop - [ ] Explicit blocked/paused handling - [ ] Deterministic completion gate - [ ] Status comment + per-run comment updated --- description: Language Server Protocol (LSP) configuration reference for gh-aw Copilot workflows — frontmatter syntax, supported servers, and file extension mapping. --- # LSP Configuration > ⚠️ **Experimental.** `lsp` emits a compile-time warning and may change. **Only supported with `engine: copilot`** — any other engine is a compile-time error. The `lsp` frontmatter field lets Copilot-engine workflows declare language servers. At compile time, the compiler: 1. Validates the configuration and rejects `lsp` with a non-Copilot engine. 2. Generates `~/.copilot/settings.json` with an `lspServers` block the Copilot CLI reads at startup. 3. Injects install steps for known server ecosystems into the agent setup job. ## Syntax ```yaml engine: id: copilot lsp: : command: args: [, ] # optional fileExtensions: ".": # at least one required ``` Each key under `lsp` is a language identifier (lowercase, alphanumeric, hyphens, or underscores). It maps to a server definition with: | Field | Required | Description | |---|---|---| | `command` | **yes** | Executable name or path for the language server | | `args` | no | Command-line arguments passed to the server on startup | | `fileExtensions` | **yes** | Map of file extension (with leading `.`) to LSP language ID | | `version` | no | Package version to install (e.g. `"5.8.3"`). Overrides the built-in pinned default for known servers. | ## Built-in Servers For the languages below, the compiler injects the install step automatically — no manual `steps:` entry needed. Each is pinned to a known-good release; override with `version`. | Language key | Default version | Install command | Example `command` | |---|---|---|---| | `bash` | `5.4.0` | `npm install -g --ignore-scripts bash-language-server@5.4.0` | `bash-language-server` | | `go` | `0.18.1` | `go install golang.org/x/tools/gopls@v0.18.1` | `gopls` | | `php` | `1.14.1` | `npm install -g --ignore-scripts intelephense@1.14.1` | `intelephense` | | `python` | `1.1.399` | `npm install -g --ignore-scripts pyright@1.1.399` | `pyright-langserver` | | `ruby` | `0.50.0` | `gem install solargraph -v 0.50.0` | `solargraph` | | `rust` | n/a | `rustup component add rust-analyzer` | `rust-analyzer` | | `typescript` | `5.8.3` / `4.3.3` | `npm install -g --ignore-scripts typescript@5.8.3 typescript-language-server@4.3.3` | `typescript-language-server` | | `yaml` | `1.15.0` | `npm install -g --ignore-scripts yaml-language-server@1.15.0` | `yaml-language-server` | > The `version` field overrides the pinned version for the primary language server package (the last package in the install list). For `typescript`, it controls `typescript-language-server`; `typescript` itself stays at its hardcoded companion version (`5.8.3`). Language keys not in this table still work — the compiler simply skips the auto-install step. Add a manual `steps:` entry to install the server yourself. ## LSP-enabled Tools (Copilot Engine) When `lsp` is configured, Copilot gets semantic code-intelligence tools from the language servers: | Tool capability | What it's used for | |---|---| | Symbol lookup | Find functions, types, methods, constants, classes by symbol name | | Go to definition / declaration | Jump from usage to source of truth | | Find references | Discover where a symbol is read/written/called | | Document / workspace symbols | Enumerate symbols in a file or project scope | | Hover / type info | Inspect signatures, inferred types, and doc comments | | Diagnostics | Surface parse/type errors from the language server | | Rename / refactor actions (server-dependent) | Apply safe symbol renames and structured edits | > [!NOTE] > Exact tool names and availability depend on the runtime engine and language server. Prompt for the capability ("find references", "go to definition"), not a hardcoded tool ID. ## Prompting Guidance for Efficient LSP Use 1. **State the semantic goal first** — symbol-level operations (definition, references, diagnostics) before broad grep scans. 2. **Constrain scope early** — name target directories/files and language keys to avoid whole-repo symbol walks. 3. **Use a two-pass flow** — quick symbol discovery first, deeper reference/type analysis only for shortlisted symbols. 4. **Require evidence** — file paths and line numbers for each definition/reference result. 5. **Set fallback behavior** — if LSP data is unavailable, fall back to text search and state lower confidence. 6. **Avoid over-requesting** — only the symbols needed for the current task. Example intent phrasing: > "Use LSP capabilities first: find symbol definitions and references for `LSPManager` in `pkg/workflow`, report file:line evidence, then propose the minimal edit." ## Examples ### TypeScript / JavaScript ```yaml engine: id: copilot lsp: typescript: command: typescript-language-server args: ["--stdio"] fileExtensions: ".ts": typescript ".tsx": typescriptreact ".js": javascript ".cjs": javascript ".mjs": javascript ``` ### Python ```yaml engine: id: copilot lsp: python: command: pyright-langserver args: ["--stdio"] fileExtensions: ".py": python ``` ### Go ```yaml engine: id: copilot lsp: go: command: gopls fileExtensions: ".go": go ``` ### Multiple Languages ```yaml engine: id: copilot lsp: typescript: command: typescript-language-server args: ["--stdio"] fileExtensions: ".ts": typescript ".js": javascript python: command: pyright-langserver args: ["--stdio"] fileExtensions: ".py": python ``` ### Custom Server (no built-in install) For servers without a built-in install spec, add a manual install step: ```yaml engine: id: copilot steps: - name: Install custom language server run: npm install -g my-custom-language-server lsp: mylang: command: my-custom-language-server args: ["--stdio"] fileExtensions: ".ml": mylang ``` ## Network Requirements Installing LSP servers requires network access to the appropriate package registry. Add the matching ecosystem to `network.allowed`: | Language | Ecosystem to add | |---|---| | `bash`, `php`, `python`, `typescript`, `yaml` | `node` | | `go` | `go` | | `ruby` | `ruby` | | `rust` | `rust` | ```yaml network: allowed: - node # for npm-installed servers (typescript, yaml, python/pyright, etc.) - go # for gopls ``` ## Compile-time Validation The compiler enforces these rules at compile time: - `lsp` requires `engine: copilot` — any other engine causes an error. - Each language entry must have a non-empty `command`. - Each language entry must define at least one `fileExtensions` mapping. - Language keys are case-insensitive and trimmed; duplicate keys that collapse to the same lowercase value are normalized deterministically with the lexicographically first original key winning, but should still be avoided because the result may be surprising. --- description: Guidance for designing bounded, stateful repository maintenance workflows that triage backlogs, improve code, and report to maintainers. --- # Repository Maintenance Workflows Use this guidance when building an agentic workflow that performs recurring repository maintenance. It distills the operating model of [Repo Assist](https://github.com/githubnext/agentics/blob/main/workflows/repo-assist.md) into reusable gh-aw design principles rather than prescribing one repository's labels, thresholds, or task weights. ## Operating principles A maintenance workflow should make useful progress without consuming disproportionate maintainer attention. - Prefer a small, valuable action over broad cleanup. - Stay silent on an individual issue or pull request unless there is something accurate and actionable to add. - Treat a whole-run `noop` as exceptional: inspect the bounded work queue and recorded follow-ups before concluding that no useful work exists. - Never merge the workflow's own pull requests. Leave acceptance to maintainers. - Read `AGENTS.md`, `CONTRIBUTING.md`, and repository-specific instructions before changing files. - Preserve public APIs and avoid new dependencies unless a maintainer has approved the change in a tracked discussion. - Create small draft pull requests with one concern, clear rationale, and validation results. - Identify automated output consistently and interact with contributors politely. These rules deliberately balance bias toward progress with quality over quantity. The workflow should search systematically for useful work, but it should not manufacture comments or changes to prove activity. ## Survey the repository before choosing a strategy Do not begin maintenance workflow design from a generic task portfolio. First inspect the target repository so the initial strategy reflects its technology, activity, backlog, and maintainer practices. For broad automation requests, use this survey to mine candidate intents; for an explicit, narrow request, skip the survey unless repository evidence can materially disambiguate the outcome. Build a bounded baseline from: | Area | Signals to inspect | |---|---| | Project shape | Languages, manifests, generated files, monorepo boundaries, package layout, build systems, and deployment targets | | Repository policy | `AGENTS.md`, `CONTRIBUTING.md`, `CODEOWNERS`, pull request templates, protected paths, release practices, and existing automation | | Activity pattern | Commits, releases, issue and pull request arrival/closure rates, contributor activity, and bot-generated activity over a stated window | | Issue state | Open count, age distribution, unlabelled and stale items, milestones, response status, common categories, and duplicate signals | | Pull request state | Open count, age, reviews, failed checks, merge conflicts, abandoned work, and workflow-owned versus contributor-owned branches | | Operational health | Format/lint/build/test commands, CI reliability, dependency update volume, flaky tests, release cadence, and recurring failures | Use deterministic GitHub queries and repository inspection for this survey. Bound every query, state the observation window and limits, and mark unavailable data instead of guessing. Distinguish observations from recommendations in the design summary. Derive evidence-backed candidate intents before the first portfolio. For each candidate, record the concise outcome, observed evidence, feasibility, expected value, risk, and uncertainties; do not persist this analysis in workflow frontmatter. Select and augment an intent using [intent.md](intent.md), then derive the first portfolio from it. For example: - a large unlabelled issue backlog favors bounded classification before code changes - many unanswered but active issues favors investigation and substantive responses - unhealthy workflow-owned pull requests favors self-maintenance before creating more - high contributor pull request volume favors review support and conservative stale-follow-up rules - low activity or sparse tests favors low cadence, documentation, test discovery, and maintainer reports - frequent releases or dependency churn favors release, dependency, and CI health tasks Recommend two or three low-risk task families, a conservative cadence, per-run limits, state requirements, and pressure valves. Ask maintainers only for policy choices that repository data cannot establish, such as acceptable attention cost, protected areas, and whether contributor-facing comments are appropriate. ## Separate invocation modes Support two distinct modes when both autonomous and requested maintenance are needed: 1. **Scheduled mode** selects bounded work from repository signals and follows the recurring maintenance loop. 2. **Command mode** follows the sanitized slash-command or `workflow_dispatch` instruction exclusively, while retaining the same safety, validation, and disclosure rules. Do not run scheduled tasks or recurring reporting after completing command mode. Keep the branches explicit in the prompt so user instructions cannot accidentally expand an autonomous run. ## Use a deterministic control plane Collect and reduce repository state in deterministic `steps:` before invoking the agent. Typical signals include: - open and unlabelled issue counts - open pull request counts, separated into workflow-owned and contributor pull requests - stale items, failed checks, or merge conflicts - age and last-human-activity timestamps - previously recorded cursors and incomplete work Write a compact JSON payload in a run-scoped artifact directory such as `/tmp/gh-aw/agent/`, containing the signals, candidate task weights, and selected task identifiers. Ask the agent to read that file rather than rediscovering the entire backlog. Choose a small number of distinct tasks per run. Weighted selection can adapt the mix: - increase labelling weight with the unlabelled backlog - increase investigation and fixing weight with the issue backlog - enable self-maintenance only when workflow-owned pull requests exist - increase contributor follow-up weight with eligible stale pull requests - retain a baseline chance for testing, performance, engineering, and roadmap work Seed probabilistic selection with the workflow run ID so a run is reproducible for debugging. Record all inputs, computed weights, selected tasks, and substitutions in logs. Define a fallback for every task that may be inapplicable. This hybrid model keeps collection, prioritization, limits, and bookkeeping deterministic while reserving agent judgment for classification, investigation, implementation, and communication. ## Define a maintenance portfolio Tailor the portfolio to the repository. A broad assistant can draw from these task families: | Task family | Expected behavior | Important bound | |---|---|---| | Label and triage | Apply only existing, allowlisted labels with high confidence; remove clearly incorrect labels | Cursor through untriaged items | | Investigate and respond | Work oldest-first, prioritizing items without a useful prior response | Comment only with substantive findings | | Fix actionable issues | Implement a minimal fix and add a regression test when practical | Skip duplicate or uncertain attempts | | Engineering investment | Improve dependencies, CI, tooling, SDKs, or build configuration | Require clear benefit and validation | | Code and documentation quality | Remove dead code, reduce duplication, clarify APIs, or close documentation gaps | Select only obvious, low-risk improvements | | Maintain owned pull requests | Repair failures caused by the workflow and resolve merge conflicts | Push only to branches identified as workflow-owned | | Follow up on stale pull requests | Offer help when a contributor is blocking progress | Never nudge when maintainers owe the response | | Performance | Remove measurable waste or improve algorithms, caching, memory, or startup | Benchmark where practical | | Testing | Add missing behavioral coverage or improve flaky, slow, or brittle tests | Do not optimize for coverage numbers alone | | Move the repository forward | Continue a feature, difficult investigation, plan, or proposal | Resume recorded work before starting more | | Maintainer report | Update a durable summary of actions and decisions needed | Report only current, actionable information | Specify applicability tests and fallbacks in a table in the workflow prompt. Avoid making open-ended code improvement the universal fallback; investigation, triage, or `noop` is safer when no clearly beneficial change exists. ## Make recurring work systematic Use persistent memory for continuity, not as a source of truth. Store only the minimum state needed to avoid duplicate work and resume fairly: - issue and pull request cursors - automated comments with timestamps and the latest observed human activity - fix attempts, created outputs, and outcomes - stale pull requests already nudged - in-progress work, blockers, and next steps - maintainer actions acknowledged or completed Read memory at the start and update it at the end. Verify every remembered item against live repository state before acting because issues, comments, branches, and checks may have changed. Treat recorded follow-ups as queued work rather than passive notes. Process bounded queues in a stable order, usually oldest-first, and advance a cursor across runs. Re-engage after new human activity, not after the workflow's own comment. Use explicit deduplication keys such as issue number plus last human comment timestamp. ## Bound activity and attention Apply limits at several layers: - Use a pre-activation check to skip scheduled runs when too many workflow-owned pull requests are already open. - Use workflow concurrency to prevent overlapping maintenance runs. - Cap selected tasks and candidate items per run. - Set conservative `max` values on every safe output. - Limit stale pull request nudges separately and remember each nudge. - Restrict labels to a repository-specific allowlist. - Use a stable title prefix or label to identify workflow-owned issues and pull requests. Provide an explicit `noop` path when no candidate meets the quality bar. Before using it, require checks for unprocessed backlog items, recorded follow-ups, actionable bugs, and unhealthy workflow-owned pull requests. ## Keep writes safe Keep the agent job read-only and route mutations through safe outputs. Enable only the GitHub toolsets needed for discovery. Recommended safeguards include: - create all pull requests as drafts - constrain `create-pull-request.allowed-files` whenever the task scope is predictable - use `protected-files: fallback-to-issue` for changes that require maintainer discussion - constrain branch updates with a workflow-owned title prefix or equivalent identity check - hide older automated comments where appropriate - use exact targets and low output caps instead of broad `target: "*"` when possible - use the highest input integrity compatible with the trigger Treat public slash-command text, issue bodies, comments, and pull request content as untrusted. Sanitize command input, keep command mode bounded by the configured tools and safe outputs, and do not lower integrity or enable all GitHub toolsets without an explicit reason. Restrict command mode by repository role when it can perform privileged maintenance. Do not automatically trigger CI for workflow-created pull requests in public repositories unless the abuse risk has been assessed and mitigated. Infer package network access from repository manifests. Do not copy a broad multi-ecosystem network allowlist into every maintenance workflow. ## Validate every proposed change Before creating a pull request: 1. inspect repository instructions and contribution requirements 2. implement the smallest focused change 3. format, lint, build, and test with existing project commands 4. add or update tests when behavior changes 5. scan the changed files for secrets and review the diff 6. create a draft pull request that explains the problem, rationale, trade-offs, related issue, and test status Do not create a pull request when the change causes validation failures. If an unrelated infrastructure failure prevents validation, document the exact limitation rather than claiming success. For performance work, include measurements or clearly state why measurement was not practical. ## Maintain a human-facing summary Persistent machine state is not a maintainer interface. Maintain a rolling issue or discussion that answers: 1. What needs maintainer attention now? 2. What did the workflow do recently? 3. What work is the workflow continuing next? Put pending actions first, include direct links, and remove completed or obsolete entries instead of preserving an ever-growing checklist. Keep run history reverse chronological and link each entry to its workflow run. Read maintainer edits and comments before updating the summary so checked-off work and new direction are preserved. When a run legitimately produces no action after checking all bounded queues and follow-ups, log a `noop` instead of adding a "nothing happened" summary entry. ## Rebuild methodology Build the workflow in stages: 1. **Survey the repository and mine intents.** Record the project shape, contribution rules, validation commands, protected paths, activity window, issue and pull request health, labels, releases, CI reliability, and existing automation. Keep observed facts separate from evidence-backed candidate intents and strategy recommendations. 2. **Select and augment an intent, then choose the initial portfolio.** Start with two or three low-risk families such as labelling, investigation, and owned-PR maintenance. Add code-writing tasks only after observing output quality. 3. **Define live signals and applicability.** Document how each signal changes priority, when each task is eligible, and its fallback. 4. **Define state and deduplication.** Specify cursors, timestamps, ownership markers, and retention. Avoid storing repository data that can be fetched cheaply. 5. **Configure triggers and pressure valves.** Add a fuzzy schedule, optional manual or slash-command entrypoint, concurrency, and an open-PR guard. 6. **Configure least privilege and safe outputs.** Derive tools, permissions, network access, allowlists, protected files, and per-run caps from the chosen portfolio. 7. **Write the execution contract.** State the selected-task input, quality bar, stop conditions, contributor etiquette, validation policy, reporting format, and memory update requirement. 8. **Compile and inspect generated Actions.** Agents must run one-shot `gh aw compile` commands and must not use `--watch`, because watch mode does not terminate automatically. 9. **Roll out gradually.** Begin with low cadence and conservative caps. Review early runs before increasing scope or frequency. Do not transplant Repo Assist's exact weights, labels, stale threshold, open-PR ceiling, or output maxima without measuring the target repository. These are policy choices, not universal defaults. ## Evaluate and tune Review both productivity and attention cost: - task selections, substitutions, and `noop` reasons - duplicate-action rate and backlog coverage - useful comments versus ignored or corrected comments - pull request acceptance, closure, and rework rates - validation failures and time to repair owned pull requests - open workflow-owned pull request pressure - maintainer actions requested and time outstanding - token use, runtime, and output volume by task family Tune deterministic weights, eligibility checks, cadence, and caps before expanding the prompt. Remove task families that consistently create low-value output. Add repository-specific tasks only when they have a measurable outcome and a clear human review path. --- description: MCP CLI command usage guidance and JSON payload patterns --- # MCP CLI Usage MCP CLI exposes mounted MCP servers as shell commands on `PATH`. Enabled by `tools.cli-proxy: true`. > **IMPORTANT**: For `safeoutputs` and `mcpscripts`, **always use the CLI commands** instead of the equivalent MCP tools — do **not** call their MCP tools directly even if they appear in your tool list. > > For `safeoutputs`, treat every successful command as a real write-intent declaration. Do **not** use it for exploratory probing, auth checks, placeholder payloads, retries with variants, or runtime experiments. Emit the final intended call once. If not ready, use `noop` or `report_incomplete`. > > All other servers listed here are **only** available as CLI commands, not MCP tools. ## How to use Each server is a standalone executable on `PATH`. Invoke from bash with `--name value` pairs: ```bash --param1 value1 --param2 value2 ``` **Examples:** ```bash github --help github issue_read --method get --owner org --repo repo --issue_number 42 safeoutputs add_comment --item_number 42 --body "Analysis complete" mcpscripts --help mcpscripts mcpscripts-gh --args "pr list --repo owner/repo --limit 5" ``` For multiple/complex arguments, pipe JSON on stdin using `.` as sentinel (preserves native types, avoids shell quoting): ```bash printf '{"item_number":42,"body":"### Title\n\nBody paragraph one.\n\nBody paragraph two."}' \ | safeoutputs add_comment . printf '{"title":"Fix: something","body":"Details here","labels":["bug","priority-high"]}' \ | safeoutputs create_issue . ``` If pipes are blocked, use file redirection: `safeoutputs create_pull_request . < /tmp/payload.json`. ## Notes - **Prefer JSON payload mode** (`. < file` or `printf '{...}' | server tool .`) for multi-argument or complex calls - Parameters also accept `--name value` pairs; boolean flags use `--flag` (no value) for `true` - `.` as sole argument parses stdin as a JSON object - Hyphens and underscores in parameter names are interchangeable (`issue-number` == `issue_number`) - Output goes to stdout; errors to stderr with non-zero exit - Run inside a `bash` tool call — these are shell executables, not MCP tools - Read-only; cannot be modified by the agent --- description: Worked patterns for stateful agentic workflows — baseline metric comparison with cache-memory, and "alert on new findings" scanning with repo-memory. --- # Stateful Memory Patterns Worked examples for the two most common persistent-state patterns. Tool decision guide and configuration reference: [memory.md](memory.md). ## Baseline Comparison (cache-memory) Persist a baseline metric with `cache-memory` and alert on regression — test coverage, build duration, benchmark scores, audit counts. Requires runs at least every 7 days (default cache retention) and tolerance for losing a baseline: the next run simply re-establishes it. If a lost baseline would cause serious side-effects — e.g. a security-finding baseline where "cache miss" floods the repo with duplicate issues — use `repo-memory` (see below). **Worked example: coverage delta on every PR** ```markdown --- description: Post a PR comment when test coverage drops by more than 1 percentage point on: pull_request: types: [opened, synchronize] permissions: pull-requests: read contents: read engine: copilot tools: github: toolsets: [pull_requests] cache-memory: true safe-outputs: add-pr-comment: max: 1 timeout-minutes: 15 --- Run the test suite and collect the overall line-coverage percentage as a single float (e.g. `82.5`). Load `/tmp/gh-aw/cache-memory/coverage-baseline.json` if it exists. The file stores: `{ "coverage": 82.5, "updated": "2026-05-01-09-00-00" }`. **First run** (file missing): write the current coverage to the file and use the `noop` safe output — no comment is needed yet. **Subsequent runs** (baseline found): compute `delta = current − baseline`. - If `delta >= −1.0` (coverage held or improved), use the `noop` safe output. - If `delta < −1.0` (coverage fell by more than 1 pp), post an `add-pr-comment` that includes baseline coverage, current coverage and delta (e.g. "82.5% → 79.3% (−3.2 pp)") plus which files lost the most coverage. Regardless of the outcome, overwrite `/tmp/gh-aw/cache-memory/coverage-baseline.json` with the current coverage and a filesystem-safe timestamp `YYYY-MM-DD-HH-MM-SS` (no colons, no `T`, no `Z`). ``` **Key design decisions** - **`cache-memory` not `repo-memory`** — coverage deltas are short-lived quality gates; a cache miss just means "no comparison this run" and the baseline is silently refreshed — no false-positive flood - **First-run handling** — treat a missing baseline as "no data yet": write it and skip the comparison; the second run is the first real gate - **Threshold guard** — ignore sub-1 pp fluctuations to reduce noise; tune the threshold to your team's standards - **Filename safety** — use `YYYY-MM-DD-HH-MM-SS` (no colons) in any timestamped filenames written to `cache-memory` (artifacts reject colons; see [memory.md](memory.md#filename-safety)) ## Stateful Scanning (repo-memory) Use `repo-memory` to persist a baseline JSON file between scheduled runs so the workflow only alerts on *new* findings — vulnerability scans, dependency audits, licence checks, or any "track changes over time" scenario. **Worked example: nightly npm vulnerability scan** ```markdown --- description: Nightly npm vulnerability scan — alerts only on new advisories on: schedule: - cron: "0 2 * * *" permissions: issues: write contents: read engine: claude tools: repo-memory: allowed-extensions: [".json"] network: allowed: - registry.npmjs.org safe-outputs: create-issue: title-prefix: "[vuln] " labels: [security, automated] max: 5 timeout-minutes: 20 --- Load `/tmp/gh-aw/repo-memory/default/vuln-baseline.json`. If missing, treat the baseline as `[]` (first run). Run `npm audit --json`. Collect each advisory's id, severity, title, and URL. Diff against the baseline: - **New** (in current, not in baseline) → open a `create-issue` per finding (max 5). - **Resolved** (in baseline, not in current) → log only. - If no new findings, use the `noop` safe output. Write the current advisory IDs to `/tmp/gh-aw/repo-memory/default/vuln-baseline.json` as a JSON array. ``` **Key design decisions** - **`repo-memory` for baselines, not `cache-memory`** — caches expire after 7 days; a lost baseline makes every known finding appear "new" on the next run, flooding the repo with duplicate issues - **First-run handling** — treat a missing baseline file as `[]` and write it at the end of the first run, giving subsequent runs a clean starting point - **`max:` flood guard** — caps issues opened per run; use `max: 5` for nightly scans, `max: 1` for secret alerts, `max: 10` for weekly audits - **Engine restriction** — `repo-memory` requires Claude or a custom engine; it is **not available** for the Copilot engine - **Baseline schema** — store only stable identifiers (advisory ID strings), not mutable fields like severity, to avoid false "new" alerts when metadata changes --- description: Guide for choosing the right persistent memory strategy in agentic workflows — cache-memory, repo-memory, and repo-memory with wiki. Covers deduplication, stateful baseline comparison (metrics/coverage), and stateful scanning ("alert on new X"). --- # Persistent Memory in Agentic Workflows For workflows that **persist state across runs** — deduplication, incremental processing, cross-run context, or knowledge accumulation. > ⚠️ **`repo-memory` is NOT a synonym for `cache-memory`**. Different backends, different tradeoffs. `cache-memory` is almost always the right first choice. --- ## Quick Decision Guide | Need | Use | |---|---| | Skip already-processed items (deduplication) | `cache-memory` ✅ first choice | | Round-robin processing across runs | `cache-memory` ✅ first choice | | Store ephemeral run state, analysis notes, or intermediate results | `cache-memory` ✅ first choice | | Track a numeric metric and compare current vs. baseline (runs at least every 7 days) | `cache-memory` ✅ first choice | | Long-lived knowledge base visible in PRs and code reviews | `repo-memory` | | Baselines that must survive cache expiry (e.g. security findings, dedup lists) | `repo-memory` | | Human-readable wiki pages for knowledge accumulation | `repo-memory` with `wiki: true` | | Persist notes/state inline on the triggering issue or PR | `comment-memory` | | Private-preview GitHub Drives backend (enrolled repos only) | `drive-memory` — see [drive-memory.md](drive-memory.md) | **Default to `cache-memory` unless you have a specific reason to use `repo-memory`.** Do not suggest `drive-memory` unless the repository is confirmed enrolled in the GitHub Drives private preview. --- ## Built-in Memory via GitHub Graph and Git History Before writing new persistent files, check whether GitHub and Git already expose the state you need. ### Practical strategies | Goal | Built-in source | Caching strategy | |---|---|---| | Skip stale files in docs/code scans | Git history (`git log` / last modified commit per file) | Cache a repo watermark SHA or per-file SHAs; compare changed paths in newer commits | | Avoid reopening known incidents | Issue/PR history (open + closed by label/title prefix) | Cache only canonical identifiers (issue numbers, advisory IDs) | | Process incrementally across repo activity | PR merge history (`merged_at`, base branch) | Cache last merged PR number/timestamp; fetch only newer merges | | Keep nightly triage focused | Issue timeline (`updated_at`, comments) | Cache last scan cursor (`updated_at` watermark); inspect only newer updates | | Reuse expensive relationship lookups | GitHub graph links (issue ↔ PR ↔ commit) | Cache normalized link maps keyed by stable node IDs | ### Design guidance - Prefer **stable identifiers** (`node_id`, issue/PR number, commit SHA) over mutable text. - Persist **watermarks** (timestamp, commit SHA, PR number) instead of full snapshots. - Treat built-in history as source of truth; store only incremental resume state. - For cheap bounded queries (latest 20-100 items), recompute from GitHub/git instead of storing derived datasets. --- ## `cache-memory` — First Choice GitHub Actions cache (`actions/cache`) persisting `/tmp/gh-aw/cache-memory/` via `@modelcontextprotocol/server-memory` MCP. ### When to use - **Deduplication**: track processed items (issues, PRs, URLs, IDs) - **Round-robin / incremental**: remember position across scheduled runs - **Ephemeral structured state**: JSON blobs, queues, intermediate results - **Metric baseline comparison**: store coverage/score/count, compare next run (see [Stateful Analysis](#stateful-analysis--baseline-comparison)) - **Visual regression baselines**: screenshots between PR runs (see `visual-regression.md`) - **Tool call caching**: avoid redundant API calls ### Configuration ```yaml tools: cache-memory: true ``` Custom key: ```yaml tools: cache-memory: key: dedup-${{ github.event.schedule }}-${{ github.run_id }} retention-days: 30 allowed-extensions: [".json"] ``` Multiple named caches: ```yaml tools: cache-memory: - id: processed key: processed-items-${{ github.run_id }} - id: results key: results-${{ github.run_id }} retention-days: 14 ``` ### Custom validation For domain-specific constraints beyond `allowed-extensions` (schema checks, cross-file uniqueness, timestamp policies), add `validation.script` — a Node.js script body (globals: `fs`, `path`, `memoryRoot`, `memoryId`, `memoryKind`) run over the memory directory after agent execution and before persistence. Throwing, returning `false`, timing out, or exiting nonzero rejects the save. Default timeout 1 minute (`validation.timeout-minutes`, max 5). Same mechanism for `repo-memory`. See [cache-memory reference](https://github.com/github/gh-aw/blob/main/docs/src/content/docs/reference/cache-memory.md#custom-validation) and [repo-memory reference](https://github.com/github/gh-aw/blob/main/docs/src/content/docs/reference/repo-memory.md#custom-validation). ```yaml tools: cache-memory: validation: timeout-minutes: 1 script: | const index = JSON.parse(fs.readFileSync(path.join(memoryRoot, "index.json"), "utf8")); if (!Array.isArray(index.entries)) throw new Error("index.json entries must be an array"); ``` ### Storage path - Single cache: `/tmp/gh-aw/cache-memory/` - Multiple caches: `/tmp/gh-aw/cache-memory/{id}/` ### Branch scoping Caches are **branch-scoped** with default-branch fallback restore. A feature branch's first restore comes from `main`; subsequent saves fork a branch-local lineage. For warmed-state workflows, schedule on the default branch to reuse one lineage instead of fragmenting state. ### Deduplication example (scheduled workflow) ```markdown --- on: schedule: - cron: "0 9 * * *" permissions: issues: read engine: copilot tools: github: toolsets: [issues] cache-memory: true safe-outputs: create-issue: title-prefix: "[daily-digest] " close-older-issues: true labels: [automation] timeout-minutes: 15 --- Fetch the 20 most recently updated open issues. Load `/tmp/gh-aw/cache-memory/processed.json` if it exists; it contains issue numbers from past digests. Skip any whose number already appears. Summarize remaining (new) issues. If none, use the `noop` safe output. Before finishing, write the updated processed-issue list back to `/tmp/gh-aw/cache-memory/processed.json` using filesystem-safe timestamp `YYYY-MM-DD-HH-MM-SS` (no colons, no `T`, no `Z`). ``` ### Stateful Analysis / Baseline Comparison Persist a baseline metric (coverage %, build time, benchmark score, audit count) and alert on regression. Cache miss → "no comparison this run" and baseline refreshes silently — tolerable for short-lived quality gates. If a lost baseline causes serious side-effects (e.g. duplicate security issues), use `repo-memory` instead (see [Stateful Scanning Pattern (repo-memory)](#stateful-scanning-pattern-repo-memory)). > **Worked example** (coverage delta on every PR, with key design decisions): [memory-stateful-patterns.md](memory-stateful-patterns.md#baseline-comparison-cache-memory). ### Tradeoffs | ✅ Pros | ❌ Cons | |---|---| | Zero repository noise — no commits, no PRs | Evicted when cache expires (default 7 days; use `retention-days` to extend up to 90) | | Fast: no Git operations required | Not human-readable in GitHub UI | | Works with Copilot, Claude, and custom engines | Data loss if cache is invalidated or expires | | Supports multiple isolated caches per workflow | Files are uploaded as GitHub Actions artifacts — **no colons in filenames** | | Scoped to workflow by default | | ### Filename safety Cache-memory files upload as Actions artifacts. **Filenames must not contain colons** (NTFS limitation). ```bash # ✅ GOOD /tmp/gh-aw/cache-memory/state-2026-02-12-11-20-45.json # ❌ BAD — colon breaks artifact upload /tmp/gh-aw/cache-memory/state-2026-02-12T11:20:45Z.json ``` When instructing the agent for timestamped files, say: "Use `YYYY-MM-DD-HH-MM-SS` (no colons, no `T`, no `Z`)." --- ## `repo-memory` — Long-lived Repository Knowledge Uses a dedicated Git branch (default: `memory/agent-notes`) to store files that persist indefinitely until explicitly deleted. The directory lives at `/tmp/gh-aw/repo-memory/`. ### When to use - Knowledge must survive cache expiration - Memory should be **visible in the repository** (auditable via Git history) - Knowledge base grows over time (architecture notes, known issues) - Changes need to appear in diffs and be reviewable ### Configuration ```yaml tools: repo-memory: branch-name: memory/agent-notes # Optional target-repo: owner/other-repo # Optional: store in another repo allowed-extensions: [".json", ".md"] format-json: true # Optional: pretty-print .json (default: false) max-file-size: 10240 # bytes max-file-count: 100 ``` Compiler creates a separate `push_repo_memory` job with `contents: write`; main agent job stays read-only. ### Tradeoffs | ✅ Pros | ❌ Cons | |---|---| | Persists indefinitely (no expiry) | Produces Git commits — repository noise | | Auditable: Git history shows every change | Slower: requires Git clone + push | | Survives cache invalidation | Not available for Copilot engine (requires GitHub tools) | | Human-readable via GitHub branch UI | More complex setup | | Can target a different repository | | --- ## `repo-memory` with `wiki: true` — GitHub Wiki Backend `repo-memory` variant that stores files in the **GitHub Wiki** (`.wiki.git`) instead of a branch. ### When to use - Structured, human-readable documentation pages - Knowledge for **human consumption** (browsable wikis) - Living knowledge base or FAQ ### Configuration ```yaml tools: repo-memory: wiki: true allowed-extensions: [".md"] ``` The compiler creates a separate `push_repo_memory` job with `contents: write`; the main agent job stays read-only. Use GitHub Wiki conventions: `[[Page Name]]` for internal links, hyphens instead of spaces in filenames. ### Tradeoffs | ✅ Pros | ❌ Cons | |---|---| | Browsable in the GitHub Wiki UI | Produces Git commits to wiki repo | | Great for human-readable knowledge bases | Restricted to `.md` files in practice | | Standard Markdown with wiki link syntax | Less suitable for structured JSON state | | Separate from main repo history | | --- ## `comment-memory` — Managed Comment Persistence Uses a `` XML block in an issue/PR comment as persistent memory. The agent edits markdown files under `/tmp/gh-aw/comment-memory/`; the safe-output processor syncs changes back to the managed comment. ### When to use - Workflow notes/statuses visible inline on the triggering issue or PR - State tied to a specific issue or PR lifecycle - Running track records (status tables, checklists, summaries) readable without leaving the issue Do NOT use for high-volume ephemeral state (use `cache-memory`), long-lived knowledge bases (use `repo-memory`), or cross-issue data. ### Configuration ```yaml tools: comment-memory: true # enable with defaults ``` Advanced: ```yaml tools: comment-memory: memory-id: status # Optional: identifier in XML marker (default: "default") target: triggering # Optional: "triggering" (default), "*", or explicit number target-repo: owner/other # Optional: cross-repository max: 1 # Optional: max updates per run (default: 1) footer: false # Optional: omit AI-generated footer (default: true) ``` ### How it works 1. **Pre-agent**: reads `` and writes to `/tmp/gh-aw/comment-memory/.md`. 2. **Agent**: edits the markdown file directly — no safe-output tool call needed. 3. **Post-agent**: processor reads edited file and upserts the managed comment, replacing only the XML-fenced block. Multiple memory IDs in one comment are supported; each maps to a separate `*.md` file. ### Tradeoffs | ✅ Pros | ❌ Cons | |---|---| | Visible in GitHub UI inline on the issue/PR | Requires `issues:write` or `pull-requests:write` | | No separate branch or cache | One comment block per `memory-id` per target | | Agent edits plain markdown — no tool call needed | Not suited for large structured data | | Tied to issue/PR lifecycle | Not available without a triggering issue or PR | --- ## Stateful Scanning Pattern (repo-memory) Persist a baseline JSON file between runs to alert only on *new* findings — vulnerability scans, dependency audits, licence checks. Unlike `cache-memory`, the baseline survives cache expiry, so a missed cycle won't flood the repo with duplicate issues. Store only stable identifiers (advisory IDs), cap output with `max:`, treat missing baseline as `[]`. Requires Claude or custom engine — not Copilot. > **Worked example** (nightly npm vulnerability scan, with key design decisions): [memory-stateful-patterns.md](memory-stateful-patterns.md#stateful-scanning-repo-memory). --- ## Summary Comparison | Feature | `cache-memory` | `repo-memory` | `repo-memory` + wiki | `comment-memory` | |---|---|---|---|---| | **First choice** | ✅ Yes | No | No | No | | **Storage backend** | GitHub Actions cache | Git branch | GitHub Wiki | Issue/PR comment | | **Persistence** | Up to 90 days | Indefinite | Indefinite | Issue/PR lifetime | | **Compiler adds `contents: write`** | No | Yes (push job) | Yes (push job) | No | | **Repository noise** | None | Git commits | Wiki commits | Comment updates | | **Human-readable in GitHub** | No | Via branch UI | Via Wiki UI | ✅ Inline on issue/PR | | **Structured data (JSON)** | ✅ Ideal | Possible | Not recommended | Not recommended | | **Filename restrictions** | No colons in names | None | Hyphens for spaces | None | | **Engine compatibility** | Copilot, Claude, custom | Claude, custom | Claude, custom | Claude, custom | --- ## Anti-patterns - ❌ **Do not invent `repo-memory` as a synonym for `cache-memory`** — they are different tools - ❌ **Do not use `repo-memory` for ephemeral per-run state** — use `cache-memory` - ❌ **Do not use `cache-memory` when you need indefinite persistence** — use `repo-memory` - ❌ **Do not include colons in cache-memory filenames** — artifact upload will fail --- description: Style guide for workflow status messages (all safe-outputs.messages template types). --- # Workflow Status Messages For writing `safe-outputs.messages`. Messages appear in GitHub issues, PR comments, and discussions. ## Rules **Tone:** Plain and professional. No casual phrases ("Mission accomplished!"), no dramatic language ("interrupted!"), no excitement punctuation (`!!`). **Emoji:** One per message, at the start. Use the same emoji across `run-started`, `run-success`, `run-failure`, and `footer`. No trailing emojis. Emoji by domain: 🔍 search · 📐 architecture · 🔬 analysis/security · 📦 dependencies · 📝 docs · 🧪 testing · 🚀 release · 👀 review ## All Message Types ### Status messages (shown on the triggering issue/PR/discussion) | Key | Variables | Default | |-----|-----------|---------| | `run-started` | `{workflow_name}`, `{run_url}`, `{event_type}` | `Agentic [{workflow_name}]({run_url}) triggered by this {event_type}.` | | `run-success` | `{workflow_name}`, `{run_url}` | `✅ Agentic [{workflow_name}]({run_url}) completed successfully.` | | `run-failure` | `{workflow_name}`, `{run_url}`, `{status}` | `❌ Agentic [{workflow_name}]({run_url}) {status} and wasn't able to produce a result.` | | `detection-failure` | `{workflow_name}`, `{run_url}` | `⚠️ Security scanning failed for [{workflow_name}]({run_url}). Review the logs for details.` | ### Footer messages (appended to every AI-generated comment/issue/PR) | Key | Variables | Default | |-----|-----------|---------| | `footer` | `{workflow_name}`, `{run_url}`, `{triggering_number}`, `{triggering_type}`, `{workflow_source}`, `{workflow_source_url}` | *(system default)* | | `footer-install` | `{workflow_source}`, `{workflow_source_url}` | *(system default)* | | `footer-workflow-recompile` | `{workflow_name}`, `{run_url}`, `{repository}` | `> Workflow sync report by [{workflow_name}]({run_url}) for {repository}` | | `footer-workflow-recompile-comment` | `{workflow_name}`, `{run_url}`, `{repository}` | `> Update from [{workflow_name}]({run_url}) for {repository}` | | `agent-failure-issue` | `{workflow_name}`, `{run_url}` | `> Agent failure tracked by [{workflow_name}]({run_url})` | | `agent-failure-comment` | `{workflow_name}`, `{run_url}` | `> Agent failure update from [{workflow_name}]({run_url})` | ### Activation comment links (appended to `run-started` comment when resources are created) | Key | Variables | Default | |-----|-----------|---------| | `pull-request-created` | `{item_number}`, `{item_url}` | `Pull request created: [#{item_number}]({item_url})` | | `issue-created` | `{item_number}`, `{item_url}` | `Issue created: [#{item_number}]({item_url})` | | `commit-pushed` | `{commit_sha}`, `{short_sha}`, `{commit_url}` | `Commit pushed: [\`{short_sha}\`]({commit_url})` | ### Staged mode messages (shown when `staged: true`) | Key | Variables | Default | |-----|-----------|---------| | `staged-title` | `{operation}` | `🎭 Preview: {operation}` | | `staged-description` | `{operation}` | `The following {operation} would occur if staged mode was disabled:` | ### Body headers (prepended to every AI-generated message body) | Key | Variables | Default | |-----|-----------|---------| | `disclosure-header` | `{workflow_name}`, `{run_url}` | *(off)* — set `true` for built-in AI-authorship disclosure text, or provide a custom string | | `body-header` | `{workflow_name}`, `{run_url}` | *(off)* — custom header text prepended to every body | Insertion order, top to bottom: threat-detection caution alert → `disclosure-header` → `body-header` → agent-generated content. Applies to issues, comments, pull requests, and discussions. ### Boolean options | Key | Default | Description | |-----|---------|-------------| | `append-only-comments` | `false` | When `true`, creates a new comment for completion instead of editing the activation comment | ## Templates ### `run-started` ``` "{emoji} [{workflow_name}]({run_url}) is [present-tense verb] for this {event_type}..." ``` End with `...`. Use `{event_type}` to show what triggered the run. ### `run-success` ``` "{emoji} [{workflow_name}]({run_url}) has [past-tense completion phrase]." ``` End with `.`. Be specific about what was produced or verified. ### `run-failure` ``` "{emoji} [{workflow_name}]({run_url}) {status}. [One sentence on what could not be completed]." ``` Include `{status}` to surface the failure reason. Keep the follow-up sentence factual. ### `footer` ``` "> {emoji} *[Action noun] by [{workflow_name}]({run_url})*{history_link}" ``` Blockquote + italics. Include `{history_link}` for navigation to run history. ## Examples ✅ **Search workflow:** ```yaml run-started: "🔍 [{workflow_name}]({run_url}) is searching the web for this {event_type}..." run-success: "🔍 [{workflow_name}]({run_url}) has completed the web search and posted results." run-failure: "🔍 [{workflow_name}]({run_url}) {status}. The search could not be completed." footer: "> 🔍 *Search results by [{workflow_name}]({run_url})*{history_link}" ``` ✅ **Compatibility checker:** ```yaml run-started: "🔬 [{workflow_name}]({run_url}) is analyzing API compatibility for this {event_type}..." run-success: "🔬 [{workflow_name}]({run_url}) has completed the compatibility analysis." run-failure: "🔬 [{workflow_name}]({run_url}) {status}. The compatibility analysis could not be completed." footer: "> 🔬 *Compatibility report by [{workflow_name}]({run_url})*{history_link}" ``` ❌ **Avoid — casual language, mismatched emojis, trailing decorations:** ```yaml run-started: "🔍 Brave Search activated! [{workflow_name}]({run_url}) is venturing into the web..." run-success: "🦁 Mission accomplished! [{workflow_name}]({run_url}) returned with findings. Knowledge acquired! 🏆" run-failure: "🔍 Search interrupted! [{workflow_name}]({run_url}) {status}. The web remains unexplored..." footer: "> 🦁 *Search results brought to you by [{workflow_name}]({run_url})*{history_link}" ``` --- description: Design guide for long-running agentic workflows that run multi-agent research — problem framing, orchestration policy, diversity, verification, and return conditions. Distilled from the OpenAI Cycle Double Cover (CDC) prompt. --- # Multi-Agent Research Workflows Use this guide when designing a long-running agentic workflow whose goal is deep research requiring multiple parallel sub-agents, adversarial verification, and sustained exploration across many rounds. --- ## Core Design Principles The CDC prompt (OpenAI, July 2026) is the best-documented example of a production multi-agent research run. Its seven structural blocks reveal six transferable principles. ### 1 — Loophole-Free Problem Specification State every load-bearing term before the task. Each definition pre-empts a specific degenerate answer: - List what does **not** count as a solution (enumerated near-miss exclusions). - Forbid exactly the partial-result classes your domain is most prone to: special-case proofs, relaxed variants, reductions to still-open lemmas, computational verification up to a finite size. - Include permissive clauses for anything the agent might over-constrain on its own. **AW application:** Put the exclusion list in the workflow prompt body, not in a sub-agent. Near-miss blocking must be visible to the orchestrator from turn 1. ### 2 — Solvability Framing Remove the "this is a famous open problem" escape hatch explicitly: > "Assume for purposes of this task that a complete solution exists." This is a permission revocation, not an optimistic claim. Pair it with: - The success predicate stated twice — once as a natural sentence, once as the exact obligation with the scope quantifier enumerated. - A ban on returning "the problem is hard" as a result. **AW application:** The workflow prompt should include a line such as: "Assume a resolution exists. Do not report that this task is intractable or has no known solution." ### 3 — Anti-Convergence Orchestration Groupthink is the dominant failure mode in multi-agent research. Counter it structurally: - **Information hiding:** Do not tell most sub-agents the currently favored approach. Preserve independence during early rounds. - **Idea-keyed registry, not wording-keyed:** Group agents by the underlying mechanism they are using. Two agents paraphrasing the same reduction are not diverse. - **Delayed cross-pollination:** Share findings across approach families only after independent agents have developed them far enough to expose real strengths and gaps. - **Anti-elegance rule:** A reduction to an equally hard lemma is zero progress regardless of how elegant it looks. **AW sub-agent pattern:** ```markdown ## Step 1 — Diversify Launch independent exploration across at least N distinct approach families. Do not share intermediate findings between sub-agents at this stage. Write each sub-agent's progress to `/tmp/gh-aw/research/approach-.md`. ## Step 2 — Register and redirect Read all `approach-*.md` files. Build or update `/tmp/gh-aw/research/registry.json` with one entry per approach family. Redirect agents away from families that are over-represented. ## Step 3 — Cross-pollinate selectively Identify the two approach families that have independently advanced furthest. Share only their strongest partial results with each other. ``` ### 4 — Blocked-Route Bookkeeping Stalled approaches must be explicitly marked and gated on materially new evidence before reopening: - **Mark blocked:** When an approach reaches a lemma that is as hard as the original problem, record it as blocked. - **Reopening condition:** Only unblock if someone proposes a materially new mechanism, invariant, or construction — not a restatement. - **Persist in cache-memory:** Store the registry between runs so subsequent runs do not repeat foreclosed paths. **AW pattern:** ```yaml tools: cache-memory: key: research-registry-${{ github.run_id }} retention-days: 30 allowed-extensions: [".json", ".md"] ``` Registry schema (stored at `/tmp/gh-aw/cache-memory/registry.json`): ```json { "approaches": [ { "name": "approach-name", "status": "active | blocked | completed", "mechanism": "one-sentence description of the mathematical/technical idea", "blocked_reason": "exact gap or hard lemma that stalled it", "reopen_condition": "what new evidence would justify reopening" } ] } ``` Read the registry at the start of every run. Skip blocked approaches unless the new evidence gate is satisfied. ### 5 — Adversarial Verification Sub-Agents Generic "check carefully" instructions fail. Auditor agents need a domain-specific hunt list: - Supply a checklist of the *exact* ways a candidate solution can look right and be wrong. - The last item should always be the domain's version of circular reasoning: "Does the solution assume the result it is proving?" - Reject status reports, vague optimism, and claims that an unproved step is "routine." **AW sub-agent pattern:** ```markdown ## agent: `auditor` --- description: Adversarial verifier — finds specific failure modes in candidate solutions model: large --- You are given a candidate solution. Check it against this exact list: 1. [Domain-specific failure mode A] 2. [Domain-specific failure mode B] 3. [Domain-specific degenerate case] 4. Circular use: does the argument assume the result it is supposed to prove? Return only one of: - `{"verdict": "pass", "notes": "..."}` — all checks passed - `{"verdict": "fail", "item": , "reason": "..."}` — first failed check Do not return status reports, optimism, or "this looks mostly right." ``` ### 6 — Artifact-Only Return Contract The return condition is a predicate over the artifact, not over confidence or effort: - **Return only when:** the artifact survives adversarial audit AND meets the success predicate exactly. - **Never return:** a reduction, partial result, isolated missing lemma, "best effort" summary, or explanation of why the task is hard. - **Effort floor:** State a minimum before even considering return. The CDC prompt used eight hours; calibrate to your domain's expected depth. **AW prompt closing block:** ```markdown Return only when a verified solution survives adversarial audit. Do not return a partial result, reduction, or explanation of difficulty. If the budget is exhausted before a solution is found, report only the strongest rigorously demonstrated partial result and its exact remaining gap. Spend at least [N] turns on this before even considering a partial return. ``` --- ## Orchestration Loop Architecture The orchestrator is the main agent. Sub-agents are bounded workers: ``` orchestrator (frontier model) ├── reads registry from cache-memory ├── selects next batch of approach families to explore (anti-convergence) ├── dispatches sub-agent workers (parallel, information-hidden) │ ├── explorer- — develops one approach family │ └── auditor — verifies candidate solutions ├── synthesizes results, updates registry ├── checks return predicate └── loops until predicate satisfied or budget exhausted ``` **One-level delegation only.** Do not cascade sub-agents further without explicit gh-aw support for validated deeper topologies. --- ## Workflow Frontmatter Template ```yaml --- engine: copilot # or claude for repo-memory support timeout-minutes: 480 # long-running; calibrate to expected depth max-ai-credits: 5000 # set based on expected sub-agent fan-out tools: github: mode: gh-proxy cache-memory: key: research-state-${{ github.run_id }} retention-days: 30 allowed-extensions: [".json", ".md"] cli-proxy: true bash: ["cat *", "ls *"] safe-outputs: create-issue: title-prefix: "[research] " labels: [research] --- ``` --- ## Prompt Structure Template ```markdown # [Research Task Name] ## Problem Definition [Every load-bearing term defined. Each definition closes one loophole.] ## Success Predicate [State the exact obligation twice: once naturally, once with exact scope and excluded assumptions.] Assume for purposes of this task that a complete solution exists. Do not report that this task is intractable or that no solution is known. ## What Does Not Count The following do NOT satisfy the success predicate: - [Near-miss class 1] - [Near-miss class 2] - [Reductions to equivalent unsolved problems] - [Partial solutions scoped to special cases] ## Orchestration Instructions Read `/tmp/gh-aw/cache-memory/registry.json` if it exists. Explore using the approach families listed as `active` in the registry. Skip any approach marked `blocked` unless new evidence satisfies its `reopen_condition`. Launch sub-agents across at least [N] distinct approach families. Do not share one sub-agent's intermediate progress with others at this stage. After each round, update the registry and redirect agents away from over-represented families. Share findings across families only after independent development has exposed their real strengths and gaps. Every candidate solution must pass the `auditor` sub-agent before being accepted. ## Return Condition Return only when a verified solution survives adversarial audit and meets the success predicate exactly. Do not return a partial result, reduction, or explanation of difficulty. If the budget is exhausted, report only the strongest rigorously demonstrated partial result and its exact remaining gap. Spend at least [N] turns before considering a partial return. ## Information Retrieval Scope Web search and external retrieval may be used only for background material and named standard results. Do not search for a solution to this exact task. ``` --- ## What This Pattern Does Not Do Per the CDC prompt's negative space — useful for authors adapting it: - **No fixed role assignments or personas.** The research strategy is left to the agent; the prompt only manages search discipline and acceptance gates. - **No token budget in the prompt.** Resource enforcement belongs in the `max-ai-credits:` frontmatter, not the prompt body. - **No requested output format for the solution itself** beyond survivability under audit. - **No emotional appeals, urgency framing, or reward promises.** Every sentence is either specification, policy, or gate. --- ## Checklist - [ ] Every load-bearing term defined; loopholes closed by definition - [ ] Success predicate stated twice with excluded assumptions enumerated - [ ] Solvability framing present ("assume a solution exists") - [ ] Near-miss exclusion list enumerated - [ ] Anti-convergence policy: information hiding + idea-keyed registry + delayed cross-pollination - [ ] Blocked-route bookkeeping in cache-memory - [ ] Adversarial auditor sub-agent with domain-specific hunt list, not "check carefully" - [ ] Return condition is a predicate over the artifact, not confidence - [ ] Effort floor before partial-return consideration - [ ] Retrieval scope restricted to background, not solutions --- ## See Also - [subagents.md](subagents.md) — inline sub-agent syntax, model aliases, planner-worker pattern - [token-optimization.md](token-optimization.md) — cost control for long runs with many sub-agents - [memory.md](memory.md) — `cache-memory` for durable registry across runs - [loop.md](loop.md) — long-running loop patterns and circuit breakers - [workflow-patterns.md](workflow-patterns.md) — orchestration and BatchOps patterns --- description: Network access configuration reference for gh-aw workflows — valid ecosystem identifiers, domain patterns, and common mistakes to avoid. --- # Network Access Configuration The `network` frontmatter controls which domains an AI engine can reach. Enforced by the Agent Workflow Firewall (AWF). ## Quick Reference ```yaml # Shorthand — use default infrastructure domains only network: defaults # Custom — allow defaults plus package registries for a Node.js project network: allowed: - defaults - node # Custom — allow specific external APIs network: allowed: - defaults - api.example.com - "*.trusted-partner.com" # No network access network: allowed: [] ``` ## Valid Values for `network.allowed` | Type | Examples | Notes | |---|---|---| | **Ecosystem identifier** | `defaults`, `node`, `python` | Expands to a curated list of domains | | **Exact domain** | `api.example.com`, `registry.npmjs.org` | Must be a fully-qualified domain (FQDN) | | **Wildcard subdomain** | `*.example.com` | Matches `sub.example.com`, `deep.nested.example.com`, and `example.com` itself | > ⚠️ **Bare shorthands like `npm`, `pypi`, `localhost` are NOT valid** unless listed below. Unrecognised single-word entries cause a **compile-time error**. Use ecosystem identifiers (`node`, `python`) or explicit FQDNs (`registry.npmjs.org`, `pypi.org`) instead. ## Ecosystem Identifiers Keywords expanding to curated domain lists: | Identifier | Runtime / Tool | Key Domains Enabled | |---|---|---| | `defaults` | Basic infrastructure | Certificate authorities, Ubuntu package verification, JSON schema | | `github` | GitHub domains | `*.githubusercontent.com`, `codeload.github.com`, `docs.github.com` | | `github-actions` | GitHub Actions artifacts | Azure Blob storage for action caches and artifacts | | `node` | npm / yarn / pnpm | `registry.npmjs.org`, `npmjs.com`, `yarnpkg.com` | | `python` | pip / PyPI / conda | `pypi.org`, `files.pythonhosted.org`, `pip.pypa.io` | | `go` | Go modules | `proxy.golang.org`, `sum.golang.org`, `go.dev` | | `dotnet` | NuGet / .NET | `api.nuget.org`, `nuget.org`, `dotnet.microsoft.com` | | `java` | Maven / Gradle | `repo1.maven.org`, `plugins.gradle.org`, `jdk.java.net` | | `ruby` | Bundler / RubyGems | `rubygems.org`, `api.rubygems.org` | | `rust` | Cargo | `crates.io`, `index.crates.io`, `static.crates.io`, `sh.rustup.rs` | | `swift` | Swift Package Manager | `swift.org`, `cocoapods.org` | | `php` | Composer / Packagist | `packagist.org`, `repo.packagist.org`, `getcomposer.org` | | `dart` | pub.dev | `pub.dev`, `pub.dartlang.org` | | `haskell` | Hackage / GHCup | `*.hackage.haskell.org`, `get-ghcup.haskell.org` | | `perl` | CPAN | `cpan.org`, `metacpan.org` | | `containers` | Docker / GHCR | `ghcr.io`, `registry.hub.docker.com`, `*.docker.io` | | `playwright` | Playwright browsers | `playwright.download.prss.microsoft.com`, `cdn.playwright.dev` | | `linux-distros` | apt / yum / apk | `deb.debian.org`, `security.debian.org`, Ubuntu/Alpine mirrors | | `terraform` | HashiCorp | `releases.hashicorp.com`, `registry.terraform.io` | | `local` | Loopback addresses | `127.0.0.1`, `::1`, `localhost` | | `bazel` | Bazel build | `releases.bazel.build`, `bcr.bazel.build` | | `clojure` | Clojure / Clojars | `clojars.org`, `repo.clojars.org` | | `deno` | Deno / JSR | `deno.land`, `jsr.io` | | `elixir` | Hex.pm | `hex.pm`, `repo.hex.pm` | | `fonts` | Google Fonts | `fonts.googleapis.com`, `fonts.gstatic.com` | | `julia` | Julia packages | `pkg.julialang.org`, `julialang.org` | | `kotlin` | Kotlin / JetBrains | `packages.jetbrains.team` | | `lua` | LuaRocks | `luarocks.org` | | `node-cdns` | JS CDNs | `cdn.jsdelivr.net`, `code.jquery.com`, `unpkg.com` | | `ocaml` | OPAM | `opam.ocaml.org`, `ocaml.org` | | `powershell` | PowerShell Gallery | `powershellgallery.com` | | `r` | CRAN | `cran.r-project.org`, `cloud.r-project.org` | | `scala` | sbt / Scala | `repo.scala-sbt.org`, `repo1.maven.org` | | `zig` | Zig packages | `ziglang.org` | | `dev-tools` | CI/CD tools | Renovate, Codecov, shields.io, and other dev tooling | | `chrome` | Chrome / Chromium | `*.googleapis.com`, `*.gvt1.com` | | `latex` | LaTeX / TeX | `ctan.org`, `mirror.ctan.org`, `miktex.org`, `tug.org` | | `lean` | Lean theorem prover | `lean-lang.org`, `elan.lean-lang.org`, `reservoir.lean-lang.org` | | `python-native` | Python native build deps | Native toolchain mirrors for building Python packages from source | | `copilot-vendor` | Copilot plan-specific APIs / telemetry | `api.business.githubcopilot.com`, `api.enterprise.githubcopilot.com`, `api.individual.githubcopilot.com`, `telemetry.enterprise.githubcopilot.com` | | `copilot` | Copilot engine transport | `api.githubcopilot.com`, GitHub API/web, `host.docker.internal`, `raw.githubusercontent.com` | | `claude` | Claude engine transport | Anthropic APIs, GitHub transport, certificate/OCSP services, Ubuntu package metadata, Playwright downloads | | `codex` | Codex engine transport | `api.openai.com`, `chatgpt.com`, GitHub API/web, `host.docker.internal` | | `gemini` | Gemini engine transport | `generativelanguage.googleapis.com`, `*.googleapis.com`, GitHub web, `host.docker.internal` | | `pi` | Pi engine transport | `api.githubcopilot.com`, GitHub web, `host.docker.internal`, `raw.githubusercontent.com` | | `pi-base` | Pi provider-independent baseline | `github.com`, `host.docker.internal`, `raw.githubusercontent.com` | | `threat-detection` | Compatibility alias for Copilot threat detection | Copilot API/telemetry hosts, GitHub API/web, `host.docker.internal`, `registry.npmjs.org` | ## Engine Domain Sets Engine domain sets are named allow-list bundles for engine CLI authentication and direct provider transport. They are **not** added automatically. Add the matching identifier to `network.allowed` only when the agent needs direct egress to that engine's domains; agent inference normally runs through the AWF API proxy. | Engine set | Included domains | |---|---| | `copilot` | `api.github.com`, `api.githubcopilot.com`, `github.com`, `host.docker.internal`, `raw.githubusercontent.com` | | `claude` | Anthropic APIs, GitHub transport, certificate/OCSP services, Ubuntu package metadata, Playwright downloads, and `host.docker.internal` | | `codex` | `172.30.0.1`, `api.github.com`, `api.openai.com`, `chatgpt.com`, `github.com`, `host.docker.internal`, `openai.com` | | `gemini` | `*.googleapis.com`, `generativelanguage.googleapis.com`, `github.com`, `host.docker.internal`, `raw.githubusercontent.com` | | `pi` | `api.githubcopilot.com`, `github.com`, `host.docker.internal`, `raw.githubusercontent.com`; provider-scoped models replace the API host with the selected provider endpoint | | `pi-base` | `github.com`, `host.docker.internal`, `raw.githubusercontent.com`; applied as the provider-independent baseline before a provider prefix is resolved | | `threat-detection` | Applied automatically only to Copilot threat-detection runs and available as a compatibility alias: Copilot API and telemetry hosts, `api.github.com`, `github.com`, `host.docker.internal`, and `registry.npmjs.org` for read-only lockfile validation. | ## Invalid Shorthands Services started inside the agent's AWF sandbox are reachable at `localhost` and `127.0.0.1` without `local`: those addresses are on the default proxy bypass list. Add `local` only when a workflow needs the firewall allowlist to represent loopback access explicitly, such as a different runtime topology. These look like ecosystem identifiers but are **not recognised** — using them causes a **compile-time error**: | Invalid value | What you probably meant | Correct value | |---|---|---| | `npm` | npm registry | `node` | | `pypi` | Python Package Index | `python` | | `pip` | pip package manager | `python` | | `cargo` | Rust crate registry | `rust` | | `gem` or `gems` | RubyGems | `ruby` | | `nuget` | NuGet package registry | `dotnet` | | `maven` | Maven Central | `java` | | `gradle` | Gradle plugins | `java` | | `composer` | PHP Composer | `php` | | `docker` | Docker Hub / GHCR | `containers` | | `localhost` | Loopback interface | `local` | ## Domain Pattern Rules - **Wildcard `*` requires a dot prefix**: `*.example.com` valid; bare `*` blocked (rejected outright in strict mode). - **No protocol prefix**: `https://api.example.com` is invalid — write `api.example.com`. - **Subdomains must be explicit**: `github.com` does not cover `api.github.com`; use `*.github.com` or both. ## Inferring Ecosystem From Repository Files For workflows that build, test, or install packages, add the matching ecosystem alongside `defaults`: | File indicators | Ecosystem to add | Enables | |---|---|---| | `package.json`, `yarn.lock`, `pnpm-lock.yaml`, `.nvmrc` | `node` | `registry.npmjs.org` | | `requirements.txt`, `pyproject.toml`, `uv.lock`, `Pipfile` | `python` | `pypi.org`, `files.pythonhosted.org` | | `go.mod`, `go.sum` | `go` | `proxy.golang.org`, `sum.golang.org` | | `*.csproj`, `*.sln`, `*.slnx` | `dotnet` | `api.nuget.org` | | `pom.xml`, `build.gradle` | `java` | `repo1.maven.org` | | `Gemfile`, `*.gemspec` | `ruby` | `rubygems.org` | | `Cargo.toml` | `rust` | `crates.io` | | `Package.swift` | `swift` | `swift.org` | | `composer.json` | `php` | `packagist.org` | | `pubspec.yaml` | `dart` | `pub.dev` | > ⚠️ **`network: defaults` alone is never sufficient for code workflows** — `defaults` covers basic infrastructure (CAs, Ubuntu verification) but not package registries. Always add the language ecosystem. ## Common Patterns Reads GitHub data only: ```yaml network: allowed: - defaults - github ``` Multi-language project: ```yaml network: allowed: - defaults - node - python ``` Single ecosystem, external APIs, and no-network forms are in [Quick Reference](#quick-reference). --- description: Analyze and reduce token consumption in agentic workflows — audit-based measurement, DataOps, gh-proxy, sub-agents, and prompt optimization. disable-model-invocation: true --- # Agentic Workflow Token Optimizer Help users reduce the AI token usage and cost of GitHub Agentic Workflows in this repository. ## Load These References First - [github-agentic-workflows.md](github-agentic-workflows.md) - [token-optimization.md](token-optimization.md) - [workflow-editing.md](workflow-editing.md) - [syntax.md](syntax.md) Load these only when relevant: - [experiments.md](experiments.md) - [safe-outputs.md](safe-outputs.md) ## Available Commands ```bash gh aw audit --json gh aw audit gh aw logs --json gh aw compile 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 --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 large file reads (> 20 KB) via `get_file_contents` that could be replaced with `grep`/`glob`/`view_range`? These are the most common cause of late-session token spikes. 4. Are there repetitive extraction steps that sub-agents could handle cheaply? 5. Does the frontier model handle tasks that a small model could do? 6. Can the workflow stay within its current budget after applying and measuring all applicable optimizations? Increasing `max-ai-credits` is the last resort. Recommend it only after the applicable optimizations below have been tried and measured, and the workflow still cannot complete with acceptable quality within the existing per-run budget. ### `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. For a large repetitive backlog, can each run process a manageable subset selected with a cache cursor or deterministic round-robin heuristic? 5. 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 ` 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. **Bound repetitive work** — for very large backlogs, cap each run to a budget-safe subset and rotate through work with a persisted cache cursor or deterministic heuristic so items are not starved 7. **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 8. **Prompt caching** — verify stable instructions and reusable experience appear before dynamic content 9. **Experiment correctness first** — add an `experiments:` entry, compare output quality first, and use `metric: "aic"` to choose among equivalent-quality variants 10. **Validate quality** — confirm the optimized run produces equivalent safe outputs 11. **Raise the per-run budget only if necessary** — consider increasing `max-ai-credits` only after all applicable optimizations have been exhausted and measured Present the plan clearly before making any edits. Confirm with the user before applying changes. ## Editing Workflow 1. Edit `.github/workflows/.md` 2. Recompile: `gh aw compile ` 3. Commit both the source and the generated `.lock.yml` 4. Report the estimated savings and link to the PR or commit --- description: Agentic workflow pattern router for selecting the best documented pattern and playbook. disable-model-invocation: true --- # Agentic Workflow Patterns Router Use this router when a user asks for a workflow architecture, strategy, operating model, or design pattern. ## Routing Rules 1. Identify the user's primary goal and constraints. 2. Match the request to the closest pattern in the index below. 3. Load and follow the matched pattern document. 4. If multiple patterns apply, pick one primary pattern and list 1-2 secondary patterns to combine. 5. If no pattern clearly fits, ask a short clarifying question before proceeding. ## Pattern Index Pattern docs base path: `https://github.com/github/gh-aw/blob/main/docs/src/content/docs/patterns/` ### MonitorOps - **Load when:** The user needs repository-wide workflow observability, trend reporting, and escalation for recurring failures or token waste. - **Pattern doc:** https://github.com/github/gh-aw/blob/main/docs/src/content/docs/patterns/monitor-ops.md ### BatchOps - **Load when:** The user needs to process large worksets in shards/chunks with throttling and aggregation. - **Pattern doc:** https://github.com/github/gh-aw/blob/main/docs/src/content/docs/patterns/batch-ops.md ### CentralRepoOps - **Load when:** The user needs a private control repository that coordinates rollouts across many target repositories. - **Pattern doc:** https://github.com/github/gh-aw/blob/main/docs/src/content/docs/patterns/central-repo-ops.mdx ### ChatOps - **Load when:** The user wants slash-command driven, human-in-the-loop automation in issues or pull requests. - **Pattern doc:** https://github.com/github/gh-aw/blob/main/docs/src/content/docs/patterns/chat-ops.md ### CorrectionOps - **Load when:** The user wants to improve workflow behavior from trusted human corrections without retraining the model. - **Pattern doc:** https://github.com/github/gh-aw/blob/main/docs/src/content/docs/experimental/correction-ops.md ### DailyOps - **Load when:** The user wants scheduled, small, recurring improvements that compound over time. - **Pattern doc:** https://github.com/github/gh-aw/blob/main/docs/src/content/docs/patterns/daily-ops.md ### DeterministicOps - **Load when:** The user needs deterministic data collection steps followed by agentic analysis and reporting. - **Pattern doc:** https://github.com/github/gh-aw/blob/main/docs/src/content/docs/patterns/deterministic-ops.md ### DispatchOps - **Load when:** The user needs manual trigger flows (`workflow_dispatch`) with custom inputs for testing or controlled runs. - **Pattern doc:** https://github.com/github/gh-aw/blob/main/docs/src/content/docs/patterns/dispatch-ops.md ### Feature Grower - **Load when:** The user wants a scheduled agent to advance long-lived features one implementation-ready sub-issue at a time. - **Pattern doc:** https://github.com/github/gh-aw/blob/main/docs/src/content/docs/patterns/feature-grower.md ### IssueOps - **Load when:** The user needs fully automated issue triage, categorization, and responses on issue events. - **Pattern doc:** https://github.com/github/gh-aw/blob/main/docs/src/content/docs/patterns/issue-ops.md ### LabelOps - **Load when:** The user needs label-driven workflow behavior when specific labels are added or removed. - **Pattern doc:** https://github.com/github/gh-aw/blob/main/docs/src/content/docs/patterns/label-ops.md ### Monitoring with Projects - **Load when:** The user needs durable tracking and monitoring of work items with GitHub Projects and safe outputs. - **Pattern doc:** https://github.com/github/gh-aw/blob/main/docs/src/content/docs/experimental/monitoring-with-projects.md ### MultiRepoOps - **Load when:** The user needs coordination and synchronization across multiple repositories. - **Pattern doc:** https://github.com/github/gh-aw/blob/main/docs/src/content/docs/patterns/multi-repo-ops.md ### Orchestration - **Load when:** The user needs orchestrator/worker architecture using reusable workflows or workflow dispatch. - **Pattern doc:** https://github.com/github/gh-aw/blob/main/docs/src/content/docs/patterns/orchestration.md ### ProjectOps - **Load when:** The user needs intelligent routing and controlled field updates in GitHub Projects. - **Pattern doc:** https://github.com/github/gh-aw/blob/main/docs/src/content/docs/patterns/project-ops.mdx ### ResearchPlanAssignOps - **Load when:** The user needs a flow from deep research to planning to automated issue assignment/implementation. - **Pattern doc:** https://github.com/github/gh-aw/blob/main/docs/src/content/docs/patterns/research-plan-assign-ops.md ### SideRepoOps - **Load when:** The user wants low-friction reporting/automation from a side repository targeting a primary repository. - **Pattern doc:** https://github.com/github/gh-aw/blob/main/docs/src/content/docs/patterns/side-repo-ops.mdx ### SpecOps - **Load when:** The user needs to maintain formal specifications and propagate spec updates to consuming implementations. - **Pattern doc:** https://github.com/github/gh-aw/blob/main/docs/src/content/docs/patterns/spec-ops.md ### TrialOps - **Load when:** The user needs isolated trial repositories to validate workflows before production rollout. - **Pattern doc:** https://github.com/github/gh-aw/blob/main/docs/src/content/docs/experimental/trial-ops.md ### WorkQueueOps - **Load when:** The user needs durable queue processing for many items via issues, sub-issues, discussions, or cache-memory. - **Pattern doc:** https://github.com/github/gh-aw/blob/main/docs/src/content/docs/patterns/workqueue-ops.md ## Notes - Prefer documented patterns over ad hoc architecture when a strong match exists. - When relevant, combine pattern guidance with core workflow rules from: - https://github.com/github/gh-aw/blob/main/.github/aw/github-agentic-workflows.md --- description: Configure and use the built-in Playwright CLI integration in GitHub Agentic Workflows. --- # Playwright Use the built-in `playwright` tool for browser automation, accessibility checks, end-to-end flows, and visual regression testing. The integration uses `@playwright/cli`; it does not expose Playwright MCP tools. ## Configure the tool Enable Playwright in workflow frontmatter: ```yaml tools: playwright: ``` The compiler installs the pinned default `@playwright/cli` package, its agent skills, and Chromium before the agent starts. The default `open` session uses Chromium. To use other browser engines, list them in `browsers`. Playwright's `chromium` download is the Chrome for Testing distribution; `chrome` and `chrome-for-testing` are accepted aliases: ```yaml tools: playwright: browsers: [chromium, firefox, webkit] ``` Supported values are `chrome`, `chrome-for-testing`, `chromium`, `firefox`, and `webkit`. The broader Playwright install-target list also contains system browser channels and platform-specific tools, but those are not portable browser engines for this field. Do not add steps such as `npx playwright install` or `npm exec playwright install`; the compiler provisions the selected engines, and browser installation during agent execution is prohibited. Pin `version` only when reproducible browser output is required, such as for visual baselines: ```yaml tools: playwright: version: "0.1.18" ``` Omit `mode`; the built-in Playwright integration is CLI-only by default. The explicit `mode: cli` setting remains accepted for compatibility, but it is not needed and should be removed from workflows that still carry it. `mode: mcp` is not supported by the built-in tool. If MCP is required, configure and pin `@playwright/mcp` explicitly under `mcp-servers` and allow only the required tools. ## Configure network access Playwright can reach `localhost` and `127.0.0.1` by default; do not add `local` for a server started in the same AWF sandbox. Add only the ecosystems and external domains the browser needs: ```yaml network: allowed: - defaults - playwright - "docs.example.com" ``` The `playwright` ecosystem permits browser downloads. An explicit domain also permits its subdomains. Prefer a local server over an external preview, and avoid broad wildcard domains. ## Use Playwright CLI Run `playwright-cli` through bash. With a restricted Bash allowlist, the compiler automatically allows `playwright-cli:*`; list only supporting lifecycle commands such as `npm`, `curl`, and `kill`. Before opening a browser, inspect package scripts, Playwright configuration, and test filenames to determine whether the task is likely to run Playwright Test. If it is, use `--browser=chromium`, which selects Playwright's Chrome for Testing engine. Start with a snapshot and use its element refs for later actions: ```bash playwright-cli open --browser=chromium "https://docs.example.com" playwright-cli snapshot playwright-cli click e15 playwright-cli fill e22 "search text" --submit playwright-cli screenshot --filename=/tmp/docs.png playwright-cli close ``` Useful commands include: | Goal | Command | |---|---| | Open a browser and URL | `playwright-cli open --browser= ` | | Navigate the open page | `playwright-cli goto ` | | Inspect the page and get refs | `playwright-cli snapshot` | | Limit snapshot size | `playwright-cli snapshot --depth=4` | | Click or fill an element | `playwright-cli click ` / `playwright-cli fill ` | | Evaluate JavaScript | `playwright-cli eval "() => document.title"` | | Capture a screenshot | `playwright-cli screenshot --filename=` | | Return only the command result | `playwright-cli --raw ` | | Close the browser | `playwright-cli close` | Prefer refs from the latest snapshot over brittle CSS selectors. Use `--raw` when piping a result or comparing snapshots so page status output does not pollute the data. Use `playwright-cli open --browser=chromium` for Chrome for Testing. Use `playwright-cli open --browser=firefox` or `playwright-cli open --browser=webkit` for the other provisioned browsers. Use named sessions when independent cookies or storage are useful: ```bash playwright-cli -s=authenticated open --browser=chromium "https://app.example.com/login" playwright-cli -s=public open --browser=chromium "https://app.example.com/" playwright-cli -s=authenticated close playwright-cli -s=public close ``` ## Run against a local application Prepare dependencies in deterministic workflow steps, but start the server from the agent when the agent needs to control its lifecycle: ```yaml steps: - name: Prepare application working-directory: ./web run: npm ci tools: playwright: bash: - "npm run dev *" - "curl *" - "kill *" network: allowed: - defaults - playwright ``` The server process then runs in the same sandbox and network namespace as `playwright-cli`, so its loopback URL is reachable without exposing a host port or adding an external domain. It remains available across the agent's tool calls until it exits, the agent stops it, or the sandbox is torn down. Direct the agent to start the server in the background, retain its PID, and use one `curl` command with built-in retries and exponential backoff for readiness: ```bash npm run dev -- --host 127.0.0.1 > /tmp/web-server.log 2>&1 & server_pid=$! curl --fail --silent --show-error --retry 10 --retry-connrefused \ --retry-all-errors --retry-max-time 30 http://127.0.0.1:4321/ >/dev/null playwright-cli open --browser=chromium "http://127.0.0.1:4321/" playwright-cli resize 1440 900 playwright-cli screenshot --filename=/tmp/home.png playwright-cli close kill "$server_pid" ``` If commands run in separate shell calls, write the PID to a file under `/tmp` and read it back for cleanup. Redirect server logs to `/tmp` so they do not consume the agent context; inspect only the relevant tail when startup fails. ## Publish screenshots Files under `/tmp`, including screenshots, disappear when the run sandbox ends. Declare `upload-artifact` and instruct the agent to publish files users need to retrieve: ```markdown --- safe-outputs: upload-artifact: allowed-paths: ["/tmp/*.png"] max-uploads: 1 retention-days: 7 --- Capture `/tmp/home.png`, then call `upload_artifact` with `name: "home-screenshot"` and `path: "/tmp/home.png"`. ``` ## Follow the AWF sandbox policy When Playwright runs in the AWF sandbox: - Never install packages, browsers, or system dependencies at runtime. Report a missing CLI or browser instead. - Navigate only to loopback URLs or domains listed in `network.allowed`. - Do not bind local servers to `0.0.0.0`, publish ports, or use preview tunnels. - Do not change browser proxy settings, proxy environment variables, or the `localhost`/`127.0.0.1` proxy bypass. - Close the browser and stop any server process started during the task. These rules differ from using the standalone `awf` command to wrap a host-side Playwright test. Standalone AWF uses `--allow-domains localhost` to expose selected host ports to its container. In a gh-aw agent sandbox, start the server inside the sandbox and keep it on loopback instead. ## Accessibility and troubleshooting Snapshots enable structural and manual inspection of headings, labels, alternative text, and keyboard flows. Comprehensive WCAG testing (for example, axe-core or programmatic contrast analysis) needs dependencies prepared in workflow steps before the agent runs; the AWF sandbox prohibits runtime installs. For failures, inspect `playwright-cli console` and `playwright-cli requests`; use `playwright-cli request ` for a request's details. Surround a failing flow with `playwright-cli tracing-start` and `playwright-cli tracing-stop`, and inspect the relevant tail of redirected local-server logs (for example, `tail -n 100 /tmp/web-server.log`). ## Sample workflow This workflow checks a public documentation site and reports actionable accessibility findings: ```markdown --- on: workflow_dispatch: permissions: contents: read tools: playwright: network: allowed: - defaults - playwright - "docs.example.com" safe-outputs: create-issue: title-prefix: "[accessibility] " labels: [accessibility] max: 3 noop: --- # Accessibility review Open https://docs.example.com with `playwright-cli open --browser=chromium`. Inspect the page snapshot, keyboard navigation, form labels, image alternatives, and heading structure. Create focused issues for actionable findings. If there are none, call `noop`. Always close the browser before finishing. ``` For visual comparisons, pin the Playwright CLI version, define the baseline source explicitly, keep screenshots under `/tmp`, and use `cache-memory` when baselines must persist across runs. ## Related guidance - [`visual-regression.md`](visual-regression.md) for baseline storage and comparison patterns - [`network.md`](network.md) for domain allowlisting - [`mcp-clis.md`](mcp-clis.md) for CLI-mounted MCP servers, which are separate from the built-in Playwright CLI integration - [Playwright CLI](https://github.com/microsoft/playwright-cli) for the complete command reference --- description: Guidance for implementing PR reviewer agentic workflows with ready_for_review triggers, centralized slash commands, and safe review actions. --- ## PR Reviewer Workflow Pattern For reviewer workflows that run automatically when a PR is ready and manually via slash command. ## Trigger Model ```yaml on: pull_request: types: [ready_for_review] slash_command: strategy: centralized name: review events: [pull_request_comment, pull_request_review_comment] ``` `ready_for_review` starts review when drafts become reviewable. Centralized routing handles both PR comments and review comments via one entrypoint. When workflows are attached to repository rulesets as required checks, also include `opened`, `synchronize`, and `reopened` to ensure the check reruns on new commits and stays green as code changes. ## Safe Outputs - `create-pull-request-review-comment` — line-level feedback - `resolve-pull-request-review-thread` — resolved threads - `submit-pull-request-review` — final review state - `update-pull-request-review` — amend an existing review Keep `max` caps conservative to avoid runaway reviews. ## Default Review Events: No APPROVE **The GitHub Actions actor (`GITHUB_TOKEN`) cannot `APPROVE` a pull request. It can post `COMMENT` and `REQUEST_CHANGES` reviews.** By default, configure `submit-pull-request-review` with `allowed-events: [COMMENT, REQUEST_CHANGES]` to enforce this constraint: ```yaml safe-outputs: submit-pull-request-review: max: 1 allowed-events: [COMMENT, REQUEST_CHANGES] ``` Do not instruct the agent to approve a PR unless the workflow uses a PAT or app token with explicit pull-request approval permissions. Using `APPROVE` with the default `GITHUB_TOKEN` will fail at runtime. ## Integrity and GitHub Tool Access ```yaml tools: github: min-integrity: approved toolsets: [pull_requests, issues, repos] ``` - Prefer `pull_requests` for reviewer operations. - Add `issues` only when interacting with issue-style comment surfaces or cross-links. - Use the lowest `min-integrity` that supports the required actions. ## Ruleset Compatibility - Keep workflow and job names stable so required-check rulesets keep matching after updates. - If imports are used, set `inlined-imports: true` to avoid runtime import failures in ruleset execution contexts. - For bot-based reviewers, prefer `allowed-events: [COMMENT, REQUEST_CHANGES]` unless you intentionally provide elevated approval credentials. ## Examples - `.github/workflows/pr-code-quality-reviewer.md` - `.github/workflows/mattpocock-skills-reviewer.md` - `.github/workflows/test-quality-sentinel.md` --- description: Guidance for creating release agentic workflows that combine classic Action jobs (build, test, publish) with an agent job that generates release highlights. --- # Release Workflow Pattern Use this guidance when the user asks to create a workflow that: - Builds, tests, and publishes a GitHub release - Generates or prepends release highlights / changelog summaries to the release description ## Pattern Overview A release workflow follows the **Classic + Agent** hybrid structure: 1. **Classic jobs** — deterministic pipeline executed as standard GitHub Actions jobs: compute the next semantic version, build binaries, run tests, scan for security issues, create the GitHub release. 2. **Agent job** — runs after the classic `release` job; reads merged PR data and changelog; generates human-readable release highlights; updates the release description using the `update-release` safe output. ``` workflow_dispatch (release_type: patch | minor | major) ├── config — compute next semver tag; output: release_tag ├── build — build binaries; upload artifact ├── test — run test suite (may be parallel to build) ├── [security] — optional: virus scan, SBOM, attestation ├── release — create prerelease; upload binaries; output: release_id └── agent — fetch PRs + changelog; generate highlights; update_release(prepend) ``` The agent job is the **only** job that uses the agentic engine. All other jobs are standard GitHub Actions steps. ## Frontmatter Template ```yaml --- private: true name: Release emoji: "🚀" description: Build, test, and release, then generate release highlights on: roles: - admin - maintainer workflow_dispatch: inputs: release_type: description: 'Release type (patch, minor, or major)' required: true type: choice default: patch options: [patch, minor, major] permissions: contents: read pull-requests: read actions: read safe-outputs: update-release: threat-detection: false # release bodies often contain code snippets; disable threat scanning network: allowed: - defaults - # add: go, node, python, rust, etc. based on project --- ``` Key frontmatter decisions: - `private: true` — release workflows should not be visible in the public agentic workflow gallery - `roles: [admin, maintainer]` — restrict triggering to trusted collaborators - `threat-detection: false` — disable threat scanning on `update-release` because release notes intentionally include code snippets and technical content that can trigger false positives - Global `permissions: contents: read` with per-job overrides for write operations ## Classic Jobs Design these jobs exactly as you would a standard GitHub Actions workflow. The compiler handles action version pinning automatically. ### config Computes the next semantic version from existing GitHub releases/tags using `actions/github-script`. Must output `release_tag`: ```yaml config: needs: ["pre_activation", "activation"] runs-on: ubuntu-latest outputs: release_tag: ${{ steps.compute_config.outputs.release_tag }} steps: - name: Compute Release Config id: compute_config uses: actions/github-script@v9 with: script: | const releaseType = context.payload.inputs.release_type; const { data: releases } = await github.rest.repos.listReleases({ owner: context.repo.owner, repo: context.repo.repo, per_page: 100 }); // parse, sort semver, bump, check for collision, set output // core.setOutput('release_tag', releaseTag); ``` ### build Checks out the repository, builds binaries, and uploads them as a GitHub Actions artifact for downstream jobs: ```yaml build: needs: ["pre_activation", "activation", "config"] runs-on: ubuntu-latest steps: - uses: actions/checkout@v7 with: { persist-credentials: false } - name: Build run: bash scripts/build-release.sh ${{ needs.config.outputs.release_tag }} - uses: actions/upload-artifact@v7 with: name: release-binaries-${{ needs.config.outputs.release_tag }} path: dist/ retention-days: 1 ``` ### release Creates the GitHub release using `gh release create`. Use `--prerelease --latest=false` initially so the release is visible but not promoted until verification is complete. Must output `release_id`: ```yaml release: needs: ["pre_activation", "activation", "config", "build"] runs-on: ubuntu-latest permissions: contents: write # override: required to create tags and releases outputs: release_id: ${{ steps.create_release.outputs.release_id }} steps: - uses: actions/checkout@v7 with: { fetch-depth: 0, persist-credentials: true } - uses: actions/download-artifact@v8 with: name: release-binaries-${{ needs.config.outputs.release_tag }} path: dist/ - name: Create GitHub release id: create_release env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} RELEASE_TAG: ${{ needs.config.outputs.release_tag }} run: | gh release create "$RELEASE_TAG" dist/* \ --title "$RELEASE_TAG" \ --generate-notes \ --prerelease \ --latest=false RELEASE_ID=$(gh release view "$RELEASE_TAG" --json databaseId --jq .databaseId) echo "release_id=$RELEASE_ID" >> "$GITHUB_OUTPUT" ``` ## Agent Job The agent job must depend on the `release` job (so the release exists before the agent runs) and run with the global read-only permissions. ### Pre-step: Fetch Release Context Use a deterministic `steps:` block to pre-fetch all data before the agent runs. Write output to `/tmp/gh-aw/agent/release-data/` (standard agent pre-fetch path). ```yaml steps: - name: Fetch release context env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} RELEASE_TAG: ${{ needs.config.outputs.release_tag }} RELEASE_ID: ${{ needs.release.outputs.release_id }} run: | mkdir -p /tmp/gh-aw/agent/release-data # Fetch the newly created release gh api "/repos/$GITHUB_REPOSITORY/releases/$RELEASE_ID" \ > /tmp/gh-aw/agent/release-data/current_release.json # Find previous release to scope PR list PREV_TAG=$(gh release list --limit 2 --json tagName --jq '.[1].tagName // empty') if [ -n "$PREV_TAG" ]; then PREV_AT=$(gh release view "$PREV_TAG" --json publishedAt --jq .publishedAt) CURR_AT=$(gh release view "$RELEASE_TAG" --json publishedAt --jq .publishedAt) gh pr list --state merged --limit 500 \ --json number,title,author,labels,mergedAt,url,body \ --jq "[.[] | select(.mergedAt >= \"$PREV_AT\" and .mergedAt <= \"$CURR_AT\")]" \ > /tmp/gh-aw/agent/release-data/pull_requests.json else echo "[]" > /tmp/gh-aw/agent/release-data/pull_requests.json fi [ -f CHANGELOG.md ] && cp CHANGELOG.md /tmp/gh-aw/agent/release-data/CHANGELOG.md || true tools: cli-proxy: true # allows gh and jq calls inside the agent sandbox ``` ### Prompt The markdown body (after the `---` separator) forms the agent prompt: ```markdown # Release Highlights Generator Generate release highlights for **$GITHUB_REPOSITORY** release `${RELEASE_TAG}`. **Release ID**: ${{ needs.release.outputs.release_id }} ## Data Pre-fetched in `/tmp/gh-aw/agent/release-data/`: - `current_release.json` — release metadata and auto-generated notes body - `pull_requests.json` — PRs merged since the previous release (empty array for first release) - `CHANGELOG.md` — changelog content (if present) ## Task 1. Read `current_release.json` and `pull_requests.json`. 2. Categorize changes: **Breaking Changes**, **New Features**, **Bug Fixes**, **Documentation**, **Internal** (omit internal from highlights unless user-impacting). 3. Write a concise "## 🌟 Release Highlights" section that is scannable in 30 seconds. 4. Call `safeoutputs/update_release(tag="${RELEASE_TAG}", operation="prepend", body="...")` to prepend the highlights before the auto-generated notes. 5. Call `noop` with a short explanation only if there are no user-facing changes. ## Output Format Use `operation: "prepend"` so the highlights appear before the GitHub-generated release notes. Do not replace the auto-generated notes — prepend only. ``` ## Key Rules - **Agent job stays read-only** — all writes route through `update-release` - **Use `operation: "prepend"`** so highlights appear before the auto-generated GitHub notes; never `replace` - **The `release` job must output `release_id`** — the agent needs the database ID to reference the correct release - **Pre-fetch all data in `steps:`** before the agent runs; write compact JSON to `/tmp/gh-aw/agent/release-data/` - **Include `cli-proxy: true`** in the agent `tools:` block to allow `gh` and `jq` use inside the sandbox - **Declare `contents: write` per-job**, not globally — only the jobs that push tags or create releases need it - **Set `threat-detection: false`** in `safe-outputs:` — release bodies contain code snippets that trigger false positives - **Network**: classic jobs installing packages need the ecosystem entry (e.g. `go`, `node`); the agent job itself only needs `defaults` ## Common Additions | Addition | Where | Notes | |---|---|---| | Security/virus scan | After build, before release | Use `runs-on: windows-latest` with Microsoft Defender for binaries | | SBOM generation | Inside the `release` job | Use `anchore/sbom-action`; upload as artifact, not as release asset | | Attestation | Inside the `release` job | Use `actions/attest-build-provenance`; requires `id-token: write` + `attestations: write` | | Gate / environment approval | Between jobs | Use `environment:` on a gate job; useful for manual sign-off before releasing | | Comment on merged PRs | After agent job | Separate classic job using `actions/github-script` to notify PR authors; requires `pull-requests: write` + `issues: write` | | Community attribution | Agent prefetch step | Fetch community-labeled issues closed in the release window for attribution in highlights | ## Reference Implementation See `.github/workflows/release.md` in this repository for a complete production-grade release workflow that implements this pattern, including: - Semantic version collision detection - Multi-platform binary builds - Microsoft Defender antivirus scanning - SBOM generation (SPDX + CycloneDX) - Build attestation - Manual sync-actions approval gate - Community attribution in release highlights --- description: Guidelines for creating agentic workflows that generate reports — output type selection, formatting style, and automatic cleanup. --- # Report Generation For workflows that generate reports — status updates, audits, summaries — posted as GitHub issues, discussions, or comments. ## Choosing the Output Type | Use case | Recommended output | |---|---| | Report (default) | `create-issue` with `close-older-issues` | | Inline update on an existing issue or PR | `add-comment` with `hide-older-comments` | | Discussion-based report (only when explicitly requested) | `create-discussion` with `close-older-discussions` | Default to `create-issue`. Use `create-discussion` only when the requester explicitly wants threaded async collaboration. ## Automatic Cleanup - **`expires`** — auto-close after a window (e.g. `7`, `2w`, `1m`). - **`close-older-issues: true`** — close previous open issues from the same workflow, matched via an embedded workflow-id marker (no `title-prefix` or `labels` needed). Use `close-older-key` for an explicit dedup key instead of the default workflow-id match. - **`close-older-discussions: true`** — close older matching discussions as "OUTDATED", matched the same way as issues. - **`hide-older-comments: true`** — minimize previous comments. Useful for rolling status updates. **Recommended for recurring reports**: `create-issue` with `close-older-issues: true` and a stable `title-prefix`. ```yaml safe-outputs: create-issue: title-prefix: "Weekly Status:" labels: [report] close-older-issues: true expires: 30 ``` ## Scheduled Report Window Scoping Define the report window explicitly in the prompt so runs are deterministic and comparable. Window examples: - `last 24 full hours ending at workflow start (UTC)` - `last 7 full days ending at workflow start (UTC)` - `since previous successful run timestamp` - `current calendar week to date (UTC, Monday 00:00 to now)` Strategy: fixed durations for trend comparisons, run-based windows for continuous monitoring, calendar windows for stakeholder reporting. Whenever a report window is defined, also fix its grouping dimensions and deduplication key up front (see [Recurring Digest Defaults](#recurring-digest-defaults) below) — a window alone is not sufficient to make a recurring report deterministic and non-duplicating. When the window has no qualifying updates, call `noop` with the evaluated window in the message: `noop("No updates in last 24 full hours ({{window_start_utc}} to {{window_end_utc}})")` ## Recurring Digest Defaults For recurring PM, stakeholder, and information-worker digests, fix all three elements up front — window, grouping dimensions, and deduplication key — before generating the report: | Element | Default guidance | Examples | |---|---|---| | Report window | Closed, explicit UTC window or `since previous successful run` (see above) | `last 7 full days ending at run start (UTC)`, `previous calendar month (UTC)` | | Grouping dimensions | Group by the dimensions the audience already uses to decide | team, area, milestone, owner, severity, status, repository | | Deduplication key | One stable key per scope and window; week-based for weekly, calendar-date for daily/monthly | `pm-digest:platform:2026-W27`, `stakeholder-digest:mobile:2026-07-02` | Duplicate-suppression: search for an existing open issue by the stable key (title prefix or dedicated label) before creating; if one exists, update it with `add-comment` instead of opening a duplicate. Use `create-issue` with `close-older-issues: true` for recurring issue-style digests. ## Fallback for Incomplete Metadata When the digest or report depends on labels, metadata, or classification fields (for example customer-impact labels, priority tiers, team assignments, or area tags) that are absent or inconsistent: - summarize what data *was* available and note which fields are missing - group by the next-best available dimension (for example repository, author, date, or milestone) - use an explicit "Unclassified" bucket for items without required metadata — do not invent or assume classifications - call `noop` only when the reporting window itself has zero events; missing metadata alone is not a reason to skip the report ## Report Style and Structure ### Header Levels - Use `###` (h3) for main sections — e.g., `### Test Summary` - Use `####` (h4) for subsections — e.g., `#### Device-Specific Results` - Never use `##` (h2) or `#` (h1) — those are reserved for titles ### Progressive Disclosure Wrap verbose logs, secondary info, and per-item breakdowns in `
Section Name`. Keep summary, critical issues, and key metrics visible. ### Alerts Instead of Emojis - `> [!NOTE]` — neutral status - `> [!WARNING]` — warnings - `> [!CAUTION]` — high-risk or blocking Do not use emoji severity markers (`✅`, `⚠️`, `❌`, `🧪`). ### Structure Pattern 1. **Overview** — 1–2 paragraphs of key findings 2. **Critical info** — summary stats, critical issues (always visible) 3. **Details** — `
...` for expanded content 4. **Context** — workflow run, date, trigger ### Example Report Structure ```markdown ### Summary - Key metric 1: value - Key metric 2: value > [!WARNING] > Status: degradation detected in one or more checks. ### Critical Issues [Always visible - these are important]
View Detailed Results [Comprehensive details, logs, traces]
View All Warnings [Minor issues and potential problems]
### Recommendations [Actionable next steps - keep visible] ``` ## Workflow Run References - Format run IDs as links: `[§12345](https://github.com/owner/repo/actions/runs/12345)` - Include up to 3 most relevant run URLs at the end under `**References:**` - Do NOT add footer attribution — the system appends it automatically ## Avoiding Mentions and Backlinks Without filtering, `@username` notifies users and `#123` creates backlinks every run. - **`mentions: false`** — escapes all `@mentions`. - **`allowed-github-references: []`** — escapes `#123` / `owner/repo#123`. - **`max-bot-mentions: 0`** — neutralizes bot-trigger phrases like `fixes #123` / `closes #456`. ```yaml safe-outputs: mentions: false allowed-github-references: [] max-bot-mentions: 0 create-issue: title-prefix: "Weekly Status:" labels: [report] close-older-issues: true expires: 30 ``` Applies globally to all safe-output types (issues, comments, discussions). --- description: Imports, shared components, import-schema, and gh aw add/update for GitHub Agentic Workflows --- # Imports & Reusability Shared components eliminate duplication of tool configs, prompts, MCP servers, and safe-output jobs across workflows. Consumers get updates automatically when shared files change. --- ## Merged Fields Only these frontmatter fields are merged on import: | Field | Merge behaviour | |---|---| | `tools:`, `mcp-servers:`, `safe-outputs:`, `network:`, `permissions:`, `runtimes:`, `services:`, `cache:`, `features:` | Deep-merged | | `env:` | Merged; duplicate keys → compile error | | `github-app:`, `on.github-app:` | First-wins across imports | | `steps:`, `pre-agent-steps:`, `post-steps:` | Appended in import order | | `jobs..setup-steps`, `jobs..pre-steps` | For each job, imported steps run first, then main workflow steps; `setup-steps` remains separate from `pre-steps` | | Markdown body | Appended as prompt instructions | All other fields (`on:`, `engine:`, `timeout-minutes:`, …) are ignored in imported files. --- ## `imports:` Field ```yaml # String form imports: - shared/reporting.md - shared/mcp/tavily.md - copilot-setup-steps.yml # merges copilot-setup-steps job steps # Object form — pass values to import-schema: imports: - uses: shared/repo-memory-standard.md with: branch-name: "memory/issue-triage" description: "Issue triage historical data" - path: shared/tool-setup.md with: environment: staging ``` `path`/`uses` and `with`/`inputs` are the only valid keys on an import entry. To supply environment variables or a checkout ref, set top-level `env:`/`checkout:` frontmatter inside the imported file itself; those are merged into the importing workflow (see [syntax-tools-imports.md](syntax-tools-imports.md)). `with:` values are accessed inside the shared file as `${{ github.aw.import-inputs. }}`. --- ## `import-schema:` Field Declare typed parameters consumers supply: ```yaml --- import-schema: branch-name: type: string required: true description: "Branch name for storage (e.g. memory/my-workflow)" max-items: type: number default: 50 description: "Maximum items to retain" environment: type: choice options: [dev, staging, prod] required: true tools: repo-memory: branch-name: ${{ github.aw.import-inputs.branch-name }} --- ``` ### Input types | Type | Notes | |---|---| | `string` | Free-form text | | `number` | Integer or float | | `boolean` | `true` / `false` | | `choice` | Enumerated; must supply `options:` | | `array` | List of values | | `object` | Sub-fields via `${{ github.aw.import-inputs.. }}` | --- ## Refactoring Patterns ### 1 — Extract shared MCP server / tool config `.github/workflows/shared/mcp/tavily.md`: ```markdown --- mcp-servers: tavily: url: "https://mcp.tavily.com/mcp/" env: TAVILY_API_KEY: "${{ secrets.TAVILY_API_KEY }}" allowed: [search, extract] --- ``` Import with one line: ```yaml imports: - shared/mcp/tavily.md ``` ### 2 — Extract shared prompt instructions ```markdown --- --- Keep all output concise. Use bullet points, not paragraphs. Never repeat information already visible in the GitHub UI. ``` ### 3 — Parameterise with `import-schema:` ```markdown --- import-schema: project-key: type: string required: true description: "Jira project key (e.g. ENG, INFRA)" mcp-servers: jira: container: "mcp/jira" version: "latest" env: JIRA_TOKEN: "${{ secrets.JIRA_TOKEN }}" JIRA_PROJECT: ${{ github.aw.import-inputs.project-key }} allowed: [search_issues, get_issue, list_sprints] --- ``` ```yaml imports: - uses: shared/jira-mcp.md with: project-key: "ENG" ``` ### 4 — Compose multiple imports ```yaml --- on: schedule: weekly on monday imports: - shared/mcp/tavily.md - shared/gh.md - shared/reporting.md - uses: shared/repo-memory-standard.md with: branch-name: "memory/weekly-research" description: "Weekly research snapshots" --- Conduct weekly research on ${{ github.repository }} dependencies... ``` ### 5 — Shared safe-output job ```markdown --- import-schema: channel: type: string required: true safe-outputs: jobs: send-slack-notification: description: "Post a message to Slack" runs-on: ubuntu-latest output: "Slack notification sent" inputs: message: description: "Message text" required: true type: string permissions: contents: read steps: - name: Post to Slack uses: actions/github-script@v7 env: SLACK_TOKEN: "${{ secrets.SLACK_TOKEN }}" CHANNEL: ${{ github.aw.import-inputs.channel }} with: script: | // post message to channel --- ``` ```yaml imports: - uses: shared/slack-notify.md with: channel: "#engineering-alerts" ``` --- ## External Imports ### `gh aw add` — Install a remote shared component ```bash gh aw add https://github.com/org/agentics/blob/main/workflows/shared/reporting.md ``` Stored under `.github/aw/imports/org/agentics//`. Reference via that local path. The `source:` field tracks origin for updates. MCP equivalent: `Use the add tool with url: ""` ### `gh aw update` — Refresh all external imports ```bash gh aw update ``` Re-fetches every file under `.github/aw/imports/` using `source:`. Follows `redirect:` and rewrites `source:` automatically. MCP equivalent: `Use the update tool` ### Fields for publishable shared components ```yaml --- source: "org/agentics/workflows/shared/my-component.md@main" redirect: "org/agentics/workflows/shared/my-component-v2.md@main" resources: - shared/mcp/dependency.md # fetched alongside this file private: false # true → prevent gh aw add from sharing import-schema: # ... --- ``` --- ## Recommended Directory Layout ``` .github/ └── workflows/ ├── my-workflow.md ├── my-workflow.lock.yml # auto-generated └── shared/ ├── mcp/ │ ├── tavily.md │ ├── notion.md │ └── github-mcp-app.md ├── reporting.md ├── gh.md ├── keep-it-short.md └── repo-memory-standard.md .github/aw/ └── imports/ # installed via gh aw add └── org/repo// └── workflows_shared_component.md ``` --- ## Compile-Time Behaviour - Imports resolved at **compile time**; `.lock.yml` loads shared `.md` bodies at **runtime** — edits to shared bodies take effect next run without recompile. - **`inlined-imports: true`** — bundles imported content at compile time (required for ruleset status check workflows). Cannot combine with `.github/agents/` file imports. - Changes to the `imports:` list require recompile: `gh aw compile `. - Editing only the *body* of a shared `.md` (not its frontmatter) does **not** require recompile. --- ## Quick Checklist: Extracting a Shared Component 1. Identify the repeated frontmatter block or prompt section 2. Create `.github/workflows/shared/.md` with the content 3. Add `import-schema:` if values differ per consumer 4. Replace duplicates with an `imports:` entry 5. Recompile: `gh aw compile` (or `gh aw compile `) 6. Verify: `gh aw compile --strict` --- description: Safe-output reference for workflow dispatch, code scanning, checks, agent sessions, and assignment operations. --- # Safe Outputs: Automation and Orchestration - `update-discussion:` - Update discussion title, body, or labels ```yaml safe-outputs: update-discussion: title: true # Optional: enable title updates body: true # Optional: enable body updates labels: true # Optional: enable label updates allowed-labels: [status, type] # Optional: restrict to specific labels max: 1 # Optional: max updates (default: 1) target: "*" # Optional: "triggering" (default), "*", or number target-repo: "owner/repo" # Optional: cross-repository ``` - `update-release:` - Update GitHub release descriptions ```yaml safe-outputs: update-release: max: 1 # Optional: max releases (default: 1, max: 10) target-repo: "owner/repo" # Optional: cross-repository github-token: ${{ secrets.GH_AW_UPDATE_RELEASE_TOKEN }} # Optional: custom token ``` Operation types: `replace`, `append`, `prepend`. - `upload-asset:` - Publish files to orphaned git branch (recommended for images/charts/screenshots) ```yaml safe-outputs: upload-asset: branch: "assets/${{ github.workflow }}" # Optional: branch name max-size: 10240 # Optional: max file size in KB (default: 10MB) allowed-exts: [.png, .jpg, .pdf] # Optional: allowed file extensions max: 10 # Optional: max assets (default: 10) ``` Default allowed extensions are common non-executable types; default max file size is 10MB (10240 KB), configurable via `max-size`. **Use this for images, charts, and screenshots that need embeddable URLs in issues/PRs/discussions.** - `upload-artifact:` - Upload files as run-scoped GitHub Actions artifacts (recommended for temporary run artifacts and attachment-style outputs) ```yaml safe-outputs: upload-artifact: max-uploads: 5 # Optional: max upload_artifact tool calls (default: 1, max: 20) retention-days: 7 # Optional: fixed retention period in days (agent cannot override; 1-90; templatable expression supported) skip-archive: false # Optional: fixed skip-archive flag (templatable expression supported); single-file only max-size-bytes: 104857600 # Optional: max bytes per upload (default: 100 MB) allowed-paths: # Optional: glob patterns restricting uploadable paths - "reports/**" - "*.json" filters: # Optional: default include/exclude glob filters include: ["*.json", "*.csv"] exclude: ["*secret*"] defaults: # Optional: default values injected when agent omits a field if-no-files: "ignore" # "error" or "ignore" when no files match (default: "error") ``` Artifacts are run-scoped and auto-cleaned when they expire. Agents call `upload_artifact` with a `name` and `path`. `retention-days` and `skip-archive` are fixed at the workflow level (templatable via expressions); the agent cannot override them. **Use this for temporary downloadable artifacts and attachment-style arbitrary data** (e.g. a comment/issue linking to a generated file bundle). Set `skip-archive: true` to serve downloads as direct files without uncompressing. Use `upload-asset` instead when you need stable embeddable URLs (images/charts in GitHub content). - `dispatch-workflow:` - Trigger other workflows with inputs ```yaml safe-outputs: dispatch-workflow: workflows: [workflow-name] # Required: list of workflow names to allow max: 3 # Optional: max dispatches (default: 1, max: 50) target-repo: org/other-repo # Optional: cross-repo dispatch target (owner/repo or expression) allowed-repos: [org/*] # Optional: allowlist for cross-repo dispatch targets target-ref: main # Optional: ref to dispatch against (overrides caller's GITHUB_REF) allowed-refs: ["release/*"] # Optional: glob allowlist for agent-provided per-call ref overrides (default: caller's ref only) ``` Triggers other agentic workflows using workflow_dispatch. Agent output includes `workflow_name` (without .md extension) and optional `inputs` (key-value pairs). Cross-repo dispatch is supported via `target-repo` plus an `allowed-repos` allowlist; cross-repo targets require a token with `actions: write` on the target repository. - `dispatch-repository:` - Dispatch `repository_dispatch` events to external repositories (experimental) ```yaml safe-outputs: dispatch-repository: trigger_ci: # Tool name (normalized to MCP tool: trigger_ci) description: "Trigger CI in target repo" workflow: ci.yml # Required: target workflow name (for traceability) event_type: ci_trigger # Required: repository_dispatch event_type repository: org/target-repo # Required: target repo (or use allowed_repositories) # allowed_repositories: # Alternative: allow multiple target repos # - org/repo1 # - org/repo2 inputs: # Optional: input schema for agent environment: type: string description: "Deployment environment" required: true max: 1 # Optional: max dispatches (templatable) github-token: ${{ secrets.MY_PAT }} # Optional: override token staged: false # Optional: preview-only mode ``` Accepts both `dispatch-repository` (dash, canonical) and `dispatch_repository` (underscore, deprecated alias). Each key in the config defines a named MCP tool. Requires a token with `repo` scope since `GITHUB_TOKEN` cannot trigger `repository_dispatch` in external repositories. Use `github-token` or set a PAT as `GH_AW_SAFE_OUTPUTS_TOKEN`. **⚠️ Experimental**: Compilation emits a warning when this feature is used. - `call-workflow:` - Call reusable workflows via workflow_call fan-out (orchestrator pattern) ```yaml safe-outputs: call-workflow: workflows: [worker-a, worker-b] # Required: workflow names (without .md) with workflow_call trigger max: 1 # Optional: max calls per run (default: 1, max: 50) github-token: ${{ secrets.TOKEN }} # Optional: token passed to called workflows ``` Array shorthand: `call-workflow: [worker-a, worker-b]` Unlike `dispatch-workflow` (which uses the GitHub Actions API at runtime), `call-workflow` generates static conditional `uses:` jobs at compile time. The agent selects which worker to activate; the compiler validates and wires up all fan-out jobs. Each listed workflow must exist in `.github/workflows/` and declare a `workflow_call` trigger. Use this for orchestrator/dispatcher patterns within the same repository. - `create-code-scanning-alert:` - Generate SARIF security advisories ```yaml safe-outputs: create-code-scanning-alert: max: 50 # Optional: max findings (default: unlimited) driver: "Custom Scanner" # Optional: SARIF tool.driver.name (default: "GitHub Agentic Workflows Security Scanner") github-token: ${{ secrets.MY_TOKEN }} # Optional: override token for security-events:write target-repo: "owner/repo" # Optional: cross-repository allowed-repos: [owner/other] # Optional: additional repos the agent may target via `repo` field ``` Severity levels: error, warning, info, note. - `autofix-code-scanning-alert:` - Add autofixes to code scanning alerts ```yaml safe-outputs: autofix-code-scanning-alert: max: 10 # Optional: max autofixes (default: 10) ``` Provides automated fixes for code scanning alerts. - `create-check-run:` - Create GitHub Check Runs to surface agent analysis results in the PR Checks UI ```yaml safe-outputs: create-check-run: name: "Security Analysis" # Optional: check run name (defaults to workflow name) target: "triggering" # Optional: "triggering" (default), "*" (any PR), or explicit PR number max: 1 # Optional: max check runs per workflow run (default: 1) output: # Optional: static fallback values used when the agent omits the field title: "Pending analysis" # Fallback title (max 256 chars) summary: "Awaiting agent output" # Fallback summary (max 65535 chars) ``` Requires `checks: write` (added automatically). Agents call `create_check_run` with `conclusion` (e.g., `success`, `failure`, `neutral`), `title`, `summary`, and optional `annotations`. Reports structured results (security findings, code quality, test outcomes) directly on commits and PRs. - `create-agent-session:` - Create GitHub Copilot coding agent sessions ```yaml safe-outputs: create-agent-session: base: main # Optional: base branch (defaults to current) target-repo: "owner/repo" # Optional: cross-repository ``` Requires PAT as `COPILOT_GITHUB_TOKEN`. - `assign-to-agent:` - Assign Copilot coding agent to issues ```yaml safe-outputs: assign-to-agent: name: "copilot" # Optional: agent name model: "claude-sonnet-4-5" # Optional: model override custom-agent: "agent-id" # Optional: custom agent ID custom-instructions: "..." # Optional: additional instructions for the agent allowed: [copilot] # Optional: restrict to specific agent names max: 1 # Optional: max assignments (default: 1) target: "*" # Optional: "triggering" (default), "*", or number target-repo: "owner/repo" # Optional: where the issue lives (cross-repository) pull-request-repo: "owner/repo" # Optional: where PR should be created (if different) allowed-pull-request-repos: [owner/repo1] # Optional: additional repos for PR creation base-branch: "develop" # Optional: target branch for PR (default: repo default) ignore-if-error: true # Optional: continue workflow on assignment error (default: false) ``` Requires PAT with elevated permissions as `GH_AW_AGENT_TOKEN`. - `assign-to-user:` - Assign users to issues or pull requests ```yaml safe-outputs: assign-to-user: allowed: [user1, user2] # Optional: restrict to specific users blocked: [copilot, "*[bot]"] # Optional: deny specific users or glob patterns max: 1 # Optional: max assignments (default: 1) target: "*" # Optional: "triggering" (default), "*", or number target-repo: "owner/repo" # Optional: cross-repository unassign-first: true # Optional: unassign all current assignees first (default: false) ``` - `unassign-from-user:` - Remove user assignments from issues or PRs ```yaml safe-outputs: unassign-from-user: allowed: [user1, user2] # Optional: restrict to specific users blocked: [copilot, "*[bot]"] # Optional: deny specific users or glob patterns max: 1 # Optional: max unassignments (default: 1) target: "*" # Optional: "triggering" (default), "*", or number target-repo: "owner/repo" # Optional: cross-repository ``` - `hide-comment:` - Hide comments on issues, PRs, or discussions ```yaml safe-outputs: hide-comment: max: 5 # Optional: max comments to hide (default: 5) allowed-reasons: # Optional: restrict hide reasons - spam - outdated - resolved target-repo: "owner/repo" # Optional: cross-repository discussions: true # Optional: opt-in to discussions:write permission for hiding discussion comments (default: false) ``` Allowed reasons: `spam`, `abuse`, `off_topic`, `outdated`, `resolved`, `low_quality`. - `set-issue-type:` - Set the type of an issue (requires organization-defined issue types) ```yaml safe-outputs: set-issue-type: allowed: [Bug, Feature, Enhancement] # Optional: restrict to specific issue type names target: "triggering" # Optional: "triggering" (default), "*", or number max: 5 # Optional: max operations (default: 5) target-repo: "owner/repo" # Optional: cross-repository ``` Set `allowed` to an empty string `""` to allow clearing the issue type. When `allowed` is omitted, any type name is accepted. - `set-issue-field:` - Set a single issue field value by name/value (avoids the broader update-issue path) ```yaml safe-outputs: set-issue-field: allowed-fields: [Priority, Iteration] # Optional: restrict which issue fields the agent may set (omit/empty = any field; ["*"] explicitly allows all) target: "triggering" # Optional: "triggering" (default), "*", or number max: 5 # Optional: max operations (default: 5) target-repo: "owner/repo" # Optional: cross-repository allowed-repos: [owner/other] # Optional: additional repos agent can target ``` Agent calls `set_issue_field` with `value` plus either `field_name` (preferred) or `field_node_id`. `issue_number` is optional and defaults to the triggering issue. - `approve-workflow-run:` - Approve a pending workflow run in the "action required" state ```yaml safe-outputs: approve-workflow-run: allowed-workflows: [ci.yml] # Required: workflow filenames eligible for approval (no paths) allowed-repos: [org/fork] # Optional: fork repositories allowed for approval (default: current repository only) allowed-pull-requests: ["123"] # Optional: restrict to specific PR numbers protected-files: blocked # Optional: "blocked" (default), "fallback-to-issue", or "allowed" github-token: ${{ secrets.APPROVE_WORKFLOW_RUN_TOKEN }} # Required: external token/app (github.token cannot approve runs requiring approval) ``` Requires `actions: write` (added automatically) plus an external `github-token` or `github-app` — the default `github.token` is not permitted to approve workflow runs requiring approval. - `noop:` - Log completion message for transparency (auto-enabled) ```yaml safe-outputs: noop: report-as-issue: false # Optional: report noop as issue (default: true) ``` Fallback ensuring workflows never complete silently. Agents emit human-visible messages even when no other action is required (e.g., "Analysis complete - no issues found"). - `missing-tool:` - Report missing tools or functionality (auto-enabled) ```yaml safe-outputs: missing-tool: create-issue: true # Optional: create issues for missing tools (default: false when this block is set; auto-enabled as true only when `missing-tool` is omitted) report-as-failure: true # Optional: classify the run as an agent failure (default: true) title-prefix: "[missing tool]" # Optional: prefix for issue titles labels: [tool-request] # Optional: labels for created issues ``` Lets agents report tools or functionality they need but lack; tracks feature requests. When `create-issue` is true, reports create or update GitHub issues. - `missing-data:` - Report missing data required to complete tasks (auto-enabled) ```yaml safe-outputs: missing-data: create-issue: true # Optional: create issues for missing data (default: false when this block is set; auto-enabled as true only when `missing-data` is omitted) report-as-failure: true # Optional: classify the run as an agent failure (default: true) title-prefix: "[missing data]" # Optional: prefix for issue titles labels: [data-request] # Optional: labels for created issues ``` Lets agents report when required data or information is unavailable. When `create-issue` is true, reports create or update GitHub issues for tracking. - `report-incomplete:` - Signal that the task could not be completed due to an infrastructure or tool failure (auto-enabled) ```yaml safe-outputs: report-incomplete: create-issue: true # Optional: create issues for incomplete tasks (default: true) title-prefix: "[incomplete]" # Optional: prefix for issue titles labels: [agent-failure] # Optional: labels for created issues ``` --- description: Safe-output reference for issue, discussion, comment, and pull request content operations. --- # Safe Outputs: GitHub Content - Jira operations are explicitly namespaced and run through Jira Cloud REST API v3: ```yaml safe-outputs: jira-create-issue: max: 1 jira-update-issue: max: 1 jira-add-comment: max: 1 jira-add-label: max: 3 ``` | Frontmatter | Tool | Agent inputs | |---|---|---| | `jira-create-issue` | `jira_create_issue` | `project_key`, `issue_type`, `summary`, optional `description` | | `jira-update-issue` | `jira_update_issue` | `issue_key` and at least one of `summary`, `description` | | `jira-add-comment` | `jira_add_comment` | `issue_key`, `body` | | `jira-add-label` | `jira_add_label` | `issue_key`, `label` | Use the Jira-prefixed tool whenever the target is Jira. Unprefixed issue, comment, and label tools target GitHub. The compiler supplies `JIRA_BASE_URL` and supplies `JIRA_USER_EMAIL` and `JIRA_API_TOKEN` from same-named secrets; `safe-outputs.env` may override them. Description and comment strings are converted to ADF internally. Label addition is additive and preserves existing labels. Each Jira output supports `max` and `staged`; staged mode sends no HTTP request and does not require credentials. Jira update, comment, and label operations require a known issue key. Same-run references to an issue created by `jira_create_issue` are not supported. The initial integration does not provide transitions, assignments, custom fields, label removal, JQL, bulk operations, or arbitrary REST calls. - **[Experimental]** Linear operations use the `LINEAR_API_KEY` secret and run through the Linear GraphQL API: ```yaml safe-outputs: linear-create-issue: max: 1 team-id: "TEAM_ID" project-id: "PROJECT_ID" linear-add-comment: max: 1 linear-update-issue: max: 1 title: true body: true ``` | Frontmatter | Tool | Agent inputs | |---|---|---| | `linear-create-issue` | `linear_create_issue` | `title`, `body` (team and optional project taken from config) | | `linear-add-comment` | `linear_add_comment` | `body` (target issue) | | `linear-update-issue` | `linear_update_issue` | `title`/`body`, gated by the matching `title:`/`body:` config flags | `linear-token:` optionally overrides the `LINEAR_API_KEY` secret and is a top-level `safe-outputs:` field, not nested under `env:`. `linear-create-issue.project-id` optionally fixes created issues to a trusted Linear project identifier from its URL or model UUID. Each output supports `max` and `staged`. Only fields explicitly enabled in `update-issue` config (`title`, `body`) can be changed by the agent. - **[Experimental]** Azure DevOps work-item operations are namespaced `ado-*` and rely on an Azure DevOps MCP server (configured separately under `mcp-servers:`/`tools:`) for the underlying connection and credentials: ```yaml safe-outputs: ado-create-work-item: max: 1 work-item-type: "Bug" ado-update-work-item: max: 1 status: true title: true ado-comment-on-work-item: max: 1 target: "*" ado-assign-work-item: max: 1 ado-link-work-items: max: 5 ado-upload-workitem-attachment: max: 1 ``` | Frontmatter | Tool | Agent inputs | |---|---|---| | `ado-create-work-item` | `ado_create_work_item` | `title`, `description`, optional `tags`, `temporary_id` | | `ado-update-work-item` | `ado_update_work_item` | `id`, plus one of `title`/`body`/`state`/`area_path`/`iteration_path`/`assignee`/`tags` enabled via config | | `ado-comment-on-work-item` | `ado_comment_on_work_item` | `work_item_id`, `body` | | `ado-assign-work-item` | `ado_assign_work_item` | `work_item_id`, `assignee` (checked against `allowed`/`blocked`) | | `ado-link-work-items` | `ado_link_work_items` | `source_id`, `target_id`, `link_type` (checked against `allowed-link-types`) | | `ado-upload-workitem-attachment` | `ado_upload_workitem_attachment` | `work_item_id`, `file_path`, `staged_file` (checked against `max-file-size`/`allowed-extensions`) | `ado-create-work-item` accepts a `temporary_id` (`#aw_xxxx`) so later outputs in the same run can reference a just-created work item. `target:` on update/comment/assign/link/attach constrains which work item IDs are addressable. Config-level allow-lists (`allowed-tags`, `allowed-area-prefixes`, `allowed-iteration-prefixes`, `allowed`, `blocked`, `allowed-link-types`, `allowed-extensions`) gate what the agent can set; unlisted values are rejected. - `create-issue:` - Safe GitHub issue creation (bugs, features) ```yaml safe-outputs: create-issue: title-prefix: "[ai] " # Optional: prefix for issue titles body-footer: "Generated by [{workflow_name}]({run_url})" # Optional: deterministic template appended after the body, even when footer: false labels: [automation, agentic] # Optional: labels to attach to issues allowed-labels: [bug, task] # Optional: restrict which labels the agent can set (any label allowed if omitted) allowed-fields: [Priority, Iteration] # Optional: restrict which issue fields the agent may set via the `fields` runtime parameter (omit/empty = any field; ["*"] explicitly allows all) assignees: [user1, copilot] # Optional: assignees (use 'copilot' for bot) max: 5 # Optional: maximum number of issues (default: 1) expires: 7 # Optional: auto-close after 7 days (supports: 2h, 7d, 2w, 1m, 1y, or false) group: true # Optional: group as sub-issues under a parent issue (default: false) group-by-day: true # Optional: group same-day runs into one issue by posting as comments (default: false) close-older-issues: true # Optional: close previous issues from same workflow (default: false) close-older-key: "my-key" # Optional: explicit deduplication key for close-older matching (uses gh-aw-close-key marker) deduplicate-by-title: true # Optional: skip creating an issue when one with the same title exists; integer N allows fuzzy matches up to edit distance N (default: off) require-temporary-id: true # Optional: require temporary_id on every create_issue call (default: false) normalize-closing-keywords: true # Optional: strip backticks around recognized issue-closing keywords in body text # create_issue output may set blocked_by to an issue reference or list of references footer: false # Optional: omit AI-generated footer while preserving XML markers (default: true) target-repo: "owner/repo" # Optional: cross-repository allowed-repos: [owner/other] # Optional: additional repos agent can target (agent uses `repo` field in output) ``` `create_issue` output validation requires: - `body` minimum length: **20** characters - `body` maximum length: **65000** characters **Auto-Expiration**: The `expires` field auto-closes issues after a time period. Supports integers (days) or relative formats (2h, 7d, 2w, 1m, 1y). Generates `agentics-maintenance.yml` workflow that runs at minimum required frequency based on shortest expiration time: 1 day or less → every 2 hours, 2 days → every 6 hours, 3-4 days → every 12 hours, 5+ days → daily. **Deduplication for Scheduled Workflows**: When `schedule:` is combined with `create-issue`, use `skip-if-match:` in the `on:` block to prevent opening a duplicate issue every run. Pair with `expires:` to clean up stale issues: ```yaml on: schedule: daily on weekdays skip-if-match: 'is:issue is:open in:title "[my-workflow] "' safe-outputs: create-issue: title-prefix: "[my-workflow] " expires: 7 # auto-close after 7 days ``` Without `skip-if-match`, the workflow creates a new issue on every scheduled run even when an identical open issue already exists. For the frequent-schedule variant that serves one item at a time and learns from how the previous issue was closed, see the [All You Can Eat Pattern](workflow-patterns.md#all-you-can-eat-pattern). **Temporary IDs and Sub-Issues:** When creating multiple issues, use `temporary_id` (format: `aw_` + 3-8 alphanumeric chars) to reference parent issues before creation. References like `#aw_abc123` in issue bodies are automatically replaced with actual issue numbers. Use the `parent` field to create sub-issue relationships: ```json {"type": "create_issue", "temporary_id": "aw_abc123", "title": "Parent", "body": "Parent issue"} {"type": "create_issue", "parent": "aw_abc123", "title": "Sub-task", "body": "References #aw_abc123"} ``` **Blocked-By Dependencies:** Set `blocked_by` in `create_issue` output to an issue number, temporary ID, `owner/repo#number` reference, GitHub issue URL, or a list of references. Temporary IDs are resolved before the issue is created, allowing dependent output to be emitted in any order. Attaching a dependency is best-effort: if the dependency API call fails the issue is still reported as created and the failure is logged as a warning. **Setting Issue Fields on Creation**: Agents can include a `fields` array in the `create_issue` output to set custom field values immediately after creation. Each item is `{"name": , "value": }`. Use a number for numeric fields; string for single-select, iteration title, date `YYYY-MM-DD`, or text. Restrict allowed names with `allowed-fields:`. ```json {"type": "create_issue", "title": "Triage: flaky parser", "body": "...", "fields": [{"name": "Priority", "value": "High"}, {"name": "Story Points", "value": 3}]} ``` - `close-issue:` - Close issues with comment (use this to close issues, not update-issue) ```yaml safe-outputs: close-issue: target: "triggering" # Optional: "triggering" (default), "*", or number required-labels: [automated] # Optional: only close if ALL these labels are present required-title-prefix: "[bot]" # Optional: only close matching prefix max: 20 # Optional: max closures (default: 1) state-reason: "not_planned" # Optional: scalar fixes the reason; list lets the agent choose a subset; omit to let the agent choose any of "completed", "not_planned", "duplicate" allow-body: false # Optional: when false, any body the agent emits is dropped (warning logged) and the issue closes without a comment; defaults to true target-repo: "owner/repo" # Optional: cross-repository allowed-repos: [owner/other] # Optional: additional repos agent can close issues in ``` `state-reason` has three config modes: **scalar** (`state-reason: not_planned`) fixes the reason; **list** (`state-reason: [not_planned, duplicate]`) restricts the agent to that subset; **omitted** lets the agent choose any of `completed`, `not_planned`, `duplicate`. In list/omitted modes a `state_reason` enum is injected into the `close_issue` tool schema and the agent's choice is validated at runtime. Set `allow-body: false` to guarantee a clean close with no comment — useful when an earlier `add-comment` step already posted the summary and you want to prevent the agent from duplicating it. To close as a duplicate, the agent emits `duplicate_of` in the `close_issue` output (a bare number, `#N`, `owner/repo#N`, or issue URL) together with `state-reason: duplicate`; this creates a native GitHub duplicate relationship (a `marked_as_duplicate` timeline event) rather than just a comment. - `create-discussion:` - Safe GitHub discussion creation (status, audits, reports, logs) ```yaml safe-outputs: create-discussion: title-prefix: "[ai] " # Optional: prefix for discussion titles category: "General" # Optional: discussion category name, slug, or ID (defaults to first category if not specified) labels: [status] # Optional: labels to attach (used for matching when close-older-discussions is enabled) allowed-labels: [status, audit] # Optional: restrict which labels the agent can set (any label allowed if omitted) max: 3 # Optional: maximum number of discussions (default: 1) close-older-discussions: true # Optional: close older discussions with same prefix/labels (default: false) close-older-key: "my-key" # Optional: explicit deduplication key for close-older matching expires: 7 # Optional: auto-close after 7 days (supports: 2h, 7d, 2w, 1m, 1y, or false) fallback-to-issue: true # Optional: create issue if discussion creation fails (default: true) footer: false # Optional: omit AI-generated footer while preserving XML markers (default: true) min-body-length: 100 # Optional: minimum required body length (default: 64) target-repo: "owner/repo" # Optional: cross-repository allowed-repos: [owner/other] # Optional: additional repos agent can target (agent uses `repo` field in output) ``` `category` accepts name (e.g., "General"), slug (e.g., "general"), or ID (e.g., "DIC_kwDOGFsHUM4BsUn3"); defaults to the first category. Resolution tries ID, then name, then slug. `close-older-discussions: true` closes up to 10 older open discussions matching the same embedded workflow-id marker (or `close-older-key` if set) as "OUTDATED" with a comment linking to the new one. `create_discussion` output validation requires `body` minimum length: **64** characters by default; override with `min-body-length:`. - `close-discussion:` - Close discussions with comment and resolution ```yaml safe-outputs: close-discussion: target: "triggering" # Optional: "triggering" (default), "*", or number required-category: "Ideas" # Optional: only close in category required-labels: [resolved] # Optional: only close if ALL these labels are present required-title-prefix: "[ai]" # Optional: only close matching prefix max: 1 # Optional: max closures (default: 1) allow-body: false # Optional: when false, any body the agent emits is dropped (warning logged) and the discussion closes without a comment; defaults to true target-repo: "owner/repo" # Optional: cross-repository ``` Resolution reasons: `RESOLVED`, `DUPLICATE`, `OUTDATED`, `ANSWERED`. Set `allow-body: false` to close without a comment when a prior `add-comment` step already posted the summary. - `add-comment:` - Safe comment creation on issues/PRs/discussions ```yaml safe-outputs: add-comment: max: 3 # Optional: maximum number of comments (default: 1) target: "*" # Optional: target for comments (default: "triggering") required-labels: [approved] # Optional: ALL of these labels must be present on the issue/PR for the comment to be posted required-title-prefix: "[bot]" # Optional: issue/PR title must start with this prefix allows-comment-ids: ["123456"] # Optional: trusted allowlist of comment IDs the agent may update when target is "*" hide-older-comments: true # Optional: minimize previous comments from same workflow allowed-reasons: [outdated] # Optional: restrict hiding reasons (default: outdated) normalize-closing-keywords: true # Optional: strip backticks around recognized issue-closing keywords in body text discussions: true # Optional: opt-in to discussions:write permission for discussion comments/replies (default: false) issues: true # Optional: set false to exclude issues:write permission (default: true) pull-requests: true # Optional: set false to exclude pull-requests:write permission (default: true) footer: true # Optional: when false, omits visible footer but preserves XML markers (default: true) target-repo: "owner/repo" # Optional: cross-repository allowed-repos: [owner/other] # Optional: additional repos agent can target (agent uses `repo` field in output) ``` **Hide Older Comments**: Set `hide-older-comments: true` to minimize previous comments from the same workflow before posting new ones. Useful for status updates. Allowed reasons: `spam`, `abuse`, `off_topic`, `outdated` (default), `resolved`. **Discussion Thread Replies**: Agents can include `reply_to_id` in their output to post a threaded reply within a GitHub Discussion (requires `discussions: true`): ```json {"type": "add_comment", "body": "Thread reply text", "reply_to_id": 12345} ``` - `comment-memory:` - Persist and update a managed memory comment on the triggering issue/PR. **Configured under `tools:`, not `safe-outputs:`.** ```yaml tools: comment-memory: max: 1 # Optional: max comment_memory updates (default: 1, range: 1-100) target: "triggering" # Optional: "triggering" (default), "*", or explicit issue/PR number memory-id: "default" # Optional: default memory identifier when items omit memory_id (default: "default") footer: true # Optional: include AI footer in the managed comment (default: true) target-repo: "owner/repo" # Optional: cross-repository allowed-repos: [owner/other] # Optional: additional repos agent can target ``` Boolean shorthand: `comment-memory: true` enables defaults; `false` or `null` disables. The handler materializes memory to files before execution and syncs edits back to a single managed comment after, providing durable cross-run state without external storage. See [memory.md](memory.md). - `create-pull-request:` - Safe pull request creation with git patches ```yaml safe-outputs: create-pull-request: title-prefix: "[ai] " # Optional: prefix for PR titles body-footer: "Generated by [{workflow_name}]({run_url})" # Optional: deterministic template appended after the body, even when footer: false require-temporary-id: true # Optional: require temporary_id on every create_pull_request call (default: false) branch-prefix: "signed/" # Optional: prefix prepended to the PR branch name (e.g. for branch-protection conventions) labels: [automation, ai-agent] # Optional: labels to attach to PRs allowed-labels: [bug, fix] # Optional: restrict which labels the agent can set (any label allowed if omitted) reviewers: [user1, copilot] # Optional: reviewers (use 'copilot' for bot) team-reviewers: [platform-team] # Optional: team slugs to assign as reviewers draft: true # Optional: create as draft PR (defaults to true) if-no-changes: "warn" # Optional: "warn" (default), "error", or "ignore" allow-empty: false # Optional: create PR with empty branch, no changes required (default: false) expires: 7 # Optional: auto-close after 7 days (supports: 2h, 7d, 2w, 1m, 1y; min: 2h) auto-merge: squash # Optional: false (default), true, or merge method: squash|merge|rebase base-branch: "vnext" # Optional: base branch for PR (defaults to workflow's branch) preserve-branch-name: true # Optional: skip random salt suffix on agent-specified branch names (default: false) recreate-ref: false # Optional: force-recreate existing remote branch when preserve-branch-name is true (default: false) allow-workflows: false # Optional: add workflows:write permission when allowed-files targets .github/workflows/ paths (default: false; requires github-app) patch-format: "bundle" # Optional: "bundle" (default, preserves merge commits & per-commit metadata) or "am" (git format-patch/am) signed-commits: true # Optional: when true (default), push via createCommitOnBranch GraphQL so GitHub signs commits; set false to use plain git push (required for merge commits) assignees: [user1] # Optional: assignees for fallback issues on PR creation failure fallback-labels: [needs-review] # Optional: labels for fallback issues (defaults to PR labels) fallback-as-issue: false # Optional: when true (default), creates a fallback issue on PR creation failure; on permission errors, the issue includes a one-click link to create the PR via GitHub's compare URL auto-close-issue: false # Optional: when true (default), adds "Fixes #N" closing keyword when triggered from an issue; set to false to prevent auto-closing the triggering issue on merge. Accepts a boolean or GitHub Actions expression. normalize-closing-keywords: true # Optional: strip backticks around recognized issue-closing keywords in PR body text close-older-pull-requests: true # Optional: close previous PRs from same workflow (default: false) close-older-key: "my-key" # Optional: explicit deduplication key for close-older matching target-repo: "owner/repo" # Optional: cross-repository head-repo: "fork-owner/repo" # Optional: head (fork) repository for cross-repository PRs; defaults to target-repo head-github-token: ${{ secrets.HEAD_REPO_PAT }} # Optional: token for branch writes to head-repo when it differs from target-repo github-token-for-extra-empty-commit: ${{ secrets.MY_CI_PAT }} # Optional: PAT or "app" to trigger CI on created PRs allowed-files: # Recommended: always restrict to specific paths or extensions to limit agent scope - "src/**/*.ts" # e.g. restrict to TypeScript source files - "docs/**/*.md" # e.g. restrict to Markdown docs excluded-files: # Optional: glob patterns to strip from the patch entirely - "**/*.lock" protected-files: request-review # Optional: "request-review" (default), "blocked", "fallback-to-issue", or "allowed" allowed-branches: # Optional: glob patterns for allowed source branch names per run - "feature/*" allowed-base-branches: # Optional: glob patterns for allowed base branch overrides per run - "release/*" - "main" max-patch-size: 2048 # Optional: per-output cap on git patch size in KB (overrides global; default: 4096 KB, max: 10240) max-patch-files: 50 # Optional: per-output cap on unique files in the patch (overrides global; default: 100) stacked: true # Optional: allow PRs based on another PR branch from the same run (default: true; set false on GHES without stacked-PR support) ``` **Dynamic Base Branch**: When `allowed-base-branches` is set, the agent can provide a `base` field in its output to override the default base branch for a single run — but only if the value matches one of the configured glob patterns. Without `allowed-base-branches`, only the static `base-branch:` is used. Accepts a literal array or a GitHub Actions expression resolving to a comma-separated list (e.g. `${{ inputs.allowed-base-branches }}`). **Allowed Source Branches**: When `allowed-branches` is set, the branch used for PR creation (agent-provided `branch` or the current checkout branch when omitted) must match one of the configured glob patterns. **File Restrictions**: **Always specify `allowed-files`** — this is the primary guardrail for `create-pull-request`. Scope it to specific file extensions (e.g., `"**/*.md"`, `"**/*.ts"`) or directory paths (e.g., `"src/**"`, `"docs/**"`) matching the workflow's purpose. Omitting `allowed-files` allows the agent to touch any file in the repository, which significantly expands blast radius. Use `excluded-files` to additionally strip specific files (e.g. lock files) from the patch before any checks. The `protected-files` field controls handling of sensitive files (package manifests, CI configs, agent instruction files): `request-review` (default — create the PR but submit a `REQUEST_CHANGES` review so a human approves before merge), `blocked` (hard-block), `fallback-to-issue` (push branch and create a review issue), or `allowed` (no restriction — use only when the workflow is explicitly designed to manage these files). Object form is also supported: `protected-files: { policy: fallback-to-issue, exclude: [AGENTS.md] }`. **Auto-Expiration**: The `expires` field auto-closes PRs after a time period. Supports integers (days) or relative formats (2h, 7d, 2w, 1m, 1y). Minimum duration: 2 hours. Only for same-repo PRs without target-repo. Generates `agentics-maintenance.yml` workflow. **Branch Name Preservation**: Set `preserve-branch-name: true` to skip the random salt suffix on agent-specified branch names. Useful when CI enforces branch naming conventions (e.g., Jira keys in uppercase). Invalid characters are still replaced for security; casing is always preserved. Set `recreate-ref: true` alongside this to force-recreate an existing remote branch (e.g., when a previous PR was already merged into the branch). **Workflow File Changes**: To modify files under `.github/workflows/`, set `allow-workflows: true`. This adds `workflows: write` to the token used for the PR — a permission that requires `safe-outputs.github-app` to be configured, since `GITHUB_TOKEN` cannot hold this permission. **CI Triggering**: By default, PRs created with `GITHUB_TOKEN` do not trigger CI workflow runs. To trigger CI, set `github-token-for-extra-empty-commit` to a PAT with `Contents: Read & Write` permission, or to `"app"` to use the configured GitHub App. Alternatively, set the magic secret `GH_AW_CI_TRIGGER_TOKEN` to a suitable PAT — this is automatically used without requiring explicit configuration in the workflow. - `create-pull-request-review-comment:` - Safe PR review comment creation on code lines ```yaml safe-outputs: create-pull-request-review-comment: max: 3 # Optional: maximum number of review comments (default: 10) side: "RIGHT" # Optional: side of diff ("LEFT" or "RIGHT", default: "RIGHT") target: "*" # Optional: "triggering" (default), "*", or number target-repo: "owner/repo" # Optional: cross-repository ``` - `submit-pull-request-review:` - Submit a PR review with status (APPROVE, REQUEST_CHANGES, COMMENT) ```yaml safe-outputs: submit-pull-request-review: max: 1 # Optional: maximum number of reviews to submit (default: 1) footer: "if-body" # Optional: footer control ("always", "none", "if-body", default: "always") allowed-events: [COMMENT, REQUEST_CHANGES] # Optional: restrict allowed review event types; omit to allow all (APPROVE, COMMENT, REQUEST_CHANGES) supersede-older-reviews: false # Optional: dismiss older same-workflow REQUEST_CHANGES reviews after a replacement is posted (default: false; best-effort, needs workflow markers) ``` **Footer Control**: The `footer` field controls when AI-generated footers appear in the PR review body. Values: `"always"` (default), `"none"`, `"if-body"` (only when body is non-empty). Boolean values supported: `true` → `"always"`, `false` → `"none"`. Useful for clean approval reviews — with `"if-body"`, approvals without explanatory text appear without a footer. - `dismiss-pull-request-review:` - Dismiss a PR review previously submitted by this workflow actor (alias: `dismiss-review`) ```yaml safe-outputs: dismiss-pull-request-review: max: 10 # Optional: maximum number of dismissals (default: 10) target: "triggering" # Optional: "triggering" (default), "*", or number target-repo: "owner/repo" # Optional: cross-repository allowed-repos: [owner/other] # Optional: extra repos where dismissal is allowed ``` Actor-bound: only reviews authored by the current workflow actor can be dismissed. Supports `required-labels` and `required-title-prefix` filters like other PR-targeted outputs. - `reply-to-pull-request-review-comment:` - Reply to existing review comments on PRs ```yaml safe-outputs: reply-to-pull-request-review-comment: max: 10 # Optional: maximum number of replies (default: 10) target-repo: "owner/repo" # Optional: cross-repository footer: "always" # Optional: footer control ("always", "none", "if-body", default: "always") ``` **Footer Control**: The `footer` field controls when AI-generated footers appear. Values: `"always"` (default), `"none"`, `"if-body"` (only when body is non-empty). Boolean values supported: `true` → `"always"`, `false` → `"none"`. - `resolve-pull-request-review-thread:` - Resolve PR review threads after addressing feedback ```yaml safe-outputs: resolve-pull-request-review-thread: max: 10 # Optional: maximum number of threads to resolve (default: 10) target-repo: "owner/repo" # Optional: cross-repository ``` Lets agents resolve review comment threads after addressing feedback. --- description: Safe-output reference for update, label, milestone, project, release, and upload operations. --- # Safe Outputs: Management and Delivery - `update-issue:` - Update issue title, body, labels, assignees, or milestone (NOT for closing - use close-issue instead) ```yaml safe-outputs: update-issue: status: true # Optional: allow updating issue status (open/closed) target: "*" # Optional: target for updates (default: "triggering") title: true # Optional: allow updating issue title body: true # Optional: allow updating issue body required-labels: [approved] # Optional: ALL of these labels must be present on the issue for the update to run max: 3 # Optional: maximum number of issues to update (default: 1) target-repo: "owner/repo" # Optional: cross-repository ``` **Note:** `update-issue` can change status between 'open'/'closed', but use `close-issue` to close with a comment. Use `update-issue` for title, body, labels, assignees, or milestone changes without closing. - `update-pull-request:` - Update PR title or body ```yaml safe-outputs: update-pull-request: title: true # Optional: enable title updates (default: true) body: true # Optional: enable body updates (default: true) operation: "replace" # Optional: "replace" (default), "append", "prepend" update-branch: false # Optional: update PR branch with latest base before updates (default: false) sync-stack: true # Optional: allow stacked-PR stack-sync fallback when update-branch is unsupported (default: true) max: 1 # Optional: max updates (default: 1) target: "*" # Optional: "triggering" (default), "*", or number target-repo: "owner/repo" # Optional: cross-repository ``` Operation types: `replace` (default), `append`, `prepend`. - `merge-pull-request:` - Merge pull requests under configured policy gates (experimental) ```yaml safe-outputs: merge-pull-request: required-labels: [ready-to-merge] # Optional: ALL listed labels must be present on the PR required-title-prefix: "[bot] " # Optional: only merge PRs with this title prefix allowed-branches: ["feature/*"] # Optional: glob patterns for allowed source branch names target: "triggering" # Optional: "triggering" (default, current PR) or "*" (any PR with pull_request_number) target-repo: "owner/repo" # Optional: cross-repository allowed-repos: [owner/other] # Optional: additional repos the agent can merge in max: 1 # Optional: max merges (default: 1) ``` **⚠️ Experimental**: Compilation emits a warning when this feature is used. The merge is blocked unless all configured gates pass. - `close-pull-request:` - Safe pull request closing with filtering ```yaml safe-outputs: close-pull-request: required-labels: [test, automated] # Optional: only close PRs with these labels required-title-prefix: "[bot]" # Optional: only close PRs with this title prefix allow-body: false # Optional: when false, any body the agent emits is dropped (warning logged) and the PR closes without a comment; defaults to true target: "triggering" # Optional: "triggering" (default), "*" (any PR), or explicit PR number max: 10 # Optional: maximum number of PRs to close (default: 1) target-repo: "owner/repo" # Optional: cross-repository github-token: ${{ secrets.CUSTOM_TOKEN }} # Optional: custom token ``` - `mark-pull-request-as-ready-for-review:` - Mark draft PRs as ready for review ```yaml safe-outputs: mark-pull-request-as-ready-for-review: max: 1 # Optional: max operations (default: 1) target: "*" # Optional: "triggering" (default), "*", or number required-labels: [automated] # Optional: only mark PRs with these labels required-title-prefix: "[bot]" # Optional: only mark PRs with this prefix target-repo: "owner/repo" # Optional: cross-repository ``` - `add-labels:` - Safe label addition to issues or PRs ```yaml safe-outputs: add-labels: allowed: [bug, enhancement, documentation] # Optional: restrict to specific labels blocked: ["~*", "*[bot]"] # Optional: blocked label patterns (glob; takes precedence over allowed) required-labels: [approved] # Optional: ALL of these labels must be present on the issue/PR for the operation to run required-title-prefix: "[bot]" # Optional: issue/PR title must start with this prefix issues: true # Optional: set false to exclude issues:write permission (default: true) pull-requests: true # Optional: set false to exclude pull-requests:write permission (default: true) max: 5 # Optional: maximum number of labels (default: 5) target: "*" # Optional: "triggering" (default), "*" (any issue/PR), or number target-repo: "owner/repo" # Optional: cross-repository ``` - `remove-labels:` - Safe label removal from issues or PRs ```yaml safe-outputs: remove-labels: allowed: [automated, stale] # Optional: restrict to specific labels blocked: ["~*", "*[bot]"] # Optional: blocked label patterns (glob; takes precedence over allowed) required-labels: [approved] # Optional: ALL of these labels must be present on the issue/PR for the operation to run required-title-prefix: "[bot]" # Optional: issue/PR title must start with this prefix max: 5 # Optional: maximum number of operations (default: 5) target: "*" # Optional: "triggering" (default), "*" (any issue/PR), or number target-repo: "owner/repo" # Optional: cross-repository ``` When `allowed` is omitted, any labels can be removed. - `replace-label:` - Atomic label state transition — removes one label and adds another in a single GraphQL request, eliminating the race window of separate remove + add operations ```yaml safe-outputs: replace-label: allowed-add: [approved, done] # Optional: glob patterns for labels that may be added (any allowed if omitted) allowed-remove: [in-review, pending] # Optional: glob patterns for labels that may be removed (any allowed if omitted) blocked: ["~*", "*[bot]"] # Optional: blocked label patterns (glob; applies to both add and remove) required-labels: [triage] # Optional: ALL of these labels must be present on the issue/PR for the operation to run required-title-prefix: "[Bug]" # Optional: issue/PR title must start with this prefix max: 5 # Optional: maximum number of replacements (default: 5) target: "triggering" # Optional: "triggering" (default), "*" (any issue/PR), or number target-repo: "owner/repo" # Optional: cross-repository ``` The agent calls `replace_label(label_to_remove, label_to_add)`. If the label to remove is not present on the item, only the add is applied (no failure). Labels that do not yet exist in the repository are auto-created with a deterministic pastel color. - `add-reviewer:` - Add reviewers to pull requests ```yaml safe-outputs: add-reviewer: allowed-reviewers: [user1, copilot] # Optional: restrict to specific reviewer usernames (any allowed if omitted) allowed-team-reviewers: [platform-team] # Optional: restrict to specific team slugs (any allowed if omitted) max: 3 # Optional: max reviewers (default: 3) target: "*" # Optional: "triggering" (default), "*", or number target-repo: "owner/repo" # Optional: cross-repository ``` At least one reviewer or team reviewer must be present in agent output. Use `allowed-reviewers: [copilot]` to assign Copilot PR reviewer bot. Requires PAT as `COPILOT_GITHUB_TOKEN`. The legacy `reviewers` / `team-reviewers` field names are deprecated aliases. - `assign-milestone:` - Assign issues to milestones ```yaml safe-outputs: assign-milestone: allowed: [v1.0, v2.0] # Optional: restrict to specific milestone titles auto_create: true # Optional: auto-create milestones from the allowed list if missing (default: false) max: 1 # Optional: max assignments (default: 1) target-repo: "owner/repo" # Optional: cross-repository ``` - `link-sub-issue:` - Safe sub-issue linking ```yaml safe-outputs: link-sub-issue: parent-required-labels: [epic] # Optional: parent must have these labels parent-title-prefix: "[Epic]" # Optional: parent must match this prefix sub-required-labels: [task] # Optional: sub-issue must have these labels sub-title-prefix: "[Task]" # Optional: sub-issue must match this prefix max: 5 # Optional: maximum number of links (default: 5) target-repo: "owner/repo" # Optional: cross-repository ``` Links issues via GitHub's parent-child relationships. Agent output includes `parent_issue_number` and `sub_issue_number`. Use with `create-issue` temporary IDs or existing issue numbers. - `create-project:` - Create a new GitHub Project board with optional fields and views ```yaml safe-outputs: create-project: max: 1 # Optional: max projects (default: 1) # github-token: ${{ secrets.GH_AW_PROJECT_GITHUB_TOKEN }} # Optional: override default PAT (NOT GITHUB_TOKEN) target-owner: "org-or-user" # Optional: owner for created projects title-prefix: "[ai] " # Optional: prefix for project titles ``` Optionally specify custom fields, project views, and an initial item. Requires PAT/App token with Projects permissions (`GH_AW_PROJECT_GITHUB_TOKEN`); `GITHUB_TOKEN` cannot access Projects v2 API. No cross-repository support. - `update-project:` - Add items to GitHub Projects, update custom fields, manage project structure ```yaml safe-outputs: update-project: max: 20 # Optional: max project operations (default: 10) project: "https://github.com/orgs/myorg/projects/42" # REQUIRED in agent output (full URL) # github-token: ${{ secrets.GH_AW_PROJECT_GITHUB_TOKEN }} # Optional here if GH_AW_PROJECT_GITHUB_TOKEN is set; PAT with projects:write (NOT GITHUB_TOKEN) is still required ``` **⚠️**: Agent must include full project URL (not just number) in every call. Requires PAT/App token with Projects access (same as `create-project:`). Not supported for cross-repository operations. **Three calling modes:** **Mode 1: Add/update existing issues or PRs** ```json { "type": "update_project", "project": "https://github.com/orgs/myorg/projects/42", "content_type": "issue", "content_number": 123, "fields": {"Status": "In Progress", "Priority": "High"} } ``` - `content_type`: "issue" or "pull_request" - `content_number`: The issue or PR number to add/update - `fields`: Custom field values to set on the item (optional) **Mode 2: Create draft issues in the project** ```json { "type": "update_project", "project": "https://github.com/orgs/myorg/projects/42", "content_type": "draft_issue", "draft_title": "Follow-up: investigate performance", "draft_body": "Check memory usage under load", "temporary_id": "aw_abc123def456", "fields": {"Status": "Backlog"} } ``` - `content_type`: "draft_issue" - `draft_title`: Title of the draft issue (required when creating new) - `draft_body`: Description in markdown (optional) - `temporary_id`: Unique ID for this draft (format: `aw_` + 3-8 alphanumeric chars) for referencing in future updates (optional) - `draft_issue_id`: Reference an existing draft by its temporary_id to update it (optional) - `fields`: Custom field values (optional) **Mode 3: Create custom fields or views** (with `operation` field) ```json { "type": "update_project", "project": "https://github.com/orgs/myorg/projects/42", "operation": "create_fields", "field_definitions": [ {"name": "Priority", "data_type": "SINGLE_SELECT", "options": ["High", "Medium", "Low"]}, {"name": "Due Date", "data_type": "DATE"} ] } ``` - `operation`: "create_fields" or "create_view" - `field_definitions`: Array of field definitions (for create_fields) - `view`: View configuration object with `name`, `layout` (table/board/roadmap), optional `filter` and `visible_fields` (for create_view) Not supported for cross-repository operations. - `create-project-status-update:` - Post status updates to GitHub Projects for progress tracking ```yaml safe-outputs: create-project-status-update: max: 1 # Optional: max status updates (default: 1) project: "https://github.com/orgs/myorg/projects/42" # REQUIRED in agent output (full URL) github-token: ${{ secrets.GH_AW_PROJECT_GITHUB_TOKEN }} # REQUIRED: PAT with projects:write (NOT GITHUB_TOKEN) ``` Requires same PAT/App token as `update-project`. Agent must include full project URL in every call. **Agent output fields:** - `project`: Full project URL (required) - MUST be explicitly included in output - `status`: ON_TRACK, AT_RISK, OFF_TRACK, COMPLETE, or INACTIVE (optional, defaults to ON_TRACK) - `start_date`: Project start date in YYYY-MM-DD format (optional) - `target_date`: Project end date in YYYY-MM-DD format (optional) - `body`: Status summary in markdown (required) Not supported for cross-repository operations. - `push-to-pull-request-branch:` - Push changes to PR branch ```yaml safe-outputs: push-to-pull-request-branch: target: "*" # Optional: "triggering" (default), "*", or number title-prefix: "[bot] " # Optional: require title prefix required-labels: [automated] # Optional: require all labels base-branch: "main" # Optional: base branch for incremental patch computation (defaults to resolving from checkout/repo default branch) target-repo: "owner/repo" # Optional: cross-repository push target head-repo: "fork-owner/repo" # Optional: head (fork) repository for cross-repository pushes; defaults to target-repo head-github-token: ${{ secrets.HEAD_REPO_PAT }} # Optional: token for branch writes to head-repo when it differs from target-repo allowed-repos: [owner/other] # Optional: additional repos the agent can target if-no-changes: "warn" # Optional: "warn" (default), "error", or "ignore" ignore-missing-branch-failure: false # Optional: treat deleted PR branches as skipped pushes (default: false) commit-title-suffix: "[auto]" # Optional: suffix appended to commit title staged: true # Optional: preview mode (default: follows global staged) github-token-for-extra-empty-commit: ${{ secrets.MY_CI_PAT }} # Optional: PAT or "app" to trigger CI on pushed commits fallback-as-pull-request: true # Optional: when push fails (e.g. diverged branch), open a fallback PR targeting the original branch (default: true) patch-format: "bundle" # Optional: "bundle" (default, supports merge commits) or "am"; auto-falls back to "bundle" when the incremental range contains a merge commit signed-commits: true # Optional: when true (default), push via createCommitOnBranch GraphQL so GitHub signs commits; set false to push merge commits via plain git push allow-workflows: false # Optional: add workflows:write permission for .github/workflows/ paths (requires github-app) check-branch-protection: true # Optional: when true (default), pre-flight check branch protection; set false to skip and avoid administration:read permission allowed-files: # Recommended: always restrict to specific paths or extensions to limit agent scope - "src/**" excluded-files: # Optional: glob patterns to strip from the patch entirely - "**/*.lock" protected-files: request-review # Optional: "request-review" (default), "blocked", "fallback-to-issue", or "allowed" max-patch-size: 2048 # Optional: per-output cap on git patch size in KB (overrides global; default: 4096 KB, max: 10240) ``` Cross-repository pushes are supported via `target-repo` (and `head-repo`/`head-github-token` for fork-backed PRs) plus an `allowed-repos` allowlist. To trigger CI on pushed commits, use `github-token-for-extra-empty-commit` or set the magic secret `GH_AW_CI_TRIGGER_TOKEN`. **File Restrictions**: Same as `create-pull-request`: **always specify `allowed-files`** scoped to specific file extensions or paths to limit the agent's reach. `excluded-files` strips files before all checks, and `protected-files` controls handling of sensitive files. Object form supported: `protected-files: { policy: fallback-to-issue, exclude: [AGENTS.md] }`. `push-to-pull-request-branch` now uses the same `request-review` default as `create-pull-request`. Protected-file changes are still surfaced in the PR as a `REQUEST_CHANGES` review, while `blocked` remains available when a workflow requires a hard failure. `CHANGELOG.md` is excluded from the PR handlers' default protected-file set so routine release updates do not require an explicit exception; other shared handlers continue to protect it. **Compile-time warnings for `target: "*"`**: When `target: "*"` is set, the compiler emits warnings if: 1. The checkout configuration does not include a wildcard fetch pattern — add `fetch: ["*"]` with `fetch-depth: 0` so the agent can access all PR branches at runtime 2. No constraints are provided — add `title-prefix` or `required-labels` to restrict which PRs can receive pushes Example with all recommended settings: ```yaml checkout: fetch: ["*"] fetch-depth: 0 safe-outputs: push-to-pull-request-branch: target: "*" required-title-prefix: "[bot] " # restrict to PRs with this title prefix --- description: Safe-output reference for runtime defaults, custom jobs, scripts, actions, global configuration, and output variables. --- # Safe Outputs: Runtime and Extensibility See [jobs.md](jobs.md) for the full compiler-generated job graph and which job each credential (`github-token`, `github-app`) configures. The `report-incomplete` safe-output is enabled by default and is distinct from `noop`. Use it when required tools or data are unavailable and the task cannot be meaningfully performed (e.g., MCP server crash, missing authentication, inaccessible repository). When an agent emits `report_incomplete`, gh-aw activates failure handling even when the agent process exits 0 — preventing empty outputs from being classified as successful, so every unrecoverable failure is tracked. **Per-handler modifiers** — most handlers accept `max`, `github-token`, `github-app`, and `staged` to override the global equivalents for that one output type. Two extras: - `issue-intent:` (boolean) on `close-issue`, `set-issue-type`, `set-issue-field`, `assign-to-user`, and `assign-to-agent` — enables issue-intent metadata (rationale/confidence/suggest) fields and their schema requirements on that tool's payload. - `normalize-closing-keywords:` (boolean) on body-carrying handlers (`create-issue`, `add-comment`, `create-pull-request`, …) — strips backticks around recognized issue-closing keywords so they stay active. - `jobs:` - Custom safe-output jobs registered as MCP tools for third-party integrations ```yaml safe-outputs: jobs: send-notification: description: "Send a notification to an external service" runs-on: ubuntu-latest output: "Notification sent successfully!" inputs: message: description: "The message to send" required: true type: string permissions: contents: read env: API_KEY: ${{ secrets.API_KEY }} steps: - name: Send notification run: | MESSAGE=$(cat "$GH_AW_AGENT_OUTPUT" | jq -r '.items[] | select(.type == "send_notification") | .message') curl -H "Authorization: $API_KEY" -d "$MESSAGE" https://api.example.com/notify ``` Post-processing GitHub Actions jobs registered as MCP tools. Agents call the tool by its normalized name (dashes → underscores, e.g., `send_notification`). The job runs after the agent completes with access to `$GH_AW_AGENT_OUTPUT` (agent output JSON path). Use to integrate Slack, Discord, external APIs, databases, or any service requiring secrets. Import from shared files via `imports:`. - `scripts:` - Inline JavaScript handlers running inside the safe-outputs job handler loop ```yaml safe-outputs: scripts: post-slack-message: description: "Post a message to Slack" inputs: channel: description: "Target Slack channel" type: string default: "#general" script: | // 'channel' is available from config inputs; 'item' contains runtime message values await fetch(process.env.SLACK_WEBHOOK_URL, { method: "POST", body: JSON.stringify({ text: item.message, channel }) }); ``` Unlike `jobs:` (which create separate GitHub Actions jobs), scripts execute in-process alongside built-in handlers. Write only the handler body — the compiler generates the outer wrapper with config input destructuring and `async function handleX(item, resolvedTemporaryIds) { ... }`. Script names with dashes are normalized to underscores (e.g., `post-slack-message` → `post_slack_message`). The handler receives `item` (runtime message with input values) and `resolvedTemporaryIds` (map of temporary IDs). - `actions:` - Custom GitHub Actions mounted as MCP tools for the AI agent (resolved at compile time) ```yaml safe-outputs: actions: my-action: uses: owner/repo/path@ref # Required: GitHub Action reference (tag, SHA, or branch) description: "Custom description" # Optional: override action's description from action.yml env: API_KEY: ${{ secrets.API_KEY }} # Optional: environment variables for the injected step ``` Resolved at compile time — the compiler fetches `action.yml`, parses inputs, and exposes them as MCP tool parameters. The agent calls the action by its normalized name (dashes → underscores). Each action runs as an injected step in the safe-outputs job. Local actions (`./path/to/action`) are also supported. **Global Safe Output Configuration:** - `github-token:` - Custom GitHub token for all safe output jobs ```yaml safe-outputs: create-issue: add-comment: github-token: ${{ secrets.GH_AW_SAFE_OUTPUTS_TOKEN }} # Use custom PAT instead of GITHUB_TOKEN ``` Useful when you need additional permissions or want to perform actions across repositories. - `urls:` - URL sanitization policy for safe output content (string) - `allowed-only` (default) - sanitize all non-allowed URLs everywhere - `allowed-or-code-region` - preserve URLs inside fenced and inline code regions while sanitizing prose - `allowed-domains:` - Allowed domains for URLs in safe output content (array) - URLs from unlisted domains are replaced with `(redacted)` - GitHub domains are always included by default - `data:` - Structured data configuration for body-based safe outputs (boolean, object, or GitHub Actions expression) - Applies to `create-issue`, `add-comment`, `create-pull-request`, `create-pull-request-review-comment`, `submit-pull-request-review`, and `reply-to-pull-request-review-comment` - `false` or omitted (default) - no structured `data` field accepted - `true` - accept any object as the `data` field alongside `body` - Inline schema object - enforce shape; supports full JSON Schema keywords (`type`, `properties`, `required`, `items`, `enum`, etc.) or shorthand (`{ verdict: string, score: number }`) - `${{ ... }}` expression - resolves to one of the above at runtime - Example: ```yaml safe-outputs: data: verdict: string score: number add-comment: ``` - `allowed-github-references:` - Allowed repositories for GitHub-style references (array) - Controls which GitHub references (`#123`, `owner/repo#456`) are allowed in workflow output - References to unlisted repositories are escaped with backticks to prevent timeline items - Configuration options: - `[]` - Escape all references (prevents all timeline items) - `["repo"]` - Allow only the target repository's references - `["repo", "owner/other-repo"]` - Allow specific repositories - Not specified (default) - All references allowed - Example: ```yaml safe-outputs: allowed-github-references: [] # Escape all references create-issue: target-repo: "my-org/main-repo" ``` With `[]`, references like `#123` become `` `#123` `` and `other/repo#456` becomes `` `other/repo#456` ``, preventing timeline clutter while preserving information. - `messages:` - Custom message templates for safe-output footer and notification messages (object) - Available placeholders: `{workflow_name}`, `{run_url}`, `{agentic_workflow_url}`, `{triggering_number}`, `{triggering_type}`, `{workflow_source}`, `{workflow_source_url}`, `{operation}`, `{event_type}`, `{status}`, `{ai_credits}`, `{ai_credits_formatted}`, `{ai_credits_suffix}` - Message types: - `footer:` - Custom footer for AI-generated content - `footer-install:` - Installation instructions appended to footer - `footer-workflow-recompile:` - Footer for workflow recompile tracking issues (placeholder: `{repository}`) - `footer-workflow-recompile-comment:` - Footer for comments on workflow recompile issues (placeholder: `{repository}`) - `run-started:` - Workflow activation notification - `run-success:` - Successful completion message - `run-failure:` - Failure notification message - `detection-failure:` - Detection job failure message - `agent-failure-issue:` - Footer for agent failure tracking issues - `agent-failure-comment:` - Footer for comments on agent failure tracking issues - `staged-title:` - Staged mode preview title - `staged-description:` - Staged mode preview description - `append-only-comments:` - Create new comments instead of editing existing ones (boolean, default: false) - `pull-request-created:` - Custom message when a PR is created. Placeholders: `{item_number}`, `{item_url}` - `issue-created:` - Custom message when an issue is created. Placeholders: `{item_number}`, `{item_url}` - `commit-pushed:` - Custom message when a commit is pushed. Placeholders: `{commit_sha}`, `{short_sha}`, `{commit_url}` - `body-header:` - Custom header text prepended to every message body (issues, comments, PRs, discussions). Placeholders: `{workflow_name}`, `{run_url}` - `disclosure-header:` - AI authorship disclosure header prepended to every message body. Set to `"true"` for built-in default text, or provide a custom template string. Placeholders: `{workflow_name}`, `{run_url}` - Example: ```yaml safe-outputs: messages: append-only-comments: true footer: "> Generated by [{workflow_name}]({run_url})" run-started: "[{workflow_name}]({run_url}) started processing this {event_type}." ``` - `mentions:` - Configuration for @mention filtering in safe outputs (boolean or object) - Boolean format: `false` - Always escape mentions; `true` - Always allow (error in strict mode) - Object format for fine-grained control: ```yaml safe-outputs: mentions: allowed-collaborators: true # Allow repository collaborators (default: true; `allow-team-members` is a deprecated alias) allow-context: true # Allow mentions from event context (default: true) allowed: [copilot, user1] # Always allow specific users/bots allowed-teams: # Allow all members of named GitHub teams - myorg/eng # org/team-slug format (cross-org) - reviewers # bare team-slug (uses current repo's org) max: 50 # Maximum mentions per message (default: 50) ``` - Team members include collaborators with any permission level (excluding bots unless explicitly listed) - Context mentions include issue/PR authors, assignees, and commenters - `allowed-teams` resolves team membership from the GitHub API at runtime; bot accounts are excluded. Use `org/team-slug` for cross-org teams or a bare `team-slug` to resolve against the current repository's organization. - **`allowed-teams` requires `read:org` scope.** The default `GITHUB_TOKEN` does **not** include this scope. Provide a classic PAT with `read:org`, a fine-grained PAT with the "Members" permission (read), or a GitHub App installation token with the "Members" permission (read) via `safe-outputs.github-token:` or `safe-outputs.github-app:`. If the token lacks the required scope, team lookup fails with a warning and the workflow continues without those team members in the allowlist. - `runs-on:` - Runner specification for all safe-outputs jobs (string) - Defaults to `ubuntu-slim` (1-vCPU runner) - Examples: `ubuntu-latest`, `windows-latest`, `self-hosted` - Applies to activation, create-issue, add-comment, and other safe-output jobs - `footer:` - Global footer control for all safe outputs (boolean, default: `true`) - When `false`, omits visible AI-generated footer content from all created/updated entities (issues, PRs, discussions, releases) while still including XML markers for searchability - Individual safe-output types can override this setting - `staged:` - Preview mode for all safe outputs (boolean) - When `true`, emits step summary messages instead of making GitHub API calls; useful for testing without side effects - `env:` - Environment variables passed to all safe output jobs (object) - Values typically reference secrets: `MY_VAR: ${{ secrets.MY_SECRET }}` - `steps:` - Custom steps injected into all safe-output jobs, running after repository checkout and before safe-output code (array) - Useful for installing dependencies or performing setup needed by safe-output logic - Example: ```yaml safe-outputs: steps: - name: Install custom dependencies run: npm install my-package create-issue: ``` - `steer:` - **Experimental.** Create a run-scoped issue during activation, before the agent starts, so users can steer the run via comments containing the keyword `steer` (boolean, default: `false`) - Requires top-level `issues: read` permission (compiler errors instead of auto-adding it) and enables the GitHub MCP issues toolset for comment reads - Activation/conclusion jobs need `issues: write` through the global `github-token` or `github-app` safe-output credential; on success the conclusion job closes the issue and links a created PR, on failure it retitles and updates the same issue instead of creating a second one - Cannot be combined with `failure-issue-repo`; no steering issue is created in staged mode - `max-bot-mentions:` - Maximum bot trigger references (e.g. `@copilot`, `@github-actions`) allowed in output before all excess are escaped with backticks (integer or expression, default: 10) - Set to `0` to escape all bot trigger phrases - Example: `max-bot-mentions: 3` - `activation-comments:` - Disable all activation and fallback comments (boolean or expression, default: `true`) - When `false`, disables run-started, run-success, run-failure, and PR/issue creation link comments - Supports templatable boolean: `false`, `true`, or GitHub Actions expressions like `${{ inputs.activation-comments }}` **Templatable Integer Fields**: The `max`, `expires`, and `max-bot-mentions` fields (and most other numeric/boolean fields) accept GitHub Actions expression strings in addition to literal values, enabling runtime-configured limits: ```yaml safe-outputs: max-bot-mentions: ${{ inputs.max-mentions }} create-issue: max: ${{ inputs.max-issues }} expires: ${{ inputs.expires-days }} ``` Fields that influence permission computation (`add-comment.discussions`, `hide-comment.discussions`, `create-pull-request.fallback-as-issue`) remain literal booleans. - `timeout-minutes:` - Timeout for the safe-outputs job in minutes (integer, default: `45`) - Increase for workflows with many sequential safe-output operations (e.g. `push-to-pull-request-branch` against large repositories) - `max-patch-size:` - Maximum allowed git patch size in kilobytes (integer, default: 4096 KB = 4 MB) - Patches exceeding this size are rejected to prevent accidental large changes - `max-patch-files:` - Maximum allowed number of unique files in a create-pull-request patch (integer, default: 100) - Counts unique file paths deduplicated across multi-commit patches; reflects how many distinct files the agent is pushing per iteration - Increase this limit for long-running branches that touch many files - `group-reports:` - Group workflow failure reports as sub-issues (boolean, default: `false`) - When `true`, creates a parent `[aw] Failed runs` issue that tracks all workflow failures as sub-issues; useful for larger repositories - `report-failure-as-issue:` - Control whether workflow failures are reported as GitHub issues (boolean, expression, or category array; default: `true`) - When `false`, suppresses automatic failure issue creation for this workflow - Supports templatable boolean expressions, e.g. `report-failure-as-issue: ${{ inputs.report-failure-as-issue }}` - Use to silence noisy failure reports for workflows where failures are expected or handled externally - `failure-issue-repo:` - Repository to create failure tracking issues in (string, format: `"owner/repo"`) - Defaults to the current repository when not specified - Use when the current repository has issues disabled: `failure-issue-repo: "myorg/infra-alerts"` - `report-failed-jobs:` - Controls whether failed non-builtin jobs (custom `jobs:` entries) are reported as issues (boolean, default: `true`) - Set to `false` to disable failure-issue creation for custom job failures while keeping agent-failure reporting - `id-token:` - Override the id-token permission for the safe-outputs job (string: `"write"` or `"none"`) - `"write"`: force-enable `id-token: write` permission (required for OIDC authentication with cloud providers) - `"none"`: suppress automatic detection and prevent adding `id-token: write` even when vault/OIDC actions are detected in steps - Default: auto-detects known OIDC/vault actions (e.g., `aws-actions/configure-aws-credentials`, `azure/login`, `hashicorp/vault-action`) and adds `id-token: write` automatically - `concurrency-group:` - Concurrency group for the safe-outputs job (string) - When set, the safe-outputs job uses this concurrency group with `cancel-in-progress: false` - Supports GitHub Actions expressions, e.g., `"safe-outputs-${{ github.repository }}"` - `needs:` - Additional custom workflow jobs the safe-outputs job depends on (array) - Example: `needs: [secrets_fetcher]` - Use when the safe-outputs job requires outputs from a custom job defined in `jobs:` - `environment:` - Override the GitHub deployment environment for the safe-outputs job (string) - Defaults to the top-level `environment:` field when not specified - Use when the main job and safe-outputs job need different deployment environments for protection rules - `github-app:` - GitHub App credentials for minting installation access tokens (object) - When configured, generates a token from the app and uses it for all safe output operations (alternative to `github-token`) - Fields: - `client-id:` - GitHub App client ID (required, e.g., `${{ vars.APP_ID }}`). Use `app-id:` for legacy compatibility. - `private-key:` - GitHub App private key (required, e.g., `${{ secrets.APP_PRIVATE_KEY }}`) - `owner:` - Optional App installation owner (defaults to current repository owner) - `repositories:` - Optional list of repositories to grant access to - `ignore-if-missing:` - When `true`, skip token minting instead of failing when `client-id`/`private-key` resolve empty (boolean, default: `false`) - `permissions:` - Optional map of extra `permission-*` fields to merge into the minted token - Example: ```yaml safe-outputs: github-app: client-id: ${{ vars.APP_ID }} private-key: ${{ secrets.APP_PRIVATE_KEY }} create-issue: ``` - `threat-detection:` - Threat detection configuration (auto-enabled for all safe-outputs workflows) - Automatically enabled by default; customizable via explicit configuration - Fields: - `enabled:` - Enable/disable threat detection (boolean or expression, default: `true`) - `prompt:` - Additional instructions appended to threat detection analysis (string) - `engine:` - AI engine for threat detection (engine config or `false` to disable AI detection) - `steps:` - Extra job steps to run before engine execution (array) - `post-steps:` - Extra job steps to run after engine execution (array) - `max-ai-credits:` - Per-run AIC budget for the detection engine (numeric only, no expressions; default `${{ vars.GH_AW_DEFAULT_DETECTION_MAX_AI_CREDITS || '400' }}`) - `runs-on:` - Runner override for the detection job (defaults to `agent.runs-on`) - `continue-on-error:` - When `true` (default), detection failures emit a warning and proceed with a `needs-review` label; when `false`, failures block safe outputs (boolean or expression) - Example to disable AI-based detection (use custom steps only): ```yaml safe-outputs: threat-detection: engine: false steps: - name: Custom check run: echo "Custom threat check" ``` ## Output Variables The safe-outputs job emits named step outputs for the first successful result of each type: | Safe Output | Step Output Variables | |---|---| | `create-issue` | `created_issue_number`, `created_issue_url` | | `create-pull-request` | `created_pr_number`, `created_pr_url` | | `add-comment` | `comment_id`, `comment_url` | | `push-to-pull-request-branch` | `push_commit_sha`, `push_commit_url` | --- description: Compact index for safe-output operations and runtime configuration in GitHub Agentic Workflows. --- # Safe Outputs Index Safe outputs are the write path for agentic workflows. Keep the main agent job read-only and use the focused reference files below. | Topic | File | |---|---| | Issues, discussions, comments, pull requests, and review operations | [safe-outputs-content.md](safe-outputs-content.md) | | Updates, labels, milestones, projects, releases, uploads, and delivery operations | [safe-outputs-management.md](safe-outputs-management.md) | | Workflow dispatch, automation, code scanning, checks, agent sessions, and assignment flows | [safe-outputs-automation.md](safe-outputs-automation.md) | | Runtime defaults, custom jobs, scripts, actions, global config, and output variables | [safe-outputs-runtime.md](safe-outputs-runtime.md) | ## Shared Rules - Prefer the most specific built-in safe output before creating a custom job. - Always scope mutating operations as tightly as possible. - For pull-request or branch mutation, always restrict `allowed-files`. - Use `noop` when no visible change is required after successful execution. --- description: Guidance for when to use the Serena LSP MCP server for semantic code analysis in agentic workflow tasks. --- # Serena Language Server Tool Serena is an **LSP MCP server** for semantic code analysis. Use ONLY when you need deep code understanding beyond text manipulation. ## When to Use Serena **Use when you need:** - Symbol navigation (find all usages of a function/type) - Call graph analysis across files - Semantic duplicate detection (not just text matching) - Refactoring analysis (functions in wrong files, extraction opportunities) - Type relationships and interface implementations **Don't use Serena for:** - Text patterns → `grep` - File edits / YAML/JSON/Markdown → `edit` tool - Commands → `bash` If `grep` or `bash` solves it in 1-2 commands, don't use Serena. ## Configuration Import the shared workflow. For multi-language, the first entry is the default fallback: ```yaml imports: - uses: shared/mcp/serena.md with: languages: ["go", "typescript"] # go, typescript, python, ruby, rust, java, cpp, csharp ``` ## Available Serena Tools ### Navigation & Analysis - `find_symbol` - Search for symbols by name - `get_symbols_overview` - List all symbols in a file - `find_referencing_symbols` - Find where a symbol is used - `find_referencing_code_snippets` - Find code snippets using a symbol - `search_for_pattern` - Search for code patterns (regex) ### Code Editing - `read_file` - Read file with semantic context - `create_text_file` - Create/overwrite files - `insert_at_line` - Insert content at line number - `insert_before_symbol` / `insert_after_symbol` - Insert near symbols - `replace_lines` - Replace line range - `replace_symbol_body` - Replace symbol definition - `delete_lines` - Delete line range ### Project Management - `activate_project` - **REQUIRED** - Activate Serena for workspace - `onboarding` - Analyze project structure - `restart_language_server` - Restart LSP if needed - `get_current_config` - View Serena configuration - `list_dir` - List directory contents ## Usage Workflow ### 1. Activate Serena First Call `activate_project` (passing the workspace path) before any other Serena tool. ### 2. Combine with Other Tools `bash` for file discovery, Serena for semantic analysis, `edit` for changes. ```yaml imports: - uses: shared/mcp/serena.md with: languages: ["go"] tools: bash: - "find pkg -name '*.go' ! -name '*_test.go'" - "cat go.mod" github: toolsets: [default] ``` ### 3. Use Cache for Recurring Analysis ```yaml imports: - uses: shared/mcp/serena.md with: languages: ["go"] cache-memory: true # Store analysis history ``` ## Common Pitfalls ❌ Serena on non-code files (use `edit`) ❌ Forgetting `activate_project` first ❌ Not using bash for file discovery ❌ Missing `languages` config ## Supported Languages Full LSP: `go` (gopls), `typescript`, `python` (jedi/pyright), `ruby` (solargraph), `rust` (rust-analyzer), `java`, `cpp`, `csharp`. See `.serena/project.yml` for full list (25+). --- description: Shared pattern for custom safe-output jobs that consume structured agent output. --- # Custom Safe-Output Job Pattern Use this pattern when a workflow must perform a controlled write action after the agent finishes. ## Rules - Define the tool schema under `safe-outputs.jobs..inputs`. - Read the output file from `GH_AW_AGENT_OUTPUT`. - Parse the JSON and iterate over `items`. - Filter items by `type`, where the type is the job name with dashes converted to underscores. - Validate required fields on every matching item. - Respect staged mode by checking `GH_AW_SAFE_OUTPUTS_STAGED === 'true'`. - Preview in staged mode instead of performing the real side effect. - Use warnings for skippable invalid items and fail the job only for fatal errors. ## Minimal Shape ```yaml safe-outputs: jobs: custom-action: description: "Process structured agent output" runs-on: ubuntu-latest inputs: field1: type: string required: true steps: - name: Process items uses: actions/github-script@v8 with: script: | const fs = require('fs'); const staged = process.env.GH_AW_SAFE_OUTPUTS_STAGED === 'true'; const file = process.env.GH_AW_AGENT_OUTPUT; const data = JSON.parse(fs.readFileSync(file, 'utf8')); const items = (data.items || []).filter(item => item.type === 'custom_action'); ``` ## Use This Pattern For - third-party API writes - notifications - controlled external-system updates - custom post-processing that should remain outside the agent job ## Do Not Use This Pattern For - direct agent-job writes - broad shell-based mutation without a typed schema - features already covered by built-in safe outputs --- description: Guide for using skills and plugins in agentic workflows — compiler-managed `skills:`/`plugins:` installs plus hint, fusion, and inline strategies --- # Skills in Agentic Workflows Use skills — domain-specific knowledge files (`SKILL.md`) under `skills/` or `.github/skills/` — in workflows. **Rule:** when a user asks for a specific skill or agent plugin, declare it in the built-in top-level `skills:` or `plugins:` frontmatter fields. gh-aw resolves and installs them before the agent runs. Never install skills or plugins on the fly — no `steps:`/`post-steps:` that run `gh skill install`, `copilot plugin install`, `npx`, `curl`, or `git clone`, and no prompt text telling the agent to fetch or install a skill or plugin at run time. --- ## Detecting Skills ```bash find "${GITHUB_WORKSPACE}" -name "SKILL.md" -maxdepth 6 ``` --- ## Frontmatter `skills:` (Preferred for External Skills) Declare skills to install at activation time with the top-level `skills:` array. The compiler emits the activation steps, prepares the required `gh` support, installs each skill, and wires it into the engine. Do **not** add manual `gh` setup or `gh skill install` steps for this. ```yaml skills: # Shared auth via the workflow activation token - mattpocock/skills/tdd@801dca688564c529fa84f247f64472520d9ebe28 # Local skill path for development (installed with --from-local) - .github/skills/my-skill # Per-skill token for a private skill repository - skill: mattpocock/skills/diagnosing-bugs@801dca688564c529fa84f247f64472520d9ebe28 github-token: ${{ secrets.MATT_SKILLS_PAT || secrets.GITHUB_TOKEN }} # Per-skill GitHub App credentials - skill: mattpocock/skills/domain-modeling@801dca688564c529fa84f247f64472520d9ebe28 github-app: client-id: ${{ vars.MATT_SKILLS_APP_CLIENT_ID }} private-key: ${{ secrets.MATT_SKILLS_APP_PRIVATE_KEY }} ``` - Static references must be pinned to a full 40-character lowercase commit SHA; `${{ ... }}` expressions are allowed in the ref position and resolved at runtime. - Local paths (for example, `skills/my-skill` or `.github/skills/my-skill`) are supported for local development and are installed via `--from-local`. - Object entries set per-skill auth via `github-token` or `github-app`. - Use `skills:` for external skill installs and `imports:` for prompt/context files you want merged into the workflow. Distinct from the prompt-side strategies below (hint / fusion / inline), which shape skill *content* into the prompt rather than installing packages. --- ## Frontmatter `plugins:` (Preferred for Agent Plugins) When the user asks for a specific [Agent Plugin](https://agent-plugins.org), declare it in the top-level `plugins:` array. The compiler resolves each `owner/repository[/path]@ref` to a commit SHA at compile time, and the agent job checks out and registers every plugin with the engine before the agent starts. ```yaml plugins: - octo-org/agent-plugin@v1 - octo-org/agent-plugins/plugins/example@main ``` - `ref` is required (branch, tag, or 40-character commit SHA); unresolvable refs fail compilation. - Experimental: compiling a workflow that uses `plugins:` emits a warning. - Supported by `copilot`, `claude`, `codex`, and imported engines that declare `engine.behaviors.plugins`; `gemini` and `pi` reject `plugins:` at compile time. - Plugin object entries support per-entry auth with `github-token` or `github-app` (mutually exclusive), so private repositories are supported. - For runtime-retrieved credentials, prefer `${{ steps..outputs. }}` from same-job `pre-steps`; use `${{ env. }}` when an action only exports through `$GITHUB_ENV`. - Keep guidance provider-neutral: do not assume a specific vault/secret manager implementation. - See [syntax-tools-imports.md](syntax-tools-imports.md) for the full field reference. --- ## Inline Skills (Fusion at Authoring Time) **Use when**: keeping the main prompt compact while shipping task-specific skill guidance with the workflow. Inline skills embed a complete skill or fragment under `## skill: \`name\``. Extraction runs in the setup/interpolation step (not at compile time): gh-aw writes each block to engine-specific skill locations and removes it from the main prompt body. **Pattern**: ```markdown on: workflow_dispatch: engine: copilot --- Triage the issue and propose next steps. ## skill: `issue-triage` --- description: Classify issues and suggest next actions. --- Classify by bug / feature / question, identify missing information, and suggest the smallest actionable next step. ``` Use a unique inline skill name per workflow file. Name must start with a lowercase letter, then lowercase letters, digits, `_`, or `-`. Avoid collisions with file-based skills under `.github/skills//SKILL.md` — inline extraction writes to the same paths. --- ## Strategy 0 — Hint (Generalist) **Use when**: the task strategy is unknown at authoring time, or the agent must adapt to whatever skills are available. The prompt tells the agent skills exist and to discover/apply the relevant ones itself. **Pattern**: ```markdown If the repository contains `SKILL.md` files under `skills/` or `.github/skills/`, check which ones are relevant to this task. For each relevant skill, read its content and apply the guidance it provides. ``` --- ## Strategy 1 — Fusion (Ultra-Cognitive) **Use when**: you know exactly which skill (or part of it) is needed and want minimal context overhead. Inline **only the specific sections** the agent needs; never paste the entire SKILL.md. **Pattern**: ```markdown When calling GitHub MCP tools, use the pre-configured token already injected into the environment. Never prompt the user for credentials. ``` --- ## Choosing Between the Two Strategies | Factor | Hint | Fusion | |---|---|---| | **Task domain** | Broad / unknown | Narrow / well-defined | | **Skill set** | Grows dynamically | Known and stable | | **Context budget** | Generous | Tight | | **Maintenance burden** | Low (agent self-selects) | Higher (manual sync with source) | | **Determinism** | Lower (agent chooses) | Higher (exact fragment) | | **Scale** | Poor (entire skills loaded) | Good (minimal content) | --- ## Example: Hint Strategy ```markdown --- on: issues: types: [opened] engine: copilot tools: github: toolsets: [issues] permissions: issues: write --- Triage the newly opened issue. If there are relevant skills under `skills/` or `.github/skills/`, read them and apply their guidance. Focus on skills related to issue classification or project conventions. ``` --- ## Example: Fusion Strategy ```markdown --- on: pull_request: types: [opened, synchronize] engine: copilot tools: github: toolsets: [pull_requests] permissions: pull-requests: write --- Review the pull request for adherence to project conventions. Prefer many smaller files grouped by functionality. Add new files for new features rather than extending existing ones. Keep validators under 300 lines; split when a single file covers more than one domain. Report findings as inline review comments. ``` --- ## Anti-Patterns - ❌ **Do not install skills or plugins on the fly** — never add `steps:`/`post-steps:` or prompt instructions that run `gh skill install`, `copilot plugin install`, `npx`, `curl`, or `git clone` to fetch a skill or plugin at run time; declare `skills:`/`plugins:` instead and let gh-aw install them before the agent runs - ❌ **Do not load entire skill files** when only one section is relevant — use fusion instead - ❌ **Do not hint without bounds** — if using the hint strategy, constrain the agent with a `maxdepth` and a relevance filter to avoid reading every SKILL.md in a large repo - ❌ **Do not paste skills verbatim** without adapting them to the workflow's context — fused fragments should read as natural prose, not as lifted documentation - ❌ **Do not hard-code skill file paths** in hints — use `find` so the prompt still works when skills are reorganised --- description: Guide for defining inline sub-agents in workflow markdown files — syntax, engine placement, frontmatter fields, and best practices. --- # Inline Sub-Agents Define specialised agents directly in a workflow markdown file. At runtime, sub-agent sections are extracted (after `{{#runtime-import}}` macros resolve) and written to the engine-specific agents directory for the engine CLI to discover. --- ## Syntax Define a sub-agent with a level-2 Markdown heading of the form `## agent: \`name\``: ```markdown ## agent: `file-summarizer` --- description: Summarizes the content of a file in a few concise sentences model: small --- You are a file summarization assistant. When given a file path, read the file and return a brief summary (2–4 sentences) describing its purpose and key contents. Be concise and factual. ``` ### Name rules - Must be enclosed in backticks: `` `name` `` - Lowercase only: `[a-z][a-z0-9_-]*` - Examples: `` `planner` ``, `` `file-summarizer` ``, `` `code-reviewer` `` ### Block boundary The block ends at the next `##` heading (any level-2 heading) or at EOF — no explicit end marker is needed. Place sub-agent blocks **at the bottom** of the file, after all main workflow content. ### Frontmatter fields Only two fields are supported inside a sub-agent frontmatter block: | Field | Required | Default | Notes | |---|---|---|---| | `description` | No | — | Human-readable summary of the sub-agent's role | | `model` | No | `"inherited"` | Model override; `"inherited"` uses the parent workflow's model. Prefer model aliases (e.g. `small`, `large`) over specific model IDs for portability. | Built-in aliases resolve to the best available model per provider and keep working as models are updated. Common sub-agent aliases: | Alias | Resolves to | When to use | |---|---|---| | `small` | `mini` → haiku, gpt-5-mini, gpt-5-nano, gemini-flash | Cheap, fast tasks: extraction, classification, formatting | | `large` | sonnet, gpt-5-pro, gpt-5, gemini-pro | Complex reasoning or synthesis tasks | | `inherited` | Parent workflow model | Default — use when the sub-agent needs the same capability as the parent | All other fields (`engine`, `tools`, `network`, etc.) are stripped at runtime with a warning. Sub-agents inherit the parent's engine, tool access, and network configuration. --- ## Engine-Specific Placement Sub-agent files are written to the directory and with the extension each engine natively expects: | Engine | Directory | Extension | |---|---|---| | Copilot (default) | `.agents/agents/` | `.agent.md` | | Claude | `.claude/agents/` | `.md` | | Codex | `.codex/agents/` | `.md` | | Gemini | `.gemini/agents/` | `.md` | The engine is detected at compile time from the `engine:` field and injected as `GH_AW_ENGINE_ID` into the interpolation step's environment. --- ## MCP Access in Sub-Agents Sub-agents **do not have their own MCP servers** — they run in the parent's agent environment without independent tool config. For file system and shell access, enable on the parent workflow: - **`cli-proxy: true`** — GitHub CLI proxy for authenticated `gh` calls. Recommended for any sub-agent that reads/writes repo content. - **`tools.github.mode: gh-proxy`** — routes GitHub API calls through the gh proxy sidecar; required for private repos or the GitHub MCP toolset. ```yaml --- engine: copilot tools: github: mode: gh-proxy cli-proxy: true --- ``` --- ## When to Use Sub-Agents ### 1 — Parallel specialised tasks with smaller models Break a large workflow into parallel units handled by small/cheap models, then let the parent (large) model reason over the aggregated results: ```markdown # Investigate: Repository Health ## Step 1 — gather data Use the `dependency-scanner` agent to list all outdated packages. Use the `test-coverage` agent to summarise uncovered code paths. Use the `secret-scanner` agent to check for leaked credentials. ## Step 2 — synthesise Combine the three reports above into a prioritised action plan. The top item must have a linked PR draft or issue. ## agent: `dependency-scanner` --- description: Lists outdated npm/pip/go packages model: small --- Run the appropriate package-manager audit command and return a machine-readable list of outdated packages with their current and latest versions. ## agent: `test-coverage` --- description: Summarises low-coverage code paths model: small --- Read the most recent test coverage report and list the top 5 files or functions with coverage below 60 %. Include the file path and line range. ## agent: `secret-scanner` --- description: Checks for potential credential leaks model: small --- Scan staged changes and recently modified files for patterns that resemble API keys, tokens, or passwords. Report any findings with the file name and approximate line number. ``` The parent model orchestrates; sub-agents do the heavy lifting with `small` at lower cost. ### 2 — Reusable specialised helpers Extract repetitive sub-tasks (file summarisation, commit-message generation, code explanation) into a named sub-agent the main prompt calls by name. --- ## Planner-Worker Pattern Split work to control cost and keep context quality high: - **Main/frontier agent (planner-orchestrator):** forms hypotheses, decides what evidence is needed, picks workers, synthesises conclusions - **Worker sub-agents (usually `model: small`):** bounded retrieval, extraction, classification, verification, one-shot summarisation Prompt workers narrowly and evidence-first (e.g. "return exact error messages and line references"), not broad analysis. Worker outputs should be compact and structured. Do not return raw logs or large file dumps to the orchestrator. ### Bounded delegation rules - keep delegation one level deep unless gh-aw explicitly supports and validates deeper topology - avoid recursive or open-ended sub-agent fan-out - cap per-run worker fan-out so high-volume events cannot trigger runaway cost - stop early with `noop` or safe output when a cheap worker can confidently classify a known/duplicate/stale/low-value case See also: [token-optimization.md](token-optimization.md) and [workflow-patterns.md](workflow-patterns.md). --- ## Full Example ```markdown --- engine: copilot tools: github: mode: gh-proxy cli-proxy: true bash: - "cat *" - "ls *" --- # PR Review Assistant 1. Use the `diff-explainer` agent to produce a plain-English summary of the diff for PR #${{ github.event.pull_request.number }}. 2. Post the summary as a PR comment. ## agent: `diff-explainer` --- description: Produces a plain-English summary of a pull request diff model: small --- You receive a unified diff. Describe each changed file in one sentence, focusing on *what changed* and *why it matters*. Ignore formatting-only changes. Return a bulleted list, one bullet per file. ``` --- ## Limitations - Sub-agents do not support `engine:`, `tools:`, `network:`, or `mcp-servers:` fields — those are stripped at runtime. - Sub-agents cannot define their own safe-output jobs. - Sub-agent blocks must appear in the main workflow file body; they are not resolved inside imported shared files. --- description: Agentic workflow specific frontmatter fields for GitHub Agentic Workflows. --- # Agentic Workflow Frontmatter Fields ### Agentic Workflow Specific Fields - **`description:`** - Human-readable workflow description (string) - **`emoji:`** - Optional single emoji used to represent the workflow visually; recommended for quicker recognition in workflow lists and status output (string) - **`source:`** - Workflow origin tracking in format `owner/repo/path@ref` (string) - **`labels:`** - Array of labels to categorize and organize workflows (array) - Labels filter workflows in status/list commands - Example: `labels: [automation, security, daily]` - **`metadata:`** - Custom key-value pairs compatible with custom agent spec (object) - Key names limited to 64 characters - Values limited to 1024 characters - Example: `metadata: { team: "platform", priority: "high" }` - **`github-token:`** - GitHub token override (must use `${{ secrets.* }}` syntax). Not a top-level field: set it under `on:` (trigger checks), `tools.github`, or `safe-outputs`. - **`on.roles:`** - Repository access roles that can trigger workflow (array or `"all"`). Default `[admin, maintainer, write]`; available roles: `admin`, `maintainer`, `maintain`, `write`, `triage`, `read`, `all`. - **`on.bots:`** - Bot identifiers allowed to trigger workflow regardless of role permissions (array; e.g. `[dependabot[bot], renovate[bot], github-actions[bot]]`). The bot must be active (installed) on the repository to trigger. - **`strict:`** - Enable enhanced validation for production workflows (boolean, defaults to `true`; strongly recommended) - Prefer `strict: true`; `strict: false` is dangerous, should be extremely rare, and must be carefully security reviewed before use - **`model:`** - Default LLM model for the agentic engine (string). A nested `engine.model` takes precedence for that engine instance. Accepts full model IDs (e.g. `claude-3-5-sonnet-20241022`, `gpt-5.4`) and aliases (e.g. `small`, `large`). - **`max-turns:`** - AWF turn cap applied consistently across all agentic engines (integer or expression, e.g. `${{ inputs.max-turns }}`). The engine-level `engine.max-turns` is a deprecated alias kept for backward compatibility — prefer this top-level field. - **`max-runs:`** - Deprecated legacy alias for the AWF invocation cap (`apiProxy.maxRuns`, defaults to `500` when omitted). Use `max-turns` instead; run `gh aw fix` to migrate. - **`max-ai-credits:`** - Per-run AI Credits (AIC) budget enforced by the AWF firewall (integer or `K`/`M` short-form string like `100M`; default `1000`). Set a negative value to disable enforcement and token steering. See [token-optimization.md](token-optimization.md). - **`max-turn-cache-misses:`** - Maximum consecutive AWF cache misses allowed before the API proxy blocks further requests (integer, default `5`). Maps to `apiProxy.maxCacheMisses`; precedence is frontmatter → `GH_AW_DEFAULT_MAX_TURN_CACHE_MISSES` env override → built-in default. - **`models:`** - Model policy and optional pricing (object). Experimental policy fields `allowed` / `blocked` (lists of model names or patterns) restrict which models the workflow may use; they map to AWF `apiProxy.allowedModels` / `disallowedModels` and merge as unions across imports. Environment-variable overrides are supported. The separate `providers` field supplies custom pricing, and `default-ai-credits-pricing` (`input`/`output` in $/1M tokens) is a fallback rate for models absent from the built-in table — required to avoid HTTP 400 rejections for self-hosted/BYOK models (set both to `0` for free/local models). See [token-optimization.md](token-optimization.md). ```yaml models: allowed: ["gpt-5", "claude-*"] blocked: ["*-preview"] ``` - **`max-daily-ai-credits:`** - Per-user 24-hour AI Credits (AIC) guardrail: activation blocks execution once the triggering user's aggregated AI Credits for this workflow over the last 24h exceed the threshold (integer or `K`/`M` short-form string, or `-1`). Disabled by default; omit the field to leave the guardrail off, or set an explicit threshold to enable it. See [token-optimization.md](token-optimization.md). - **`user-rate-limit:`** - Rate limiting configuration to prevent users from triggering the workflow too frequently (object) - **`max-runs-per-window:`** - Maximum runs allowed per user per time window (required, integer 1-10) - **`window:`** - Time window in minutes (integer 1-180, default: 60) - **`events:`** - Event types to apply rate limiting to (array; if omitted, applies to all programmatic events) - Available: `workflow_dispatch`, `issue_comment`, `pull_request_review`, `pull_request_review_comment`, `issues`, `pull_request`, `discussion_comment`, `discussion` - **`ignored-roles:`** - Roles exempt from rate limiting (array of `admin`, `maintain`, `write`, `triage`, `read`; default: `[admin, maintain, write]`). Set to `[]` to apply to all users. - Example: ```yaml user-rate-limit: max-runs-per-window: 5 window: 60 ignored-roles: [admin, maintain] ``` - **`check-for-updates:`** - Whether the activation job checks that the compiled `gh-aw` version is still supported (boolean, default `true`). When `true`, blocked versions fail fast and below-recommended versions warn. Set `false` only for isolated environments (compiler then warns at compile time). - **`features:`** - Feature flags for experimental or optional features (object) - Each flag is a key-value pair; boolean flags (`true`/`false`) or string values are accepted - Known feature flags: - `copilot-requests: true` - Use GitHub Actions token for Copilot authentication instead of `COPILOT_GITHUB_TOKEN` secret - `disable-xpia-prompt: true` - Disable the built-in cross-prompt injection attack (XPIA) system prompt - `action-tag: "v0"` - Pin compiled action references to a specific version of the `gh-aw-actions` repository. Accepts version tags (e.g., `"v0"`, `"v1"`, `"v1.0.0"`) or a full 40-character commit SHA. When set, overrides the compiler's default action mode and resolves all action references from the external `github/gh-aw-actions` repository at the specified tag. - `action-mode: "script"` - Control how the compiler generates action references: `"dev"` (local paths, default), `"release"` (SHA-pinned remote), `"action"` (gh-aw-actions repo), `"script"` (direct shell calls). Can also be overridden via `--action-mode` CLI flag. - `difc-proxy: true` - Enable DIFC (Data Integrity and Flow Control) proxy injection. When set alongside `tools.github.min-integrity`, injects proxy steps around the agent for full network-boundary integrity enforcement. - `cli-proxy: true` - Enable AWF CLI proxy sidecar for secure read-only `gh` CLI access without exposing `GITHUB_TOKEN` (requires AWF v0.26.0+). Prerequisite for `integrity-reactions`; the compiler enables it automatically when `integrity-reactions: true` is set. - `integrity-reactions: true` - Enable reaction-based integrity promotion/demotion. Maintainers can use 👍/❤️ reactions to promote content to `approved` and 👎/😕 to demote it to `none`. Compiler automatically enables `cli-proxy`. Requires `tools.github.min-integrity` to be set and MCPG >= v0.2.18. Defaults: endorsement reactions THUMBS_UP/HEART, disapproval reactions THUMBS_DOWN/CONFUSED, endorser-min-integrity: approved, disapproval-integrity: none. - `dangerously-disable-sandbox-agent: true` - Required when `sandbox.agent: false` is set. This opt-out is rejected in strict mode. - **`experiments:`** - A/B testing experiments for balanced variant selection (object) - Maps experiment names to variant lists (bare array) or full config objects - Bare array form: `prompt_style: [concise, detailed]` — round-robin balanced across runs - Object form for weighted/gated experiments: ```yaml experiments: prompt_style: variants: [concise, detailed, step_by_step] weight: [2, 1, 1] # Optional: proportional weights (defaults to round-robin) start_date: "2026-05-01" # Optional: ISO-8601; returns control variant before this date end_date: "2026-06-01" # Optional: ISO-8601; returns control variant after this date description: "Verbosity test" # Optional: experiment description metric: "token_count" # Optional: primary metric name issue: "42" # Optional: linked tracking issue number ``` - Selected variant available as `${{ experiments. }}` and in `{{#if experiments. }}` template blocks - See [A/B Testing Experiments](experiments.md) for full design guidance - **`evals:`** - ⚠️ Experimental. BinEval binary (YES/NO) evaluation questions run after safe-outputs and before the conclusion job. Shorthand: a list of `{ id, question, model? }` objects. Extended form: object with `questions`, plus optional `model` (default alias/ID for all questions) and `runs-on`. - **`imports:`** - Array of workflow specifications to import (array) - Format: `owner/repo/path@ref` or local paths like `shared/common.md` - Markdown files under `.github/agents/` are treated as custom agent files - Only one agent file is allowed per workflow - See [Imports Field](syntax-tools-imports.md#imports-field) section for detailed documentation - **`inlined-imports:`** - Inline all imports at compile time (boolean, default: `false`) - When `true`, all imports (including those without inputs) are inlined in the generated `.lock.yml` instead of using runtime-import macros - The frontmatter hash covers the entire markdown body when enabled, so any content change invalidates the hash - **Required for repository rulesets**: Workflows used as required status checks in repository rulesets run without access to repository files at runtime. Set `inlined-imports: true` to bundle all imported content at compile time to avoid "Runtime import file not found" errors - **Constraint**: Cannot be combined with agent file imports (`.github/agents/` files). Remove any custom agent file imports before enabling - **`import-schema:`** - Define typed input parameters for this shared workflow (object). Use when other workflows import this one via the `uses:`/`with:` syntax (see [Imports Field](syntax-tools-imports.md#imports-field)). - Parameters are accessible inside the shared workflow via `${{ github.aw.import-inputs. }}` expressions - Object inputs (type: `object`) allow one-level deep sub-fields: `${{ github.aw.import-inputs.. }}` - Fields per parameter: - `type:` - Input type: `string`, `number`, `boolean`, `choice`, or `array` - `description:` - Human-readable parameter description - `required:` - Whether the input is required when imported (default: `false`) - `default:` - Default value when not provided - `options:` - Allowed values for `choice` type inputs - Example: ```yaml import-schema: environment: type: choice description: "Target environment" options: [dev, staging, prod] required: true max-issues: type: number default: 5 ``` - **`mcp-servers:`** - MCP (Model Context Protocol) server definitions (object) - Defines custom MCP servers for additional tools beyond built-in ones - **`private:`** - Mark this workflow as private, preventing it from being shared via `gh aw add` (boolean, default: `false`) - Example: `private: true` - **`redirect:`** - Workflow relocation path for updates (string). When present, `gh aw update` follows this location and rewrites the `source:` field. Format: `owner/repo/path@ref` or full GitHub URL. - Example: `redirect: "org/agentics/workflows/my-workflow-v2.md@main"` - **`resources:`** - Additional workflow or action files fetched alongside this workflow when running `gh aw add` (array). Entries are relative paths from the same directory to `.md` or `.yml`/`.yaml` files. - Example: `resources: [shared/tool-setup.md, shared/mcp/tavily.md]` - **`threat-detection-suppress:`** - Auditable false-positive suppression annotations for compiler threat-detection rules (array of objects) - Each entry requires `rule:` (a `CTR-###` identifier) and `reason:` (non-empty string); optional `expires:` (ISO-8601 date) - Example: `threat-detection-suppress: [{ rule: CTR-025, reason: "reviewed false positive", expires: "2026-12-31" }]` - **`ambient-folders:`** - Workspace-relative folders bundled into the activation artifact and restored before the agent runs (array of strings) - Useful for activation steps that generate reusable prompt, skill, or agent context ahead of the agent job - Merges with `ambient-folders` declared by imported workflows - Example: `ambient-folders: [".claude/skills", ".github/agents"]` - **`tracker-id:`** - Optional identifier to tag all created assets (string) - Must be at least 8 characters and contain only alphanumeric characters, hyphens, and underscores - This identifier is inserted in the body/description of all created assets (issues, discussions, comments, pull requests) - Enables searching and retrieving assets associated with this workflow - Examples: `"workflow-2024-q1"`, `"team-alpha-bot"`, `"security_audit_v2"` - **`secret-masking:`** - Configuration for secret redaction behavior in workflow outputs and artifacts (object) - `steps:` - Additional secret redaction steps to inject after the built-in secret redaction (array) - Use this to mask secrets in generated files using custom patterns - Example: ```yaml secret-masking: steps: - name: Redact custom secrets run: find /tmp/gh-aw -type f -exec sed -i 's/password123/REDACTED/g' {} + ``` - **`observability:`** - Workflow observability and telemetry configuration (object) - **`otlp:`** - Export OpenTelemetry spans to any OTLP-compatible backend (Honeycomb, Grafana Tempo, Sentry, etc.) (object) - `endpoint:` - OTLP collector endpoint URL. When a static URL is provided, its hostname is added to the AWF firewall allowlist automatically. Supports GitHub Actions expressions. - `github-app:` - Optional runtime auth configuration. - Preferred: provide GitHub App credentials (`app-id`/`client-id` + `private-key`) to mint a token with `actions/create-github-app-token` before `actions/setup`. - OIDC mode is used when `github-app` is configured without credentials (`app-id`/`client-id` + `private-key`). - OIDC mode requires `permissions.id-token: write` on the workflow/job. - `workload-identity:` - Exchange a GitHub Actions OIDC token for a cloud access token before OTLP export. Only `provider: google` is currently supported; requires `audience:` (Google Workload Identity Provider resource name) and accepts optional `service-account:` to impersonate after STS token exchange. - `headers:` - Comma-separated `key=value` HTTP headers included in every OTLP export request (e.g. `Authorization=Bearer `). Injected as `OTEL_EXPORTER_OTLP_HEADERS`. Supports GitHub Actions expressions. - `resource-attributes:` - Optional map of additional OTEL resource attributes appended to gh-aw/GitHub defaults. Values may be static strings or GitHub Actions expressions. Do not use `secrets.*` or `vars.*` here because resource attributes are exported to external observability backends and are not treated as secret values. - Example: ```yaml observability: otlp: endpoint: ${{ secrets.GH_AW_OTEL_ENDPOINT }} github-app: app-id: ${{ vars.APP_ID }} private-key: ${{ secrets.APP_PRIVATE_KEY }} headers: ${{ secrets.GH_AW_OTEL_HEADERS }} ``` Every job emits setup and conclusion spans with rich attributes (`gh-aw.job.name`, `gh-aw.workflow.name`, `gh-aw.engine.id`, token usage). All jobs in a run share one trace ID. Dispatched child workflows inherit the parent's trace context via `aw_context`. - **`runtimes:`** - Runtime environment version overrides (object) - Allows customizing runtime versions (e.g., Node.js, Python) or defining new runtimes - Runtimes from imported shared workflows are also merged - Each runtime is identified by a runtime ID (e.g., 'node', 'python', 'go') - Runtime configuration properties: - `version:` - Runtime version as string or number (e.g., '22', '3.12', 'latest', 22, 3.12) - `action-repo:` - GitHub Actions repository for setup (e.g., 'actions/setup-node') - `action-version:` - Version of the setup action (e.g., 'v4', 'v5') - `if:` - Optional GitHub Actions condition to control when runtime setup runs (e.g., `"hashFiles('go.mod') != ''"`) - `cooldown:` - Enable a default 3-day dependency cooldown for installs on this runtime (boolean, default: `true`); set `false` to disable - Example: ```yaml runtimes: node: version: "22" python: version: "3.12" action-repo: "actions/setup-python" action-version: "v5" go: version: "1.22" if: "hashFiles('go.mod') != ''" # Only install Go when go.mod exists ``` - **`runtimes.node.run-install-scripts:`** - Allow npm pre/post install scripts to execute during package installation for the Node.js runtime (boolean, default: `false`) - By default, `--ignore-scripts` is added to all generated npm install commands to prevent supply chain attacks via malicious install hooks - Set `run-install-scripts: true` under `runtimes.node` to allow scripts for Node.js installs - A supply chain security warning is emitted at compile time; in strict mode this is an error - **`checkout:`** - Override how the repository is checked out in the agent job (object, array, or `false`) - By default, the workflow automatically checks out the repository. Use this field to customize checkout behavior. - Set to `false` to disable automatic checkout entirely (reduces startup time when repo access is not needed): ```yaml checkout: false ``` - Target-only checkout for sidecar/MultiRepoOps workflows: set `permissions.contents: none` to skip only the automatic workflow-repository checkout while still checking out other explicitly configured `checkout:` entries (e.g. a target repository). Unlike `checkout: false`, additional checkout entries are unaffected: ```yaml permissions: contents: none checkout: - repository: octo-org/target-repository path: target github-token: ${{ secrets.TARGET_REPO_PAT }} ``` - Single checkout (object): ```yaml checkout: fetch-depth: 0 # Fetch full history (default: 1 = shallow clone) github-token: ${{ secrets.MY_PAT }} # Override token for private repos ``` - Multiple checkouts (array): ```yaml checkout: - path: . fetch-depth: 0 - repository: owner/other-repo path: ./libs/other ref: main ``` - Supported fields per checkout entry: - `repository:` - Repository in `owner/repo` format (defaults to current repository) - `ref:` - Branch, tag, or SHA to check out (defaults to triggering ref) - `path:` - Relative path within `GITHUB_WORKSPACE` (defaults to workspace root) - `fetch-depth:` - Number of commits to fetch; `0` = full history, `1` = shallow (default) - `fetch:` - Additional Git refs to fetch after checkout (array of patterns) - `"*"` - fetch all remote branches - `"refs/pulls/open/*"` - all open pull-request refs - Branch names, glob patterns (e.g., `"feature/*"`) - Example: `fetch: ["*"]`, `fetch: ["refs/pulls/open/*"]` - `sparse-checkout:` - Newline-separated glob patterns for sparse checkout - `submodules:` - Submodule handling: `"recursive"`, `"true"`, or `"false"` - `lfs:` - Download Git LFS objects (boolean, default: `false`) - `wiki:` - Check out the repository's wiki (boolean, default: `false`). When `true`, automatically appends `.wiki` to the repository name. Combine with `repository:` to check out a different repo's wiki. - `github-token:` - Token for authentication (`${{ secrets.MY_PAT }}`); credentials removed after checkout - **`jobs:`** - Groups together all the jobs that run in the workflow (object) - Standard GitHub Actions jobs configuration - Each job can have: `name`, `runs-on`, `steps`, `needs`, `if`, `env`, `permissions`, `timeout-minutes`, etc. - For most agentic workflows, jobs are auto-generated; only specify this for advanced multi-job workflows - **Security Notice**: Custom jobs run OUTSIDE the firewall sandbox. Execute with standard GitHub Actions security but NO network egress controls. Use only for deterministic preprocessing, data fetching, or static analysis—not agentic compute or untrusted AI execution. - **`setup-steps:`** - Steps injected at the earliest point in a custom or built-in job, before framework GitHub App token minting and before checkout (array). Use this for OIDC login, secret fetch, and credential bootstrap that must happen before framework token/checkout steps. Imported `setup-steps` run before main workflow `setup-steps`. - **`pre-steps:`** - Steps injected after framework setup scaffolding and before the job's main `steps:` in a custom or built-in job (array). For built-in jobs, this is after the `id: setup` step (which includes framework token minting/checkout setup) and before the first checkout. Imported `pre-steps` run before main workflow `pre-steps`. - **`setup-steps` vs `pre-steps`** - Use `setup-steps` for work that must run before framework GitHub App token minting and checkout (e.g., OIDC/secret bootstrap). Use `pre-steps` for work that should run later, after setup scaffolding and before the job's main `steps:`. - **Migration note** - No migration is required. `setup-steps` is additive; existing workflows that only use `pre-steps` continue to behave as before. - Example: ```yaml jobs: custom-job: runs-on: ubuntu-latest setup-steps: - name: Bootstrap credentials run: echo "runs before framework token/checkout setup" pre-steps: - name: Pre-flight setup run: echo "runs before checkout" steps: - name: Custom step run: echo "Custom job" ``` - `setup-steps`/`pre-steps` also apply to built-in jobs (e.g. `activation`): use `setup-steps` for OIDC/secret bootstrap that must run before framework token minting, then verify the result in `pre-steps`. Use `jobs.activation.steps` for activation work that must run after the activation checkout and before the activation artifact is staged. - **`needs`/`if` on built-in jobs** — targeting a compiler-generated job (`agent`, `activation`, `safe_outputs`, etc.) under `jobs:` also accepts additive `needs` and `if`: `jobs.agent.needs` merges with compiler-generated dependencies, and `jobs.agent.if` combines with compiler-generated conditions using `&&`. Use this to gate the agent job on a custom setup job's outcome. - **`engine:`** - AI processor configuration (string or object: `id`, `model`, `permission-mode`, `agent`, `max-continuations`, `driver`, `copilot-sdk`, `auth`, and more). See [syntax-engine.md](syntax-engine.md) for the full field reference, per-engine support notes, and inline driver examples. - **`network:`** - Network access control for AI engines (top-level field) - String format: `"defaults"` (curated allow-list of development domains) - Empty object format: `{}` (no network access) - Object format for custom permissions: ```yaml network: allowed: - "example.com" - "*.trusted-domain.com" - "https://api.secure.com" # Optional: protocol-specific filtering blocked: - "blocked-domain.com" - "*.untrusted.com" - python # Block ecosystem identifiers ``` - **Firewall (AWF) configuration** is set under `sandbox.agent`, not `network`. Use `sandbox.agent.version` to pin the AWF version (see below). The legacy `network.firewall` field is deprecated; run `gh aw fix` to migrate. - **`sandbox:`** - Sandbox configuration for AI engines (string or object) - String format: `"default"` (default sandbox), `"awf"` (Agent Workflow Firewall) - Object format to pin an AWF version (strict mode requires explicit `id: awf`): ```yaml sandbox: agent: id: awf # Required in strict mode version: "v0.25.29" # Optional: pin AWF version model-fallback: false # Optional: disable model fallback (default true); set false for BYOK Azure OpenAI to prevent deployment-name rewriting token-steering: false # Optional: disable API proxy token steering to preserve the configured provider and model ``` - When `engine.env` sets `OPENAI_BASE_URL` or `ANTHROPIC_BASE_URL` (custom provider endpoints, e.g. OpenRouter), `model-fallback` is disabled automatically so provider-specific model slugs pass through verbatim; set it explicitly to override. - To disable the agent firewall while keeping MCP gateway enabled, set `strict: false` and enable the dangerous sandbox opt-out: ```yaml features: dangerously-disable-sandbox-agent: true sandbox: agent: false strict: false ``` - **`sandbox.agent.runtime`** (string) selects the sandbox security and topology profile: `docker` (default: rootless AWF with network isolation), `docker-sudo-iptables` (privileged AWF with legacy iptables networking and host/service access), `gvisor` (gVisor `runsc` kernel-level isolation), `docker-sbx` (KVM microVM), or `cloud-hypervisor` (preview KVM runtime). Omitting the field is equivalent to `docker`. gVisor and Docker sbx are incompatible with `runner.topology: arc-dind`; the compiler derives the privileged setup each runtime needs. Docker sbx also requires `DOCKER_PAT`/`DOCKER_USERNAME` secrets and a KVM-capable runner when runtime installation is enabled. - **`sandbox.agent.runtime-install`** (boolean) controls generated gVisor or Docker sbx provisioning and defaults to `true`. Set it to `false` only when the runner is pre-provisioned; Docker sbx credential refresh still runs. False wins when imported workflows merge this field. See [agent-runtime-instructions.md](agent-runtime-instructions.md) for requirements and troubleshooting. - **`sandbox.agent.allow-host-ports`** (array of integers) additional host TCP ports the agent may connect to. Requires `runtime: docker-sudo-iptables`. Ports published by `services:` are reached via `--allow-host-service-ports` instead; use this only for host daemons not declared there. There is no `sandbox.agent.legacy-security` field — that mode was replaced by `runtime: docker-sudo-iptables`. - **Strict mode**: `sandbox.agent` blocks without an explicit `id: awf` are rejected in strict mode. Any non-nil, non-disabled agent config without `id`/`type` defaults to AWF at runtime. - **`enclaves:`** - AWF-owned private-repository executors exposed only through the compiler-launched MCP gateway (array). See [enclaves.md](enclaves.md) for the full schema and usage. - **`tools:`** - Tool configuration for the coding agent (`github`, `agentic-workflows`, `edit`, `web-fetch`, `web-search`, `bash`, `playwright`, custom MCP server names, plus `timeout`/`startup-timeout`/`cli-proxy`). See [syntax-tools-imports.md](syntax-tools-imports.md#tool-configuration) for the full schema (GitHub `mode`/`toolsets`/integrity fields, bash allowlist decision rule, Playwright CLI mode). - **`safe-outputs:`** - Safe output processing configuration. See [safe-outputs.md](safe-outputs.md) for complete documentation of all output types: `create-issue`, `create-discussion`, `add-comment`, `create-pull-request`, `push-to-pull-request-branch`, `close-issue`, `close-discussion`, `update-issue`, `update-pull-request`, `add-labels`, `remove-labels`, `replace-label`, `dispatch-workflow`, `call-workflow`, `create-code-scanning-alert`, `upload-asset`, `upload-artifact`, `assign-to-agent`, `assign-to-user`, `approve-workflow-run`, and more. **Key safe-outputs global fields** (detail in [safe-outputs-runtime.md](safe-outputs-runtime.md)): `github-token`, `github-app`, `staged` (preview mode, no API calls), `footer`, `threat-detection`, `runs-on` (default `ubuntu-slim`), `messages`, `env`, `max-patch-size` (KB, default `4096`). - **`mcp-scripts:`** - Define custom lightweight MCP tools as JavaScript, shell, Python, or Go scripts (object) - Tools mounted in MCP server with access to specified secrets - Each tool requires `description` and one of: `script` (JavaScript), `run` (shell), `py` (Python), or `go` (Go) - Tool configuration properties: - `description:` - Tool description (required) - `inputs:` - Input parameters with type and description (object) - `script:` - JavaScript implementation (CommonJS format) - `run:` - Shell script implementation - `py:` - Python script implementation - `go:` - Go script implementation (executed via `go run`, receives inputs as JSON via stdin) - `env:` - Environment variables for secrets (supports `${{ secrets.* }}`) - `dependencies:` - Runtime packages installed before first invocation (list of strings). Manager inferred from script type: `script`→npm, `py`→pip, `go`→`go get`, `run`→apt. Must be exact-version-pinned (`name@1.2.3`, `name==1.2.3`, `module@v1.2.3`, `name=1.6`); floating refs are rejected. - `timeout:` - Execution timeout in seconds (default: 60) - Example: ```yaml mcp-scripts: search-issues: description: "Search GitHub issues using API" inputs: query: { type: string, description: "Search query", required: true } script: | const { Octokit } = require('@octokit/rest'); const octokit = new Octokit({ auth: process.env.GH_TOKEN }); const r = await octokit.search.issuesAndPullRequests({ q: inputs.query }); return r.data.items; dependencies: ["@octokit/rest@21.0.2"] env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} ``` - **`slash_command:`** - Command trigger configuration for /mention workflows (under `on:`) - **`cache:`** - Cache configuration for workflow dependencies (object or array) - **`cache-memory:`** - Memory MCP server with persistent cache storage (boolean or object, under `tools:`) - **`repo-memory:`** - Repository-specific memory storage (boolean, under `tools:`) - **`comment-memory:`** - Managed issue/PR comment memory with file-based agent editing (boolean or object, under `tools:`) --- description: Core GitHub Actions frontmatter fields supported by GitHub Agentic Workflows. --- ## Complete Frontmatter Schema The YAML frontmatter supports these fields: ### Core GitHub Actions Fields - **`on:`** - Workflow triggers (required) - String: `"push"`, `"issues"`, etc. - Object: Complex trigger configuration - Special: `slash_command:` for /mention triggers - **`forks:`** - Fork allowlist for `pull_request` triggers (array or string). By default, workflows block all forks and only allow same-repo PRs. Use `["*"]` to allow all forks, or specify patterns like `["org/*", "user/repo"]` - **`stop-after:`** - Can be included in the `on:` object to set a deadline for workflow execution. Supports absolute timestamps ("YYYY-MM-DD HH:MM:SS"), relative time deltas (+25h, +3d, +1d12h), or a GitHub Actions expression (e.g. `${{ inputs.stop-after }}`) resolved at runtime instead of compile time. The minimum unit for relative/literal deltas is hours (h). Literal values use precise date calculations that account for varying month lengths; recompile with `gh aw compile --refresh-stop-time` to reset a literal deadline. - **`cooldown:`** - Can be included in the `on:` object to block the `agent` job from starting again shortly after the most recent completed run. Value must be a literal Go duration string of at least 5 minutes (e.g. `"30m"`, `"2h"`); GitHub Actions expressions are rejected. Fails open (allows activation) if run history cannot be queried. - **`reaction:`** - Add emoji reactions to triggering items - **`status-comment:`** - Post status comments when workflow starts/completes on the triggering issue, pull request, or discussion (boolean, or object with `issues`/`pull-requests`/`discussions` booleans to control trigger groups independently). Defaults to `true` for `slash_command` and `label_command` triggers; defaults to `false` for all other triggers. Must be explicitly enabled for non-command triggers with `status-comment: true`. - **`manual-approval:`** - Require manual approval using environment protection rules - **`skip-roles:`** - Skip workflow execution for users with specific repository roles (array) - Available roles: `admin`, `maintainer`/`maintain`, `write`, `triage`, `read` - Example: `skip-roles: [read]` - Skip execution for users with read-only access - **`skip-bots:`** - Skip workflow execution when triggered by specific GitHub actors (array) - Bot name matching is flexible (handles with/without `[bot]` suffix) - Example: `skip-bots: [dependabot, renovate]` - Skip for Dependabot and Renovate - **`skip-author-associations:`** - Skip workflow execution per-event based on the triggering payload's `author_association` (object keyed by event name, e.g. `issue_comment`, `issues`, `pull_request`; each value a string or array of associations like `CONTRIBUTOR`, case-insensitive) - Example: `skip-author-associations: { issue_comment: [first_time_contributor, contributor] }` - **`labels:`** - Filter label-triggered events to only fire when the triggering label matches one of these names (string or array) - String format: `labels: "my-label"` (single label name) - Array format: `labels: [label-a, label-b]` (any matching label fires the workflow) - Unmatched label events show as Skipped (⊘) rather than Failed (❌) - Use with `pull_request` triggers with `types: [labeled]` to respond only to specific labels - **`skip-if-match:`** - Skip workflow execution when a GitHub search query returns results (string or object) - String format: `skip-if-match: "is:issue is:open label:bug"` (implies max=1) - Object format with threshold: ```yaml skip-if-match: query: "is:issue is:open label:in-progress" max: 3 # Skip if 3 or more matches (default: 1) scope: none # Optional: disable automatic repo:owner/repo scoping for org-wide queries ``` - Query is automatically scoped to the current repository (use `scope: none` for cross-repo queries) - Use to avoid duplicate work (e.g., skip if an open issue already exists) - **`skip-if-no-match:`** - Skip workflow execution when a GitHub search query returns no results (string or object) - String format: `skip-if-no-match: "is:pr is:open label:ready-to-deploy"` (implies min=1) - Object format with threshold: ```yaml skip-if-no-match: query: "is:pr is:open label:ready-to-deploy" min: 2 # Require at least 2 matches to proceed (default: 1) scope: none # Optional: disable automatic repo:owner/repo scoping for org-wide queries ``` - Query is automatically scoped to the current repository (use `scope: none` for cross-repo queries) - Use to gate workflows on preconditions (e.g., only run if open PRs exist) - **`skip-if-check-failing:`** - Skip workflow execution when CI checks are failing on the triggering ref (boolean or object) - Boolean format: `skip-if-check-failing: true` (skip if any check is failing or pending) - Object format with filtering: ```yaml skip-if-check-failing: include: - build - test # Only check these specific CI checks exclude: - lint # Ignore this check branch: main # Optional: check a specific branch instead of triggering ref allow-pending: true # Optional: treat pending/in-progress checks as passing (default: false) ``` - When `include` is omitted, all checks are evaluated - By default, pending/in-progress checks count as failing; set `allow-pending: true` to ignore them - Use to avoid running agents against broken code (e.g., skip PR review if CI is red) - **`github-token:`** - Custom GitHub token for pre-activation reactions, status comments, and skip-if search queries (string) - When specified, overrides the default `GITHUB_TOKEN` for these operations - Example: `github-token: ${{ secrets.MY_GITHUB_TOKEN }}` - **`github-app:`** - GitHub App credentials for minting a token used in pre-activation operations (object) - Mints a single installation access token shared across reactions, status comments, and skip-if queries - Can be defined in a shared agentic workflow and inherited by importing workflows - Fields: - `client-id:` - GitHub App client ID (required, e.g., `${{ vars.APP_ID }}`). Use `app-id:` for legacy compatibility. - `private-key:` - GitHub App private key (required, e.g., `${{ secrets.APP_PRIVATE_KEY }}`) - `owner:` - Optional installation owner (defaults to current repository owner) - `repositories:` - Optional list of repositories to grant access to - Example: ```yaml on: issues: types: [opened] github-app: client-id: ${{ vars.APP_ID }} private-key: ${{ secrets.APP_PRIVATE_KEY }} ``` - **`stale-check:`** - Control whether the activation job verifies hashes against the compiled workflow (boolean or `"full"`, default: `true`) - When `false`, disables the hash check step; useful when workflow files are managed outside the default repository context (e.g., cross-repo org rulesets) - When `"full"`, checks both the frontmatter hash and body hash; use when prompt-body edits should also trigger recompilation detection - **`report-blocked-version:`** - Whether the activation job creates/updates a notification issue when compiled with a blocked `gh-aw` version (boolean, default: `true`). Set `false` to suppress just the notification issue while keeping the blocked-version hard failure active; independent of `check-for-updates` (disables the whole check) and `safe-outputs.report-failure-as-issue`. - **`github-app:`** - Top-level GitHub App credentials, used as a fallback for every nested `github-app` token-minting operation (`on.github-app`, `safe-outputs.github-app`, `checkout.github-app`, `tools.github.github-app`, `dependencies.github-app`) that does not define its own. Same fields as `on.github-app` above (`client-id`/`app-id`, `private-key`, `owner`, `repositories`). - **`permissions:`** - GitHub token permissions - Object with permission levels: `read`, `none` (and limited `write` for specific scopes) - Common permission scopes (not exhaustive; standard GitHub Actions scopes plus `models`, `copilot-requests`): `contents`, `issues`, `pull-requests`, `discussions`, `actions`, `checks`, `statuses`, `models`, `deployments`, `security-events`, `packages`, `pages`, `attestations`, `copilot-requests` - Write permissions are not allowed for security reasons; use `safe-outputs` for write operations instead - Exceptions: `id-token: write` is allowed to enable OIDC token minting; `copilot-requests: write` is recommended when targeting the Copilot coding agent so it can authenticate with `${{ github.token }}` - **`runs-on:`** - Runner type for the main agent job (string, array, or object) - **`runs-on-slim:`** - Runner type for all framework/generated jobs (activation, safe-outputs, unlock, etc.). Defaults to `ubuntu-slim`. `safe-outputs.runs-on` takes precedence for safe-output jobs specifically. - **`runner:`** - Runner topology configuration (object). `topology: arc-dind` (only enum value) targets GitHub ARC runners with rootless Docker-in-Docker: gh-aw emits the topology in the AWF config, redirects the tool cache to a shared volume, and validates that no generated step requires root. AWF then activates split-filesystem handling, network isolation, sysroot staging, and DinD pre-staging automatically. ```yaml runner: topology: arc-dind ``` - **`timeout-minutes:`** - Agent execution step timeout in minutes (integer or GitHub Actions expression, defaults to `${{ vars.GH_AW_DEFAULT_TIMEOUT_MINUTES }}` or 20 minutes; custom and safe-output jobs use the GitHub Actions platform default of 360 minutes unless explicitly set). It bounds the `agentic_execution` step only; the generated `agent` and `detection` jobs have their own timeouts (see [jobs.md](jobs.md)). Expressions are useful in compiled workflows that define `workflow_call` inputs, for example `timeout-minutes: ${{ inputs.timeout }}`. This setting applies to the workflow being compiled, not to plain GitHub Actions caller jobs that use job-level `uses:` (GitHub does not allow `timeout-minutes` on those caller jobs). - **`concurrency:`** - Concurrency control (string or object) - **`queue:`** - Pending run queue behavior for the concurrency group (`single` or `max`, defaults to `single`). `single` keeps one pending run and replaces older pending runs; `max` allows up to 100 pending runs in FIFO order (useful for conclusion jobs that must not be dropped). ```yaml concurrency: group: "my-workflow" queue: max ``` - **`job-discriminator:`** - Expression appended to compiler-generated job-level concurrency groups (`agent`, `output`, and `conclusion` jobs), preventing fan-out cancellations when multiple workflow instances run concurrently with different inputs. Common usage: ```yaml concurrency: job-discriminator: ${{ inputs.finding_id }} ``` Common expressions: | Scenario | Expression | |---|---| | Fan-out by input | `${{ inputs.finding_id }}` | | Universal uniqueness | `${{ github.run_id }}` | | Dispatched or scheduled fallback | `${{ inputs.organization \|\| github.run_id }}` | `job-discriminator` is a gh-aw extension stripped from the compiled lock file. Has no effect on `workflow_dispatch`-only, `push`, or `pull_request` triggered workflows. - **`env:`** - Environment variables (object or string) - **`if:`** - Conditional execution expression (string) - **`run-name:`** - Custom workflow run name (string) - **`name:`** - Workflow name (string) - **`pre-steps:`** - Custom workflow steps to run at the very beginning of the agent job, before checkout (object). Use for token minting or setup that must happen before the repository is checked out. Step outputs are available via `${{ steps..outputs. }}` and can be referenced in `checkout.github-token` to avoid masked-value cross-job boundary issues. Same security restrictions apply as for `steps:`. - For job-scoped hooks under `jobs.`, `setup-steps` run before framework GitHub App token minting and checkout, while `pre-steps` run after compiler setup and before the job's main steps. - **`steps:`** - Custom workflow steps before AI execution (object). **Security Notice**: Custom steps run OUTSIDE the firewall sandbox with standard GitHub Actions security but NO network egress controls. Use only for deterministic data preparation, not agentic compute. **Secrets restriction**: Using `${{ secrets.* }}` expressions (other than `secrets.GITHUB_TOKEN`) in custom steps is an error in strict mode and a warning otherwise — move secret-dependent operations to a separate job outside the agent job. - **`pre-agent-steps:`** - Custom workflow steps to run before MCP gateway startup (object or array). Use when preparation must install or configure MCP dependencies before the gateway starts. Same security restrictions apply as for `steps:`. - **`post-steps:`** - Custom workflow steps after AI execution (object). **Security Notice**: Post-execution steps run OUTSIDE the firewall sandbox. Use only for deterministic cleanup, artifact uploads, or notifications—not agentic compute or untrusted AI execution. Same secrets restriction applies as for `steps:`. - **`environment:`** - Environment that the job references for protection rules (string or object) - **`container:`** - Container to run job steps in (string or object) - **`services:`** - Service containers that run alongside the job (object) - **`secrets:`** - Secret values passed to workflow execution (object) - Use GitHub Actions expressions: `${{ secrets.API_KEY }}` - String format: `secrets: { API_TOKEN: "${{ secrets.API_TOKEN }}" }` - Object format with descriptions: ```yaml secrets: API_TOKEN: value: ${{ secrets.API_TOKEN }} description: "API token for external service" ``` - Never commit plaintext secrets - For reusable workflows, use `jobs..secrets` instead - **`excluded-env:`** - Optional list of environment variable names to unconditionally exclude from the AWF agent container via `--exclude-env` (array of strings). Use when an env var carries a credential the compiler cannot auto-detect (for example a `workflow_dispatch` input holding a token). Names are deduplicated and merged with those auto-detected from `secrets.*` and `needs.*.outputs.*` references. - Example: `excluded-env: [MY_DISPATCH_TOKEN, GH_TOKEN]` --- description: `engine:` frontmatter field detail for GitHub Agentic Workflows. --- # Engine Configuration See [syntax-agentic.md](syntax-agentic.md) for the full frontmatter field index. - **`engine:`** - AI processor configuration - String format: `"copilot"` (current default), `"claude"`, `"codex"`, `"gemini"`, or `"pi"`. Omit `engine:` when there is no engine preference or engine-specific requirement so the configured default remains in effect. If an explicit model requirement forces engine selection, try Copilot first. - The experimental `opencode` engine is available through `imports: [shared/opencode.md]`; see [`smoke-opencode.md`](../workflows/smoke-opencode.md) for an example. - The experimental `deepseek-harness` engine is available through `imports: [shared/deepseek-harness.md]`; see [`smoke-deepseek-harness.md`](../workflows/smoke-deepseek-harness.md) for an example. It runs the developer-preview `dsh` headless profile with AWF provider routing and uses `provider/model` syntax. - The experimental `cursor` engine is available through `imports: [shared/cursor.md]`; see [`smoke-cursor.md`](../workflows/smoke-cursor.md) for an example. Requires the `CURSOR_API_KEY` secret. Cursor reads project rules from `.cursor/rules/*.mdc` and respects the root-level `.cursorignore` and `AGENTS.md`; both are protected in the manifest. Use `model: cursor/auto` or a specific model such as `cursor/claude-3-7-sonnet`. - The experimental `kiro` engine is available through `imports: [shared/kiro.md]`; see [`smoke-kiro.md`](../workflows/smoke-kiro.md) for an example. Requires the `KIRO_API_KEY` secret. Kiro reads steering documents from `.kiro/steering/` and hook definitions from `.kiro/hooks/`; these directories and `AGENTS.md` are protected in the manifest. Model must use `kiro/` prefix, e.g. `model: kiro/claude-sonnet-4-5`. - The experimental `pydantic-ai` engine is available through `imports: [pydantic/pydantic-ai-harness/gh-aw/pydantic.md@main]`; see [`smoke-pydantic.md`](../workflows/smoke-pydantic.md) for an example. It runs the Pydantic AI `pai` CLI with the `pydantic-ai-harness` coder agent and uses `provider/model` syntax. - The experimental `crush`, `aider`, `goose`, and `custom` (GenAIScript) engines are also available through `imports: [shared/.md]`; see [`smoke-crush.md`](../workflows/smoke-crush.md), [`smoke-aider.md`](../workflows/smoke-aider.md), and [`smoke-goose.md`](../workflows/smoke-goose.md) for examples. Full list of import-based engines: see `.github/aw/engines.json`. - Object format for extended configuration: ```yaml engine: id: copilot # Required: coding agent identifier (copilot, claude, codex, gemini, pi) version: beta # Optional: version of the action (has sensible default); also accepts GitHub Actions expressions: ${{ inputs.engine-version }} model: gpt-5 # Deprecated alias for the top-level `model`; prefer the top-level field permission-mode: acceptEdits # Optional (claude only): auto | acceptEdits | plan | bypassPermissions. Default: acceptEdits (auto when tools.edit is false) agent: technical-doc-writer # Optional: custom agent file (Copilot only, references .github/agents/{agent}.agent.md) max-turns: 5 # Deprecated alias for the top-level `max-turns`; prefer the top-level field max-continuations: 3 # Optional: max autopilot continuations (copilot only; >1 enables --autopilot mode, default: 1) concurrency: "gh-aw-${{ github.workflow }}" # Optional: agent job concurrency group (string or GitHub Actions concurrency object) env: # Optional: custom environment variables (object) DEBUG_MODE: "true" args: ["--verbose"] # Optional: custom CLI arguments injected before prompt (array) api-target: api.acme.ghe.com # Optional: custom API endpoint hostname for GHEC/GHES (hostname only, no protocol/path) command: /usr/local/bin/copilot # Optional: override default engine executable (skips installation) bare: true # Optional: disable automatic context loading. Only supported by 'copilot' (--no-custom-instructions) and 'claude' (--bare); ignored with a warning on other engines. Default: false user-agent: "myapp/1.0" # Optional: custom user agent string (codex engine only) config: | # Optional: additional TOML config appended to config.toml (codex engine only) [extra] key = "value" ``` - **`gemini` engine**: Google Gemini CLI. Requires `GEMINI_API_KEY` secret. Does not support `web-search`. Supports AWF firewall and LLM gateway. - **`engine.driver:`** — canonical field to run a custom inner driver script instead of the engine's built-in CLI. For the `pi` engine it launches the driver directly with Node.js (e.g. built-in `pi_agent_core_driver.cjs`, or a workspace-relative path like `.github/drivers/pi_agent_core_driver_sample_node.cjs`); the driver must emit JSONL compatible with `parse_pi_log.cjs` so step summaries and token tracking keep working. Accepts a bare basename (resolved from the setup-action directory) or a workspace-relative path; no absolute paths, no `..`, only `.js`/`.cjs`/`.mjs` (pi). - **`copilot-sdk`** (copilot only): set `copilot-sdk: true` to start a headless Copilot CLI SDK sidecar. **`engine.driver`** (experimental, copilot only): set `driver: ` to supply a custom SDK driver (`.js`/`.cjs`/`.mjs`/`.py`/`.ts`/`.mts`/`.rb`, or a bare PATH command); this also enables `copilot-sdk: true` automatically. Tune the repeated-tool-denial safeguard with the top-level `max-tool-denials:` field (default `5`). **Inline driver source** (copilot engine only): instead of pointing to a checked-in file, you can embed the driver source directly in the frontmatter using an object with exactly one runtime key (`node`, `python`, `go`, or `java`). The compiler materializes the source under `.gh-aw/copilot-sdk/` at runtime and generates a launcher wrapper. The required SDK package is installed automatically. ```yaml # Node.js / TypeScript inline driver (SDK installed via npm) engine: id: copilot driver: node: | const sdk = require("@github/copilot-sdk"); // ... driver implementation ``` ```yaml # Python inline driver (SDK installed via pip into workspace target dir) engine: id: copilot driver: python: | import sys from github_copilot_sdk import CopilotAgent # ... driver implementation ``` ```yaml # Go inline driver (SDK installed via go get; go.mod generated automatically) engine: id: copilot driver: go: | package main import "github.com/github/copilot-sdk/go" func main() { /* driver implementation */ } ``` ```yaml # Java inline driver (SDK resolved via Maven pom.xml generated automatically) engine: id: copilot driver: java: | public class Main { public static void main(String[] args) { /* driver implementation */ } } ``` Constraints: exactly one runtime key per `driver` object; source must be non-empty; only supported on the `copilot` engine. Use `runtimes..version` to pin the runtime version used for the generated module files (e.g. `runtimes.go.version: "1.22"`). - **`engine.auth:`** — keyless Workload Identity Federation via the AWF API proxy instead of a static API key; requires `id-token: write`. Set `type: github-oidc` (only supported type) plus `provider: azure` (`azure-tenant-id`, `azure-client-id`, optional `azure-scope`/`azure-cloud`) for Azure OpenAI, `provider: anthropic` (`federation-rule-id`, `organization-id`, `service-account-id`, `workspace-id`) for Claude, or `provider: gcp` (`workload-identity-provider`, `service-account`, optional `project`/`location`, default region `us-central1`) for Vertex AI / Gemini Enterprise. Optional `audience:`. Maps to `AWF_AUTH_*` env vars. - **Advanced engine sub-fields** (see the `engine_config` definition in `pkg/parser/schemas/main_workflow_schema.json`): `model-provider` (`github` | `anthropic` | `openai`), `harness` (`max-retries`/`initial-delay-ms`/`backoff-multiplier`/`max-delay-ms` retry policy, plus `watchdog-timeout` — a post-result idle-process watchdog, in seconds, for the built-in Copilot/Codex harnesses), engine-level `mcp` (`session-timeout`/`tool-timeout`), `extensions`, and `cwd`. See [Harness Settings and Runtime Tuning Variables](https://github.com/github/gh-aw/blob/main/docs/src/content/docs/reference/environment-variables.md#harness-settings-and-runtime-tuning-variables) for defaults, units, and `GH_AW_HARNESS_*` env var equivalents. --- description: Cache, tool, import, and permission reference for GitHub Agentic Workflows frontmatter. --- # Tools, Imports, and Permissions ### Cache Configuration The `cache:` field supports the same syntax as the GitHub Actions `actions/cache` action: **Single Cache:** ```yaml cache: key: node-modules-${{ hashFiles('package-lock.json') }} path: node_modules restore-keys: | node-modules- ``` **Multiple Caches:** ```yaml cache: - key: node-modules-${{ hashFiles('package-lock.json') }} path: node_modules restore-keys: | node-modules- - key: build-cache-${{ github.sha }} path: - dist - .cache restore-keys: - build-cache- fail-on-cache-miss: false ``` **Supported Cache Parameters:** - `key:` - Cache key (required) - `path:` - Files/directories to cache (required, string or array) - `restore-keys:` - Fallback keys (string or array) - `upload-chunk-size:` - Chunk size for large files (integer) - `fail-on-cache-miss:` - Fail if cache not found (boolean) - `lookup-only:` - Only check cache existence (boolean) Cache steps are auto-added to the workflow job; cache config is removed from the final `.lock.yml`. > **Memory configuration**: For `cache-memory:`, `repo-memory:`, and `comment-memory:`, see [memory.md](memory.md). ## Tool Configuration The `tools:` field configures which tools the coding agent may use. ### GitHub Tools (`tools.github`) - `allowed:` - Array of allowed GitHub API functions. Each entry is either a string tool name (e.g., `issue_read`) or an object `{ name: , max-calls: }` to cap how many times that tool may be called per run. Colon shorthand (`"issue_read:1"`) is **not** a call-limit form. ```yaml tools: github: allowed: - { name: issue_read, max-calls: 1 } - list_labels - pull_request_read ``` - `mode:` - GitHub access mode. **Prefer `"gh-proxy"`** — it is faster (no MCP server startup) and lets the agent use `gh` shell commands directly for all GitHub reads (issues, PRs, discussions, commits, etc.): - `"gh-proxy"` (**preferred**) — pre-authenticated `gh` CLI available in bash; no GitHub MCP server is registered. Use `gh` commands for all GitHub reads. - `"local"` (default) — Docker-based GitHub MCP Server; use GitHub MCP tools for reads, `gh` is not authenticated. - **do NOT use `"remote"`** — it does not work with the GitHub Actions token; use `"gh-proxy"` instead. - `version:` - MCP server version (local mode only) - `args:` - Additional command-line arguments (local mode only) - `read-only:` - The GitHub MCP server always operates in read-only mode; this field is accepted but has no effect - `github-token:` - Custom GitHub token - `lockdown:` - Enable lockdown mode to limit content surfaced from public repositories to items authored by users with push access (boolean, default: false) - `github-app:` - GitHub App configuration for token minting; when set, mints an installation access token at workflow start that overrides `github-token` - `client-id:` - GitHub App client ID (required, e.g., `${{ vars.APP_ID }}`). Use `app-id:` for legacy compatibility. - `private-key:` - GitHub App private key (required, e.g., `${{ secrets.APP_PRIVATE_KEY }}`) - `owner:` - Optional installation owner (defaults to current repository owner) - `repositories:` - Optional list of repositories to grant access to (array) - `permissions:` - Optional extra permissions to include in the minted token for org-level API access (object) - Example: `permissions: { members: read, organization-administration: read }` — required when calling org-level APIs (e.g., `orgs`, `users` toolsets) since the default GITHUB_TOKEN does not have org-scoped permissions - `min-integrity:` - Minimum integrity level for MCP Gateway guard policy; controls which content the agent may act on based on author trust (`none`, `unapproved`, `approved`, `merged`) - `blocked-users:` - Usernames whose content is unconditionally blocked (array or GitHub Actions expression); these users receive integrity below `none` and are always denied - `approval-labels:` - Label names that elevate a content item's integrity to `approved` when present (array or GitHub Actions expression); does not override `blocked-users` - `trusted-users:` - Usernames elevated to `approved` integrity regardless of `author_association` (array or GitHub Actions expression); takes precedence over `min-integrity` but not over `blocked-users`; requires `min-integrity` to be set - `private-to-public-flows:` - Opt out of MCP Gateway cross-visibility protections (which block private-repo data from reaching public sinks). `allow` disables `forcePublicRepos` and sink-visibility enforcement for all servers (**not compatible with strict mode**); an array of MCP server IDs (e.g. `[github, my-server]`) exempts only those servers from sink-visibility enforcement (strict-mode compatible, keeps `forcePublicRepos`). Security-sensitive — only use when private→public flows are intended. - `toolsets:` - Enable specific GitHub toolset groups (single name string or array; a string is shorthand for a one-element array) - **Default toolsets** (when unspecified): `context`, `repos`, `issues`, `pull_requests` (excludes `users` as GitHub Actions tokens don't support user operations) - **Group aliases**: `default` (recommended action-friendly set), `action-friendly` (action-safe toolsets, excludes `users`), `all` (everything) - **Individual toolsets**: `context`, `repos`, `issues`, `pull_requests`, `actions`, `code_quality`, `code_security`, `copilot`, `copilot_issue_intents`, `copilot_spaces`, `dependabot`, `discussions`, `gists`, `git`, `github_support_docs_search`, `labels`, `notifications`, `orgs`, `projects`, `secret_protection`, `security_advisories`, `stargazers`, `users` Search tools are distributed across `repos`, `orgs`, `users`, and `issues`; there is no standalone `search` toolset. - Examples: `toolsets: [default]`, `toolsets: [default, discussions]`, `toolsets: [repos, issues]` - **Recommended**: Prefer `toolsets:` over `allowed:` for better organization and reduced configuration verbosity ### Other Built-in Tools - `agentic-workflows:` - GitHub Agentic Workflows MCP server for workflow introspection. Provides `status`, `compile`, `logs`, `audit`, and `checks` tools so agents can analyze run traces and improve workflows. Enable with `agentic-workflows: true`. - `edit:` - File editing tools (required to write to files in the repository) - `web-fetch:` - Web content fetching tools - `web-search:` - Web search tools - `bash:` - Shell command tools - **Bash allowlist decision rule:** - **PR-triggered workflows** processing **untrusted input** (issue/PR body, comment text, user-provided filenames): use a **narrow allowlist** (e.g. `[find, cat, grep, wc, jq]`). This limits blast radius if shell injection is embedded in untrusted content. - **`schedule` or `workflow_dispatch` workflows** with **no untrusted input** (only trusted API data or internal state): `["*"]` is acceptable. - **Rule of thumb**: If the workflow reads issue/PR bodies, comment text, or other user-provided strings, use a narrow list. Otherwise `["*"]` is acceptable. ```yaml # PR-triggered workflow reading untrusted user text on: pull_request: tools: bash: [find, cat, grep, wc, jq] # Internal scheduled workflow reading only trusted/internal data on: schedule: - cron: "0 * * * *" tools: bash: ["*"] ``` - `playwright:` - Browser automation for visual regression, accessibility, and end-to-end testing. The built-in integration uses `playwright-cli ` in bash, and `localhost` reaches local servers directly. `mode: mcp` is removed; use a custom `mcp-servers` entry if MCP is required. Pin the CLI with `version:` and restrict network to `local` + `playwright`. ```yaml tools: playwright: version: "0.1.11" # optional: @playwright/cli npm package version ``` - `timeout:` - Per-operation timeout in seconds for all tool and MCP calls (integer or expression, default: 60 s for all engines). - `startup-timeout:` - Timeout in seconds for MCP server initialization (integer or expression, default: 120). - `cli-proxy:` - Mount each user-facing MCP server as a standalone CLI tool on `PATH` (boolean, default: `false`). When enabled, the agent can call MCP servers via shell (e.g. `github issue_read --method get ...`). ### Custom MCP Tools Stdio MCP servers must be Docker-based (use `container:` + `entrypoint:`). For Node/Python servers already installed on the runner, use HTTP transport instead: ```yaml # Stdio (Docker-based) mcp-servers: my-custom-tool: container: "ghcr.io/my-org/my-tool:latest" entrypoint: "my-tool" allowed: - custom_function_1 - custom_function_2 # HTTP (for Node/Python servers running on the runner) mcp-servers: my-node-tool: type: http url: "http://localhost:8765/mcp" ``` HTTP MCP servers are also supported with optional upstream authentication: ```yaml mcp-servers: my-server: type: http url: "https://myserver.example.com/mcp" headers: Authorization: "Bearer ${{ secrets.API_KEY }}" # Optional: custom headers my-oidc-server: type: http url: "https://myserver.example.com/mcp" auth: type: github-oidc # GitHub Actions OIDC token authentication audience: "https://myserver.example.com" # Optional: custom OIDC audience ``` `auth.type: github-oidc` uses GitHub Actions OIDC tokens for secure server-to-server authentication without static credentials. The `audience` field defaults to the server URL when omitted. - `required:` - Whether a stdio or HTTP MCP server must pass its startup connectivity check (boolean, default: `true`). Set `false` for an optional server so a failed startup check only logs a warning and the workflow continues without it, instead of failing the run. ## Agent Plugins (`plugins:`) :::caution[Experimental] Compiling a workflow that uses `plugins:` emits a warning; the interface may change. ::: Installs [Agent Plugins](https://agent-plugins.org) through the selected engine (top-level field, distinct from Pi's `engine.extensions`): ```yaml plugins: - octo-org/agent-plugin@v1 - octo-org/agent-plugins/plugins/example@main ``` - Entries use `owner/repository[/path]@ref`; `ref` is required (branch, tag, or 40-char commit SHA). - The compiler resolves every branch/tag to a commit SHA at compile time; unresolvable refs fail compilation, so generated workflows never install from a moving ref. - Supported by `copilot`, `claude`, and `codex` (each installs plugins its own way — see [syntax-engine.md](syntax-engine.md)); `gemini` and `pi` reject `plugins:` at compile time. Imported engine definitions opt in via `engine.behaviors.plugins` (see [configure-agentic-engine.md](configure-agentic-engine.md)). - Plugin object entries support per-entry `github-token` or `github-app` (mutually exclusive), so private plugin repositories are supported. - Merge behavior across imports: see the imports merge list above. ### Engine Network Permissions Control network access via the top-level `network:` field (defaults to `network: defaults` — basic infrastructure only). For workflows that build, test, or install packages, always add the language ecosystem alongside `defaults`: ```yaml network: allowed: - defaults # Basic infrastructure (CAs, Ubuntu verification, JSON schema) - node # Node.js / npm ecosystem - "api.custom.com" # Custom domain blocked: - "*.ads.com" # Block domain patterns ``` > **Full reference**: valid ecosystem identifiers, invalid shorthands, wildcard/protocol rules, and per-language inference live in [network.md](network.md). Do not restate the ecosystem table here. ## Imports Field Import shared components using the `imports:` field in frontmatter: ```yaml --- on: issues engine: copilot imports: - copilot-setup-steps.yml # Import setup steps from copilot-setup-steps.yml - shared/security-notice.md - shared/tool-setup.md - shared/mcp/tavily.md --- ``` **Object form with inputs** — Use `path:`/`uses:` + `with:`/`inputs:` to pass values to shared workflows that define an `import-schema:`: ```yaml imports: - path: shared/tool-setup.md with: environment: staging max-issues: 3 - uses: shared/security-notice.md # 'uses' is an alias for 'path' ``` `path`/`uses` and `with`/`inputs` are the only valid keys on an import entry. To supply environment variables or a checkout ref, set top-level `env:`/`checkout:` frontmatter inside the imported file itself — those are merged into the importing workflow (see the merge list below), not configured per import entry. Conditional `imports:` entries are not supported. For experiment-specific prompt variants, keep the import unconditional and gate a `{{#runtime-import? ...}}` block (optional form) in the workflow body instead. The optional form is not promoted to unconditional lock-file macros, so the content is only injected when the condition is true at runtime. Inside the imported workflow, access values via `${{ github.aw.import-inputs. }}`. ### Import File Structure Import files are in `.github/workflows/shared/` and can contain: - Tool configurations - Safe-outputs configurations - Text content - Mixed frontmatter + content The following frontmatter fields in imported files are merged into the importing workflow: - `tools:` - Merged with the importing workflow's tools - `safe-outputs:` - Merged with safe-output configuration - `env:` - Environment variables merged; conflicts between two imports defining the same key are compilation errors (remove the duplicate or move it to the main workflow to override) - `checkout:` - Checkout configurations appended (main workflow's checkouts take precedence) - `github-app:` - Top-level GitHub App credentials (first-wins across imports) - `on.github-app:` - Activation GitHub App credentials (first-wins across imports) - `steps:` - Steps appended in import order - `pre-agent-steps:` - Steps appended in import order - `post-steps:` - Steps appended in import order - `jobs..setup-steps`, `jobs..pre-steps`, and `jobs.activation.steps` - Merged per job with imported steps first, then main workflow steps. Execution order is `setup-steps` before `pre-steps`; `jobs.activation.steps` run later in the activation job before the activation artifact is staged. - `runtimes:`, `network:`, `permissions:`, `services:`, `cache:`, `features:`, `mcp-servers:` - `plugins:` - Union by plugin path; identical refs dedupe, compatible semantic versions select the highest, incompatible majors/non-semver conflicts fail compilation Example import file: ```markdown --- tools: github: allowed: [get_repository, list_commits] safe-outputs: create-issue: labels: [automation] env: MY_VAR: "shared-value" checkout: fetch-depth: 0 --- Additional instructions for the coding agent. ``` ### Special Import: copilot-setup-steps.yml The `copilot-setup-steps.yml` file receives special handling when imported. Instead of importing the entire job structure, **only the steps** from the `copilot-setup-steps` job are extracted and inserted **at the start** of your workflow's agent job. **Key behaviors:** - Only the steps array is imported (job metadata like `runs-on`, `permissions` is ignored) - Imported steps are placed **at the start** of the agent job (before all other steps) - Other imported steps are placed after copilot-setup-steps but before main frontmatter steps - Main frontmatter steps come last - Final order: **copilot-setup-steps → other imported steps → main frontmatter steps** - Supports both `.yml` and `.yaml` extensions - Enables clean reuse of common setup configurations across workflows **Example:** ```yaml --- on: issue_comment engine: copilot imports: - copilot-setup-steps.yml - shared/common-tools.md steps: - name: Custom environment setup run: echo "Main frontmatter step runs last" --- ``` In the compiled workflow, the order is: copilot-setup-steps → imported steps from shared/common-tools.md → main frontmatter steps. ## Permission Patterns **IMPORTANT**: Agentic workflows should not include write permissions (`contents: write`, `issues: write`, `pull-requests: write`) on the main agent job. Safe-outputs provide these via separate secured jobs. In `strict: true` mode, granting any of these three write scopes to the main job is a compilation error; outside strict mode it compiles but is against the recommended security posture (see [workflow-constraints.md](workflow-constraints.md)). ### Read-Only Pattern ```yaml permissions: contents: read metadata: read ``` ### Output Processing Pattern (Recommended) ```yaml permissions: contents: read # Main job minimal permissions actions: read safe-outputs: create-issue: # Automatic issue creation add-comment: # Automatic comment creation create-pull-request: # Automatic PR creation ``` **Key Benefits of Safe-Outputs:** - Main job runs with minimal permissions - Write operations handled by dedicated jobs - Safe-outputs jobs auto-receive required permissions - Clear audit trail between AI processing and GitHub API --- description: Compact index for the GitHub Agentic Workflows frontmatter schema. --- # Frontmatter Schema Index Use the smallest relevant reference instead of loading one large schema file. | Topic | File | |---|---| | Core GitHub Actions fields (`on`, `permissions`, `runs-on`, `steps`, `env`, `secrets`) | [syntax-core.md](syntax-core.md) | | Agentic workflow specific fields (`strict`, `bots`, `labels`, metadata) | [syntax-agentic.md](syntax-agentic.md) | | `engine:` field detail (per-engine support, inline drivers, auth) | [syntax-engine.md](syntax-engine.md) | | Cache configuration, tools, imports, and permission patterns | [syntax-tools-imports.md](syntax-tools-imports.md) | | `skills` field | [skills.md](skills.md) | | `plugins` field (experimental Agent Plugins) | [syntax-tools-imports.md](syntax-tools-imports.md#agent-plugins-plugins) | | `lsp` field | [lsp.md](lsp.md) | | `evals` field (BinEval binary evaluations) | [evals.md](evals.md) | ## Usage Guidance - Load only the section required for the current task. - Prefer the dedicated topic files over copying schema details into creator or updater prompts. - Keep examples short and route deep detail to the relevant syntax sub-file. --- description: Guidance for creating agentic workflows that analyze test coverage — prefer reading pre-computed CI artifacts over re-running tests. --- # Test Coverage Workflow Guidance Consult this file when creating or updating a workflow that analyzes test coverage. ## Core Principle: Read Artifacts First Always prefer fetching pre-computed coverage artifacts from CI over re-running tests. Re-running duplicates CI work. ## Coverage Data Strategy Include this decision block in every coverage workflow prompt: ``` 1. Find the latest successful CI run for this commit: `gh run list --commit "$HEAD_SHA" --status success --limit 5 --json databaseId,workflowName` 2. Download the coverage artifact (try names: coverage-report, coverage, test-results): `gh run download --name coverage-report --dir /tmp/coverage` 3. If found, parse and analyze it — do NOT re-run tests. 4. If not found, run tests with coverage and note in the report that data was computed fresh. ``` ## Frontmatter Template ```yaml engine: copilot on: pull_request: types: [opened, synchronize] permissions: actions: read # download artifacts network: defaults tools: github: toolsets: [default, actions] # actions toolset enables artifact download safe-outputs: add-comment: hide-older-comments: true upload-code-coverage: ``` `upload-code-coverage` is experimental and publishes a Cobertura XML coverage report to GitHub's code coverage API via [`actions/upload-code-coverage`](https://github.com/actions/upload-code-coverage). Compilation emits a warning when this feature is used. The compiler automatically grants the dedicated `code-quality: write` (and `pull-requests: read` for push-triggered workflows) permission needed by the upload job — no need to add it to the `permissions:` block above. ## Fallback: Run Tests Use **only when** no prior CI artifact exists or CI doesn't upload coverage. Supported commands: - infer the repository ecosystem from project files before running fallback coverage - configure `network.allowed` to include `defaults` plus the inferred ecosystem(s) (for example `node`, `python`, `go`) - never run fallback coverage with `network: defaults` alone - convert the freshly generated coverage report to Cobertura XML format (e.g. `coverage.py xml`, `go-cobertura`, or a JaCoCo/Istanbul Cobertura reporter), stage it under `$RUNNER_TEMP/gh-aw/safeoutputs/upload-code-coverage/`, and call `upload_code_coverage` with `file: "cobertura.xml"`, `language` set to the inferred ecosystem's Linguist name (e.g. `"Go"`, `"Python"`, `"JavaScript"`), and a descriptive `label` (e.g. `"code-coverage/fallback"`) Example fallback network config: ```yaml network: allowed: - defaults - node ``` | Language | Command | Cobertura conversion | |---|---|---| | Node.js | `npx jest --coverage --coverageReporters=cobertura` | Jest's `cobertura` reporter writes `coverage/cobertura-coverage.xml` directly | | Python | `python -m pytest --cov=src --cov-report=xml` | `pytest-cov`'s `--cov-report=xml` writes Cobertura-format `coverage.xml` directly | | Go | `go test ./... -coverprofile=/tmp/coverage.out` | convert with `gocover-cobertura < /tmp/coverage.out > cobertura.xml` | --- on: workflow_call: inputs: engine-version: type: string engine: id: copilot version: ${{ inputs.engine-version }} --- Fix the bug --- description: Prompt caching, AI-credit budget guardrails, and bounded file reads for GitHub Agentic Workflows. --- # Token Optimization — Caching, Budgets, and Bounded Reads See [token-optimization.md](token-optimization.md) for the full technique index and quick-reference checklist. ## Technique 9 — Enable Prompt Caching Prompt caching is automatic via the AWF gateway. Cached input tokens are weighted at `0.1` versus `1.0` for uncached input — repeated context (system prompt, shared preamble) costs ~10× less when cached. To maximize cache hits: - **Keep stable content at the top of the prompt** — instructions that don't change between runs (role, output format, schema) before dynamic content (issue body, event context). - **Use `cache-memory`** for workflows that re-read the same large knowledge base across runs; avoids duplicate context every turn. - **Minimize dynamic context** — inject only the fields the agent needs: `${{ github.event.issue.number }}` instead of the full event payload. --- ## Technique 10 — Cap Spend with AI-Credit Guardrails Two top-level frontmatter fields enforce AI Credit budgets directly, independent of the techniques above. Both accept an integer or a `K`/`M` short-form string (e.g. `100M`, `500K`). Typical workflow range: `100` to `2500`. Do not treat a workflow exhausting its per-run budget as a reason to increase `max-ai-credits` immediately. First apply and measure every applicable cost optimization in this guide. Increase the limit only as a last resort when the workflow still cannot complete with acceptable quality within the existing budget. - **`max-ai-credits:`** — Per-run AI credit budget enforced by the AWF firewall/API proxy (default `1000`). The agent is steered to stay within budget; set a negative value to disable enforcement and steering. - **`max-daily-ai-credits:`** — Per-user 24-hour guardrail. At activation, gh-aw sums the triggering user's AI credits across their runs of this workflow over the last 24 hours and blocks execution once the total exceeds the threshold. Enabled by default with a system default threshold; set `-1` to disable, or an explicit value to override the default. ```yaml max-ai-credits: 100M # per-run cap (short-form string) max-daily-ai-credits: 500M # per-user 24h cap; -1 disables ``` For custom or private models, the top-level **`models:`** frontmatter field supplies pricing in the same structure as `models.json` (keyed `providers..models..cost` with `input`/`output`/`cache_read`/`cache_write` per-token costs). Entries are merged with the built-in `models.json` at runtime — they override matching models and fill gaps for unknown ones — so AI Credit accounting stays accurate for models gh-aw does not price by default. For self-hosted or BYOK models absent from the built-in table (e.g. Ollama, vLLM), set **`models.default-ai-credits-pricing`** (`input`/`output` in $/1M tokens, both `0` for free/local models); without it the AWF proxy rejects unrecognized models with HTTP 400 `unknown_model_ai_credits`. --- ## Technique 11 — Cap Session Context Growth from Large File Reads > **Files larger than 20 KB must not be read in full.** Use targeted reads instead. Before calling `get_file_contents`, check size with `wc -c `. If > 20 KB, use `grep`, `glob`, `bash head`, or `view` with `view_range` to read only the section you need. The same rule applies after `glob **/*.md` — read each matched file with `grep` or `view_range`, not full-file reads. For GitHub-hosted files, prefer `mode: gh-proxy` and access via `gh`/`bash` so output can be piped through `jq`, `grep`, or `head` before it enters context — the agent never receives the full file: ```bash # gh-proxy: fetch only the lines you need, no full-file injection gh api repos/{owner}/{repo}/contents/.github/aw/syntax-agentic.md \ --jq '.content' | base64 -d | grep -n "## Sub-agents" ``` ```bash # Without gh-proxy: targeted local read bash: grep -n "## Sub-agents" .github/aw/syntax-agentic.md # or view: .github/aw/syntax-agentic.md view_range=[45, 90] ``` --- description: OpenTelemetry export and harness-execution-experience learning loops for token optimization in GitHub Agentic Workflows. --- # Token Optimization — Observability and Harness Learning See [token-optimization.md](token-optimization.md) for the full technique index and quick-reference checklist. ## Technique 7 — Measure Continuously with OpenTelemetry and AgenticOps Export telemetry automatically and add workflows that keep finding token waste over time. ### Enable OTLP export Add workflow-level OpenTelemetry export so each run emits token and phase data to your observability backend: ```yaml observability: otlp: endpoint: ${{ secrets.GH_AW_OTEL_ENDPOINT }} headers: ${{ secrets.GH_AW_OTEL_HEADERS }} ``` Setup, agent, and conclusion spans carry token usage attributes. See [Frontmatter syntax](syntax-agentic.md#agentic-workflow-specific-fields). ### Add AgenticOps token workflows - `copilot-token-audit` — scheduled audit of token usage across workflows - `copilot-token-optimizer` — scheduled follow-up that identifies one expensive workflow and proposes concrete savings Loop: export OTEL → summarize usage → open optimization issues → re-measure. See `.github/workflows/` for examples. --- ## Technique 8 — Learn from Harness Execution Experience Treat the agent harness as six separate control surfaces rather than one prompt: | Dimension | gh-aw control surface | |---|---| | Context assembly | Prompt structure, imports, DataOps, and context compression | | Tool interaction | Tool selection, `gh-proxy`, `cli-proxy`, permissions, and result filtering | | Generation control | Engine and model selection, `max-turns`, and `timeout-minutes` | | Orchestration | Deterministic steps, sub-agents, planning, execution, and refinement | | Memory management | `cache-memory`, `repo-memory`, summaries, and stale-context removal | | Output processing | Safe outputs, schema validation, fallbacks, and `noop` behavior | Start with the smallest known-good harness. Per experiment, record a compact entry (task features, config change, outcome quality, AIC/token cost, diagnosed failure dimension), distill repeated diagnoses into reusable patterns, and retrieve only relevant cases later instead of re-searching broadly. Select changes **correctness first**: maximize the quality metric, then minimize AIC among equivalent-quality variants so a cheap but degraded result cannot win. Prioritize this for long-horizon, tool-heavy workflows with measurable headroom; keep retrieved experience compact so prompt caching offsets its input-token overhead. Based on [MemoHarness](https://arxiv.org/pdf/2607.14159) — treat its gains as directional (small held-out set, unablated components, cache-dependent cost advantage). --- description: Guide for reducing token consumption in agentic workflows — DataOps, gh-proxy, inline sub-agents, caveman experiments, and audit-based measurement. --- # Token Consumption Optimization If a task can be solved using deterministic tools, use deterministic tools. Only use agents when necessary, as they incur higher cost. Agentic workflows allow you to run deterministic tools first and gate agent execution using conditions, enabling workflows that avoid triggering agents most of the time and only use them when needed. ## Quick-Reference Checklist Apply these in order, measuring cost and quality after each change: - [ ] **Cheap triage first**: classify duplicates, stale items, low-value events, and known cases before escalating - [ ] **Frontier model as planner**: use frontier models for planning, synthesis, ambiguous decisions, and final judgment — not bulk extraction - [ ] **DataOps**: Move data fetching into `steps:` — agent reads compact JSON, not raw API responses - [ ] **gh-proxy**: Set `tools.github.mode: gh-proxy` — skips Docker MCP server startup and extra tool definitions - [ ] **cli-proxy**: Mount additional MCP servers as CLIs via `cli-proxy: true` — agent pipes output through `jq` before it enters context - [ ] **Sub-agents**: Delegate repetitive per-item tasks to `model: small` sub-agents (~10–20× cheaper) - [ ] **Sub-skills (inline `## skill:` blocks)**: Keep the main prompt as a short execution plan; move detailed playbooks, output templates, and formatting rules into `## skill:` blocks — the runtime extracts these before the first model call, so they are available on demand without entering the initial request context - [ ] **Prompt size**: Strip redundant instructions, examples, and pleasantries from the prompt body - [ ] **Dynamic context**: Inject only required fields — `${{ github.event.issue.number }}` not the full event payload - [ ] **Pull context on demand**: query logs/data only after a hypothesis forms; avoid preloading large raw dumps into the initial prompt - [ ] **Bound file reads**: for files > 20 KB, use `bash`/`grep`/`glob`/`view_range` instead of full-file MCP reads — late-session token spikes most often trace to unguarded `get_file_contents` calls on large workflow or skill markdown - [ ] **Prompt caching**: Put stable instructions before dynamic content to maximize cache hits - [ ] **Context hygiene**: keep the orchestrator context compact; prefer short worker summaries over raw output - [ ] **Harness-wide diagnosis**: classify failures across context, tools, generation, orchestration, memory, and output processing before changing configuration - [ ] **Execution experience**: retain compact diagnoses and outcomes, then reuse recurring patterns instead of restarting optimization from scratch - [ ] **Correctness first**: compare quality before cost; use AIC or token count only to choose among equally successful variants - [ ] **Cadence**: If the result is not time-sensitive, schedule less often (`hourly` → `daily`, `daily` → `weekly`) - [ ] **Batching**: Prefer scheduled batch processing over reactive events when delayed processing is acceptable - [ ] **Bounded subsets**: For large repetitive backlogs, process only a budget-safe subset per run and use a cache cursor or deterministic heuristic to rotate fairly through the remaining work - [ ] **Telemetry**: Configure `observability.otlp` so token usage and run phases are measurable outside individual run logs - [ ] **AgenticOps**: Add `copilot-token-audit` / `copilot-token-optimizer` workflows so the repository keeps finding waste automatically - [ ] **Measure first**: Back every change with an `experiments:` field and `metric: "aic"` before promoting - [ ] **Budget increase last**: Increase `max-ai-credits` only after all applicable optimizations above have been exhausted and measured --- ## Frontier-Model Cost Pattern A frontier model can reduce **total** cost when architecture prevents unnecessary invocations and keeps expensive context narrow. - use frontier model for planning, hypothesis selection, synthesis, ambiguous decisions, final judgment - do not spend frontier turns on repetitive extraction, duplicate detection, or broad first-pass scanning - add a cheap triage stage for known/duplicate/stale/low-value events; stop with `noop` when escalation is unnecessary - escalate to frontier model only when triage is uncertain or the case is genuinely new/high-value - cap sub-agent fan-out so escalations cannot recurse without bound Cost wins come from architecture and selective execution, not model tier alone. --- ## Pull Context, Do Not Push Context Avoid front-loading large raw context when data can be fetched on demand. Prefer deterministic pre-steps that materialize compact files under `/tmp/gh-aw/`, `gh` + filtering (`jq`, `grep`) before context reaches the model, pre-aggregated summaries over full API payloads, and directed tool calls issued only after the agent forms a hypothesis. Anchoring warning: preselecting raw logs too early can make the model over-focus and miss the actual cause. --- ## How to Measure Token Usage `gh aw audit` reports per-run cost. See [cli-commands.md](cli-commands.md#gh-aw-audit) for full command syntax (single run, `--json`, multi-run diff) and the MCP `audit` equivalent. Token-specific fields in `gh aw audit --json`: - `agent_usage.aic` — AI Credits (AIC), the normalized cost metric (1 AIC = $0.01; accounts for model price differences and cache discounts) - `agent_usage.input_tokens` / `agent_usage.output_tokens` — raw token counts - `agent_usage.cache_read_tokens` / `agent_usage.cache_write_tokens` — tokens served from the prompt cache For per-call detail, `gh aw audit ` downloads artifacts into `logs/run-/`; read `firewall-audit-logs/api-proxy-logs/token-usage.jsonl` (one API call per line, with `model` and token counts) to find the most expensive calls. Diff two runs with `gh aw audit ` to detect AI-credit regressions. Treat optimization as successful only when quality remains acceptable. A quality regression is a failure even if AI Credits decrease. --- ## Technique 1 — DataOps: Move Compute to Steps The single biggest optimization. Replace agentic data fetching with deterministic shell commands in `steps:`. Shell steps run outside the AI sandbox (no tokens) and produce structured output the agent reads directly. ### Before (agent does all the work) ```markdown --- engine: copilot tools: github: mode: gh-proxy toolsets: [default, pull_requests] --- Fetch all open PRs in ${{ github.repository }}, compute the merge rate, identify authors with the most contributions, and create a weekly summary discussion. ``` ### After (DataOps pattern) ```markdown --- engine: copilot tools: github: mode: gh-proxy bash: ["*"] steps: - name: Fetch and aggregate PR data env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | mkdir -p /tmp/gh-aw/data gh pr list --repo "${{ github.repository }}" \ --state all --limit 100 \ --json number,title,state,author,createdAt,mergedAt,additions,deletions \ > /tmp/gh-aw/data/prs.json jq '{ total: length, merged: [.[] | select(.state=="MERGED")] | length, open: [.[] | select(.state=="OPEN")] | length, top_authors: ([.[].author.login] | group_by(.) | map({author:.[0], count:length}) | sort_by(-.count) | .[0:5]) }' /tmp/gh-aw/data/prs.json > /tmp/gh-aw/data/stats.json safe-outputs: create-discussion: title-prefix: "[weekly-pr] " category: "General" close-older-discussions: true --- Read the pre-computed stats at `/tmp/gh-aw/data/stats.json` and `/tmp/gh-aw/data/prs.json`. Create a concise weekly PR summary discussion. ``` **Best practices:** - One JSON file per data source; `jq` to pre-aggregate - Store files under `/tmp/gh-aw/` - Document file locations and schema in the prompt body so the agent doesn't need to explore --- ## Technique 2 — Use `gh-proxy` and `cli-proxy` Instead of the MCP Server ### `mode: gh-proxy` (GitHub reads) ```yaml tools: github: mode: gh-proxy # ✅ preferred — pre-authenticated gh CLI, no MCP server startup toolsets: [default] ``` Agent reads GitHub via `gh issue list`, `gh pr view`, etc. and pipes through `jq` before data enters context. `mode: local` starts a Docker-based MCP server with startup latency and verbose tool results. ### `cli-proxy: true` (other MCP servers as CLIs) When a workflow uses additional MCP servers (e.g., a custom Notion or Slack MCP), `cli-proxy: true` mounts each server as a standalone CLI tool on `PATH`: ```yaml tools: cli-proxy: true github: mode: gh-proxy my-custom-mcp: ... ``` With `cli-proxy`, the agent calls `my-custom-mcp ` from bash and pipes output through `jq`/`grep` to extract only needed fields — instead of receiving the full MCP tool response in context. **Summary:** | Mode | Docker startup | Extra tool definitions | Agent output processing | |---|---|---|---| | `mode: local` + MCP tools | Yes | Yes | Tool result (full JSON) | | `mode: gh-proxy` + bash | No | No | Agent pipes through jq | | `cli-proxy: true` + bash | Yes (once) | Reduced | Agent pipes through jq | --- ## Technique 3 — Inline Sub-Agents with Smaller Models Sub-agents with `model: small` cost 10–20× less than the parent model. Use them for classification, one-sentence summarization, structured extraction, and scoring; reserve the large model for synthesis. ### Pattern ``` steps: → deterministic shell (zero AI tokens) sub-agents: → small model per item (cheap, parallelizable) main agent: → synthesizes compact sub-agent results (one high-quality pass) ``` ### Example (skeleton — see [subagents.md](subagents.md) for full syntax) A shell step splits issues into per-item files; the main prompt dispatches a `model: small` sub-agent per file and synthesizes the compact results: ```markdown ## agent: `classifier` --- description: Classifies a GitHub issue into a single category model: small --- Read the JSON file provided. Return only: `{"number": , "category": "bug|feature|question|docs|security|other"}` Nothing else. ``` **Why this saves tokens:** sub-agents run the cheap `small` model; main agent reads only compact `{"number":…, "category":…}` JSON; dispatches run in parallel. ### Pair sub-agents with sub-skills (progressive disclosure) - Keep the main prompt short and plan-like (what to do, in what order). - Put verbose instructions (report layout, rubric details, formatting constraints) into `## skill:` blocks. - Invoke skills only when needed (e.g., producing final output), so early turns stay lean. This delays expensive instruction payloads until the final phase, lowering ambient context. See [subagents.md](subagents.md) for full syntax. **Sub-agent model aliases:** | Alias | Use when | |---|---| | `small` | Classification, extraction, one-sentence summaries, scoring | | `large` | Complex reasoning, multi-step synthesis, code generation | | `inherited` | Sub-agent needs same capability as the parent (default) | Always use aliases, not model IDs — aliases resolve to the best available model per provider. --- ## Technique 3b — Inline Skills for Delayed Instruction Loading Large output templates, formatting rubrics, and phase-specific playbooks are often included verbatim in the workflow prompt body even though they are only needed when the agent is about to produce output. Moving them into `## skill:` blocks keeps the initial request lean while still making the content available on demand. The gh-aw runtime extracts `## skill:` blocks from the prompt before the first model call and stores them at engine-specific skill locations. The agent retrieves a skill only when it explicitly needs that guidance — the content does not appear in the ambient context of early turns. ### When to use inline skills Use `## skill:` blocks for content that: - is only needed in the final output phase (issue body templates, report formats, discussion templates) - describes a specific sub-task rubric (scoring criteria, formatting rules, classification guides) - is verbose (> ~500 characters) and not required to understand the task Keep in the main prompt body anything the agent needs from the very first turn: task goal, inputs, decision criteria, tool guidance. ### Pattern ````markdown --- engine: copilot --- Analyze the run logs. For each finding that meets threshold, create a GitHub issue using the `report-issue-template` skill. Record each created issue in `known-issues.json`. ## skill: `report-issue-template` --- description: Issue title, body structure, and known-issues recording format. --- **Title**: `[my-workflow] ` **Body**: ```markdown ### Finding: **Severity**: ... ...full template... ``` ```` ### Technique scope Prefer inline skills over separate `.github/aw/*.md` shared files when the content is only relevant to one workflow. Use a shared import (see [reuse.md](reuse.md)) when the same template is used by multiple workflows. --- ## Technique 4 — Apply the Caveman Technique A/B compare a verbose prompt against a minimal one. Adopt minimal if quality holds. ```yaml experiments: prompt_style: [verbose, minimal] ``` ```markdown {{#if experiments.prompt_style == "verbose" }} Please analyze all of the open issues in this repository and provide a comprehensive, detailed report covering: the number of open issues, any significant trends or patterns you observe, the most frequently occurring labels, the oldest unresolved issues, a prioritized list of the most critical items, and any recommendations for the team. {{#else}} List open issues by priority. Top 5 critical items. Be brief. {{/if}} ``` Measure AIC via run summary or `gh aw audit`. If `minimal` wins on cost at acceptable quality, promote as baseline. --- ## Technique 5 — Use Experiments to Measure Impact Declare an experiment before making any prompt or configuration change, and compare before/after cost and quality. Run ≥ 20 cycles per variant for statistical significance on high-frequency workflows. ```yaml experiments: optimization_v1: variants: [control, optimized] description: "DataOps refactor — move issue fetching to steps:" metric: "aic" issue: "123" ``` Reference the active variant in the prompt: ```markdown {{#if experiments.optimization_v1 == "optimized" }} Read the pre-fetched data from `/tmp/gh-aw/data/`. {{#else}} Fetch open issues from ${{ github.repository }} using the GitHub tools. {{/if}} ``` **After enough runs:** 1. Compare variants using `gh aw audit <control-run-id> <optimized-run-id>` 2. Inspect `aic`, `input_tokens`, `output_tokens`, `cache_read_tokens`, and `cache_write_tokens` 3. Validate output quality and decision accuracy against the control run 4. If the optimized variant wins on cost **and** quality, rewrite the baseline prompt and remove the `experiments:` field. See [experiments.md](experiments.md) for A/B testing details. **Key experiment dimensions for token optimization:** | Dimension | Example variants | |---|---| | Prompt verbosity | `verbose` / `concise` / `minimal` | | Data source | `agentic-fetch` / `dataops-steps` | | Model tier | Run separate workflows for each engine | | Sub-agent usage | `single-agent` / `with-subagents` | | Tool mode | `mcp-local` / `gh-proxy` | --- ## Technique 6 — Reduce Trigger Frequency and Batch Work The cheapest run is the one you don't execute. If a workflow doesn't need near-real-time feedback, run it less often and batch. ### Prefer slower schedules when latency is acceptable - `hourly` → `daily on weekdays` for team-facing summaries or audits - `daily` → `weekly` for trend reports, optimization reviews, backlog hygiene - `every N hours` → daily/weekly batch when the workflow only produces guidance ### Prefer scheduled batches over reactive triggers Reactive triggers (`issues:`, `pull_request:`, comment commands) suit immediate feedback. Otherwise prefer `schedule: daily on weekdays` and batch work. Typical batch-friendly tasks: triage summaries, stale backlog review, token audits, security digests. Combine with `cache-memory` or `repo-memory` to track processed items. ### Bound repetitive work to a manageable subset Do not require one run to finish an unbounded backlog such as hundreds of lint violations. Set a per-run item, time, turn, or AI-credit budget and stop after a useful subset. Persist a compact cursor or processed-item set in `cache-memory` when stable state is available; otherwise use a deterministic heuristic such as file-path buckets, issue-number modulo, or oldest-first ordering. Rotate buckets round-robin across runs so every item eventually receives attention without repeatedly selecting the easiest items. Keep each batch idempotent, skip items already fixed, and report the processed subset plus remaining work. Prefer smaller complete batches over a broad set of partial fixes that may exhaust the budget. --- ## Techniques 7–8 — Observability and Harness Learning See [token-optimization-observability.md](token-optimization-observability.md) for OpenTelemetry export, AgenticOps token workflows, and learning from harness execution experience. --- ## Techniques 9–11 — Caching, AI-Credit Guardrails, and Bounded File Reads See [token-optimization-caching-budgets.md](token-optimization-caching-budgets.md) for prompt-caching mechanics, `max-ai-credits`/`max-daily-ai-credits` guardrails, custom model pricing, and the 20 KB bounded-file-read rule. --- ## Additional Resources | Topic | File | |---|---| | OpenTelemetry export, AgenticOps, harness-experience learning | [token-optimization-observability.md](token-optimization-observability.md) | | Prompt caching, AI-credit guardrails, bounded file reads | [token-optimization-caching-budgets.md](token-optimization-caching-budgets.md) | | Inline sub-agents syntax | [subagents.md](subagents.md) | | A/B experiments | [experiments.md](experiments.md) | | Persistent memory | [memory.md](memory.md) | | DataOps pattern | [DataOps guide](https://github.com/github/gh-aw/blob/main/docs/src/content/docs/patterns/data-ops.md) | | Audit command reference | [cli-commands.md](cli-commands.md) | | Frontmatter syntax | [syntax.md](syntax.md) | <!-- file: triggers.md --> --- description: Trigger patterns for GitHub Agentic Workflows — events, fuzzy scheduling, fork security, slash commands, and label commands. --- ## Trigger Selection Use the smallest trigger that matches the request. ### Decision Matrix | User intent | Trigger | Typical read tools | Typical safe output | |---|---|---|---| | Review PR changes, comment on quality, suggest fixes | `pull_request` | `github` (`gh-proxy`), optional `playwright` for UI diffs | `add-comment` | | Investigate failed CI/Actions runs and summarize incident | `workflow_run` | `github` (`gh-proxy`) with `actions: read` | `create-issue` | | Monitor external service deployment failures (Heroku, Vercel, Fly.io) | `deployment_status` | `github` (`gh-proxy`) with `deployments: read` | `create-issue` | | Run visual regression checks on PR UI changes | `pull_request` | `playwright` + `cache-memory` | `add-comment` | | Publish weekly stakeholder/product digest | `schedule` | `github` (`gh-proxy`) | `create-issue` (default), `create-discussion` only if explicitly requested | | Review dependency licenses or design-token governance on PRs | `pull_request` with `paths:` | `github` (`gh-proxy`) | `add-comment`; `create-issue` only for blocked/policy-violating findings | | Govern documentation content (stale pages, broken links, outdated ownership) | `schedule` or `pull_request` with `paths:` | `github` (`gh-proxy`) | `add-comment` on PR; `create-issue` for stale content | | PM / product health digest (release velocity, open issues by area) | `schedule` | `github` (`gh-proxy`) | `create-issue` with `close-older-issues: true` | | Compliance or regulatory review | `pull_request` with `paths:` or `schedule` | `github` (`gh-proxy`) | `add-comment` for findings; `create-issue` for violations | > **`workflow_run` vs `deployment_status`**: Use `workflow_run` when monitoring another GitHub Actions workflow in the same repository. Use `deployment_status` when an external service (Heroku, Vercel, Fly.io) reports deployment results back to GitHub via the Deployments API. See [deployment-status.md](deployment-status.md) for the full pattern. > > For `workflow_run`, always scope explicitly: set `workflows:` to named upstream workflow(s), use `types: [completed]`, and gate outcomes with an `if:` guard on `${{ github.event.workflow_run.conclusion }}` (for incident triage, usually `failure`, `timed_out`, `cancelled`, `action_required`) unless the user asked for success reporting. ### Scenario Examples The matrix above gives trigger, tools, and output. These add the `paths:` scoping and definitions the matrix cannot express. Engineering-focused: - **Schema/API review on PRs**: `paths:` scoped to backend contract files (`db/migrate/**`, `migrations/**`, `schema/**`, `openapi/**`, `api/**`); `noop` when contracts are unchanged. - **Visual regression on UI changes**: use only `playwright` + `cache-memory` (no extra tools), allowlist only target preview/app hosts, and state the exact baseline source (`cache-memory` key, artifact, or branch path). - **Design-token governance on PRs**: `paths:` scoped to token sources and theme/config files (`tokens/**`, `**/*tokens*.json`, `**/theme/**`, `**/tailwind*.{js,ts}`, `**/*design-token*`); validate linked token references (style dictionary source, token registry, or design-spec URL) before assessment; `noop` when required references are absent from the in-scope changes or no token drift is detected. - **Dependency-license compliance review on PRs**: `paths:` scoped to dependency manifests (`package.json`, `go.mod`, `requirements.txt`, `Cargo.toml`); classify each addition by license tier (allowed / needs-review / blocked); escalate blocked additions with `create-issue`; `noop` when all additions are pre-approved. - **Deployment incident triage**: `deployment_status` for external provider failures, `workflow_run` for GitHub Actions failures; derive a stable failure key (workflow + job + failing step or error signature); `noop` when a failure self-recovers or matches an existing open incident. Non-engineering personas: - **Documentation governance**: `schedule` (weekly) or `pull_request` with `paths:` scoped to docs directories; check stale ownership, broken links, and missing metadata; `create-issue` for pages needing owner action. - **PM / roadmap / stakeholder digests**: `schedule` (weekly on weekdays) plus optional `workflow_dispatch`; publish with `create-issue` and `close-older-issues: true`. Fix up front: the window (`last 7 full days ending at run start (UTC)` or `since previous successful run`), the grouping dimensions (team, service, owner, severity, or status), and a stable dedup key (`pm-digest:<scope>:2026-W27`). `noop` when the window has zero qualifying updates. See [report.md](report.md) for the canonical defaults. - **Compliance audit / review**: `schedule: daily on weekdays` plus `workflow_dispatch` for drift detection, or `schedule` (monthly) / `pull_request` with `paths:` scoped to policy files. Define **material drift** as any control-state change that affects compliance posture (required policy file removed, control owner missing, control status downgraded from pass to fail, or required approval evidence link missing). Compare current control evidence against the previous successful run window; publish with `create-issue` using `close-older-issues: true` and a stable key such as `compliance-drift:<framework>:<window-id>`; `noop` when no material drift is detected. ### Pattern-specific `noop` examples - **PR reviewer (`pull_request`)**: `noop` when only docs/metadata changed outside scoped `paths:`. - **Failure triage (`workflow_run`)**: `noop` when rerun succeeds, signal is flake-only, or an open incident already exists for the same failure key. - **Scheduled digest (`schedule`)**: `noop` when the exact reporting window (for example `since previous successful run`) has zero qualifying updates. - **Deployment monitor (`deployment_status`)**: `noop` when non-terminal statuses (`queued`, `in_progress`) arrive without a terminal failure. ## Trigger Patterns ### Standard GitHub Events ```yaml on: issues: types: [opened, edited, closed] pull_request: types: [opened, edited, closed] forks: ["*"] # Allow from all forks (default: same-repo only) push: branches: [main] schedule: - cron: "0 9 * * 1" # Monday 9AM UTC workflow_dispatch: # Manual trigger ``` ### `workflow_run` Failure-Triage Pattern Use this when reacting to failures from another workflow in the same repository: ```yaml on: workflow_run: workflows: ["CI", "Deploy"] types: [completed] workflow_dispatch: ``` Then gate analysis to failure outcomes: ```yaml if: contains(fromJson('["failure","timed_out","cancelled","action_required"]'), github.event.workflow_run.conclusion) ``` These are "non-success outcomes requiring triage"; keep the list explicit so readers can tighten (e.g., only `failure`) or broaden it. Escalation rules for this pattern (required): - Derive a stable failure key before any write (for example `<workflow>:<job>:<step>:<error-signature>`). See [create-agentic-workflow-trigger-details.md](create-agentic-workflow-trigger-details.md#incident-dedup-key-templates-workflow_run-and-deployment_status) for concrete key-format templates. - Search for an existing open incident by that key **before** calling `create-issue`. - `noop` when the monitored run concludes `success`, or when an open incident already exists for the same key (duplicate suppression). #### Fuzzy Scheduling Use fuzzy scheduling instead of exact cron to distribute execution times. Avoids load spikes and the "Monday wall of work" from weekend accumulation. **Basic Fuzzy Schedules:** ```yaml on: schedule: daily on weekdays # Monday-Friday only (recommended for daily workflows) schedule: daily # All 7 days schedule: weekly # Once per week schedule: hourly # Every hour ``` **Examples with Intervals:** ```yaml on: schedule: every 2 hours on weekdays # Every 2 hours, Monday-Friday schedule: every 6 hours # Every 6 hours, all days ``` The compiler converts fuzzy schedules to deterministic cron (e.g., `daily on weekdays` → `43 5 * * 1-5`), scatters execution to avoid load spikes, and adds `workflow_dispatch:` for manual runs. **Recommended Pattern:** ```yaml # ✅ GOOD - Weekday schedule avoids Monday wall of work on: schedule: daily on weekdays # ⚠️ ACCEPTABLE - But may create Monday backlog on: schedule: daily ``` #### Fork Security for Pull Requests By default, `pull_request` triggers **block all forks** and only allow PRs from the same repository. Use the `forks:` field to explicitly allow forks: ```yaml # Default: same-repo PRs only (forks blocked) on: pull_request: types: [opened] # Allow all forks on: pull_request: types: [opened] forks: ["*"] # Allow specific fork patterns on: pull_request: types: [opened] forks: ["trusted-org/*", "trusted-user/repo"] ``` ### Command Triggers (/mentions) ```yaml on: slash_command: name: my-bot # Responds to /my-bot in issues/comments ``` This automatically creates conditions to match `/my-bot` mentions in issue bodies and comments. You can restrict where commands are active using the `events:` field: ```yaml on: slash_command: name: my-bot events: [issues, issue_comment] # Only in issue bodies and issue comments ``` **Supported event identifiers:** - `issues` - Issue bodies (opened, edited, reopened) - `issue_comment` - Comments on issues only (excludes PR comments) - `pull_request_comment` - Comments on pull requests only (excludes issue comments) - `pull_request` - Pull request bodies (opened, edited, reopened) - `pull_request_review_comment` - Pull request review comments - `*` - All comment-related events (default) **Note**: `issue_comment` and `pull_request_comment` both map to GitHub Actions' `issue_comment` event with filtering to distinguish them. ### Label Command Triggers Trigger workflows when specific labels are added to issues, PRs, or discussions: ```yaml # Shorthand: trigger on any labeled event on: label-command my-label # Or with explicit configuration on: label_command: name: ai-review # Single label name (or use names: [...] for multiple) events: [pull_request] # Optional: restrict to issues, pull_request, discussion (default: all three) strategy: decentralized # Optional: route labeled events via generated agentic_commands.yml remove_label: false # Optional: remove triggering label after activation (default: true) ``` Use `names:` for multiple labels that activate the same workflow: ```yaml on: label_command: names: [ai-review, copilot-review] events: [pull_request] ``` By default, the triggering label is automatically removed after the workflow activates (`remove_label: true`). Set `remove_label: false` to keep the label. The activated label name is exposed to downstream jobs as `${{ needs.activation.outputs.label_command }}`. ### Semi-Active Agent Pattern ```yaml on: schedule: - cron: "0/10 * * * *" # Every 10 minutes issues: types: [opened, edited, closed] issue_comment: types: [created, edited] pull_request: types: [opened, edited, closed] push: branches: [main] workflow_dispatch: ``` ### All You Can Eat Pattern ```yaml on: schedule: every 30 minutes skip-if-match: 'is:issue is:open "gh-aw-workflow-id: my-workflow" in:body' ``` A frequent schedule whose activation is skipped while the previous output of the same workflow is still open, so the next item is produced as soon as the user closes the last one. See [All You Can Eat Pattern](workflow-patterns.md#all-you-can-eat-pattern). <!-- file: update-agentic-workflow.md --> --- description: Update existing agentic workflows using GitHub Agentic Workflows (gh-aw) with concise guidance on minimal changes and validation. disable-model-invocation: true --- # GitHub Agentic Workflow Updater Update existing workflow files in `.github/workflows/`. ## Load These References First - [github-agentic-workflows.md](github-agentic-workflows.md) - [workflow-editing.md](workflow-editing.md) - [workflow-constraints.md](workflow-constraints.md) - [safe-outputs.md](safe-outputs.md) - [syntax.md](syntax.md) - [intent.md](intent.md) for preserving the outcome and re-deriving evals or operational value when it changes Load these additional files only when relevant: - [campaign.md](campaign.md) - [experiments.md](experiments.md) - [visual-regression.md](visual-regression.md) - [serena-tool.md](serena-tool.md) - [linter-workflows.md](linter-workflows.md) - [agent-runtime-instructions.md](agent-runtime-instructions.md) for changes involving Docker, gVisor, Docker sbx, ARC DinD, self-hosted runners, or `sandbox.agent.runtime-install` - [skills.md](skills.md) when the user asks to add specific skills or agent plugins ## Scope This prompt is for **updating existing workflows only**. For new workflows, use the creator prompt. ## Start the Conversation 1. Ask which workflow to update. 2. Ask what change is needed. 3. Then inspect the existing file, including its `intent:`, before proposing edits. ## First Decision: Frontmatter or Prompt Body? Use [workflow-editing.md](workflow-editing.md) as the source of truth for when recompilation is required. Always compile after any edit to keep `.lock.yml` in sync, even for body-only changes. ## Update Rules - make the smallest possible change - preserve existing style and structure unless reorganization is required - do not rewrite unrelated frontmatter sections - preserve the existing `intent:` for implementation-only changes, including trigger or output-channel redesigns - when the requested outcome materially expands, contracts, or changes, update `intent:` and re-derive its applicability, required effects, no-op conditions, architecture, and evals using [intent.md](intent.md) - when an implementation-only change selects a different architecture, revalidate activation conditions, evidence window, deduplication or previous-result strategy, no-op behavior, and evals so event-specific rules do not survive an incompatible redesign - when targeting the Copilot coding agent, recommend `permissions: { copilot-requests: write }` for Copilot authentication - prefer `toolsets:` for GitHub tools - when the user asks for specific skills or agent plugins, add them to the top-level `skills:` / `plugins:` frontmatter fields; never add on-the-fly install steps or prompt instructions to install them at run time (see [skills.md](skills.md)) See [workflow-constraints.md](workflow-constraints.md) for the read-only security posture (keep the agent job read-only, route writes through `safe-outputs:`). ## Common Update Categories See [workflow-editing.md](workflow-editing.md) for the full frontmatter-vs-body recompilation taxonomy and the field list that requires `gh aw compile <workflow-id>` plus a `.lock.yml` review. ## Cost-Oriented Update Checks When refining existing workflows, keep edits minimal and confirm the design still follows the [High-Volume Triage and Escalation Pattern](workflow-patterns.md#high-volume-triage-and-escalation-pattern): cheap triage before escalation, `noop`/safe output for known/duplicate/stale cases, frontier reasoning reserved for high-value cases, and context pulled on demand. Keep sub-agent fan-out bounded (see [subagents.md](subagents.md)), then measure the change with `gh aw audit` and treat token or quality regressions as failures (see [token-optimization.md](token-optimization.md)). ## Security Rules - never suggest GitHub mutation through raw GitHub tools when a safe output exists - do not recommend `mode: remote` for GitHub tools unless explicitly required and properly configured - do not replace `pull_request` with `pull_request_target` unless the user explicitly needs a `pull_request_target` design - do not use `post-steps:` for agent-driven write behavior that belongs in a safe-output job ## Safer-Alternatives Pattern Follow the "Safer Alternatives First" pattern in [workflow-constraints.md](workflow-constraints.md) when a requested change raises risk. ## Minimal Examples ### Add a GitHub toolset ```yaml tools: github: toolsets: [default] ``` ### Add a safe output ```yaml safe-outputs: add-comment: max: 1 ``` ### Add network access ```yaml network: allowed: - defaults - node ``` ### Add a skill or agent plugin ```yaml skills: - mattpocock/skills/tdd@801dca688564c529fa84f247f64472520d9ebe28 plugins: - octo-org/agent-plugin@v1 ``` ## Validation Flow - always inspect the workflow before editing - explicitly determine whether the existing intent is preserved or changed - always compile after any change to keep `.lock.yml` in sync - keep the workflow valid at every step - summarize what changed and whether recompilation was needed ## Final Steps 1. compile with `gh aw compile <workflow-id>` 2. fix all compile errors 3. include the updated `.lock.yml` in the PR ## Final Message Rules At the end, tell the user: - what changed - whether the change touched frontmatter or prompt body - whether recompilation was required - any next step they should take Keep the summary short. <!-- file: upgrade-agentic-workflows.md --> --- description: Upgrade agentic workflows to the latest version of gh-aw with automated compilation and error fixing disable-model-invocation: true --- You are specialized in **upgrading GitHub Agentic Workflows (gh-aw)** to the latest version. Your job is to upgrade workflows in a repository to work with the latest gh-aw version, handling breaking changes and compilation errors. Read the ENTIRE content of this file carefully before proceeding. Follow the instructions precisely. ## Capabilities & Responsibilities **Prerequisites** - The `gh aw` CLI may be available in this environment. - Always consult the **instructions file** for schema and features: - Local copy: @.github/aw/github-agentic-workflows.md - Canonical upstream: https://raw.githubusercontent.com/github/gh-aw/main/.github/aw/github-agentic-workflows.md - If the user says “campaign”, “KPI”, “pacing”, “cadence”, or “stop-after”, consult @.github/aw/campaign.md (campaign/KPI workflows are still just agentic workflows; this is a design pattern playbook). - If the user says "experiment", "A/B test", "variants", "prompt comparison", or "measure the impact", consult @.github/aw/experiments.md (A/B experiments are configured via the `experiments:` frontmatter field). **Key Commands Available** - `upgrade` → upgrade repository to latest version (combines all steps below) - `fix` → apply automatic codemods to fix deprecated fields - `compile` → compile all workflows - `compile <workflow-name>` → compile a specific workflow > [!NOTE] > **Command Execution** > > When running in GitHub Copilot Cloud, you don't have direct access to `gh aw` CLI commands. Instead, use the **agentic-workflows** MCP tool: > - `upgrade` tool → upgrade repository to latest version (recommended) > - `fix` tool → apply automatic codemods to fix deprecated fields > - `compile` tool → compile workflows > > When running in other environments with `gh aw` CLI access, prefix commands with `gh aw` (e.g., `gh aw upgrade`, `gh aw compile`). > > These tools provide the same functionality through the MCP server without requiring GitHub CLI authentication. ## Instructions ### 1. Fetch Latest gh-aw Changes Before upgrading, always review what's new: 1. **Fetch Latest Release Information** - Use GitHub tools to fetch the CHANGELOG.md from the `github/gh-aw` repository - Review and understand: - Breaking changes - New features - Deprecations - Migration guides or upgrade instructions - Summarize key changes with clear indicators: - 🚨 Breaking changes (requires action) - ✨ New features (optional enhancements) - ⚠️ Deprecations (plan to update) - 📖 Migration guides (follow instructions) ### 2. Run the Upgrade Command **The primary and recommended way to upgrade is to use the `gh aw upgrade` command**, which automates all the upgrade steps in one command: 1. **Run the Upgrade Command** ```bash gh aw upgrade ``` This single command will automatically: - Update all agent and prompt files to the latest templates (like `gh aw init`) - Apply automatic codemods to fix deprecated fields in all workflows (like `gh aw fix --write`) - Update GitHub Actions versions in `.github/aw/actions-lock.json` - Compile all workflows to generate lock files (like `gh aw compile`) 2. **Optional Flags** - `gh aw upgrade --create-pull-request` - Open a pull request with the upgrade changes (alias: `--pr`) - `gh aw upgrade --no-fix` - Update agent files only (skip codemods, actions, and compilation) - `gh aw upgrade --no-actions` - Skip updating GitHub Actions versions - `gh aw upgrade --dir custom/workflows` - Upgrade workflows in custom directory 3. **Review the Results** - The command will display progress for each step - Note any warnings or errors that occur - All changes will be applied automatically > [!TIP] > **Use `gh aw upgrade` for most upgrade scenarios.** It combines all necessary steps and ensures consistency. Only use the manual steps below if you need fine-grained control or if the upgrade command fails. ### 3. Manual Upgrade Steps (Fallback) If the `gh aw upgrade` command is not available or you need more control, follow these manual steps: #### 3.1. Apply Automatic Fixes with Codemods Before attempting to compile, apply automatic codemods: 1. **Run Automatic Fixes** Use the `fix` tool with the `--write` flag to apply automatic fixes. This will automatically update workflow files with changes like: - Replacing 'timeout_minutes' with 'timeout-minutes' - Replacing `network.firewall: false` with `sandbox.agent: false`. To keep the sandbox disabled, explicitly add: ```yaml features: dangerously-disable-sandbox-agent: true sandbox: agent: false strict: false ``` - Removing deprecated 'mcp-scripts.mode' field 2. **Review the Changes** - Note which workflows were updated by the codemods - These automatic fixes handle common deprecations #### 3.2. Attempt Recompilation Try to compile all workflows: 1. **Run Compilation** Use the `compile` tool to compile all workflows. 2. **Analyze Results** - Note any compilation errors or warnings - Group errors by type (schema validation, breaking changes, missing features) - Identify patterns in the errors ### 4. Fix Compilation Errors If compilation fails, work through errors systematically: 1. **Analyze Each Error** - Read the error message carefully - Reference the changelog for breaking changes - Check the gh-aw instructions for correct syntax 2. **Common Error Patterns** **Schema Changes:** - Old field names that have been renamed - New required fields - Changed field types or formats **Breaking Changes:** - Deprecated features that have been removed - Changed default behaviors - Updated tool configurations **Example Fixes:** ```yaml # Old format (deprecated) mcp-servers: github: mode: remote # New format (do NOT include mode: remote - it does not work with GitHub Actions token) tools: github: toolsets: [default] ``` 3. **Apply Fixes Incrementally** - Fix one workflow or one error type at a time - After each fix, use the `compile` tool with `<workflow-name>` to verify - Verify the fix works before moving to the next error 4. **Document Changes** - Keep track of all changes made - Note which breaking changes affected which workflows - Document any manual migration steps taken ### 5. Verify All Workflows After fixing all errors: 1. **Final Compilation Check** Use the `compile` tool to ensure all workflows compile successfully. 2. **Review Generated Lock Files** - Ensure all workflows have corresponding `.lock.yml` files - Check that lock files are valid GitHub Actions YAML > [!NOTE] > If you used the `gh aw upgrade` command in step 2, agent files and instructions have already been updated. The manual refresh step below is only needed if you followed the manual upgrade process. ## Creating Outputs After completing the upgrade: ### If All Workflows Compile Successfully Create a **pull request** with: **Title:** `Upgrade workflows to latest gh-aw version` **Description:** ```markdown ## Summary Upgraded all agentic workflows to gh-aw version [VERSION]. ## Changes ### gh-aw Version Update - Previous version: [OLD_VERSION] - New version: [NEW_VERSION] ### Key Changes from Changelog - [List relevant changes from the changelog] - [Highlight any breaking changes that affected this repository] ### Workflows Updated - [List all workflow files that were modified] ### Upgrade Method - Used `gh aw upgrade` command to automatically apply all changes ### Automatic Fixes Applied - [List changes made by the upgrade command] - [Reference which deprecated fields were updated by codemods] ### Manual Fixes Applied (if any) - [Describe any manual changes made to fix compilation errors after upgrade] - [Reference specific breaking changes that required manual fixes] ### Testing - ✅ All workflows compile successfully - ✅ All `.lock.yml` files generated - ✅ No compilation errors or warnings ### Post-Upgrade Steps - ✅ Ran `gh aw upgrade` to update all components - ✅ All agent files and instructions updated automatically ## Files Changed - Updated `.md` workflow files: [LIST] - Generated `.lock.yml` files: [LIST] - Updated agent files: [LIST] ``` ### If Compilation Errors Cannot Be Fixed Create an **issue** with: **Title:** `Failed to upgrade workflows to latest gh-aw version` **Description:** ```markdown ## Summary Attempted to upgrade workflows to gh-aw version [VERSION] but encountered compilation errors that could not be automatically resolved. ## Version Information - Current gh-aw version: [VERSION] - Target version: [NEW_VERSION] ## Compilation Errors ### Error 1: [Error Type] ``` [Full error message] ``` **Affected Workflows:** - [List workflows with this error] **Attempted Fixes:** - [Describe what was tried] - [Explain why it didn't work] **Relevant Changelog Reference:** - [Link to changelog section] - [Excerpt of relevant documentation] ### Error 2: [Error Type] [Repeat for each distinct error] ## Investigation Steps Taken 1. [Step 1] 2. [Step 2] 3. [Step 3] ## Recommendations - [Suggest next steps] - [Identify if this is a bug in gh-aw or requires repository changes] - [Link to relevant documentation or issues] ## Additional Context - Changelog review: [Link to CHANGELOG.md] - Migration guide: [Link if available] ``` ## Best Practices 1. **Always Review Changelog First** - Understanding breaking changes upfront saves time - Look for migration guides or specific upgrade instructions - Pay attention to deprecation warnings 2. **Fix Errors Incrementally** - Don't try to fix everything at once - Validate each fix before moving to the next - Group similar errors and fix them together 3. **Test Thoroughly** - Compile workflows to verify fixes - Check that all lock files are generated - Review the generated YAML for correctness 4. **Document Everything** - Keep track of all changes made - Explain why changes were necessary - Reference specific changelog entries 5. **Clear Communication** - Use emojis to make output engaging - Summarize complex changes clearly - Provide actionable next steps ## Important Notes - When running in GitHub Copilot Cloud, use the **agentic-workflows** MCP tool for all commands - When running in environments with `gh aw` CLI access, prefix commands with `gh aw` - Breaking changes are inevitable - expect to make manual fixes - If stuck, create an issue with detailed information for the maintainers <!-- file: visual-regression.md --> --- name: visual-regression description: Reference prompt for visual regression testing using playwright + cache-memory for baseline screenshot storage across pull requests --- # Visual Regression Testing Use `playwright` for screenshots and `cache-memory` to persist baselines between PR runs. ## Example Workflow ```markdown --- description: Capture screenshots on every PR and compare against cached baselines to detect visual regressions on: pull_request: types: [opened, synchronize, reopened] permissions: contents: read pull-requests: read engine: copilot network: allowed: - local - playwright tools: playwright: cache-memory: key: visual-regression-baselines-${{ github.event.pull_request.base.ref }} retention-days: 30 allowed-extensions: [".png", ".json"] bash: - "mkdir *" - "cp *" - "diff *" - "date *" safe-outputs: add-comment: max: 1 timeout-minutes: 30 --- Build and serve the app locally, then use Playwright to capture full-page screenshots of key pages into `/tmp/visual-regression/current/`. Use filesystem-safe timestamps (no colons — colons break artifact uploads): `date -u "+%Y-%m-%d-%H-%M-%S"` If `/tmp/gh-aw/cache-memory/baselines/manifest.json` does not exist, copy screenshots there as new baselines and post: "Baselines initialized — N pages captured." Otherwise compare each screenshot to its baseline. Post a comment summarizing: pages unchanged / pages with diffs. If nothing changed, use the `noop` safe-output. ``` ## Key Design Decisions - **`cache-memory` key per base branch** — scopes baselines to `main`, `develop`, etc. - **Explicit baseline source** — state whether baselines come from `cache-memory`, a generated artifact, or a branch directory; do not leave baseline origin implicit. - **`network.allowed: [local, playwright]`** — prevents SSRF; serve app locally, allow browser binary downloads - **`retention-days: 30`** — beyond the default 7-day cache expiry - **Filesystem-safe timestamps** — `YYYY-MM-DD-HH-MM-SS`; colons break artifact filenames - **Minimal permissions** — all PR writes go through `safe-outputs` ## Network-Minimization Reminders - Prefer local preview (`localhost`/`127.0.0.1`) over external preview environments. - If external previews are required, allowlist exact domains (no broad wildcards). - Enable `network.node` only when installing/building Node deps; scope to registries and preview hosts. - Keep Playwright navigation limited to app-under-test URLs. <!-- file: workflow-constraints.md --> --- description: Shared architectural and security constraints for designing or updating agentic workflows. --- # Agentic Workflow Constraints ## Execution Model Agentic workflows run as a **single GitHub Actions job** with one agent execution. ## Can Do - read GitHub data, APIs, web pages, and local repository files - run tools inside the single job - use MCP servers and safe outputs - create GitHub resources through `safe-outputs:` - persist lightweight state with `cache-memory` or other approved mechanisms ## Cannot Do - pause and resume for external events - orchestrate multi-stage pipelines with job dependencies - pass state between multiple AI jobs in one workflow run - implement built-in rollback across external systems - wait for another workflow or deployment to finish inside the same agent run ## Recommend Traditional GitHub Actions When - multi-stage deployment pipelines - fan-out/fan-in job orchestration - long waits for approvals or external systems - rollback logic across several steps or systems - cross-job state transfer Suggested response: > This requires capabilities the single-job agentic model does not support. Use traditional GitHub Actions for orchestration and agentic workflows for the AI-specific step. ## Security Posture - Keep the main agent job read-only. - Do not add GitHub write permissions to the agent job. - Route GitHub writes through `safe-outputs:`. - Prefer `tools.github.mode: gh-proxy` with `gh` for GitHub reads. - Prefer `tools.cli-proxy: true` with mounted `mcp-clis` commands for non-GitHub MCP tools. - Constrain `network.allowed:` to the minimum required ecosystems or domains. - Use `${{ steps.sanitized.outputs.text }}` for untrusted user content. ## Safer Alternatives First When a requested feature increases risk: 1. explain the risk 2. propose the safer pattern first 3. require explicit confirmation before relaxing safeguards ## Common Risk Areas - direct write permissions instead of safe outputs - auto-merge or bypassing review - overly broad network access - unbounded bash allowlists for untrusted input - shell injection: interpolating `${{ github.event.* }}` or other untrusted expressions directly into `run:` scripts; pass untrusted values through environment variables instead - placing OIDC/secret bootstrap in `pre-steps` instead of earlier `setup-steps` - using `post-steps:` for agent-driven write actions ## Self-Hosted Runner Compatibility When `runs-on` is any value other than GitHub-hosted labels (`ubuntu-latest`, `ubuntu-slim`, `windows-latest`, `macos-latest`): - Set `runs-on` explicitly (not inherited from imports); accepts string, array, or runner-group object. Framework jobs (activation, safe-outputs, unlock, etc.) default to hosted `ubuntu-slim`, so also set `runs-on-slim` (same forms) to route them to the self-hosted runner. - Write transient state, tool downloads, and outputs under `$RUNNER_TEMP`, not `/tmp` (which can persist across jobs on shared runners). - Agent steps run as the runner user, not root — don't install to system-wide paths. The egress firewall needs sudo; if unavailable, it can be disabled (removing egress filtering) — surface the trade-off to the user rather than encoding it. - Declare every outbound domain in `network.allowed` (keep `defaults` for core GitHub/Copilot/registry endpoints). Non-allow-listed domains are blocked when the firewall is enabled. - Do not install to `/usr/local` or the toolcache (may be read-only/shared); use job-scoped writable paths. - Do not hardcode `/home/runner` or any literal home path — read `$HOME`; use `$RUNNER_TEMP` for transient state. - For GitHub Enterprise Server, enable GHES compatibility (GHES-compatible artifact action versions, enterprise API endpoint). For the full set of requirements (Docker socket, ARC / Docker-in-Docker, network egress, GHES specifics), follow the [Self-Hosted Runners](/gh-aw/reference/self-hosted-runners/) reference page. ## Shared Reminder Reference this file from creator, updater, and debugger prompts instead of repeating the architectural explanation. <!-- file: workflow-editing.md --> --- description: Shared guidance for editing, recompiling, and validating GitHub Agentic Workflow files. --- # Workflow Editing Basics Agentic workflows are single markdown files at `.github/workflows/<workflow-id>.md`. ## File Structure 1. **YAML frontmatter** between `---` markers: triggers, permissions, tools, network, imports, safe outputs. 2. **Markdown body**: the agent prompt. ## Recompile When Changing Frontmatter Fields Run `gh aw compile <workflow-id>` after changing: - `on:` - `permissions:` - `tools:` - `network:` - `imports:` - `safe-outputs:` - `mcp-servers:` - engine, timeout, concurrency, or other YAML configuration ## No Recompile Required for Runtime Behavior Body-only edits take effect on the next run without recompilation. Edit the markdown body directly for: - agent instructions - task descriptions - examples - formatting guidance - clarifications and guardrails Body changes take effect on the next run. **Always run `gh aw compile` after any change** (frontmatter or body) to keep `.lock.yml` metadata in sync. ## Validation Commands ```bash gh aw compile <workflow-id> gh aw compile <workflow-id> --strict gh aw compile --purge ``` Use `--strict` for production-quality validation. ## Editing Rules - Smallest change that satisfies the request. - Preserve structure unless reorganization is the task. - Never leave a workflow broken. - Always run `gh aw compile <workflow-id>` after any change (frontmatter or body) to keep `.lock.yml` in sync. - If compile fails, fix all errors before stopping. - After any change, review the generated `.lock.yml`. ## Prompt-Authoring Rules - Specific and imperative. - Short examples over long tutorials. - Reference dedicated instruction files instead of duplicating. - Tell agents to use `noop` when no visible action is needed. <!-- file: workflow-patterns.md --> --- description: Shared design patterns for command workflows, monitoring workflows, scheduled one-item-at-a-time (All You Can Eat) workflows, large-repository workflows, database migration reviews, and cross-repository operations. --- # Workflow Patterns ## Command Workflows ### Prefer `slash_command` when - the action is conversational - the user may pass arguments in the comment body - the workflow should work across issues, pull requests, and discussions ### Prefer `label_command` when - the action is one-shot and argument-free - discoverability in the GitHub UI matters - the workflow fits a label-driven process ### Combine both when - the action is common enough to justify both invocation styles - you want UI discoverability plus comment-based flexibility See also: [triggers.md](triggers.md) ## Monitoring Workflows ### Use `workflow_run` when - monitoring another GitHub Actions workflow in the **same repository** - reacting to workflow completion/conclusion Incident-triage pattern: - trigger: `on.workflow_run` for the named deployment/CI workflow - permissions: include `actions: read`; main job read-only - reads: failed job logs/artifacts via GitHub tools - output: `create-issue` with impact/root cause; `noop` when no action needed Compact `workflow_run` examples: - **Deploy workflow failure triage**: trigger on `workflow_run` for `Deploy`, read failed jobs/logs/artifacts, create one incident issue, `noop` when rerun succeeds. - **CI regression watcher**: trigger on `workflow_run` for `CI`, compare current failure against recent runs, create issue only for new regressions, `noop` for known flakes. Incident duplicate-suppression pattern: - derive a stable incident key from the monitored workflow and failure signal (for example `<workflow-name>#<head-sha>#<failed-job-name>`) - search open issues by title-prefix/label/key before creating a new issue - create via `safe-outputs.create-issue` only when no matching open incident exists - use `noop` for duplicates and include the matching issue number in the explanation ### Use `deployment_status` when - monitoring an external deployment service reporting back to GitHub Rule of thumb: - `workflow_run` → GitHub Actions outcomes in this repo - `deployment_status` → external platform outcomes via Deployments API Do triage, evidence collection, and summary in one agent job — the single-job limits (no multi-job fan-out/fan-in, no cross-workflow waits or chaining) from [workflow-constraints.md](workflow-constraints.md) apply. See also: [deployment-status.md](deployment-status.md) ## High-Volume Triage and Escalation Pattern For workflows receiving many similar events (issues, PR comments, CI failures, security alerts, dependency events): - start with a cheap triage/classification pass - detect known/duplicate/stale/low-value cases first - emit `noop` or a safe output when triage is confident - escalate to the main agent only when uncertain or genuinely new/high-value Decision flow: ```text IF cheap triage is confident (known/duplicate/stale/low-value) THEN emit safe output or noop ELSE escalate to the main agent END IF ``` Use with pull-context workflows: fetch targeted evidence on demand instead of pushing raw logs into the initial prompt. ## All You Can Eat Pattern Nickname for a scheduled workflow that keeps at most one *unconsumed* output alive at a time. The workflow wakes up frequently (typically every 30 minutes), but activation is skipped while the previous output from that workflow is still open. As soon as the user consumes the previous output (closes the issue, merges or closes the pull request), the next scheduled run produces the next item — content is served one plate at a time, on demand, and runs proceed sequentially. Use when: - the work is an open-ended backlog (improvement ideas, maintenance chores, research notes), not an event-driven reaction - each output needs human consumption, so producing another before the previous one is closed only creates noise - low latency matters: the next item should appear within one schedule tick after the user clears the last one Avoid when outputs are independent and reviewable in parallel, or when the schedule is a periodic report tied to a window — use the recurring digest defaults in [report.md](report.md) instead. ### Shape ```yaml on: schedule: every 30 minutes skip-if-match: 'is:issue is:open "gh-aw-workflow-id: my-workflow" in:body' permissions: read-all safe-outputs: create-issue: title-prefix: "[all-you-can-eat] " max: 1 expires: 7 ``` Rules: - **One open item at a time.** Cap the safe output with `max: 1`. The string form of `skip-if-match` implies a threshold of `max: 1`, so any single open match skips activation; no extra field is needed. - **Match on stable identity.** Prefer the hidden `gh-aw-workflow-id: <workflow-file-name-without-.md>` marker (`in:body`) over a title prefix, because humans rename titles; see [Footer Control](https://github.com/github/gh-aw/blob/main/docs/src/content/docs/reference/footers.md). A title match (`in:title "[all-you-can-eat] "`) works when the workflow also sets `title-prefix:`. The query is auto-scoped to the current repository. - **Pull requests use the same shape** with `is:pr is:open` and `create-pull-request`; drafts count as open. Allow a small queue depth by raising the threshold (`skip-if-match: { query: ..., max: 3 }`) when the user can consume several items in parallel. - **Do not starve.** If the user never closes the item, the workflow never runs again. Set `expires:` on the safe output (or an equivalent auto-close) so an abandoned item eventually unblocks the schedule. - **Skipped runs are cheap.** The check runs in the `pre_activation` job, so the agent never starts and no tokens are spent on a skipped tick. - **Keep concurrency on.** `skip-if-match` is evaluated before activation and cannot cancel a run already in flight; default workflow concurrency prevents two runs from producing at once. ### Learn from the closed output Because the run only activates after the previous item was closed, the closing action is the feedback signal. Instruct the agent to: 1. search the most recently closed items from this workflow (same marker or title prefix), newest first and bounded — for example the last three 2. read the close reason (`completed` vs `not planned`), the closing comment, labels, and any review feedback 3. treat "not planned" or a rejecting comment as a negative signal and do not re-propose the same idea; treat completed/merged as a positive signal for similar work 4. persist a compact accept/reject list across runs with `cache-memory`, or `repo-memory` when losing the list would cause repeat proposals (see [memory-stateful-patterns.md](memory-stateful-patterns.md)) 5. emit `noop` when nothing clears the quality bar left by past rejections See also: [triggers.md](triggers.md), [safe-outputs-content.md](safe-outputs-content.md), [maintainer.md](maintainer.md) ## Large-Repository Improvement Pattern For recurring maintenance in large repos: - use `cache-memory` - process one package/module/directory per run - store last-processed item; round-robin - prefer small focused PRs over wide sweeps See also: [memory.md](memory.md) ## Step Authoring Guidance When writing `steps:`, `pre-steps:`, and `post-steps:`, choose the implementation type in this order of preference: ### 1. Preferred: `actions/github-script` Use `actions/github-script` for GitHub API interactions and general scripting. The workflow compiler handles action pinning automatically; specify a recent major version tag (`@v7`) without a SHA. - Provides typed access to the GitHub REST API via `github.rest.*` - Exposes `context`, `core`, `github`, `io`, and `exec` helpers - Eliminates shell injection risks for untrusted input - Example: ```yaml steps: - name: Fetch issue data uses: actions/github-script@v7 with: script: | const issue = await github.rest.issues.get({ owner: context.repo.owner, repo: context.repo.repo, issue_number: context.issue.number, }); core.setOutput('title', issue.data.title); ``` ### 2. Shell scripts Use `run:` steps when `actions/github-script` is not suitable. To prevent shell injection, never interpolate untrusted values directly into the script body. Any value that originates from user input — including `github.event.issue.title`, `github.event.issue.body`, `github.event.comment.body`, `github.event.pull_request.title`, `github.event.pull_request.body`, and `github.head_ref` — must be passed through environment variables: ```yaml # ❌ Unsafe: direct expression interpolation into the shell script - name: Unsafe comment run: gh issue comment ${{ github.event.issue.number }} --body "${{ github.event.issue.title }}" # ✅ Safe: pass untrusted values through env vars and reference them as $VAR_NAME - name: Safe comment env: ISSUE_NUMBER: ${{ github.event.issue.number }} TITLE: ${{ github.event.issue.title }} run: gh issue comment "$ISSUE_NUMBER" --body "$TITLE" ``` ### 3. Python (last resort) Use Python only when the task genuinely requires data science or numeric libraries (for example `pandas`, `numpy`, `matplotlib`). Prefer `actions/github-script` or a shell step for everything else. ## Pre-Step Data Fetching Pattern Use deterministic `steps:` when the workflow needs large external data before the agent runs. Rules: - write prepared files to `/tmp/gh-aw/agent/` - trim large outputs before handing to the agent - set `GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}` on every `gh` step - add `permissions: actions: read` for downloading workflow logs/artifacts - use `jq` to reduce JSON payload size Compact reporting/incident prefetch example: ```yaml steps: - name: Prefetch compact failure context env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} REPO: ${{ github.repository }} RUN_ID: ${{ github.event.workflow_run.id }} run: | gh api "repos/$REPO/actions/runs/$RUN_ID/jobs" \ --jq '[.jobs[] | select(.conclusion != "success") | {name, conclusion, started_at, completed_at}]' \ > /tmp/gh-aw/agent/failed_jobs.json ``` ## PR Visual Regression Pattern For PR UI validation and screenshot diffs: - trigger: `pull_request` - tools: `playwright` plus `cache-memory` for baseline metadata - permissions: read-only repo/PR access - output: `add-comment` with pass/fail summary and artifact links - fallback: `noop` when no UI changes detected ## Design Token / CSS Governance Pattern For PRs touching design tokens or CSS files that require a linked design reference (Figma link, design doc URL, or ADR token): - trigger: `pull_request` with `paths:` scoped to token/style files (for example `tokens/**`, `**/*.tokens.json`, `**/*.css`, `src/styles/**`, `design-system/**`) - permissions: `pull-requests: read`, `contents: read`; agent job read-only - reads: PR body and comments via `gh pr view` to locate the linked design reference; validate the link target is reachable and matches the changed components - output: apply the classify flow from [PR Checks with Linked References](github-agentic-workflows.md) (valid → ✅ comment; incomplete → gap comment; missing → request comment, escalating to `create-issue` only for a required blocking gate with no open issue already covering the scope) - fallback: `noop` when the `paths:` guard excludes all changed files ## QA Coverage Report Pattern For PR QA coverage summaries (gaps, risks, suggested test focus): - trigger: `pull_request` (optionally scoped with `paths:`) - tools: `github` (`gh-proxy`) for changed files, PR metadata, labels, checks - permissions: `contents: read`, `pull-requests: read`; agent job read-only - output: `add-comment` with coverage matrix and untested/high-risk areas - fallback: `noop` for non-testable changes (e.g. docs-only) ## PM Stakeholder Digest Pattern For recurring product/stakeholder digests: - trigger: fuzzy `schedule` (e.g. `weekly on mondays`) - tools: `github` (`gh-proxy`), optional `cache-memory` for period-over-period continuity - permissions: read-only - output: `create-issue` by default; `create-discussion` only when requested - prompt: audience-aware language (summary first, details second) ## Database Migration Safety Pattern For PRs adding/modifying migration files: - trigger: `pull_request` with `paths:` scoped to migration dirs (e.g. `db/migrate/**`, `migrations/**`, `*.sql`) - permissions: `contents: read`, `pull-requests: read`; agent job read-only - reads: changed migration content via GitHub tools - output: `add-comment` flagging risky operations; `noop` when clean - prompt: include migration best practices ## Release Automation Pattern For workflows that build, test, publish a GitHub release, and generate release highlights: - trigger: `workflow_dispatch` with a `release_type` input (`patch`, `minor`, `major`); restrict with `roles: [admin, maintainer]` - structure: **Classic + Agent** hybrid — all build/test/release jobs are standard GitHub Actions jobs; the agent job runs last and only updates the release description - classic jobs: `config` (compute semver), `build` (compile + upload artifact), `test`, `release` (create prerelease with `--generate-notes --latest=false`); output `release_id` from the release job - agent job: depends on `release` job; pre-fetches merged PRs and changelog in `steps:`; uses `tools: cli-proxy: true`; writes highlights via `update-release` with `operation: prepend` - safe output: `update-release` with `threat-detection: false` (release bodies contain code snippets) - permissions: global `contents: read`; per-job `contents: write` only on jobs that push tags or create releases See [release-workflow.md](release-workflow.md) for the full pattern, frontmatter template, job skeletons, and reference implementation pointer. ## Cross-Repository Pattern For cross-repo reads and writes: - enable GitHub toolsets needed for external repos - configure PAT or GitHub App auth in `safe-outputs:` for cross-repo writes - tell the agent to set `target-repo` explicitly - document required token scopes in the prompt or instructions Cross-repo workflows inherit single-job constraints from [workflow-constraints.md](workflow-constraints.md).