diff --git a/.github/workflows/security-alert-burndown.campaign.lock.yml b/.github/workflows/security-alert-burndown.campaign.lock.yml index 891055e70d..c89d95fee6 100644 --- a/.github/workflows/security-alert-burndown.campaign.lock.yml +++ b/.github/workflows/security-alert-burndown.campaign.lock.yml @@ -69,11 +69,9 @@ jobs: needs: activation runs-on: ubuntu-latest permissions: - actions: read contents: read issues: read pull-requests: read - security-events: read concurrency: group: "gh-aw-claude-${{ github.workflow }}" env: @@ -112,12 +110,11 @@ jobs: run: mkdir -p ./.gh-aw - env: GH_AW_CAMPAIGN_ID: security-alert-burndown - GH_AW_CURSOR_PATH: /tmp/gh-aw/repo-memory/campaigns/security-alert-burndown/cursor.json - GH_AW_DISCOVERY_REPOS: githubnext/gh-aw + GH_AW_CURSOR_PATH: "" GH_AW_MAX_DISCOVERY_ITEMS: "100" GH_AW_MAX_DISCOVERY_PAGES: "5" GH_AW_PROJECT_URL: https://github.com/orgs/githubnext/projects/134 - GH_AW_TRACKER_LABEL: z_campaign_security-alert-burndown + GH_AW_TRACKER_LABEL: "" GH_AW_WORKFLOWS: code-scanning-fixer,security-fix-pr,dependabot-bundler,secret-scanning-triage id: discovery name: Run campaign discovery precomputation @@ -197,71 +194,10 @@ jobs: mkdir -p /tmp/gh-aw/safeoutputs mkdir -p /tmp/gh-aw/mcp-logs/safeoutputs cat > /opt/gh-aw/safeoutputs/config.json << 'EOF' - {"add_comment":{"max":3},"create_issue":{"max":1},"create_project_status_update":{"max":1},"missing_data":{},"missing_tool":{},"noop":{"max":1},"update_project":{"max":10}} + {"dispatch_workflow":{"max":3,"workflows":["code-scanning-fixer","security-fix-pr","dependabot-bundler","secret-scanning-triage"]},"missing_data":{},"missing_tool":{},"noop":{"max":1}} EOF cat > /opt/gh-aw/safeoutputs/tools.json << 'EOF' [ - { - "description": "Create a new GitHub issue for tracking bugs, feature requests, or tasks. Use this for actionable work items that need assignment, labeling, and status tracking. For reports, announcements, or status updates that don't require task tracking, use create_discussion instead. CONSTRAINTS: Maximum 1 issue(s) can be created.", - "inputSchema": { - "additionalProperties": false, - "properties": { - "body": { - "description": "Detailed issue description in Markdown. Do NOT repeat the title as a heading since it already appears as the issue's h1. Include context, reproduction steps, or acceptance criteria as appropriate.", - "type": "string" - }, - "labels": { - "description": "Labels to categorize the issue (e.g., 'bug', 'enhancement'). Labels must exist in the repository.", - "items": { - "type": "string" - }, - "type": "array" - }, - "parent": { - "description": "Parent issue number for creating sub-issues. This is the numeric ID from the GitHub URL (e.g., 42 in github.com/owner/repo/issues/42). Can also be a temporary_id (e.g., 'aw_abc123def456') from a previously created issue in the same workflow run.", - "type": [ - "number", - "string" - ] - }, - "temporary_id": { - "description": "Unique temporary identifier for referencing this issue before it's created. Format: 'aw_' followed by 12 hex characters (e.g., 'aw_abc123def456'). Use '#aw_ID' in body text to reference other issues by their temporary_id; these are replaced with actual issue numbers after creation.", - "type": "string" - }, - "title": { - "description": "Concise issue title summarizing the bug, feature, or task. The title appears as the main heading, so keep it brief and descriptive.", - "type": "string" - } - }, - "required": [ - "title", - "body" - ], - "type": "object" - }, - "name": "create_issue" - }, - { - "description": "Add a comment to an existing GitHub issue, pull request, or discussion. Use this to provide feedback, answer questions, or add information to an existing conversation. For creating new items, use create_issue, create_discussion, or create_pull_request instead. CONSTRAINTS: Maximum 3 comment(s) can be added.", - "inputSchema": { - "additionalProperties": false, - "properties": { - "body": { - "description": "The comment text in Markdown format. This is the 'body' field - do not use 'comment_body' or other variations. Provide helpful, relevant information that adds value to the conversation.", - "type": "string" - }, - "item_number": { - "description": "The issue, pull request, or discussion number to comment on. This is the numeric ID from the GitHub URL (e.g., 123 in github.com/owner/repo/issues/123). If omitted, the tool will attempt to resolve the target from the current workflow context (triggering issue, PR, or discussion).", - "type": "number" - } - }, - "required": [ - "body" - ], - "type": "object" - }, - "name": "add_comment" - }, { "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": { @@ -304,133 +240,6 @@ jobs: }, "name": "noop" }, - { - "description": "Add or update items in GitHub Projects v2 boards. Can add issues/PRs to a project and update custom field values. Requires the project URL, content type (issue or pull_request), and content number. Use campaign_id to group related items.\n\nThree usage modes:\n1. Add/update project item: Requires project + content_type. For 'issue' or 'pull_request', also requires content_number. For 'draft_issue', requires draft_title.\n2. Create project fields: Requires project + operation='create_fields' + field_definitions.\n3. Create project view: Requires project + operation='create_view' + view.", - "inputSchema": { - "additionalProperties": false, - "properties": { - "campaign_id": { - "description": "Campaign identifier to group related project items. Used to track items created by the same campaign or workflow run.", - "type": "string" - }, - "content_number": { - "description": "Issue or pull request number to add to the project. This is the numeric ID from the GitHub URL (e.g., 123 in github.com/owner/repo/issues/123 for issue #123, or 456 in github.com/owner/repo/pull/456 for PR #456). Required when content_type is 'issue' or 'pull_request'.", - "type": "number" - }, - "content_type": { - "description": "Type of item to add to the project. Use 'issue' or 'pull_request' to add existing repo content, or 'draft_issue' to create a draft item inside the project. Required when operation is not specified.", - "enum": [ - "issue", - "pull_request", - "draft_issue" - ], - "type": "string" - }, - "create_if_missing": { - "description": "Whether to create the project if it doesn't exist. Defaults to false. Requires projects:write permission when true.", - "type": "boolean" - }, - "draft_body": { - "description": "Optional body for a Projects v2 draft issue (markdown). Only used when content_type is 'draft_issue'.", - "type": "string" - }, - "draft_title": { - "description": "Title for a Projects v2 draft issue. Required when content_type is 'draft_issue'.", - "type": "string" - }, - "field_definitions": { - "description": "Field definitions to create when operation is create_fields. Required when operation='create_fields'.", - "items": { - "additionalProperties": false, - "properties": { - "data_type": { - "description": "Field type. Use SINGLE_SELECT with options for enumerated values.", - "enum": [ - "TEXT", - "NUMBER", - "DATE", - "SINGLE_SELECT", - "ITERATION" - ], - "type": "string" - }, - "name": { - "description": "Field name to create (e.g., 'size', 'priority').", - "type": "string" - }, - "options": { - "description": "Options for SINGLE_SELECT fields.", - "items": { - "type": "string" - }, - "type": "array" - } - }, - "required": [ - "name", - "data_type" - ], - "type": "object" - }, - "type": "array" - }, - "fields": { - "description": "Custom field values to set on the project item (e.g., {'Status': 'In Progress', 'Priority': 'High'}). Field names must match custom fields defined in the project.", - "type": "object" - }, - "operation": { - "description": "Optional operation mode. Use create_fields to create required campaign fields up-front, or create_view to add a project view. When omitted, the tool adds/updates project items.", - "enum": [ - "create_fields", - "create_view" - ], - "type": "string" - }, - "project": { - "description": "Full GitHub project URL (e.g., 'https://github.com/orgs/myorg/projects/42' or 'https://github.com/users/username/projects/5'). Project names or numbers alone are NOT accepted.", - "pattern": "^https://github\\.com/(orgs|users)/[^/]+/projects/\\d+$", - "type": "string" - }, - "view": { - "additionalProperties": false, - "description": "View definition to create when operation is create_view. Required when operation='create_view'.", - "properties": { - "filter": { - "type": "string" - }, - "layout": { - "enum": [ - "table", - "board", - "roadmap" - ], - "type": "string" - }, - "name": { - "type": "string" - }, - "visible_fields": { - "description": "Field IDs to show in the view (table/board only).", - "items": { - "type": "number" - }, - "type": "array" - } - }, - "required": [ - "name", - "layout" - ], - "type": "object" - } - }, - "required": [ - "project" - ], - "type": "object" - }, - "name": "update_project" - }, { "description": "Report that data or information needed to complete the task is not available. Use this when you cannot accomplish what was requested because required data, context, or information is missing.", "inputSchema": { @@ -459,139 +268,55 @@ jobs: "name": "missing_data" }, { - "description": "Create a status update on a GitHub Projects v2 board to communicate project progress. Use this when you need to provide stakeholder updates with status indicators, timeline information, and progress summaries. Status updates create a historical record of project progress tracked over time. Requires project URL, status indicator, dates, and markdown body describing progress/trends/findings.", + "_workflow_name": "code-scanning-fixer", + "description": "Dispatch the 'code-scanning-fixer' workflow with workflow_dispatch trigger. This workflow must support workflow_dispatch and be in the same repository.", + "inputSchema": { + "additionalProperties": false, + "properties": {}, + "type": "object" + }, + "name": "code_scanning_fixer" + }, + { + "_workflow_name": "security-fix-pr", + "description": "Dispatch the 'security-fix-pr' workflow with workflow_dispatch trigger. This workflow must support workflow_dispatch and be in the same repository.", "inputSchema": { "additionalProperties": false, "properties": { - "body": { - "description": "Status update body in markdown format describing progress, findings, trends, and next steps. Should provide stakeholders with clear understanding of project state.", - "type": "string" - }, - "project": { - "description": "Full GitHub project URL (e.g., 'https://github.com/orgs/myorg/projects/42' or 'https://github.com/users/username/projects/5'). Project names or numbers alone are NOT accepted.", - "pattern": "^https://github\\\\.com/(orgs|users)/[^/]+/projects/\\\\d+$", - "type": "string" - }, - "start_date": { - "description": "Optional project start date in YYYY-MM-DD format (e.g., '2026-01-06').", - "pattern": "^\\\\d{4}-\\\\d{2}-\\\\d{2}$", - "type": "string" - }, - "status": { - "description": "Status indicator for the project. Defaults to ON_TRACK. Values: ON_TRACK (progressing well), AT_RISK (has issues/blockers), OFF_TRACK (significantly behind), COMPLETE (finished), INACTIVE (paused/cancelled).", - "enum": [ - "ON_TRACK", - "AT_RISK", - "OFF_TRACK", - "COMPLETE", - "INACTIVE" - ], - "type": "string" - }, - "target_date": { - "description": "Optional project target/end date in YYYY-MM-DD format (e.g., '2026-12-31').", - "pattern": "^\\\\d{4}-\\\\d{2}-\\\\d{2}$", + "security_url": { + "default": "", + "description": "Security alert URL (e.g., https://github.com/owner/repo/security/code-scanning/123)", "type": "string" } }, - "required": [ - "project", - "body" - ], "type": "object" }, - "name": "create_project_status_update" + "name": "security_fix_pr" + }, + { + "_workflow_name": "dependabot-bundler", + "description": "Dispatch the 'dependabot-bundler' workflow with workflow_dispatch trigger. This workflow must support workflow_dispatch and be in the same repository.", + "inputSchema": { + "additionalProperties": false, + "properties": {}, + "type": "object" + }, + "name": "dependabot_bundler" + }, + { + "_workflow_name": "secret-scanning-triage", + "description": "Dispatch the 'secret-scanning-triage' workflow with workflow_dispatch trigger. This workflow must support workflow_dispatch and be in the same repository.", + "inputSchema": { + "additionalProperties": false, + "properties": {}, + "type": "object" + }, + "name": "secret_scanning_triage" } ] EOF cat > /opt/gh-aw/safeoutputs/validation.json << 'EOF' { - "add_comment": { - "defaultMax": 1, - "fields": { - "body": { - "required": true, - "type": "string", - "sanitize": true, - "maxLength": 65000 - }, - "item_number": { - "issueOrPRNumber": true - } - } - }, - "create_issue": { - "defaultMax": 1, - "fields": { - "body": { - "required": true, - "type": "string", - "sanitize": true, - "maxLength": 65000 - }, - "labels": { - "type": "array", - "itemType": "string", - "itemSanitize": true, - "itemMaxLength": 128 - }, - "parent": { - "issueOrPRNumber": true - }, - "repo": { - "type": "string", - "maxLength": 256 - }, - "temporary_id": { - "type": "string" - }, - "title": { - "required": true, - "type": "string", - "sanitize": true, - "maxLength": 128 - } - } - }, - "create_project_status_update": { - "defaultMax": 10, - "fields": { - "body": { - "required": true, - "type": "string", - "sanitize": true, - "maxLength": 65536 - }, - "project": { - "required": true, - "type": "string", - "sanitize": true, - "maxLength": 512, - "pattern": "^https://github\\.com/(orgs|users)/[^/]+/projects/\\d+", - "patternError": "must be a full GitHub project URL (e.g., https://github.com/orgs/myorg/projects/42)" - }, - "start_date": { - "type": "string", - "pattern": "^\\d{4}-\\d{2}-\\d{2}$", - "patternError": "must be in YYYY-MM-DD format" - }, - "status": { - "type": "string", - "enum": [ - "INACTIVE", - "ON_TRACK", - "AT_RISK", - "OFF_TRACK", - "COMPLETE" - ] - }, - "target_date": { - "type": "string", - "pattern": "^\\d{4}-\\d{2}-\\d{2}$", - "patternError": "must be in YYYY-MM-DD format" - } - } - }, "missing_tool": { "defaultMax": 20, "fields": { @@ -624,43 +349,6 @@ jobs: "maxLength": 65000 } } - }, - "update_project": { - "defaultMax": 10, - "fields": { - "campaign_id": { - "type": "string", - "sanitize": true, - "maxLength": 128 - }, - "content_number": { - "optionalPositiveInteger": true - }, - "content_type": { - "type": "string", - "enum": [ - "issue", - "pull_request" - ] - }, - "fields": { - "type": "object" - }, - "issue": { - "optionalPositiveInteger": true - }, - "project": { - "required": true, - "type": "string", - "sanitize": true, - "maxLength": 512, - "pattern": "^https://github\\.com/(orgs|users)/[^/]+/projects/\\d+", - "patternError": "must be a full GitHub project URL (e.g., https://github.com/orgs/myorg/projects/42)" - }, - "pull_request": { - "optionalPositiveInteger": true - } - } } } EOF @@ -734,7 +422,7 @@ jobs: "GITHUB_LOCKDOWN_MODE": "$GITHUB_MCP_LOCKDOWN", "GITHUB_PERSONAL_ACCESS_TOKEN": "$GITHUB_MCP_SERVER_TOKEN", "GITHUB_READ_ONLY": "1", - "GITHUB_TOOLSETS": "context,repos,issues,pull_requests,actions,code_security" + "GITHUB_TOOLSETS": "context,repos,issues,pull_requests" } }, "safeoutputs": { @@ -852,7 +540,7 @@ jobs: To create or modify GitHub resources (issues, discussions, pull requests, etc.), you MUST call the appropriate safe output tool. Simply writing content will NOT work - the workflow requires actual tool calls. - **Available tools**: add_comment, create_issue, create_project_status_update, missing_tool, noop, update_project + **Available tools**: dispatch_workflow, missing_tool, noop **Critical**: Tool calls write structured data that downstream jobs process. Without tool calls, follow-up actions will be skipped. @@ -898,9 +586,6 @@ jobs: This workflow orchestrates the 'Security Alert Burndown' campaign. - Associated workflows: code-scanning-fixer, security-fix-pr, dependabot-bundler, secret-scanning-triage - - Memory paths: memory/campaigns/security-alert-burndown/** - - Metrics glob: `memory/campaigns/security-alert-burndown/metrics/*.json` - - Cursor glob: `memory/campaigns/security-alert-burndown/cursor.json` - Project URL: https://github.com/orgs/githubnext/projects/134 - Governance: max new items per run: 3 - Governance: max discovery items per run: 100 @@ -1207,11 +892,11 @@ jobs: --- # Orchestrator Instructions - This orchestrator coordinates a single campaign by discovering worker outputs, making deterministic decisions, - and synchronizing campaign state into a GitHub Project board. + This orchestrator coordinates a single campaign by discovering worker outputs and making deterministic decisions. - **Scope:** orchestration only (discovery, planning, pacing, reporting). - **Write authority:** all project write semantics are governed by **Project Update Instructions** and MUST be followed. + **Scope:** orchestration only (discovery, planning, pacing, reporting). + **Actuation model:** **dispatch-only** — the orchestrator may only act by dispatching allowlisted worker workflows. + **Write authority:** all GitHub writes (Projects, issues/PRs, comments, status updates) must happen in worker workflows. --- @@ -1224,35 +909,9 @@ jobs: - On throttling (HTTP 429 / rate-limit 403), do not retry aggressively; back off and end the run after reporting what remains. - **Cursor file (repo-memory)**: `memory/campaigns/security-alert-burndown/cursor.json` - **File system path**: `/tmp/gh-aw/repo-memory/campaigns/security-alert-burndown/cursor.json` - - If it exists: read first and continue from its boundary. - - If it does not exist: create it by end of run. - - Always write the updated cursor back to the same path. - **Metrics snapshots (repo-memory)**: `memory/campaigns/security-alert-burndown/metrics/*.json` - **File system path**: `/tmp/gh-aw/repo-memory/campaigns/security-alert-burndown/metrics/*.json` - - Persist one append-only JSON metrics snapshot per run (new file per run; do not rewrite history). - - Use UTC date (`YYYY-MM-DD`) in the filename (example: `metrics/2025-12-22.json`). - - Each snapshot MUST include ALL required fields (even if zero): - - `campaign_id` (string): The campaign identifier - - `date` (string): UTC date in YYYY-MM-DD format - - `tasks_total` (number): Total number of tasks (>= 0, even if 0) - - `tasks_completed` (number): Completed task count (>= 0, even if 0) - - Optional fields (include only if available): `tasks_in_progress`, `tasks_blocked`, `velocity_per_day`, `estimated_completion` - - Example minimum valid snapshot: - ```json - { - "campaign_id": "security-alert-burndown", - "date": "2025-12-22", - "tasks_total": 0, - "tasks_completed": 0 - } - ``` - - **Read budget**: max discovery items per run: 100 @@ -1260,12 +919,6 @@ jobs: **Read budget**: max discovery pages per run: 5 - **Write budget**: max project updates per run: 10 - - - **Write budget**: max project comments per run: 3 - - --- ## Core Principles @@ -1275,130 +928,26 @@ jobs: 3. Correlation is explicit (tracker-id AND labels) 4. Reads and writes are separate steps (never interleave) 5. Idempotent operation is mandatory (safe to re-run) - 6. Only predefined project fields may be updated - 7. **Project Update Instructions take precedence for all project writes** - 8. **Campaign items MUST be labeled** for discovery and isolation - - --- - - ## Campaign Label Requirements - - **All campaign-related issues, PRs, and discussions MUST have two labels:** - - 1. **`agentic-campaign`** - Generic label marking content as part of ANY campaign - - Prevents other workflows from processing campaign items - - Enables campaign-wide queries and filters - - 2. **`z_campaign_security-alert-burndown`** - Campaign-specific label - - Enables precise discovery of items belonging to THIS campaign - - Format: `z_campaign_` (lowercase, hyphen-separated) - - Example: `z_campaign_security-q1-2025` - - **Worker Responsibilities:** - - Workers creating issues/PRs as campaign output MUST add both labels - - Workers SHOULD use `create-issue` or `create-pr` safe outputs with labels configuration - - If workers cannot add labels automatically, campaign orchestrator will attempt to add them during discovery - - **Non-Campaign Workflow Responsibilities:** - - Workflows triggered by issues/PRs SHOULD skip items with `agentic-campaign` label - - Use `skip-if-match` configuration to filter out campaign items: - ```yaml - on: - issues: - types: [opened, labeled] - skip-if-match: - query: "label:agentic-campaign" - max: 0 # Skip if ANY campaign items match - ``` + 6. Orchestrators do not write GitHub state directly --- ## Execution Steps (Required Order) - ### Step 0 — Epic Issue Initialization [FIRST RUN ONLY] - - **Campaign Epic Issue Requirements:** - - Each project board MUST have exactly ONE Epic issue representing the campaign - - The Epic serves as the parent for all campaign work issues - - The Epic is narrative-only and tracks overall campaign progress - - **On every run, before other steps:** - - 1) **Check for existing Epic issue** by searching the repository for: - - An open issue with label `epic` or `type:epic` - - Body text containing: `campaign_id: security-alert-burndown` - - 2) **If no Epic issue exists**, create it using `create-issue`: - ```yaml - create-issue: - title: "Security Alert Burndown" - body: | - ## Campaign Overview - - This Epic issue tracks the overall progress of the campaign. All work items are sub-issues of this Epic. - - **Campaign Details:** - - Campaign ID: `security-alert-burndown` - - Project Board: https://github.com/orgs/githubnext/projects/134 - - Worker Workflows: `code-scanning-fixer`, `security-fix-pr`, `dependabot-bundler`, `secret-scanning-triage` - - --- - `campaign_id: security-alert-burndown` - labels: - - agentic-campaign - - z_campaign_security-alert-burndown - - epic - - type:epic - ``` - - 3) **After creating the Epic** (or if Epic exists but not on board), add it to the project board: - ```yaml - update-project: - project: "https://github.com/orgs/githubnext/projects/134" - campaign_id: "security-alert-burndown" - content_type: "issue" - content_number: - fields: - status: "In Progress" - campaign_id: "security-alert-burndown" - worker_workflow: "unknown" - repository: "" - priority: "High" - size: "Large" - start_date: "" - end_date: "" - ``` - - 4) **Record the Epic issue number** in repo-memory for reference (e.g., in cursor file or metadata). - - **Note:** This step typically runs only on the first orchestrator execution. On subsequent runs, verify the Epic exists and is on the board, but do not recreate it. - - --- - ### Step 1 — Read State (Discovery) [NO WRITES] **IMPORTANT**: Discovery has been precomputed. Read the discovery manifest instead of performing GitHub-wide searches. 1) Read the precomputed discovery manifest: `./.gh-aw/campaign.discovery.json` - - This manifest contains all discovered worker outputs with normalized metadata - PROMPT_EOF - cat << 'PROMPT_EOF' >> "$GH_AW_PROMPT" - - Schema version: v1 - - Fields: campaign_id, generated_at, discovery (total_items, cursor info), summary (counts), items (array of normalized items) - - 2) Read current GitHub Project board state (items + required fields). - 3) Parse discovered items from the manifest: + 2) Parse discovered items from the manifest: - Each item has: url, content_type (issue/pull_request/discussion), number, repo, created_at, updated_at, state - Closed items have: closed_at (for issues) or merged_at (for PRs) - Items are pre-sorted by updated_at for deterministic processing - 4) Check the manifest summary for work counts: - - `needs_add_count`: Number of items that need to be added to the project - - `needs_update_count`: Number of items that need status updates - - If both are 0, you may skip to reporting step + 3) Check the manifest summary for work counts. - 5) Discovery cursor is maintained automatically in repo-memory; do not modify it manually. + 4) Discovery cursor is maintained automatically in repo-memory; do not modify it manually. ### Step 2 — Make Decisions (Planning) [NO WRITES] @@ -1407,66 +956,27 @@ jobs: - Closed (issue/discussion) → `Done` - Merged (PR) → `Done` - **Why use explicit GitHub state?** - GitHub is the source of truth for work status. Inferring status from other signals (labels, comments) would be unreliable and could cause incorrect tracking. - - 6) Calculate required date fields for each item (per Project Update Instructions): + 6) Calculate required date fields (for workers that sync Projects): - `start_date`: format `created_at` as `YYYY-MM-DD` - `end_date`: - if closed/merged → format `closed_at`/`merged_at` as `YYYY-MM-DD` - - if open → **today's date** formatted `YYYY-MM-DD` (required for roadmap view) - - **Why use today for open items?** - GitHub Projects requires end_date for roadmap views. Using today's date shows the item is actively tracked and updates automatically each run until completion. - - 7) Do NOT implement idempotency by comparing against the board. You may compare for reporting only. - - **Why no comparison for idempotency?** - The safe-output system handles deduplication. Comparing would add complexity and potential race conditions. Trust the infrastructure. - - 8) Apply write budget: - - If `MaxProjectUpdatesPerRun > 0`, select at most that many items this run using deterministic order - (e.g., oldest `updated_at` first; tie-break by ID/number). - - Defer remaining items to next run via cursor. - - **Why use deterministic order?** - Ensures predictable behavior and prevents starvation. Oldest items are processed first, ensuring fair treatment of all work items. The cursor saves progress for next run. - - ### Step 3 — Write State (Execution) [WRITES ONLY] + - if open → **today's date** formatted `YYYY-MM-DD` - 9) For each selected item, send an `update-project` request. - - Do NOT interleave reads. - - Do NOT pre-check whether the item is on the board. - - **All write semantics MUST follow Project Update Instructions**, including: - - first add → full required fields (status, campaign_id, worker_workflow, repo, priority, size, start_date, end_date) - - existing item → status-only update unless explicit backfill is required + 7) Reads and writes are separate steps (never interleave). - 10) Record per-item outcome: success/failure + error details. + ### Step 3 — Dispatch Workers (Execution) [DISPATCH ONLY] - ### Step 4 — Report & Status Update + 8) For each selected unit of work, dispatch a worker workflow using `dispatch-workflow`. - 11) **REQUIRED: Create a project status update summarizing this run** + Constraints: + - Only dispatch allowlisted workflows. + - Keep within the dispatch-workflow max for this run. - Every campaign run MUST create a status update using `create-project-status-update` safe output. This is the primary communication mechanism for conveying campaign progress to stakeholders. + ### Step 4 — Report (No Writes) - **Required Sections:** + 9) Summarize what you dispatched, what remains, and what should run next. - - **Most Important Findings**: Highlight the 2-3 most critical discoveries, insights, or blockers from this run - - **What Was Learned**: Document key learnings, patterns observed, or insights gained during this run - - **Campaign Progress**: Report on campaign metrics and trends with baseline → current → target format, including direction and velocity - - **Campaign Summary**: Tasks completed, in progress, blocked, and overall completion percentage - - **Next Steps**: Clear action items and priorities for the next run - - **Configuration:** - - Set appropriate status: ON_TRACK, AT_RISK, OFF_TRACK, or COMPLETE - - Use today's date for start_date and target_date (or appropriate future date for target) - - Body must be comprehensive yet concise (target: 200-400 words) - - Example status update: - ```yaml - create-project-status-update: - project: "https://github.com/orgs/githubnext/projects/134" - status: "ON_TRACK" - start_date: "2026-01-06" - target_date: "2026-01-31" - body: | - ## Campaign Run Summary + If a status update is required on the GitHub Project, dispatch a dedicated reporting/sync worker to perform that write. **Discovered:** 25 items (15 issues, 10 PRs) **Processed:** 10 items added to project, 5 updated @@ -1536,7 +1046,8 @@ jobs: ## 0) Hard Requirements (Do Not Deviate) - - Writes MUST use only the `update-project` safe-output. + - Orchestrators are dispatch-only and MUST NOT perform project writes directly. + - Worker workflows performing project writes MUST use only the `update-project` safe-output. - All writes MUST target exactly: - **Project URL**: `https://github.com/orgs/githubnext/projects/134` - Every item MUST include: @@ -1561,6 +1072,8 @@ jobs: | `start_date` | date | `YYYY-MM-DD` | | `end_date` | date | `YYYY-MM-DD` | + PROMPT_EOF + cat << 'PROMPT_EOF' >> "$GH_AW_PROMPT" Field names are case-sensitive. --- @@ -1778,13 +1291,13 @@ jobs: 1. Read State (no writes) 2. Make Decisions (no writes) - 3. Write State (update-project only) + 3. Dispatch Workers (dispatch-workflow only) 4. Report The following rules are mandatory and override inferred behavior: - The GitHub Project board is the single source of truth. - - All project writes MUST comply with `project_update_instructions.md`. + - All project writes MUST comply with the Project Update Instructions (in workers). - State reads and state writes MUST NOT be interleaved. - Do NOT infer missing data or invent values. - Do NOT reorganize hierarchy. @@ -2385,18 +1898,13 @@ jobs: if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (needs.detection.outputs.success == 'true') runs-on: ubuntu-slim permissions: - contents: read - discussions: write - issues: write - pull-requests: write + actions: write timeout-minutes: 15 env: GH_AW_ENGINE_ID: "claude" GH_AW_WORKFLOW_ID: "security-alert-burndown.campaign.g" GH_AW_WORKFLOW_NAME: "Security Alert Burndown" outputs: - process_project_safe_outputs_processed_count: ${{ steps.process_project_safe_outputs.outputs.processed_count }} - process_project_safe_outputs_temporary_project_map: ${{ steps.process_project_safe_outputs.outputs.temporary_project_map }} process_safe_outputs_processed_count: ${{ steps.process_safe_outputs.outputs.processed_count }} process_safe_outputs_temporary_id_map: ${{ steps.process_safe_outputs.outputs.temporary_id_map }} steps: @@ -2421,27 +1929,12 @@ jobs: mkdir -p /tmp/gh-aw/safeoutputs/ find "/tmp/gh-aw/safeoutputs/" -type f -print echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/safeoutputs/agent_output.json" >> "$GITHUB_ENV" - - name: Process Project-Related Safe Outputs - id: process_project_safe_outputs - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 - env: - GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }} - GH_AW_SAFE_OUTPUTS_PROJECT_HANDLER_CONFIG: "{\"create_project_status_update\":{\"max\":1},\"update_project\":{\"max\":10}}" - GH_AW_PROJECT_GITHUB_TOKEN: ${{ secrets.GH_AW_PROJECT_GITHUB_TOKEN }} - with: - github-token: ${{ secrets.GH_AW_PROJECT_GITHUB_TOKEN }} - script: | - const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs'); - setupGlobals(core, github, context, exec, io); - const { main } = require('/opt/gh-aw/actions/safe_output_project_handler_manager.cjs'); - await main(); - name: Process Safe Outputs id: process_safe_outputs uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 env: GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }} - GH_AW_TEMPORARY_PROJECT_MAP: ${{ steps.process_project_safe_outputs.outputs.temporary_project_map }} - GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"add_comment\":{\"max\":3},\"create_issue\":{\"max\":1},\"missing_data\":{},\"missing_tool\":{}}" + GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"dispatch_workflow\":{\"max\":3,\"workflows\":[\"code-scanning-fixer\",\"security-fix-pr\",\"dependabot-bundler\",\"secret-scanning-triage\"]},\"missing_data\":{},\"missing_tool\":{}}" with: github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} script: | diff --git a/pkg/cli/.github/aw/imports/.gitattributes b/pkg/cli/.github/aw/imports/.gitattributes deleted file mode 100644 index f0516fad90..0000000000 --- a/pkg/cli/.github/aw/imports/.gitattributes +++ /dev/null @@ -1,5 +0,0 @@ -# Mark all cached import files as generated -* linguist-generated=true - -# Use 'ours' merge strategy to keep local cached versions -* merge=ours diff --git a/pkg/cli/.github/aw/imports/githubnext/agentics/d3422bf940923ef1d43db5559652b8e1e71869f3/workflows_shared_reporting.md b/pkg/cli/.github/aw/imports/githubnext/agentics/d3422bf940923ef1d43db5559652b8e1e71869f3/workflows_shared_reporting.md deleted file mode 100644 index baedaa9a63..0000000000 --- a/pkg/cli/.github/aw/imports/githubnext/agentics/d3422bf940923ef1d43db5559652b8e1e71869f3/workflows_shared_reporting.md +++ /dev/null @@ -1,80 +0,0 @@ ---- -# No frontmatter configuration needed - this is a pure instructions file ---- - -## Report Formatting - -Structure your report with an overview followed by detailed content: - -1. **Content Overview**: Start with 1-2 paragraphs that summarize the key findings, highlights, or main points of your report. This should give readers a quick understanding of what the report contains without needing to expand the details. - -2. **Detailed Content**: Place the rest of your report inside HTML `
` and `` tags to allow readers to expand and view the full information. **IMPORTANT**: Always wrap the summary text in `` tags to make it bold. - -**Example format:** - -`````markdown -Brief overview paragraph 1 introducing the report and its main findings. - -Optional overview paragraph 2 with additional context or highlights. - -
-Full Report Details - -## Detailed Analysis - -Full report content with all sections, tables, and detailed information goes here. - -### Section 1 -[Content] - -### Section 2 -[Content] - -
-````` - -## Reporting Workflow Run Information - -When analyzing workflow run logs or reporting information from GitHub Actions runs: - -### 1. Workflow Run ID Formatting - -**Always render workflow run IDs as clickable URLs** when mentioning them in your report. The workflow run data includes a `url` field that provides the full GitHub Actions run page URL. - -**Format:** - -`````markdown -[§12345](https://github.com/owner/repo/actions/runs/12345) -````` - -**Example:** - -`````markdown -Analysis based on [§456789](https://github.com/githubnext/gh-aw/actions/runs/456789) -````` - -### 2. Document References for Workflow Runs - -When your analysis is based on information mined from one or more workflow runs, **include up to 3 workflow run URLs as document references** at the end of your report. - -**Format:** - -`````markdown ---- - -**References:** -- [§12345](https://github.com/owner/repo/actions/runs/12345) -- [§12346](https://github.com/owner/repo/actions/runs/12346) -- [§12347](https://github.com/owner/repo/actions/runs/12347) -````` - -**Guidelines:** - -- Include **maximum 3 references** to keep reports concise -- Choose the most relevant or representative runs (e.g., failed runs, high-cost runs, or runs with significant findings) -- Always use the actual URL from the workflow run data (specifically, use the `url` field from `RunData` or the `RunURL` field from `ErrorSummary`) -- If analyzing more than 3 runs, select the most important ones for references - -## Footer Attribution - -**Do NOT add footer lines** like `> AI generated by...` to your comment. The system automatically appends attribution after your content to prevent duplicates. diff --git a/pkg/cli/templates/close-agentic-campaign.md b/pkg/cli/templates/close-agentic-campaign.md index e22f090cee..b3a40b6e01 100644 --- a/pkg/cli/templates/close-agentic-campaign.md +++ b/pkg/cli/templates/close-agentic-campaign.md @@ -4,13 +4,13 @@ Execute all four steps in strict order: 1. Read State (no writes) 2. Make Decisions (no writes) -3. Write State (update-project only) +3. Dispatch Workers (dispatch-workflow only) 4. Report The following rules are mandatory and override inferred behavior: - The GitHub Project board is the single source of truth. -- All project writes MUST comply with `project_update_instructions.md`. +- All project writes MUST comply with the Project Update Instructions (in workers). - State reads and state writes MUST NOT be interleaved. - Do NOT infer missing data or invent values. - Do NOT reorganize hierarchy. diff --git a/pkg/cli/templates/orchestrate-agentic-campaign.md b/pkg/cli/templates/orchestrate-agentic-campaign.md index 343477a35b..9318bd46ec 100644 --- a/pkg/cli/templates/orchestrate-agentic-campaign.md +++ b/pkg/cli/templates/orchestrate-agentic-campaign.md @@ -1,10 +1,10 @@ # Orchestrator Instructions -This orchestrator coordinates a single campaign by discovering worker outputs, making deterministic decisions, -and synchronizing campaign state into a GitHub Project board. +This orchestrator coordinates a single campaign by discovering worker outputs and making deterministic decisions. -**Scope:** orchestration only (discovery, planning, pacing, reporting). -**Write authority:** all project write semantics are governed by **Project Update Instructions** and MUST be followed. +**Scope:** orchestration only (discovery, planning, pacing, reporting). +**Actuation model:** **dispatch-only** — the orchestrator may only act by dispatching allowlisted worker workflows. +**Write authority:** all GitHub writes (Projects, issues/PRs, comments, status updates) must happen in worker workflows. --- @@ -17,33 +17,18 @@ and synchronizing campaign state into a GitHub Project board. - On throttling (HTTP 429 / rate-limit 403), do not retry aggressively; back off and end the run after reporting what remains. {{ if .CursorGlob }} -**Cursor file (repo-memory)**: `{{ .CursorGlob }}` -**File system path**: `/tmp/gh-aw/repo-memory/campaigns/{{.CampaignID}}/cursor.json` -- If it exists: read first and continue from its boundary. -- If it does not exist: create it by end of run. +**Cursor file (repo-memory)**: `{{ .CursorGlob }}` +**File system path**: `/tmp/gh-aw/repo-memory/campaigns/{{.CampaignID}}/cursor.json` +- If it exists: read first and continue from its boundary. +- If it does not exist: create it by end of run. - Always write the updated cursor back to the same path. {{ end }} {{ if .MetricsGlob }} -**Metrics snapshots (repo-memory)**: `{{ .MetricsGlob }}` -**File system path**: `/tmp/gh-aw/repo-memory/campaigns/{{.CampaignID}}/metrics/*.json` +**Metrics snapshots (repo-memory)**: `{{ .MetricsGlob }}` +**File system path**: `/tmp/gh-aw/repo-memory/campaigns/{{.CampaignID}}/metrics/*.json` - Persist one append-only JSON metrics snapshot per run (new file per run; do not rewrite history). - Use UTC date (`YYYY-MM-DD`) in the filename (example: `metrics/2025-12-22.json`). -- Each snapshot MUST include ALL required fields (even if zero): - - `campaign_id` (string): The campaign identifier - - `date` (string): UTC date in YYYY-MM-DD format - - `tasks_total` (number): Total number of tasks (>= 0, even if 0) - - `tasks_completed` (number): Completed task count (>= 0, even if 0) -- Optional fields (include only if available): `tasks_in_progress`, `tasks_blocked`, `velocity_per_day`, `estimated_completion` -- Example minimum valid snapshot: - ```json - { - "campaign_id": "{{.CampaignID}}", - "date": "2025-12-22", - "tasks_total": 0, - "tasks_completed": 0 - } - ``` {{ end }} {{ if gt .MaxDiscoveryItemsPerRun 0 }} @@ -52,12 +37,6 @@ and synchronizing campaign state into a GitHub Project board. {{ if gt .MaxDiscoveryPagesPerRun 0 }} **Read budget**: max discovery pages per run: {{ .MaxDiscoveryPagesPerRun }} {{ end }} -{{ if gt .MaxProjectUpdatesPerRun 0 }} -**Write budget**: max project updates per run: {{ .MaxProjectUpdatesPerRun }} -{{ end }} -{{ if gt .MaxProjectCommentsPerRun 0 }} -**Write budget**: max project comments per run: {{ .MaxProjectCommentsPerRun }} -{{ end }} --- @@ -68,128 +47,26 @@ and synchronizing campaign state into a GitHub Project board. 3. Correlation is explicit (tracker-id AND labels) 4. Reads and writes are separate steps (never interleave) 5. Idempotent operation is mandatory (safe to re-run) -6. Only predefined project fields may be updated -7. **Project Update Instructions take precedence for all project writes** -8. **Campaign items MUST be labeled** for discovery and isolation - ---- - -## Campaign Label Requirements - -**All campaign-related issues, PRs, and discussions MUST have two labels:** - -1. **`agentic-campaign`** - Generic label marking content as part of ANY campaign - - Prevents other workflows from processing campaign items - - Enables campaign-wide queries and filters - -2. **`z_campaign_{{.CampaignID}}`** - Campaign-specific label - - Enables precise discovery of items belonging to THIS campaign - - Format: `z_campaign_` (lowercase, hyphen-separated) - - Example: `z_campaign_security-q1-2025` - -**Worker Responsibilities:** -- Workers creating issues/PRs as campaign output MUST add both labels -- Workers SHOULD use `create-issue` or `create-pr` safe outputs with labels configuration -- If workers cannot add labels automatically, campaign orchestrator will attempt to add them during discovery - -**Non-Campaign Workflow Responsibilities:** -- Workflows triggered by issues/PRs SHOULD skip items with `agentic-campaign` label -- Use `skip-if-match` configuration to filter out campaign items: - ```yaml - on: - issues: - types: [opened, labeled] - skip-if-match: - query: "label:agentic-campaign" - max: 0 # Skip if ANY campaign items match - ``` +6. Orchestrators do not write GitHub state directly --- ## Execution Steps (Required Order) -### Step 0 — Epic Issue Initialization [FIRST RUN ONLY] - -**Campaign Epic Issue Requirements:** -- Each project board MUST have exactly ONE Epic issue representing the campaign -- The Epic serves as the parent for all campaign work issues -- The Epic is narrative-only and tracks overall campaign progress - -**On every run, before other steps:** - -1) **Check for existing Epic issue** by searching the repository for: - - An open issue with label `epic` or `type:epic` - - Body text containing: `campaign_id: {{.CampaignID}}` - -2) **If no Epic issue exists**, create it using `create-issue`: - ```yaml - create-issue: - title: "{{if .CampaignName}}{{.CampaignName}}{{else}}Campaign: {{.CampaignID}}{{end}}" - body: | - ## Campaign Overview - - This Epic issue tracks the overall progress of the campaign. All work items are sub-issues of this Epic. - - **Campaign Details:** - - Campaign ID: `{{.CampaignID}}` - - Project Board: {{.ProjectURL}} - {{ if .Workflows }}- Worker Workflows: {{range $i, $w := .Workflows}}{{if $i}}, {{end}}`{{$w}}`{{end}}{{ end }} - - --- - `campaign_id: {{.CampaignID}}` - labels: - - agentic-campaign - - z_campaign_{{.CampaignID}} - - epic - - type:epic - ``` - -3) **After creating the Epic** (or if Epic exists but not on board), add it to the project board: - ```yaml - update-project: - project: "{{.ProjectURL}}" - campaign_id: "{{.CampaignID}}" - content_type: "issue" - content_number: - fields: - status: "In Progress" - campaign_id: "{{.CampaignID}}" - worker_workflow: "unknown" - repository: "" - priority: "High" - size: "Large" - start_date: "" - end_date: "" - ``` - -4) **Record the Epic issue number** in repo-memory for reference (e.g., in cursor file or metadata). - -**Note:** This step typically runs only on the first orchestrator execution. On subsequent runs, verify the Epic exists and is on the board, but do not recreate it. - ---- - ### Step 1 — Read State (Discovery) [NO WRITES] **IMPORTANT**: Discovery has been precomputed. Read the discovery manifest instead of performing GitHub-wide searches. 1) Read the precomputed discovery manifest: `./.gh-aw/campaign.discovery.json` - - This manifest contains all discovered worker outputs with normalized metadata - - Schema version: v1 - - Fields: campaign_id, generated_at, discovery (total_items, cursor info), summary (counts), items (array of normalized items) - -2) Read current GitHub Project board state (items + required fields). -3) Parse discovered items from the manifest: +2) Parse discovered items from the manifest: - Each item has: url, content_type (issue/pull_request/discussion), number, repo, created_at, updated_at, state - Closed items have: closed_at (for issues) or merged_at (for PRs) - Items are pre-sorted by updated_at for deterministic processing -4) Check the manifest summary for work counts: - - `needs_add_count`: Number of items that need to be added to the project - - `needs_update_count`: Number of items that need status updates - - If both are 0, you may skip to reporting step +3) Check the manifest summary for work counts. -5) Discovery cursor is maintained automatically in repo-memory; do not modify it manually. +4) Discovery cursor is maintained automatically in repo-memory; do not modify it manually. ### Step 2 — Make Decisions (Planning) [NO WRITES] @@ -198,66 +75,27 @@ and synchronizing campaign state into a GitHub Project board. - Closed (issue/discussion) → `Done` - Merged (PR) → `Done` -**Why use explicit GitHub state?** - GitHub is the source of truth for work status. Inferring status from other signals (labels, comments) would be unreliable and could cause incorrect tracking. - -6) Calculate required date fields for each item (per Project Update Instructions): +6) Calculate required date fields (for workers that sync Projects): - `start_date`: format `created_at` as `YYYY-MM-DD` - `end_date`: - if closed/merged → format `closed_at`/`merged_at` as `YYYY-MM-DD` - - if open → **today's date** formatted `YYYY-MM-DD` (required for roadmap view) - -**Why use today for open items?** - GitHub Projects requires end_date for roadmap views. Using today's date shows the item is actively tracked and updates automatically each run until completion. - -7) Do NOT implement idempotency by comparing against the board. You may compare for reporting only. - -**Why no comparison for idempotency?** - The safe-output system handles deduplication. Comparing would add complexity and potential race conditions. Trust the infrastructure. - -8) Apply write budget: -- If `MaxProjectUpdatesPerRun > 0`, select at most that many items this run using deterministic order - (e.g., oldest `updated_at` first; tie-break by ID/number). -- Defer remaining items to next run via cursor. - -**Why use deterministic order?** - Ensures predictable behavior and prevents starvation. Oldest items are processed first, ensuring fair treatment of all work items. The cursor saves progress for next run. - -### Step 3 — Write State (Execution) [WRITES ONLY] - -9) For each selected item, send an `update-project` request. -- Do NOT interleave reads. -- Do NOT pre-check whether the item is on the board. -- **All write semantics MUST follow Project Update Instructions**, including: - - first add → full required fields (status, campaign_id, worker_workflow, repo, priority, size, start_date, end_date) - - existing item → status-only update unless explicit backfill is required - -10) Record per-item outcome: success/failure + error details. + - if open → **today's date** formatted `YYYY-MM-DD` -### Step 4 — Report & Status Update +7) Reads and writes are separate steps (never interleave). -11) **REQUIRED: Create a project status update summarizing this run** +### Step 3 — Dispatch Workers (Execution) [DISPATCH ONLY] -Every campaign run MUST create a status update using `create-project-status-update` safe output. This is the primary communication mechanism for conveying campaign progress to stakeholders. +8) For each selected unit of work, dispatch a worker workflow using `dispatch-workflow`. -**Required Sections:** +Constraints: +- Only dispatch allowlisted workflows. +- Keep within the dispatch-workflow max for this run. -- **Most Important Findings**: Highlight the 2-3 most critical discoveries, insights, or blockers from this run -- **What Was Learned**: Document key learnings, patterns observed, or insights gained during this run -- **Campaign Progress**: Report on campaign metrics and trends with baseline → current → target format, including direction and velocity -- **Campaign Summary**: Tasks completed, in progress, blocked, and overall completion percentage -- **Next Steps**: Clear action items and priorities for the next run +### Step 4 — Report (No Writes) -**Configuration:** -- Set appropriate status: ON_TRACK, AT_RISK, OFF_TRACK, or COMPLETE -- Use today's date for start_date and target_date (or appropriate future date for target) -- Body must be comprehensive yet concise (target: 200-400 words) +9) Summarize what you dispatched, what remains, and what should run next. -Example status update: -```yaml -create-project-status-update: - project: "{{.ProjectURL}}" - status: "ON_TRACK" - start_date: "2026-01-06" - target_date: "2026-01-31" - body: | - ## Campaign Run Summary +If a status update is required on the GitHub Project, dispatch a dedicated reporting/sync worker to perform that write. **Discovered:** 25 items (15 issues, 10 PRs) **Processed:** 10 items added to project, 5 updated diff --git a/pkg/cli/templates/update-agentic-campaign-project.md b/pkg/cli/templates/update-agentic-campaign-project.md index 8ed4c79a66..c64c49f666 100644 --- a/pkg/cli/templates/update-agentic-campaign-project.md +++ b/pkg/cli/templates/update-agentic-campaign-project.md @@ -10,7 +10,8 @@ If any other instructions conflict with this file, THIS FILE TAKES PRECEDENCE fo ## 0) Hard Requirements (Do Not Deviate) -- Writes MUST use only the `update-project` safe-output. +- Orchestrators are dispatch-only and MUST NOT perform project writes directly. +- Worker workflows performing project writes MUST use only the `update-project` safe-output. - All writes MUST target exactly: - **Project URL**: `{{.ProjectURL}}` - Every item MUST include: diff --git a/pkg/parser/schemas/main_workflow_schema.json b/pkg/parser/schemas/main_workflow_schema.json index ea8ecd4de1..b70bd33bc8 100644 --- a/pkg/parser/schemas/main_workflow_schema.json +++ b/pkg/parser/schemas/main_workflow_schema.json @@ -2504,7 +2504,7 @@ [ { "name": "Verify Post-Steps Execution", - "run": "echo \"✅ Post-steps are executing correctly\"\necho \"This step runs after the AI agent completes\"\n" + "run": "echo \"\u2705 Post-steps are executing correctly\"\necho \"This step runs after the AI agent completes\"\n" }, { "name": "Upload Test Results", @@ -5735,8 +5735,8 @@ }, "staged-title": { "type": "string", - "description": "Custom title template for staged mode preview. Available placeholders: {operation}. Example: '🎭 Preview: {operation}'", - "examples": ["🎭 Preview: {operation}", "## Staged Mode: {operation}"] + "description": "Custom title template for staged mode preview. Available placeholders: {operation}. Example: '\ud83c\udfad Preview: {operation}'", + "examples": ["\ud83c\udfad Preview: {operation}", "## Staged Mode: {operation}"] }, "staged-description": { "type": "string", @@ -5750,18 +5750,18 @@ }, "run-success": { "type": "string", - "description": "Custom message template for successful workflow completion. Available placeholders: {workflow_name}, {run_url}. Default: '✅ Agentic [{workflow_name}]({run_url}) completed successfully.'", - "examples": ["✅ Agentic [{workflow_name}]({run_url}) completed successfully.", "✅ [{workflow_name}]({run_url}) finished."] + "description": "Custom message template for successful workflow completion. Available placeholders: {workflow_name}, {run_url}. Default: '\u2705 Agentic [{workflow_name}]({run_url}) completed successfully.'", + "examples": ["\u2705 Agentic [{workflow_name}]({run_url}) completed successfully.", "\u2705 [{workflow_name}]({run_url}) finished."] }, "run-failure": { "type": "string", - "description": "Custom message template for failed workflow. Available placeholders: {workflow_name}, {run_url}, {status}. Default: '❌ Agentic [{workflow_name}]({run_url}) {status} and wasn't able to produce a result.'", - "examples": ["❌ Agentic [{workflow_name}]({run_url}) {status} and wasn't able to produce a result.", "❌ [{workflow_name}]({run_url}) {status}."] + "description": "Custom message template for failed workflow. Available placeholders: {workflow_name}, {run_url}, {status}. Default: '\u274c Agentic [{workflow_name}]({run_url}) {status} and wasn't able to produce a result.'", + "examples": ["\u274c Agentic [{workflow_name}]({run_url}) {status} and wasn't able to produce a result.", "\u274c [{workflow_name}]({run_url}) {status}."] }, "detection-failure": { "type": "string", - "description": "Custom message template for detection job failure. Available placeholders: {workflow_name}, {run_url}. Default: '⚠️ Security scanning failed for [{workflow_name}]({run_url}). Review the logs for details.'", - "examples": ["⚠️ Security scanning failed for [{workflow_name}]({run_url}). Review the logs for details.", "⚠️ Detection job failed in [{workflow_name}]({run_url})."] + "description": "Custom message template for detection job failure. Available placeholders: {workflow_name}, {run_url}. Default: '\u26a0\ufe0f Security scanning failed for [{workflow_name}]({run_url}). Review the logs for details.'", + "examples": ["\u26a0\ufe0f Security scanning failed for [{workflow_name}]({run_url}). Review the logs for details.", "\u26a0\ufe0f Detection job failed in [{workflow_name}]({run_url})."] }, "append-only-comments": { "type": "boolean", @@ -5814,6 +5814,48 @@ "runs-on": { "type": "string", "description": "Runner specification for all safe-outputs jobs (activation, create-issue, add-comment, etc.). Single runner label (e.g., 'ubuntu-slim', 'ubuntu-latest', 'windows-latest', 'self-hosted'). Defaults to 'ubuntu-slim'. See https://github.blog/changelog/2025-10-28-1-vcpu-linux-runner-now-available-in-github-actions-in-public-preview/" + }, + "dispatch-workflow": { + "oneOf": [ + { + "type": "object", + "description": "Configuration for dispatching workflow_dispatch events to other workflows. Orchestrators use this to delegate work to worker workflows.", + "properties": { + "workflows": { + "type": "array", + "description": "List of workflow names (without .md extension) to allow dispatching. Each workflow must exist in .github/workflows/.", + "items": { + "type": "string", + "minLength": 1 + }, + "minItems": 1 + }, + "max": { + "type": "integer", + "description": "Maximum number of workflow dispatch operations per run (default: 1, max: 3)", + "minimum": 1, + "maximum": 3, + "default": 1 + }, + "github-token": { + "$ref": "#/$defs/github_token", + "description": "GitHub token to use for dispatching workflows. Overrides global github-token if specified." + } + }, + "required": ["workflows"], + "additionalProperties": false + }, + { + "type": "array", + "description": "Shorthand array format: list of workflow names (without .md extension) to allow dispatching", + "items": { + "type": "string", + "minLength": 1 + }, + "minItems": 1 + } + ], + "description": "Dispatch workflow_dispatch events to other workflows. Used by orchestrators to delegate work to worker workflows with controlled maximum dispatch count." } }, "additionalProperties": false @@ -5841,12 +5883,12 @@ "additionalProperties": false }, "roles": { - "description": "Repository access roles required to trigger agentic workflows. Defaults to ['admin', 'maintainer', 'write'] for security. Use 'all' to allow any authenticated user (⚠️ security consideration).", + "description": "Repository access roles required to trigger agentic workflows. Defaults to ['admin', 'maintainer', 'write'] for security. Use 'all' to allow any authenticated user (\u26a0\ufe0f security consideration).", "oneOf": [ { "type": "string", "enum": ["all"], - "description": "Allow any authenticated user to trigger the workflow (⚠️ disables permission checking entirely - use with caution)" + "description": "Allow any authenticated user to trigger the workflow (\u26a0\ufe0f disables permission checking entirely - use with caution)" }, { "type": "array",