From 2c41f51d6177bf6e48e67076803ffee439358e8e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 23 Jan 2026 08:39:55 +0000 Subject: [PATCH 1/6] Initial plan From 8498b1cde2ed2c54c33060227bd7c0794e8e4377 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 23 Jan 2026 08:45:09 +0000 Subject: [PATCH 2/6] Initial plan: Apply documentation workflows to improve campaign docs Co-authored-by: mnkiefer <8320933+mnkiefer@users.noreply.github.com> --- .github/workflows/smoke-codex.lock.yml | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/.github/workflows/smoke-codex.lock.yml b/.github/workflows/smoke-codex.lock.yml index fc223cbaa5..e6af4d2124 100644 --- a/.github/workflows/smoke-codex.lock.yml +++ b/.github/workflows/smoke-codex.lock.yml @@ -296,6 +296,30 @@ jobs: }, "name": "add_labels" }, + { + "description": "Remove labels from an existing GitHub issue or pull request. Silently skips labels that don't exist on the item. Use this to clean up labels or manage label lifecycles (e.g., removing 'needs-review' after review is complete). CONSTRAINTS: Only these labels can be removed: [smoke].", + "inputSchema": { + "additionalProperties": false, + "properties": { + "item_number": { + "description": "Issue or PR number to remove labels from. This is the numeric ID from the GitHub URL (e.g., 456 in github.com/owner/repo/issues/456). If omitted, removes labels from the item that triggered this workflow.", + "type": "number" + }, + "labels": { + "description": "Label names to remove (e.g., ['smoke', 'needs-triage']). Non-existent labels are silently skipped.", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "labels" + ], + "type": "object" + }, + "name": "remove_labels" + }, { "description": "Report that a tool or capability needed to complete the task is not available, or share any information you deem important about missing functionality or limitations. Use this when you cannot accomplish what was requested because the required functionality is missing or access is restricted.", "inputSchema": { From 2d1223e33c214bbf89859610f317cba9d6495428 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 23 Jan 2026 08:55:00 +0000 Subject: [PATCH 3/6] Apply documentation workflow principles to campaign docs - 65% bloat reduction Co-authored-by: mnkiefer <8320933+mnkiefer@users.noreply.github.com> --- docs/src/content/docs/examples/campaigns.md | 218 +++++-- .../docs/guides/campaigns/cli-commands.md | 143 +++-- .../docs/guides/campaigns/getting-started.md | 72 ++- .../docs/guides/campaigns/lifecycle.md | 563 ++++-------------- .../content/docs/guides/campaigns/specs.md | 336 +++++++---- 5 files changed, 624 insertions(+), 708 deletions(-) diff --git a/docs/src/content/docs/examples/campaigns.md b/docs/src/content/docs/examples/campaigns.md index 77ef5c46fd..f8742ea3aa 100644 --- a/docs/src/content/docs/examples/campaigns.md +++ b/docs/src/content/docs/examples/campaigns.md @@ -1,61 +1,43 @@ --- title: Campaign Examples -description: Example campaign workflows demonstrating worker orchestration with standardized contracts +description: Example campaign workflows with worker patterns and idempotency sidebar: badge: { text: 'Examples', variant: 'note' } --- -This section contains example campaign workflows that demonstrate how to use first-class campaign workers with standardized input contracts and idempotency. +Example campaigns demonstrating worker coordination, standardized contracts, and idempotent execution patterns. ## Security Audit Campaign -[**Security Audit 2026**](/gh-aw/examples/campaigns/security-auditcampaign/) - A comprehensive security audit campaign that demonstrates: +[**Security Audit 2026**](/gh-aw/examples/campaigns/security-auditcampaign/) demonstrates: -- **Worker Discovery**: Finding security-related issues and PRs via tracker labels -- **Dispatch-Only Workers**: Workers designed specifically for campaign orchestration -- **Standardized Contract**: All workers accept `campaign_id` and `payload` inputs -- **Idempotency**: Workers check for existing work before creating duplicates -- **KPI Tracking**: Measuring vulnerability reduction over time +- Worker discovery via tracker labels +- Dispatch-only worker design +- Standardized input contracts (`campaign_id`, `payload`) +- Idempotent execution with deterministic keys +- KPI tracking for vulnerability metrics -### Key Features +The campaign coordinates three workers (scanner, fixer, reviewer) that create security-related issues and pull requests. Workers use deterministic branch names and titles to prevent duplicates. -- 3 dispatch-only worker workflows (scanner, fixer, reviewer) -- Governance policies for pacing and opt-out -- Deterministic work item keys to prevent duplicates -- Quarterly timeline with weekly status updates -- Executive sponsorship and risk management +### Key patterns -### Worker Example +**Orchestrator responsibilities:** +- Dispatches workers on schedule +- Discovers worker outputs via labels +- Updates project board +- Reports progress metrics -[**Security Scanner**](/gh-aw/examples/campaigns/security-scanner/) - An example security scanner workflow that: +**Worker responsibilities:** +- Accepts `workflow_dispatch` only +- Uses standardized inputs +- Generates deterministic keys +- Checks for existing work +- Labels outputs with `campaign:` -- Accepts `campaign_id` and `payload` inputs via workflow_dispatch -- Uses deterministic keys for branch names and PR titles -- Checks for existing PRs before creating new ones -- Labels all created items with `campaign:{id}` for tracking -- Reports completion status back to orchestrator +## Security Scanner Worker -## Using These Examples +[**Security Scanner**](/gh-aw/examples/campaigns/security-scanner/) shows worker implementation: -### 1. Campaign Spec Structure - -Campaign specs (`.campaign.md` files) define: -- Campaign goals and KPIs -- Worker workflows to reference (by name) -- Discovery scope (repos/orgs to search) -- Memory paths for state persistence -- Governance and pacing policies - -### 2. Worker Workflow Pattern (Dispatch-Only) - -Worker workflows MUST: -- Use `workflow_dispatch` as the ONLY trigger (no schedule/push/pull_request) -- Accept standardized inputs: `campaign_id` (string) and `payload` (string; JSON) -- Implement idempotency via deterministic work item keys -- Label all created items with `campaign:{campaign_id}` -- Focus on specific, repeatable tasks - -Example: ```yaml on: workflow_dispatch: @@ -70,41 +52,145 @@ on: type: string ``` -### 3. Idempotency Requirements +The worker: +1. Receives dispatch from orchestrator +2. Scans for vulnerabilities +3. Generates deterministic key: `campaign-{id}-{repo}-{vuln_id}` +4. Checks for existing PR with that key +5. Creates PR only if none exists +6. Labels PR with `campaign:{id}` + +## Worker design patterns + +### Standardized contract + +All campaign workers accept the same inputs: + +```yaml +inputs: + campaign_id: + description: 'Campaign identifier' + required: true + type: string + payload: + description: 'JSON payload with work details' + required: true + type: string +``` + +The payload contains work item details in JSON format. + +### Idempotency + +Workers prevent duplicate work using deterministic keys: + +``` +campaign-{campaign_id}-{repository}-{work_item_id} +``` + +Used in: +- Branch names: `campaign-security-audit-myorg-myrepo-vuln-123` +- PR titles: `[campaign-security-audit] Fix vulnerability 123` +- Issue titles: `[campaign-security-audit] Security finding 123` + +Before creating items, workers search for existing items with the same key. + +### Dispatch-only triggers + +Workers in the campaign's `workflows` list must use only `workflow_dispatch`: + +```yaml +# Correct +on: + workflow_dispatch: + inputs: ... + +# Incorrect - campaign-controlled workers should not have other triggers +on: + schedule: daily + workflow_dispatch: + inputs: ... +``` -Workers prevent duplicates by: -1. Computing deterministic keys: `campaign-{campaign_id}-{repository}-{work_item_id}` -2. Using keys in branch names, PR titles, issue titles -3. Checking for existing work with the key before creating -4. Skipping or updating existing items rather than creating duplicates +Workflows with schedules or event triggers should run independently and let the campaign discover their outputs. -### 4. Folder Organization +## File organization ``` .github/workflows/ -├── my-campaign.campaign.md # Campaign spec -├── my-worker.md # Worker workflow (dispatch-only) -└── my-campaign.campaign.lock.yml # Compiled orchestrator +├── security-audit.campaign.md # Campaign spec +├── security-audit.campaign.lock.yml # Compiled orchestrator +├── security-scanner.md # Worker workflow +├── security-fixer.md # Worker workflow +└── security-reviewer.md # Worker workflow +``` + +Workers are regular workflows, not in campaign-specific folders. The dispatch-only trigger indicates campaign ownership. + +## Campaign lifecycle integration + +### Startup + +1. Orchestrator dispatches workers +2. Workers create issues/PRs with campaign labels +3. Next run discovers these items +4. Items added to project board -docs/ -└── campaign-workers.md # Worker pattern documentation +### Ongoing execution + +1. Orchestrator dispatches workers (new work) +2. Discovers outputs from previous runs +3. Updates project board incrementally +4. Reports progress against KPIs + +### Completion + +1. All work items processed +2. Final status update with metrics +3. Campaign state set to `completed` +4. Orchestrator disabled + +## Idempotency example + +```yaml +# Worker checks for existing PR before creating +- name: Check for existing PR + id: check + run: | + KEY="campaign-${{ inputs.campaign_id }}-${{ github.repository }}-vuln-123" + EXISTING=$(gh pr list --search "$KEY in:title" --json number --jq '.[0].number') + echo "existing=$EXISTING" >> $GITHUB_OUTPUT + +- name: Create PR + if: steps.check.outputs.existing == '' + uses: ./actions/safe-output + with: + type: create_pull_request + title: "[$KEY] Fix vulnerability 123" + body: "Automated security fix" + labels: "campaign:${{ inputs.campaign_id }}" ``` -Workers are stored alongside regular workflows, not in campaign-specific folders. The dispatch-only trigger makes ownership clear. +## Independent workflows -## Learn More +Workflows not in the campaign's `workflows` list can run independently with their own triggers: -- [Campaign Guides](/gh-aw/guides/campaigns/) - Campaign setup and configuration -- [Campaign lifecycle](/gh-aw/guides/campaigns/lifecycle/) - How the orchestrator runs -- [Safe Outputs](/gh-aw/reference/safe-outputs/) - dispatch_workflow configuration +```yaml +# Independent worker - keeps its schedule +on: + schedule: + - cron: '0 2 * * *' + workflow_dispatch: + +# Creates items with campaign label for discovery +labels: ["campaign:security-audit", "security"] +``` -## Pattern Analysis +The campaign discovers these via tracker labels without controlling execution. -These examples demonstrate best practices for campaign workers: -- **Explicit ownership**: Workers are dispatch-only, clearly orchestrated -- **Standardized contract**: All workers use the same input format -- **Idempotent behavior**: Workers avoid duplicate work across runs -- **Deterministic keys**: Enable reliable duplicate detection -- **Simple units**: Workers are focused, stateless, deterministic +## Further reading -The dispatch-only pattern eliminates confusion about trigger precedence and makes orchestration explicit. +- [Campaign guides](/gh-aw/guides/campaigns/) - Setup and configuration +- [Campaign lifecycle](/gh-aw/guides/campaigns/lifecycle/) - Execution model +- [Campaign specs](/gh-aw/guides/campaigns/specs/) - Configuration reference +- [Safe outputs](/gh-aw/reference/safe-outputs/) - dispatch_workflow configuration diff --git a/docs/src/content/docs/guides/campaigns/cli-commands.md b/docs/src/content/docs/guides/campaigns/cli-commands.md index ff276b8bbf..333a83594c 100644 --- a/docs/src/content/docs/guides/campaigns/cli-commands.md +++ b/docs/src/content/docs/guides/campaigns/cli-commands.md @@ -1,110 +1,173 @@ --- title: CLI commands -description: Command reference for managing agentic campaigns with gh aw +description: Command reference for campaign management banner: content: 'Do not use. Campaigns are still incomplete and may produce unreliable or unintended results.' --- -The GitHub Agentic Workflows CLI provides commands for inspecting, validating, and managing agentic campaigns. +The GitHub Agentic Workflows CLI provides commands for listing, inspecting, validating, and managing campaigns. -> [!IMPORTANT] -> **Use the automated creation flow to create campaigns.** The CLI commands below are for inspecting, validating, and managing existing campaigns. See the [Getting started guide](/gh-aw/guides/campaigns/getting-started/) for campaign creation. +:::note +Use the automated creation flow to create campaigns. These commands are for managing existing campaigns. See [Getting started](/gh-aw/guides/campaigns/getting-started/). +::: ## Campaign commands -From the root of the repo: - ```bash -gh aw campaign # List all agentic campaigns -gh aw campaign security # Filter by ID or name substring -gh aw campaign --json # JSON output +gh aw campaign # List all campaigns +gh aw campaign security # Filter by ID or name +gh aw campaign --json # JSON output -gh aw campaign status # Live status for all agentic campaigns -gh aw campaign status incident # Filter by ID or name substring -gh aw campaign status --json # JSON status output +gh aw campaign status # Status for all campaigns +gh aw campaign status incident # Filter status by ID or name +gh aw campaign status --json # JSON status output -gh aw campaign new my-campaign-id # Scaffold a new agentic campaign spec -gh aw campaign validate # Validate agentic campaign specs (fails on problems) -gh aw campaign validate --no-strict # Report problems without failing +gh aw campaign new my-campaign # Scaffold new spec (advanced) +gh aw campaign validate # Validate all specs +gh aw campaign validate --no-strict # Report without failing ``` -## Most common tasks - -- See what campaigns exist: `gh aw campaign` -- Check which ones look unhealthy: `gh aw campaign status` -- Validate specs (locally or in CI): `gh aw campaign validate` - ## List campaigns -Display all agentic campaigns defined in `.github/workflows/*.campaign.md`: +View all campaign specs in `.github/workflows/*.campaign.md`: ```bash gh aw campaign ``` -Filter by campaign ID or name: +Output shows campaign ID, name, state, and file path. + +### Filter by name or ID ```bash gh aw campaign security ``` -Get machine-readable JSON output: +Shows campaigns containing "security" in ID or name. + +### JSON output ```bash gh aw campaign --json ``` +Returns structured data for scripting and automation. + ## Check campaign status -View live status of all agentic campaigns with their associated project boards: +View live status from project boards: ```bash gh aw campaign status ``` -Filter status by campaign ID or name: +Shows active campaigns with project board statistics, progress, and health indicators. + +### Filter status ```bash gh aw campaign status incident ``` -Get status in JSON format: +Shows status for campaigns matching "incident". + +### JSON status ```bash gh aw campaign status --json ``` +Returns structured status data including metrics, KPIs, and item counts. + +## Validate campaigns + +Check all campaign specs for configuration errors: + +```bash +gh aw campaign validate +``` + +Validates: +- Required fields present +- Valid YAML syntax +- Proper KPI configuration +- Discovery scope configured +- Project URLs valid +- Workflow references exist + +Exit code 1 indicates validation failures. + +### Non-failing validation + +```bash +gh aw campaign validate --no-strict +``` + +Reports problems without failing. Useful for CI pipelines during development. + ## Create new campaign (advanced) -> [!WARNING] -> This command is for advanced use cases only. **Use the [automated creation flow](/gh-aw/guides/campaigns/getting-started/) instead.** +:::caution +Advanced users only. Most users should use the [automated creation flow](/gh-aw/guides/campaigns/getting-started/). +::: -Scaffold a new agentic campaign spec file interactively: +Scaffold a new campaign spec: ```bash gh aw campaign new my-campaign-id ``` -This creates `.github/workflows/my-campaign-id.campaign.md` with a basic structure, but you'll still need to manually configure all fields and compile the campaign. +Creates `.github/workflows/my-campaign-id.campaign.md` with basic structure. You must: +1. Configure all required fields +2. Set up project board manually +3. Compile the spec with `gh aw compile` +4. Test thoroughly before running -## Validate campaigns +The automated flow handles all this for you. + +## Common workflows -Validate all agentic campaign specs: +### Check campaign health ```bash -gh aw campaign validate +# Quick health check +gh aw campaign status + +# Detailed inspection of specific campaign +gh aw campaign status security-audit --json | jq '.campaigns[0]' ``` -By default, validation fails if problems are found. For non-failing validation (useful in CI while you iterate): +### Pre-commit validation ```bash +# In CI or pre-commit hook gh aw campaign validate --no-strict ``` -
-Compilation details (advanced) +### Find inactive campaigns + +```bash +# List campaigns with their states +gh aw campaign --json | jq '.campaigns[] | {id, state}' +``` + +### Monitor campaign progress + +```bash +# Watch campaign status (requires watch/jq) +watch -n 300 'gh aw campaign status my-campaign' +``` + +## Exit codes + +| Code | Meaning | +|------|---------| +| 0 | Success | +| 1 | Validation error or command failed | +| 2 | Invalid arguments | -The automated campaign creation flow handles compilation for you. +## Further reading -If you’re working on a campaign spec manually, see the [compile command documentation](/gh-aw/setup/cli/#compile). -
+- [Campaign specs](/gh-aw/guides/campaigns/specs/) - Configuration format +- [Getting started](/gh-aw/guides/campaigns/getting-started/) - Create your first campaign +- [Campaign lifecycle](/gh-aw/guides/campaigns/lifecycle/) - Execution model diff --git a/docs/src/content/docs/guides/campaigns/getting-started.md b/docs/src/content/docs/guides/campaigns/getting-started.md index dd3a8576b0..537df11348 100644 --- a/docs/src/content/docs/guides/campaigns/getting-started.md +++ b/docs/src/content/docs/guides/campaigns/getting-started.md @@ -5,57 +5,55 @@ banner: content: 'Do not use. Campaigns are still incomplete and may produce unreliable or unintended results.' --- -This guide shows you how to create your first campaign using the automated creation flow. +Create your first campaign using the automated creation flow. The flow generates a Project board, campaign spec, and orchestrator workflow based on an issue description. -> [!IMPORTANT] -> **Automated creation is the only supported way to create campaigns.** It creates the Project, spec, and orchestrator for you. +## Prerequisites -## Quick start +- Repository with GitHub Agentic Workflows installed +- `create-agentic-campaign` label configured in your repository +- Write access to create issues and merge pull requests +- GitHub Actions enabled -1. Create an issue describing the goal -2. Apply the `create-agentic-campaign` label -3. Review the generated pull request -4. Merge and run the orchestrator from the Actions tab +## Create a campaign -> [!IMPORTANT] -> Use the automated campaign creation flow—it's the only supported way to create campaigns. +1. **Create an issue** describing your campaign goal and scope +2. **Apply the label** `create-agentic-campaign` to the issue +3. **Wait for automation** - A pull request appears within a few minutes +4. **Review the PR** - Verify the generated Project, spec, and orchestrator +5. **Merge the PR** when ready +6. **Run the orchestrator** from the Actions tab to start the campaign -## Create a campaign (supported flow) +## Generated files -1. Create an issue describing the goal and scope. -2. Apply the `create-agentic-campaign` label. -3. Wait for a pull request to appear (usually a couple of minutes). -4. Review and merge the PR. -5. Go to Actions and run the campaign orchestrator workflow. +The pull request creates three components: -## What you’ll see after merge +**Project board** - GitHub Project for tracking campaign progress with custom fields and views. -- A **Project board** for tracking progress -- A **campaign spec** file (`.github/workflows/.campaign.md`) -- A compiled **orchestrator** workflow (`.github/workflows/.campaign.lock.yml`) +**Campaign spec** - Configuration file at `.github/workflows/.campaign.md` defining goals, workers, and governance. -## Run it day-to-day +**Orchestrator workflow** - Compiled workflow at `.github/workflows/.campaign.lock.yml` that executes the campaign logic. -The orchestrator runs on a schedule (daily by default) and will: +## Campaign execution -- (Optional) dispatch worker workflows via `workflow_dispatch` -- sync issues/PRs into the Project -- post a Project status update each run +The orchestrator runs on the configured schedule (daily by default): -For details, see [Campaign lifecycle](/gh-aw/guides/campaigns/lifecycle/). +1. Dispatches worker workflows via `workflow_dispatch` (if configured) +2. Discovers issues and pull requests created by workers +3. Updates the Project board with new items +4. Posts a status update summarizing progress -## Keep it simple (best practices) +See [Campaign lifecycle](/gh-aw/guides/campaigns/lifecycle/) for execution details. -- Start with one goal and 1–3 workflows. -- Keep worker workflows dispatchable (`workflow_dispatch`) and remove other triggers if the campaign is responsible for running them. -- Use conservative governance limits at first (e.g., 10 updates per run). +## Best practices -
-What gets created for you? +Start with focused scope: +- Define one clear objective +- Include 1-3 worker workflows maximum +- Set conservative governance limits (e.g., 10 project updates per run) -- A Project with standard fields and views -- A campaign spec wired to that Project -- A compiled orchestrator workflow +Configure worker triggers: +- Workers should accept `workflow_dispatch` only +- Remove cron schedules, push, and pull_request triggers +- Let the orchestrator control execution timing -You’ll review everything in the generated pull request before it runs. -
+See [Campaign specs](/gh-aw/guides/campaigns/specs/) for configuration options. diff --git a/docs/src/content/docs/guides/campaigns/lifecycle.md b/docs/src/content/docs/guides/campaigns/lifecycle.md index dd76b2c3f8..3fff82f05e 100644 --- a/docs/src/content/docs/guides/campaigns/lifecycle.md +++ b/docs/src/content/docs/guides/campaigns/lifecycle.md @@ -1,520 +1,183 @@ --- title: Campaign Lifecycle -description: What happens when the campaign orchestrator runs, and how to pause or finish a campaign. +description: Campaign execution phases, state management, and workflow coordination banner: content: 'Do not use. Campaigns are still incomplete and may produce unreliable or unintended results.' --- -This page explains what the orchestrator does when it runs, and what you do to pause or end a campaign. +Campaign orchestrators execute on a schedule to coordinate worker workflows, discover outputs, and update project boards. This page explains the execution model, state management, and workflow coordination. -## Lifecycle states +## Execution flow -Campaign specs include a `state` field. - -| State | Meaning | -| --- | --- | -| `planned` | Drafting and review; not intended to run yet | -| `active` | Running on schedule | -| `paused` | Temporarily stopped | -| `completed` | Finished and no longer running | -| `archived` | Kept for reference only | - -> [!CAUTION] -> The current implementation does not automatically disable workflows based on `state`. To pause/stop execution, disable the workflow in the GitHub Actions UI. - -## What happens on each run - -At a high level, the orchestrator: - -1. (Optional) dispatches worker workflows via `workflow_dispatch` -2. discovers relevant issues/PRs -3. updates the GitHub Project (within governance limits) -4. posts a Project status update (summary + next steps) - -## Dispatching worker workflows - -If your campaign lists `workflows`, the orchestrator dispatches them sequentially. - -> [!NOTE] -> Dispatch is fire-and-forget: the orchestrator does not wait for worker workflows to finish. Results are picked up on later runs. - -### Worker workflow requirements - -- The workflow must exist (compiled `.lock.yml` or standard `.yml`). -- The workflow must support `workflow_dispatch`. -- If the campaign is responsible for running it, remove other triggers (cron/push) to avoid duplicates. - -## Pausing and ending a campaign +```mermaid +graph TD + A[Orchestrator Triggered] --> B[Phase 0: Dispatch Workers] + B --> C[Phase 1: Discover Items] + C --> D[Phase 2: Plan Updates] + D --> E[Phase 3: Apply Updates] + E --> F[Phase 4: Status Report] +``` -### Pause +Each run follows this sequence: -1. Set `state: paused` in the campaign spec (for clarity). -2. Disable the orchestrator workflow in GitHub Actions. +1. **Phase 0** - Dispatches worker workflows via `workflow_dispatch` (if configured) +2. **Phase 1** - Discovers issues and pull requests with campaign tracker labels +3. **Phase 2** - Plans project board updates within governance limits +4. **Phase 3** - Applies updates to project board +5. **Phase 4** - Posts status update to project with progress summary -### Finish +## Campaign states -1. Set `state: completed` (or `archived`). -2. Disable the orchestrator workflow. +| State | Description | Execution | +|-------|-------------|-----------| +| `planned` | Draft configuration under review | Not running | +| `active` | Production campaign | Runs on schedule | +| `paused` | Temporarily stopped | Not running | +| `completed` | Objectives achieved | Not running | +| `archived` | Historical reference | Not running | -> [!TIP] -> Consider running the orchestrator one last time before disabling it, so the Project gets a final status update. +:::caution +The `state` field is documentation only. To stop execution, disable the workflow in GitHub Actions settings. +::: -## When something goes wrong +## Worker workflows -Campaigns are designed to keep going and report what happened in the Project status update. +Worker workflows perform campaign tasks (scanning, analysis, remediation). The orchestrator dispatches them via `workflow_dispatch` and discovers their outputs. -- **Dispatch failed**: fix the worker workflow (missing, not dispatchable), then wait for the next run. -- **Project updates hit a limit**: increase governance limits or let the campaign catch up over multiple runs. -- **Permissions errors**: ensure the workflow token has the required Projects permissions. +### Requirements -
-Implementation notes (advanced) +Worker workflows in the campaign's `workflows` list must: -The orchestrator precomputes discovery before the agent phase and uses budgets to avoid scanning too much in one run. It can write a discovery manifest under `./.gh-aw/` for deterministic processing. -
- -## Limits and governance +- Accept `workflow_dispatch` as the **only** trigger +- Remove all other triggers (`schedule`, `push`, `pull_request`) +- Label created items with `campaign:` +- Accept standardized inputs: `campaign_id` (string) and `payload` (string JSON) -Campaigns typically enforce per-run budgets (for discovery, project updates, comments, etc.) so a run can’t “do everything at once”. When a budget is reached, the campaign reports what was deferred and continues on the next run. +```yaml +# Worker workflow configuration +on: + workflow_dispatch: + inputs: + campaign_id: + description: 'Campaign identifier' + required: true + type: string + payload: + description: 'JSON payload with work details' + required: true + type: string +``` -See [Campaign Specs](/gh-aw/guides/campaigns/specs/) for the `governance` fields. +### Independent workflows -**Example scenario**: +Workflows not in the `workflows` list can keep their original triggers. The campaign discovers their outputs via tracker labels without controlling execution. ```yaml # Campaign spec -governance: - max-discovery-items-per-run: 50 - max-project-updates-per-run: 10 +tracker-label: "campaign:security-audit" +workflows: + - vulnerability-scanner # Orchestrator controls this one + # dependency-check runs independently with its cron schedule ``` -**Run 1**: - -- Discovers: 50 items (budget reached) -- Processes: 10 items (budget reached) -- Deferred: 40 items - -**Run 2**: -- Discovers: 50 more items (starting from cursor) -- Processes: 10 items (from deferred 40 + newly discovered) -- Deferred: 30 + 50 = 80 items -- Cursor: Saved at item 100 - -**Run 3-N**: Continues until all items processed - -### Should the Campaign Stop? - -**No** - campaigns do NOT stop when max items are reached. They continue processing incrementally: - -- Discovery budget limits **pace** the work (prevents overwhelming API) -- Project update limits **throttle** writes (prevents project board spam) -- Cursor-based pagination ensures **all items are eventually processed** - -**Campaign stops only when**: - -1. All discovered items have been processed -2. No new items are being created by workers -3. State is changed to `completed` or `archived` (manual action) -4. Orchestrator workflow is disabled/deleted (manual action) +## Discovery and governance -## Campaign Ending & Termination - -### How to End a Campaign - -Campaigns are ended through **manual actions** - there is no automatic termination: - -#### Option 1: Update State to `completed` - -Edit the campaign spec (`.campaign.md`): +Discovery finds items created by workers based on tracker labels. Governance limits control the pace of work. ```yaml ---- -id: security-q1-2025 -name: Security Q1 2025 -state: completed # Changed from 'active' ---- +governance: + max-discovery-items-per-run: 50 + max-project-updates-per-run: 10 ``` -1. Compile: `gh aw compile security-q1-2025` -2. Commit updated files -3. **Manually disable** the workflow in GitHub Actions UI - -**Important**: Changing state to `completed` does NOT automatically stop execution - you must disable the workflow. - -#### Option 2: Disable the Workflow -In GitHub UI: +When limits are reached: +- Discovery cursor saves the current position +- Remaining items are deferred to the next run +- Status update reports deferred count +- Campaign continues on next schedule -1. Go to Actions → Workflows -2. Select the campaign orchestrator workflow -3. Click "Disable workflow" (three-dot menu) +The campaign processes items incrementally across multiple runs until all are handled. -**Effect**: Scheduled executions stop, but workflow can be manually triggered. +## Pausing and ending campaigns -#### Option 3: Delete Workflow Files +### Pause temporarily -Remove the campaign workflow files: - -git commit -m "End security-q1-2025 campaign" -git push -``` +1. Update spec: `state: paused` +2. Disable workflow in Actions settings -**Effect**: Workflow is completely removed and cannot execute. +### Complete permanently -### Archive Completed Campaigns +1. Run orchestrator one final time for completion status +2. Update spec: `state: completed` +3. Disable workflow in Actions settings +4. Optionally delete `.campaign.lock.yml` (keep `.campaign.md` for history) -For historical reference, use the `archived` state: +### Archive for reference ```yaml --- id: security-q1-2025 -name: Security Q1 2025 state: archived --- -# Campaign completed on 2025-03-15 - -Final metrics: - -- Tasks completed: 200/200 +Completed 2025-03-15. Final metrics: +- Tasks: 200/200 - Duration: 90 days -- Final velocity: 7.5 tasks/day +- Velocity: 7.5 tasks/day ``` -**Best practice**: Keep `.campaign.md` file with `state: archived` but delete `.campaign.lock.yml` to prevent accidental execution. - -### Final Status Update - -Before ending a campaign, run the orchestrator one final time to generate the **completion status update**: - -```yaml -create-project-status-update: - project: "https://github.com/orgs/ORG/projects/1" - status: "COMPLETE" - start_date: "2024-12-15" - target_date: "2025-03-15" - body: | - ## Campaign Complete - - The Security Q1 2025 campaign has successfully completed all objectives. - - ## Final Metrics - - - **Total tasks**: 200/200 (100%) - - **Duration**: 90 days - - **Average velocity**: 7.5 tasks/day - - ## KPI Achievement - - **Vulnerabilities Resolved** (Primary KPI): - - Baseline: 0% → Final: 100% → Target: 100% - - Status: ✅ TARGET ACHIEVED - - **Mean Time to Resolution** (Supporting KPI): - - Baseline: 14 days → Final: 3 days → Target: 5 days - - Status: ✅ TARGET EXCEEDED - - ## Lessons Learned - - 1. Automated vulnerability scanning reduced manual triage time by 80% - 2. Dependency upgrades prevented 15 potential security incidents - 3. Worker workflows enabled consistent, repeatable processes - - ## Next Steps - - - Archive campaign materials to `memory/campaigns/security-q1-2025/archive/` - - Transition ongoing vulnerability monitoring to BAU workflows - - Plan follow-up campaign for infrastructure modernization -``` - -### What Happens to Repo-Memory - -Campaign repo-memory (cursor, metrics snapshots) is preserved when a campaign ends: - -**Cursor file**: `memory/campaigns//cursor.json` - -- Remains at final position -- Can be used for historical reference -- Not automatically deleted - -**Metrics snapshots**: `memory/campaigns//metrics/*.json` - -- Append-only history preserved -- Valuable for retrospectives and trend analysis -- Should be retained for organizational learning - -**Best practice**: Keep repo-memory indefinitely for historical analysis and reporting. +## Troubleshooting -## Pre-existing Workflows & Trigger Behavior +**Worker dispatch fails** +- Verify workflow exists and has `workflow_dispatch` trigger +- Check workflow file name matches spec +- Ensure no compilation errors in worker -### Critical Requirement: Trigger Management +**Discovery finds no items** +- Verify tracker label matches campaign ID +- Check workers are creating items with correct labels +- Confirm discovery scope includes correct repos/orgs -**When a campaign executes a workflow** (workflow is listed in campaign's `workflows` field), the workflow's original triggers (cron schedules, push events, pull_request events) **must be disabled**. +**Project updates hit limit** +- Increase `max-project-updates-per-run` in governance +- Accept incremental processing across multiple runs +- Verify project token has required permissions -The campaign orchestrator controls execution timing via `workflow_dispatch`, and keeping other triggers active would cause: +**Items processed multiple times** +- Ensure workers use deterministic keys +- Check for duplicate labels on items +- Verify idempotency logic in worker code -- Duplicate executions (original trigger + campaign trigger) -- Resource waste and potential conflicts -- Loss of campaign control over execution timing +## Advanced: Pre-existing workflows -> [!CAUTION] -> **Required workflow trigger configuration:** -> -> ```yaml -> on: -> workflow_dispatch: # ONLY this trigger for campaign-executed workflows -> ``` +### Converting scheduled workflows -**Alternative approach**: If a workflow should keep its original triggers, **do not add it to the campaign's `workflows` list**. Instead, let it run independently and have the campaign discover its outputs via tracker labels. - -### Campaign Impact on Existing Workflows - -A critical aspect of campaigns is understanding how they interact with workflows that have existing triggers (cron jobs, push events, etc.). - -### Worker Workflows with Cron Jobs - -**Scenario**: A repository has an existing workflow that runs on a schedule: - -```yaml -# .github/workflows/daily-dependency-check.md ---- -name: Daily Dependency Check -on: daily # Runs once per day at automatically scattered time - workflow_dispatch: ---- -``` - -**When picked up by campaign**: - -The campaign spec references this workflow: +When adding an existing scheduled workflow to a campaign: +**Before** (independent): ```yaml -# .github/workflows/security-audit.campaign.md ---- -id: security-audit -workflows: - - daily-dependency-check ---- -``` - -### Required: Disable Original Triggers - -**IMPORTANT**: When a campaign picks up an existing workflow for execution, **you must disable the workflow's original triggers** (cron schedules, push events, etc.). The campaign orchestrator will control when the workflow runs. - -Campaign orchestrators execute workflows programmatically using `workflow_dispatch`: - -```yaml -# In orchestrator Phase 0 -- name: Dispatch worker workflow - uses: ./actions/safe-output - with: - type: daily_dependency_check -``` - -**Why disable original triggers?** - -- Prevents duplicate executions (campaign + original schedule) -- Ensures campaign has full control over execution timing -- Avoids resource waste and potential conflicts -- Maintains clear ownership of workflow execution - -#### How to Disable Original Triggers - -Modify the worker workflow to remove/comment out the original trigger: - -```yaml -# .github/workflows/daily-dependency-check.md ---- -name: Daily Dependency Check on: - # schedule: daily # DISABLED - controlled by campaign - workflow_dispatch: # REQUIRED - allows campaign to trigger workflow ---- -``` - -**Result**: Workflow only runs when triggered by campaign orchestrator. - -#### Alternative: Keep Workflow Independent - -If the workflow should continue running on its own schedule (not controlled by campaign), **do not add it to the campaign's `workflows` list**. Instead, let it run independently and have the campaign discover its outputs via tracker labels: - -```yaml -# .github/workflows/security-audit.campaign.md ---- -id: security-audit -tracker-label: "campaign:security-audit" -workflows: - - vulnerability-scanner # Only workflows the campaign should execute ---- -``` - -**How it works**: - -- `daily-dependency-check` keeps its cron schedule and runs independently -- It creates issues/PRs with the tracker label `campaign:security-audit` -- Campaign orchestrator discovers these items via the tracker label -- Campaign tracks progress without executing the workflow - -**Effect**: Campaign does not execute this workflow; it runs independently but campaign tracks its outputs. - -### Push/PR Triggers - -**Scenario**: A workflow has push or pull_request triggers: - -```yaml -# .github/workflows/code-quality-check.md ---- -name: Code Quality Check -on: - push: - branches: [main] - pull_request: + schedule: daily workflow_dispatch: ---- ``` -**IMPORTANT**: If you want the campaign to execute this workflow, you **must remove the push/PR triggers**: - +**After** (campaign-controlled): ```yaml -# .github/workflows/code-quality-check.md ---- -name: Code Quality Check on: - # push: # DISABLED - controlled by campaign - # branches: [main] - # pull_request: # DISABLED - controlled by campaign - workflow_dispatch: # REQUIRED for campaign execution ---- -``` - -**However**, push/PR triggers are usually **inappropriate for campaigns** because: - -- Code quality checks should respond to code changes (push/PR events) -- Campaign schedules (e.g., daily) don't align with code change events -- The workflow's purpose (event-driven validation) conflicts with campaign control - -**Recommended approach**: Do NOT add event-driven workflows to campaign's `workflows` list. Instead: - -- Let them run independently on their original triggers -- Have the campaign discover their outputs via tracker labels - -```yaml -# .github/workflows/quality-initiative.campaign.md ---- -id: quality-initiative -tracker-label: "campaign:quality-initiative" -workflows: - # code-quality-check NOT listed - runs independently on push/PR - - quality-reporter # Only campaign-controlled workflows here ---- + workflow_dispatch: # Only this trigger + # schedule: daily # Removed - campaign controls timing ``` -**Result**: Event-driven workflows continue responding to code changes, while campaign tracks their outputs. - -### Campaign Item Protection - -A related concern is preventing non-campaign workflows from interfering with campaign-tracked items. - -#### How Protection Works - -Items with campaign labels (`campaign:*`) are automatically excluded from other workflows: - -```javascript -// Example from issue-monster workflow -if (issueLabels.some(label => label.startsWith('campaign:'))) { - core.info(`Skipping #${issue.number}: has campaign label`); - return false; -} -``` - -**Protection mechanisms**: - -1. **Automatic labeling**: When campaign adds items to project, applies `campaign:` label -2. **Workflow filtering**: Other workflows skip items with `campaign:` labels -3. **Opt-out labels**: `no-bot`, `no-campaign` provide additional exclusion - -#### Example: Issue Monster vs Campaign - -**Scenario**: Both `issue-monster` and a campaign workflow process issues. - -**Without protection**: - -- Issue monster adds comment: "This issue needs attention" -- Campaign orchestrator adds comment: "Added to security-q1-2025 project" -- Result: Duplicate/conflicting actions - -**With protection**: - -- Campaign adds `campaign:security-q1-2025` label when adding to project -- Issue monster checks labels: `if (label.startsWith('campaign:'))` → skip -- Result: Only campaign orchestrator manages the issue - -### Pre-existing Cron Jobs: Summary - -| Scenario | Behavior | Recommendation | -| --- | --- | --- | -| **Worker with cron in campaign** | Workflow added to campaign's `workflows` list | **REQUIRED: Disable cron**, keep only `workflow_dispatch` | -| **Worker with push trigger in campaign** | Workflow added to campaign's `workflows` list | **REQUIRED: Remove push trigger**, or remove from campaign | -| **Worker with workflow_dispatch only** | Runs only when campaign triggers | ✅ Ideal for campaign workers | -| **Independent workflow with cron** | NOT in campaign's `workflows` list | Keep cron, campaign discovers outputs via tracker labels | - -**Key requirement**: If a workflow is in the campaign's `workflows` list, it must have ONLY `workflow_dispatch` trigger. All other triggers (cron, push, pull_request) must be disabled to prevent duplicate executions. - -## Summary: Complete Campaign Flow - -### Startup (First Run) - -1. **Orchestrator triggered** (schedule or manual) -2. **Discovery precomputation**: Searches GitHub, generates manifest -3. **Phase 0**: Creates Epic issue, adds to project -4. **Phase 1**: Reads discovery manifest, reads project board -5. **Phase 2**: Plans updates (apply budgets, deterministic order) -6. **Phase 3**: Writes updates to project board -7. **Phase 4**: Creates status update, reports initial state - -### Ongoing Execution (Subsequent Runs) - -1. **Orchestrator triggered** (daily schedule) -2. **Discovery precomputation**: Continues from cursor, finds new items -3. **Phase 0** (optional): Dispatches worker workflows if configured -4. **Phase 1**: Reads manifest + project state -5. **Phase 2**: Plans updates for discovered items -6. **Phase 3**: Writes up to max updates -7. **Phase 4**: Reports progress, KPIs, deferred items - -### Incident Handling Summary - -- **Discovery failure**: Partial results used, cursor not advanced, retry next run -- **Workflow dispatch failure**: Logged, other workflows continue, reported in status -- **Update failure**: Individual item failure recorded, processing continues -- **Limit reached**: Remaining items deferred, status update explains - -### Max Items Budget - -- **Discovery limit**: Stops discovery early, saves cursor -- **Update limit**: Processes first N items, defers rest -- **Next run**: Continues from cursor with deferred items -- **Campaign never stops** due to limits - processes incrementally - -### Campaign Ending - -1. **Completion criteria**: All items processed, objectives met -2. **Manual action**: Update state to `completed`, disable workflow -3. **Final status update**: Reports completion, KPI achievement, lessons learned -4. **Archival**: Keep `.campaign.md` with `state: archived`, delete `.campaign.lock.yml` -5. **Repo-memory**: Preserved for historical reference +### Event-driven workflows -### Pre-existing Workflows +Workflows triggered by code events (`push`, `pull_request`) should not be campaign-controlled. These respond to specific events, not campaign schedules. -- **REQUIRED**: Workflows in campaign's `workflows` list must have ONLY `workflow_dispatch` trigger -- **Original triggers must be disabled**: Cron, push, and PR triggers must be removed/commented out -- **Alternative**: Keep workflows independent with their triggers, let campaign discover outputs via tracker labels -- **Protection**: Campaign labels prevent interference from other workflows -- **Key rule**: Campaign-executed workflows = `workflow_dispatch` only; Independent workflows = keep their triggers +**Recommended**: Keep them independent and let the campaign discover their outputs. - +**Not recommended**: Adding them to campaign's `workflows` list requires removing event triggers, which defeats their purpose. -## Further Reading +## Further reading -- [Campaign Specs](/gh-aw/guides/campaigns/specs/) - Configuration reference -- [Getting Started](/gh-aw/guides/campaigns/getting-started/) - Create your first campaign -- [Safe Outputs](/gh-aw/reference/safe-outputs/) - Project automation operations +- [Campaign specs](/gh-aw/guides/campaigns/specs/) - Configuration reference +- [Getting started](/gh-aw/guides/campaigns/getting-started/) - Create your first campaign +- [CLI commands](/gh-aw/guides/campaigns/cli-commands/) - Management commands diff --git a/docs/src/content/docs/guides/campaigns/specs.md b/docs/src/content/docs/guides/campaigns/specs.md index 54747dd06d..536387668e 100644 --- a/docs/src/content/docs/guides/campaigns/specs.md +++ b/docs/src/content/docs/guides/campaigns/specs.md @@ -1,57 +1,27 @@ --- title: Campaign specs -description: Define and configure agentic campaigns with spec files, tracker labels, and recommended wiring +description: Campaign specification format and configuration reference banner: content: 'Do not use. Campaigns are still incomplete and may produce unreliable or unintended results.' --- -Campaigns are defined as Markdown files under `.github/workflows/` with a `.campaign.md` suffix. The YAML frontmatter is the campaign “contract”; the body can contain optional narrative context. +Campaign specs are YAML frontmatter configuration files at `.github/workflows/.campaign.md`. The frontmatter defines campaign metadata, goals, workers, and governance. The body can contain narrative context. -## What this file does - -The campaign spec is a reviewable configuration file that: - -- names the campaign -- points to a GitHub Project for tracking -- defines where to discover worker-created items -- lists the workflows the orchestrator should dispatch -- defines goals (objective + KPIs) - -Most users should create specs via the [Getting started flow](/gh-aw/guides/campaigns/getting-started/). - -## Complete spec example - -This example shows a complete, working campaign spec with all commonly-used fields: +## Spec structure ```yaml -# .github/workflows/framework-upgrade.campaign.md --- id: framework-upgrade -version: "v1" name: "Framework Upgrade" description: "Move services to Framework vNext" +state: active project-url: "https://github.com/orgs/ORG/projects/1" tracker-label: "campaign:framework-upgrade" -# Discovery: Where to find worker-created issues/PRs discovery-repos: - "myorg/service-a" - "myorg/service-b" -# Or use discovery-orgs for organization-wide discovery: -# discovery-orgs: -# - "myorg" - -# Optional: Custom GitHub token for Projects v2 operations -# project-github-token: "${{ secrets.GH_AW_PROJECT_GITHUB_TOKEN }}" - -# Optional: Restrict which repos this campaign can operate on -# If omitted, defaults to the repository where the campaign spec lives. -# allowed-repos: -# - "myorg/service-a" -# - "myorg/service-b" -# allowed-orgs: -# - "myorg" objective: "Upgrade all services to Framework vNext with zero downtime." kpis: @@ -63,133 +33,269 @@ kpis: target: 50 time-window-days: 30 direction: "increase" - - id: incidents - name: "Incidents caused" - priority: supporting - unit: count - baseline: 5 - target: 0 - time-window-days: 30 - direction: "decrease" workflows: - - framework-upgrade + - framework-upgrade-scanner + +governance: + max-project-updates-per-run: 10 + max-discovery-items-per-run: 50 -state: "active" owners: - "platform-team" --- + +Additional narrative context about the campaign... ``` -## Core fields (what they do) +## Required fields -### Required +### Identity -- `id`: Stable identifier used for file naming and reporting (lowercase letters, digits, hyphens only). -- `name`: Human-friendly name for the campaign. -- `project-url`: GitHub Project URL used for tracking. +**id** - Stable identifier for file naming and reporting +- Format: lowercase letters, digits, hyphens only +- Example: `security-audit-2025` -### Required for discovery +**name** - Human-friendly display name +- Example: `"Security Audit 2025"` -When your campaign uses `workflows` or `tracker-label`, you must specify where to discover worker-created items: +**project-url** - GitHub Project board URL for tracking +- Format: `https://github.com/orgs/ORG/projects/N` +- Example: `https://github.com/orgs/mycompany/projects/1` -- `discovery-repos`: List of repositories (in `owner/repo` format) where worker workflows create issues/PRs. -- `discovery-orgs`: List of GitHub organizations where worker workflows operate (searches all repos in those orgs). +### Discovery scope -At least one of `discovery-repos` or `discovery-orgs` is required when using workflows or tracker labels. +At least one of these is required when using `workflows` or `tracker-label`: -### Commonly used +**discovery-repos** - Specific repositories to search +- Format: List of `owner/repo` strings +- Example: `["myorg/api", "myorg/web"]` -- `objective`: One sentence describing what success means for this campaign. -- `kpis`: List of 1-3 KPIs used to measure progress toward the objective. -- `workflows`: Workflow IDs the orchestrator can dispatch via `workflow_dispatch`. -- `tracker-label`: Label used to discover worker-created issues/PRs (commonly `campaign:`). -- `state`: Lifecycle state (`planned`, `active`, `paused`, `completed`, or `archived`). +**discovery-orgs** - Organizations to search (all repos) +- Format: List of organization names +- Example: `["myorg"]` -### Optional +## Common fields -- `allowed-repos`: Repositories this campaign can operate on (defaults to the repo containing the spec). -- `allowed-orgs`: Organizations this campaign can operate on. -- `project-github-token`: Token expression for Projects v2 operations (e.g., `${{ secrets.GH_AW_PROJECT_GITHUB_TOKEN }}`). -- `description`: Brief description of the campaign. -- `version`: Spec version (defaults to `v1`). -- `owners`: Primary human owners for this campaign. -- `governance`: Pacing and opt-out policies (see Governance section below). +**objective** - One-sentence success definition +- Example: `"Eliminate all critical security vulnerabilities"` -> [!IMPORTANT] -> - Use `priority: primary` (not `primary: true`) to mark your primary KPI. -> - The `discovery-*` fields control WHERE to search for worker outputs. -> - The `allowed-*` fields control WHERE the campaign can operate. +**kpis** - Key performance indicators (1-3 maximum) +- See [KPI specification](#kpi-specification) below -## Strategic goals (objective + KPIs) +**workflows** - Worker workflows to dispatch +- Format: List of workflow IDs (file names without extension) +- Example: `["security-scanner", "dependency-fixer"]` -Use `objective` and `kpis` to define what “done” means and how progress should be reported. +**tracker-label** - Label for discovering worker outputs +- Format: `campaign:` +- Example: `campaign:security-audit` -- `objective`: a one-sentence definition of success. -- `kpis`: a small set of measures shown in status updates. +**state** - Lifecycle state +- Values: `planned`, `active`, `paused`, `completed`, `archived` +- Default: `planned` -## KPIs (recommended shape) +**governance** - Pacing and safety limits +- See [Governance fields](#governance-fields) below -Each KPI requires these fields: +## Optional fields + +**description** - Brief campaign description + +**version** - Spec format version +- Default: `v1` -- `name`: Human-readable KPI name. -- `baseline`: Starting value. -- `target`: Goal value. -- `time-window-days`: Rolling window for measurement (e.g., 7, 14, 30 days). +**owners** - Primary human owners +- Format: List of team or user names -Optional fields: +**allowed-repos** - Repositories campaign can modify +- Default: Repository containing the spec +- Format: List of `owner/repo` strings -- `id`: Stable identifier (lowercase letters, digits, hyphens). -- `priority`: `primary` or `supporting` (exactly one KPI should be primary). -- `unit`: Unit of measurement (e.g., `count`, `percent`, `days`). -- `direction`: `increase` or `decrease` (describes improvement direction). -- `source`: Signal source (`ci`, `pull_requests`, `code_security`, or `custom`). +**allowed-orgs** - Organizations campaign can modify +- Format: List of organization names -Keep KPIs small and crisp: +**project-github-token** - Custom token for Projects API +- Format: Token expression like `${{ secrets.TOKEN_NAME }}` +- Use when default `GITHUB_TOKEN` lacks Projects permissions -- Use 1 primary KPI + up to 2 supporting KPIs (maximum 3 total). -- When you define `kpis`, also define `objective` (and vice versa). +## KPI specification + +Each KPI requires these fields: -## Unified tracking (GitHub Project) +```yaml +kpis: + - id: vulnerabilities_fixed # Stable identifier + name: "Vulnerabilities resolved" # Display name + priority: primary # One KPI must be primary + unit: count # Measurement unit + baseline: 50 # Starting value + target: 0 # Goal value + time-window-days: 30 # Measurement period + direction: "decrease" # Improvement direction +``` -Use `project-url` to point the campaign at a GitHub Project board for tracking. +### Required KPI fields -- `project-url`: the Project URL (for example: `https://github.com/orgs/ORG/projects/1`). -- `project-github-token` (optional): a token to use for Projects operations when `GITHUB_TOKEN` isn’t enough. +- **name** - Human-readable name +- **baseline** - Starting value +- **target** - Goal value +- **time-window-days** - Rolling window (7, 14, 30, or 90 days) -Project updates are applied by the orchestrator using safe outputs; see [Update Project](/gh-aw/reference/safe-outputs/#project-board-updates-update-project). +### Optional KPI fields -## Worker workflows +- **id** - Stable identifier (defaults to sanitized name) +- **priority** - `primary` or `supporting` (exactly one primary) +- **unit** - Measurement unit (`count`, `percent`, `days`, `hours`) +- **direction** - `increase` or `decrease` +- **source** - Signal source (`ci`, `pull_requests`, `code_security`, `custom`) -Use `workflows` to list the dispatchable workflows (“workers”) the orchestrator can trigger via `workflow_dispatch`. +### KPI guidelines -For worker requirements and dispatch behavior, see [Dispatching worker workflows](/gh-aw/guides/campaigns/lifecycle/#dispatching-worker-workflows). +- Define 1 primary KPI + up to 2 supporting KPIs (3 maximum) +- Always pair `objective` with `kpis` (define both or neither) +- Use concrete, measurable targets +- Choose realistic time windows -## Governance (pacing & safety) +## Governance fields -Use `governance` to keep orchestration predictable and reviewable: +Governance controls execution pace and safety: ```yaml governance: - max-new-items-per-run: 10 - max-discovery-items-per-run: 100 + max-project-updates-per-run: 10 + max-discovery-items-per-run: 50 max-discovery-pages-per-run: 5 - opt-out-labels: ["campaign:skip"] - do-not-downgrade-done-items: true - max-project-updates-per-run: 50 + max-new-items-per-run: 10 max-comments-per-run: 10 + do-not-downgrade-done-items: true + opt-out-labels: ["campaign:skip", "no-bot"] +``` + +**max-project-updates-per-run** - Maximum project board updates per execution +- Default: Conservative limit +- Start low (10) and increase with confidence + +**max-discovery-items-per-run** - Maximum items to discover per execution +- Controls API load +- Remaining items discovered on next run + +**max-discovery-pages-per-run** - Maximum API pages to fetch +- Alternative to item limit + +**max-new-items-per-run** - Maximum new items to add to project +- Separate from total updates + +**max-comments-per-run** - Maximum comments to post +- Prevents notification spam + +**do-not-downgrade-done-items** - Prevent moving completed items backward +- Recommended: `true` + +**opt-out-labels** - Labels that exclude items from campaign +- Default: `["no-bot", "no-campaign"]` + +## Discovery configuration + +### Repository-scoped discovery + +```yaml +discovery-repos: + - "myorg/frontend" + - "myorg/backend" + - "myorg/api" ``` -> [!TIP] -> Start conservative with low limits (e.g., `max-project-updates-per-run: 10`) for your first campaign, then increase as you gain confidence. +Searches only specified repositories for issues and pull requests with tracker labels. -### Common fields +### Organization-scoped discovery -- `max-project-updates-per-run`: cap Project updates per run (default is conservative). -- `max-comments-per-run`: cap comments per run. -- `do-not-downgrade-done-items`: prevents moving items backward. +```yaml +discovery-orgs: + - "myorg" +``` + +Searches all repositories in the organization. Use carefully - can be expensive for large organizations. + +### Hybrid approach + +```yaml +discovery-repos: + - "myorg/critical-service" # Always scan this one +discovery-orgs: + - "myorg" # Scan all others +``` + +## Validation + +Validate campaign specs before committing: + +```bash +gh aw campaign validate +``` + +Common validation errors: + +- Missing required fields (`id`, `name`, `project-url`) +- Missing discovery scope when using `workflows` or `tracker-label` +- Invalid KPI configuration (no primary, too many KPIs) +- Invalid `state` value +- Malformed URLs or identifiers + +## Example: Security audit campaign + +```yaml +--- +id: security-audit-q1 +version: "v1" +name: "Security Audit Q1 2025" +description: "Quarterly security review and remediation" +state: active + +project-url: "https://github.com/orgs/myorg/projects/5" +tracker-label: "campaign:security-audit-q1" + +discovery-orgs: + - "myorg" + +objective: "Resolve all high and critical security vulnerabilities" +kpis: + - id: critical_vulns + name: "Critical vulnerabilities" + priority: primary + unit: count + baseline: 15 + target: 0 + time-window-days: 90 + direction: "decrease" + - id: mttr + name: "Mean time to resolution" + priority: supporting + unit: days + baseline: 14 + target: 3 + time-window-days: 30 + direction: "decrease" + +workflows: + - security-scanner + - dependency-updater + +governance: + max-project-updates-per-run: 20 + max-discovery-items-per-run: 100 + do-not-downgrade-done-items: true + +owners: + - "security-team" +--- + +This campaign runs weekly to scan for vulnerabilities and track remediation. +Workers create issues with severity labels and automated fix PRs where possible. +``` -## Next +## Further reading -- See [Campaign lifecycle](/gh-aw/guides/campaigns/lifecycle/) for what happens each run. -- See [CLI commands](/gh-aw/guides/campaigns/cli-commands/) to validate and inspect campaigns. +- [Campaign lifecycle](/gh-aw/guides/campaigns/lifecycle/) - Execution model +- [Getting started](/gh-aw/guides/campaigns/getting-started/) - Create your first campaign +- [CLI commands](/gh-aw/guides/campaigns/cli-commands/) - Validation and management From fae37e743dd8a11e11c721ef7bc23be6f5c310e6 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 23 Jan 2026 09:41:23 +0000 Subject: [PATCH 4/6] Improve About campaigns page (index.mdx) with doc workflow principles Co-authored-by: mnkiefer <8320933+mnkiefer@users.noreply.github.com> --- .../content/docs/guides/campaigns/index.mdx | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/docs/src/content/docs/guides/campaigns/index.mdx b/docs/src/content/docs/guides/campaigns/index.mdx index 38ff18c905..35f4f86735 100644 --- a/docs/src/content/docs/guides/campaigns/index.mdx +++ b/docs/src/content/docs/guides/campaigns/index.mdx @@ -12,15 +12,15 @@ import FeatureGrid from '../../../../components/FeatureGrid.astro'; ## What are Agentic Campaigns? -**[Agentic campaigns](/gh-aw/reference/glossary/#agentic-campaign)** are a way to bundle agentic workflows around a shared goal. +**[Agentic campaigns](/gh-aw/reference/glossary/#agentic-campaign)** bundle agentic workflows around a shared goal. -This can be as lightweight tracking or grow over time to coordinate work across repositories and teams. Campaigns keep agentic work visible and easier to manage as it scales. +Campaigns provide tracking infrastructure that coordinates work across repositories and teams. All campaign work is visible through GitHub Projects. ## Why use campaigns? - Define what “done” means with an objective and KPIs (and optional narrative context). + Define campaign objectives and key performance indicators (KPIs). Optional narrative context. Coordinate existing dispatchable workflows instead of rewriting automation. @@ -35,18 +35,16 @@ This can be as lightweight tracking or grow over time to coordinate work across ## Natural language to Campaign -Creating campaigns without agentic workflows would be tedious and error-prone. -Just like agentic workflows turn natural language into GitHub Actions, -campaigns turn brief natural language goal definitions into coordinated work tracked in GitHub Projects. +Campaigns use agentic workflows to generate configuration from natural language descriptions. -**Example input**: Describe your goal in plain language, such as: +**Example input**: Describe your goal in plain language: ```md Burn down all open code security alerts, prioritizing file-write alerts first and batching up to 3 related alerts/PR with a brief fix rationale comment. ``` -The campaign generator automatically converts this into a **[campaign spec](/gh-aw/guides/campaigns/specs/)** in a pull request where you can review and iterate on the details. Here's what the essential parts look like: +The campaign generator converts this into a **[campaign spec](/gh-aw/guides/campaigns/specs/)** in a pull request. Essential spec components: ```yaml --- @@ -78,10 +76,9 @@ governance: --- ``` -The spec is validated and compiled to create the campaign's orchestrator workflow (`.campaign.lock.yml`) that GitHub Actions can execute. -Think of it like compiling code: you write a human-friendly campaign definition, and the compiler produces a hardened, machine-executable workflow. +The spec is validated and compiled into the campaign orchestrator workflow (`.campaign.lock.yml`) that GitHub Actions executes. -**What happens next**: Once merged, the campaign orchestrator runs on schedule (daily by default) to [dispatch worker workflows, discover items, update the Project board, and report status](/gh-aw/guides/campaigns/lifecycle/). The campaign coordinates all work toward your objective while respecting governance limits. +Once merged, the orchestrator runs on schedule (daily by default) to [dispatch worker workflows, discover items, update the Project board, and report status](/gh-aw/guides/campaigns/lifecycle/). ## Next steps From 51237d877f27a974aeedce74b9d5ab85beb1304a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 23 Jan 2026 09:43:30 +0000 Subject: [PATCH 5/6] Address code review feedback - improve clarity in About page Co-authored-by: mnkiefer <8320933+mnkiefer@users.noreply.github.com> --- docs/src/content/docs/guides/campaigns/index.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/src/content/docs/guides/campaigns/index.mdx b/docs/src/content/docs/guides/campaigns/index.mdx index 35f4f86735..8093549e8f 100644 --- a/docs/src/content/docs/guides/campaigns/index.mdx +++ b/docs/src/content/docs/guides/campaigns/index.mdx @@ -14,13 +14,13 @@ import FeatureGrid from '../../../../components/FeatureGrid.astro'; **[Agentic campaigns](/gh-aw/reference/glossary/#agentic-campaign)** bundle agentic workflows around a shared goal. -Campaigns provide tracking infrastructure that coordinates work across repositories and teams. All campaign work is visible through GitHub Projects. +Campaigns provide tracking infrastructure to coordinate work across repositories and teams. All campaign work is visible through GitHub Projects. ## Why use campaigns? - Define campaign objectives and key performance indicators (KPIs). Optional narrative context. + Define campaign objectives and key performance indicators (KPIs) with optional narrative context. Coordinate existing dispatchable workflows instead of rewriting automation. From af6be4a9f97dcc1f6951c0f55d5ea06db774dae5 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 23 Jan 2026 09:44:14 +0000 Subject: [PATCH 6/6] Final polish - address remaining code review nitpicks in About page Co-authored-by: mnkiefer <8320933+mnkiefer@users.noreply.github.com> --- docs/src/content/docs/guides/campaigns/index.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/src/content/docs/guides/campaigns/index.mdx b/docs/src/content/docs/guides/campaigns/index.mdx index 8093549e8f..eebbef37ad 100644 --- a/docs/src/content/docs/guides/campaigns/index.mdx +++ b/docs/src/content/docs/guides/campaigns/index.mdx @@ -14,7 +14,7 @@ import FeatureGrid from '../../../../components/FeatureGrid.astro'; **[Agentic campaigns](/gh-aw/reference/glossary/#agentic-campaign)** bundle agentic workflows around a shared goal. -Campaigns provide tracking infrastructure to coordinate work across repositories and teams. All campaign work is visible through GitHub Projects. +Campaigns provide tracking infrastructure to coordinate work across repositories and teams, with all work visible through GitHub Projects. ## Why use campaigns? @@ -44,7 +44,7 @@ Burn down all open code security alerts, prioritizing file-write alerts first and batching up to 3 related alerts/PR with a brief fix rationale comment. ``` -The campaign generator converts this into a **[campaign spec](/gh-aw/guides/campaigns/specs/)** in a pull request. Essential spec components: +The campaign generator converts this into a **[campaign spec](/gh-aw/guides/campaigns/specs/)** in a pull request for review. Essential spec components include: ```yaml ---