diff --git a/docs/src/content/docs/examples/campaigns.md b/docs/src/content/docs/examples/campaigns.md index 77ef5c46fd4..f8742ea3aa9 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 ff276b8bbf6..333a83594c4 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 dd3a8576b01..537df113485 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/index.mdx b/docs/src/content/docs/guides/campaigns/index.mdx index 38ff18c9056..eebbef37ad6 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 to coordinate work across repositories and teams, with all work 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) with 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 for review. Essential spec components include: ```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 diff --git a/docs/src/content/docs/guides/campaigns/lifecycle.md b/docs/src/content/docs/guides/campaigns/lifecycle.md index dd76b2c3f84..3fff82f05e2 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 edc42883c71..63f38807277 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: "z_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 (format: `z_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: ["z_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