Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions .github/workflows/ci-full.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,16 @@ name: CI (full matrix)

# Weekly compatibility run across the supported Node versions
# (engine `>=18`). PR-time CI only runs Node 20 for budget reasons;
# this catches Node 18 / 22 regressions within seven days, and can be
# triggered on-demand via workflow_dispatch before a release.
# this catches Node 18 / 22 regressions within seven days, can be
# triggered on-demand via workflow_dispatch before a release, and can
# be opted-into per-PR by applying the `needs-ci-full` label.

on:
schedule:
- cron: '15 4 * * 1'
workflow_dispatch:
pull_request:
types: [labeled, synchronize]

permissions:
contents: read
Expand All @@ -20,6 +23,12 @@ concurrency:
jobs:
test:
name: test (node ${{ matrix.node }})
# PR runs only fire when the `needs-ci-full` label is present.
# Schedule and workflow_dispatch always run.
if: >-
github.event_name != 'pull_request' ||
contains(github.event.pull_request.labels.*.name, 'needs-ci-full') ||
(github.event.action == 'labeled' && github.event.label.name == 'needs-ci-full')
runs-on: ubuntu-latest
strategy:
fail-fast: false
Expand Down
13 changes: 8 additions & 5 deletions .github/workflows/cr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: Code Review

on:
pull_request:
types: [opened, reopened, synchronize, ready_for_review]
types: [opened, reopened, synchronize, ready_for_review, labeled]

permissions:
contents: read
Expand All @@ -20,12 +20,15 @@ jobs:
# skip review. The agent flow lands hundreds of PRs per month; AI
# review on each one burns both Actions minutes and OpenAI tokens
# without adding signal. Human-authored PRs (any non-`agent/*`
# head branch) still get reviewed; agent PRs can opt-in by adding
# a `needs-review` label, which a maintainer can re-run via
# `workflow_dispatch`-style label trigger if desired.
# head branch) still get reviewed; agent PRs opt-in by applying
# the `needs-review` label.
if: >-
github.event.pull_request.draft == false &&
!startsWith(github.event.pull_request.head.ref, 'agent/')
(
!startsWith(github.event.pull_request.head.ref, 'agent/') ||
contains(github.event.pull_request.labels.*.name, 'needs-review') ||
(github.event.action == 'labeled' && github.event.label.name == 'needs-review')
)
runs-on: ubuntu-latest
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
schema: spec-driven
created: 2026-05-13
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# agent-claude-ci-label-based-opt-in-2026-05-14-01-28 (minimal / T1)

Branch: `agent/<your-name>/<branch-slug>`

Describe the change in a sentence or two. Commit message is the spec of record.

## Handoff

- Handoff: change=`agent-claude-ci-label-based-opt-in-2026-05-14-01-28`; branch=`agent/<your-name>/<branch-slug>`; scope=`TODO`; action=`continue this sandbox or finish cleanup after a usage-limit/manual takeover`.
- Copy prompt: Continue `agent-claude-ci-label-based-opt-in-2026-05-14-01-28` on branch `agent/<your-name>/<branch-slug>`. Work inside the existing sandbox, review `openspec/changes/agent-claude-ci-label-based-opt-in-2026-05-14-01-28/notes.md`, continue from the current state instead of creating a new sandbox, and when the work is done run `gx branch finish --branch agent/<your-name>/<branch-slug> --base dev --via-pr --wait-for-merge --cleanup`.

## Cleanup

- [ ] Run: `gx branch finish --branch agent/<your-name>/<branch-slug> --base dev --via-pr --wait-for-merge --cleanup`
- [ ] Record PR URL + `MERGED` state in the completion handoff.
- [ ] Confirm sandbox worktree is gone (`git worktree list`, `git branch -a`).
20 changes: 20 additions & 0 deletions templates/github/workflows/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,26 @@ If your team relies on AI review as a true gating signal (not just
advisory), remove the `!startsWith(head.ref, 'agent/')` guard in
`cr.yml`. Expect the OpenAI bill to scale linearly with merge volume.

## Per-PR label opt-in

Both `cr.yml` and `ci-full.yml` honor PR labels so the occasional
agent PR that actually needs the heavier check can opt in without
flipping a global toggle:

| Label | Effect |
| --- | --- |
| `needs-review` | Run AI code review on this PR even though it's `agent/*`. Useful for security-sensitive changes or public-API redesigns. |
| `needs-ci-full` | Run the full cross-runtime matrix from `ci-full.yml` on this PR instead of waiting for the weekly schedule. Useful before a release branch lands. |

To enable: open the PR, then `gh pr edit <num> --add-label needs-review`
(or click the labels picker in the GitHub UI). The label-trigger fires
the workflow immediately; you don't need to re-push.

Add label definitions to your repo with `gh label create needs-review
--description "Run AI code review on this PR"` and similar for
`needs-ci-full`, or define them in `.github/labels.yml` if you use a
label-sync workflow.

## What about CodeQL / Scorecard?

The gitguardex repo itself runs CodeQL and Scorecard on the **weekly
Expand Down
11 changes: 10 additions & 1 deletion templates/github/workflows/ci-full.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
#
# Strategy: PR-time `ci.yml` runs the primary runtime only (cheap).
# This workflow runs the full matrix on the weekly schedule, and
# on-demand via `workflow_dispatch` before a release.
# on-demand via `workflow_dispatch` before a release. Per-PR opt-in
# is available by applying the `needs-ci-full` label to a PR.
#
# Customize the matrix rows below to match your supported runtimes.

Expand All @@ -14,6 +15,8 @@ on:
schedule:
- cron: '15 4 * * 1'
workflow_dispatch:
pull_request:
types: [labeled, synchronize]

permissions:
contents: read
Expand All @@ -25,6 +28,12 @@ concurrency:
jobs:
test:
name: test (node ${{ matrix.node }})
# PR runs only fire when the `needs-ci-full` label is present.
# Schedule and workflow_dispatch always run.
if: >-
github.event_name != 'pull_request' ||
contains(github.event.pull_request.labels.*.name, 'needs-ci-full') ||
(github.event.action == 'labeled' && github.event.label.name == 'needs-ci-full')
runs-on: ubuntu-latest
strategy:
fail-fast: false
Expand Down
17 changes: 11 additions & 6 deletions templates/github/workflows/cr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: Code Review

on:
pull_request:
types: [opened, reopened, synchronize, ready_for_review]
types: [opened, reopened, synchronize, ready_for_review, labeled]

permissions:
contents: read
Expand All @@ -17,13 +17,18 @@ concurrency:

jobs:
review:
# Skip on draft PRs and on `agent/*` head branches. Gitguardex
# agent flows land high-volume PRs that don't benefit from AI
# review; skipping them is the single largest CR-bill cut.
# Review fires on `ready_for_review` automatically for human PRs.
# Skip on draft PRs and on `agent/*` head branches by default.
# Agent PRs can opt-in by applying the `needs-review` label —
# useful for the occasional agent PR that genuinely needs AI
# eyes (security-sensitive change, public-API redesign, etc.).
# Human-authored PRs (any non-`agent/*` head branch) always run.
if: >-
github.event.pull_request.draft == false &&
!startsWith(github.event.pull_request.head.ref, 'agent/')
(
!startsWith(github.event.pull_request.head.ref, 'agent/') ||
contains(github.event.pull_request.labels.*.name, 'needs-review') ||
(github.event.action == 'labeled' && github.event.label.name == 'needs-review')
)
runs-on: ubuntu-latest
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
Expand Down
Loading