Skip to content

refactor: collapse paired picker-open booleans and tidy boot-size cleanup #3757

refactor: collapse paired picker-open booleans and tidy boot-size cleanup

refactor: collapse paired picker-open booleans and tidy boot-size cleanup #3757

Workflow file for this run

name: Agent loop
# Autonomous manager loop for Compass GitHub issues across ordered milestones.
# Contract: docs/CI-CD/agent-loop-routine.md
# Prompt: .github/prompts/agent-loop.md (or .github/prompts/<milestone-slug>.md)
#
# Kill switch: repo variable AGENT_LOOP_ENABLED (string "true"; default off).
# Manual re-runs: dispatch a fresh run instead of "Re-run jobs" on a failed
# snapshot so workflow file fixes apply.
#
# Two launch paths: kick (hourly cron + workflow_dispatch) and launch-next
# (automerge PR merged). post-deploy only smokes staging and annotates.
#
# Concurrency is per job, not per workflow. One shared group used to hold
# every merge-guard, post-deploy, and launch in a single queue; GitHub keeps
# one pending run per group and cancels the older one, so a merge-guard
# waiting on CI cancelled the launch of the next WP (56 cancellations on
# 2026-09-03). merge-guard now runs per PR and never waits on CI: it enables
# GitHub auto-merge and exits. The loop-wide group only serialises the jobs
# that launch agents.
on:
workflow_dispatch:
inputs:
issue_number:
description: "Issue number to launch (blank = pick next eligible WP)"
required: false
type: string
schedule:
# Hourly watchdog. Launch-on-merge fills the fleet; docs-only merges
# skip Release, so kick is the recovery path for those.
- cron: "0 * * * *"
workflow_run:
workflows: ["Release on main"]
types: [completed]
pull_request:
# Label and close only. Removing a label is skip-noise; merge-guard
# does not use it. synchronize/opened/ready_for_review on every PR
# created a skipped run even with no agent-automerge label. Auto-merge,
# once enabled, does not need a re-run on each push; the hourly job
# re-runs merge-guard on labeled PRs.
types: [labeled, closed]
permissions:
contents: read
issues: write
pull-requests: write
jobs:
merge-guard:
name: Merge agent-automerge PRs
if: >-
vars.AGENT_LOOP_ENABLED == 'true' &&
github.event_name == 'pull_request' &&
github.event.action != 'closed' &&
github.event.pull_request.head.repo.full_name == github.repository &&
(
github.event.action != 'labeled' ||
github.event.label.name == 'agent-automerge'
) &&
contains(github.event.pull_request.labels.*.name, 'agent-automerge')
runs-on: ubuntu-latest
timeout-minutes: 5
concurrency:
group: agent-merge-${{ github.event.pull_request.number }}
cancel-in-progress: true
steps:
- name: Check out repository
uses: actions/checkout@v7
- name: Deterministic merge guard, then enable auto-merge
env:
GH_TOKEN: ${{ secrets.AGENT_LOOP_GITHUB_TOKEN || secrets.AUTOFIX_GITHUB_TOKEN }}
DISCORD_ERRORS_WEBHOOK_URL: ${{ secrets.DISCORD_ERRORS_WEBHOOK_URL }}
AGENT_LOOP_MILESTONES: ${{ vars.AGENT_LOOP_MILESTONES }}
run: .github/scripts/agent-loop-merge-guard.sh "${{ github.event.pull_request.number }}"
launch-next:
name: Launch next WP after merge
if: >-
vars.AGENT_LOOP_ENABLED == 'true' &&
github.event_name == 'pull_request' &&
github.event.action == 'closed' &&
github.event.pull_request.merged == true &&
contains(github.event.pull_request.labels.*.name, 'agent-automerge')
runs-on: ubuntu-latest
timeout-minutes: 10
concurrency:
group: agent-loop
cancel-in-progress: false
steps:
- name: Check out repository
uses: actions/checkout@v7
with:
ref: main
- name: Smoke the staging that is live now
env:
GH_TOKEN: ${{ github.token }}
run: .github/scripts/agent-loop-staging-smoke.sh
- name: Pick next WP
id: next
env:
GH_TOKEN: ${{ github.token }}
AGENT_LOOP_MILESTONES: ${{ vars.AGENT_LOOP_MILESTONES }}
AGENT_LOOP_CONCURRENCY: ${{ vars.AGENT_LOOP_CONCURRENCY }}
run: .github/scripts/agent-loop-next.sh
- name: Launch next agent
if: steps.next.outputs.found == 'true'
env:
GH_TOKEN: ${{ github.token }}
CURSOR_API_KEY: ${{ secrets.CURSOR_API_KEY }}
AGENT_LOOP_MILESTONES: ${{ vars.AGENT_LOOP_MILESTONES }}
run: .github/scripts/agent-loop-launch.sh ${{ steps.next.outputs.issue_numbers }}
post-deploy:
name: Smoke staging after release
if: >-
vars.AGENT_LOOP_ENABLED == 'true' &&
github.event_name == 'workflow_run' &&
github.event.workflow_run.conclusion == 'success'
runs-on: ubuntu-latest
timeout-minutes: 15
concurrency:
group: agent-loop
cancel-in-progress: false
steps:
- name: Check out repository
uses: actions/checkout@v7
with:
ref: main
- name: Smoke staging and annotate the issue
env:
GH_TOKEN: ${{ github.token }}
DISCORD_ERRORS_WEBHOOK_URL: ${{ secrets.DISCORD_ERRORS_WEBHOOK_URL }}
HEAD_SHA: ${{ github.event.workflow_run.head_sha }}
CONCLUSION: ${{ github.event.workflow_run.conclusion }}
run: .github/scripts/agent-loop-postdeploy.sh
kick:
name: Pick and launch a WP
if: >-
vars.AGENT_LOOP_ENABLED == 'true' &&
(github.event_name == 'workflow_dispatch' || github.event_name == 'schedule')
runs-on: ubuntu-latest
timeout-minutes: 10
concurrency:
group: agent-loop
cancel-in-progress: false
steps:
- name: Check out repository
uses: actions/checkout@v7
- name: Re-run merge guard on labeled PRs
if: github.event_name == 'schedule'
continue-on-error: true
env:
GH_TOKEN: ${{ secrets.AGENT_LOOP_GITHUB_TOKEN || secrets.AUTOFIX_GITHUB_TOKEN }}
DISCORD_ERRORS_WEBHOOK_URL: ${{ secrets.DISCORD_ERRORS_WEBHOOK_URL }}
AGENT_LOOP_MILESTONES: ${{ vars.AGENT_LOOP_MILESTONES }}
run: .github/scripts/agent-loop-merge-guard.sh
- name: Use dispatched issue number
id: given
if: github.event_name == 'workflow_dispatch' && inputs.issue_number != ''
run: |
echo "found=true" >> "$GITHUB_OUTPUT"
echo "issue_number=${{ inputs.issue_number }}" >> "$GITHUB_OUTPUT"
- name: Pick next WP
id: next
if: steps.given.outputs.found != 'true'
env:
GH_TOKEN: ${{ github.token }}
AGENT_LOOP_MILESTONES: ${{ vars.AGENT_LOOP_MILESTONES }}
AGENT_LOOP_CONCURRENCY: ${{ vars.AGENT_LOOP_CONCURRENCY }}
run: .github/scripts/agent-loop-next.sh
- name: Launch dispatched issue
if: steps.given.outputs.found == 'true'
env:
GH_TOKEN: ${{ github.token }}
CURSOR_API_KEY: ${{ secrets.CURSOR_API_KEY }}
AGENT_LOOP_MILESTONES: ${{ vars.AGENT_LOOP_MILESTONES }}
run: .github/scripts/agent-loop-launch.sh "${{ steps.given.outputs.issue_number }}"
- name: Launch selected issues
if: steps.next.outputs.found == 'true'
env:
GH_TOKEN: ${{ github.token }}
CURSOR_API_KEY: ${{ secrets.CURSOR_API_KEY }}
AGENT_LOOP_MILESTONES: ${{ vars.AGENT_LOOP_MILESTONES }}
run: .github/scripts/agent-loop-launch.sh ${{ steps.next.outputs.issue_numbers }}