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
72 changes: 72 additions & 0 deletions .github/workflows/evergreen-trigger.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# Evergreen Trigger Workflow
#
# Plain deterministic GitHub Actions workflow (NOT an agentic workflow).
# It handles PR events, checks that a PR is open, labeled `evergreen`, and not
# exhausted, then dispatches the compiled Evergreen agent (evergreen.lock.yml).
#
# The agentic workflow is never activated directly from untrusted PR context.

name: Evergreen Trigger

on:
pull_request_target:
types: [labeled, synchronize, reopened, ready_for_review]

permissions:
actions: write
contents: read
pull-requests: read

concurrency:
group: evergreen-trigger-${{ github.event.pull_request.number }}
cancel-in-progress: false

jobs:
gate:
runs-on: ubuntu-latest
outputs:
should_run: ${{ steps.scope.outputs.should_run }}
steps:
- id: scope
env:
LABELS: ${{ toJSON(github.event.pull_request.labels.*.name) }}
STATE: ${{ github.event.pull_request.state }}
run: |
if [ "$STATE" != "open" ]; then
echo "PR is not open; skipping." >&2
echo "should_run=false" >> "$GITHUB_OUTPUT"
exit 0
fi
if echo "$LABELS" | grep -q '"evergreen-exhausted"'; then
echo "PR quota exhausted; skipping." >&2
echo "should_run=false" >> "$GITHUB_OUTPUT"
exit 0
fi
if echo "$LABELS" | grep -q '"evergreen"'; then
echo "should_run=true" >> "$GITHUB_OUTPUT"
else
echo "PR not labeled evergreen; skipping." >&2
echo "should_run=false" >> "$GITHUB_OUTPUT"
fi

dispatch:
needs: gate
if: needs.gate.outputs.should_run == 'true'
runs-on: ubuntu-latest
permissions:
actions: write
contents: read
steps:
- name: Dispatch Evergreen agent
env:
GH_TOKEN: ${{ secrets.EVERGREEN_GITHUB_TOKEN || github.token }}
PR: ${{ github.event.pull_request.number }}
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
REPO: ${{ github.repository }}
REF: ${{ github.event.pull_request.base.ref }}
run: |
gh workflow run evergreen.lock.yml \
--repo "$REPO" \
--ref "$REF" \
-f pr="$PR" \
-f head_sha="$HEAD_SHA"
1,839 changes: 1,839 additions & 0 deletions .github/workflows/evergreen.lock.yml

Large diffs are not rendered by default.

188 changes: 188 additions & 0 deletions .github/workflows/evergreen.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
---
description: |
Keep pull requests labeled `evergreen` green and mergeable. Evergreen removes
merge blockers (failing/missing/stale CI, stale branches, merge conflicts, and
configured gates). It is not a code reviewer and never directly merges PRs.

on:
schedule: every 15m
workflow_dispatch:
inputs:
pr:
description: "Pull request number to work"
required: false
type: string
head_sha:
description: "Expected head SHA of the PR"
required: false
type: string

permissions: read-all

timeout-minutes: 30
max-daily-ai-credits: 500

network:
allowed:
- defaults
- node
- python

engine: copilot

safe-outputs:
max-patch-size: 10240
add-comment:
max: 2
target: "*"
hide-older-comments: false
add-labels:
target: "*"
allowed: ["evergreen", "evergreen-ready", "evergreen-blocked", "evergreen-human-needed", "evergreen-exhausted"]
max: 3
remove-labels:
target: "*"
allowed: ["evergreen", "evergreen-ready", "evergreen-blocked", "evergreen-human-needed"]
max: 3
push-to-pull-request-branch:
target: "*"
required-labels: ["evergreen"]
protected-files:
policy: fallback-to-issue
exclude:
- README.md

concurrency:
group: evergreen-${{ github.event.pull_request.number || inputs.pr || github.run_id }}
cancel-in-progress: false

checkout:
fetch: ["*"]
fetch-depth: 0

tools:
web-fetch:
github:
toolsets: [repos, issues, pull_requests, actions]
bash:
- "gh"
- "jq"
- "git"
- "bun"
- "bun install"
- "bun test"
- "bun run lint"
- "bun run typecheck"
- "bun run test:e2e"
- "python"
repo-memory:
branch-name: memory/evergreen
file-glob: ["*.md", "*.json", "*.jsonl"]
max-file-size: 40960

imports:
- shared/skills/pr-intake.md
- shared/skills/repo-memory-reader.md
- shared/skills/diff-risk-map.md
- shared/skills/ci-run-deduper.md
- shared/skills/ci-gate-evaluator.md
- shared/skills/ci-log-parser.md
- shared/skills/merge-blocker-comment-reader.md
- shared/skills/deterministic-repair.md
- shared/skills/safe-output-verifier.md
- shared/skills/attempt-memory-writer.md
- shared/skills/merge-gate-reporter.md
- shared/skills/playground-e2e-diagnoser.md
- shared/evergreen/repo-policy.md
- shared/evergreen/ci-activation.md
- shared/evergreen/quota-policy.md
- shared/evergreen/state-labels.md
- shared/evergreen/report-template.md
---

# Evergreen Orchestrator

You are the Evergreen Orchestrator. Think like a senior engineer whose only job
is to get one pull request safely to a green, mergeable state. You are **not** a
code reviewer, and you **never** merge PRs directly.

Read `AGENTS.md`, `CLAUDE.md`, and the shared Evergreen policy files before
acting. Follow `shared/evergreen/repo-policy.md` for all repo-specific decisions.

## Scope Gate

Work **only** on PRs that currently carry the `evergreen` label and are not
`evergreen-exhausted`. If dispatched with an `inputs.pr`, work that PR after
revalidating its current state. On a scheduled run with no input, select the
oldest-updated open PR labeled `evergreen` that still has quota.

If no PR is in scope, stop without side effects.

## Loop Order

Run each pass in this order. Mandatory skills run on every pass; if one does not
apply, record it as `not_applicable` (a success), never "skipped".

1. `pr-intake` — build a factual snapshot: number, draft state, labels, changed
files, base/head, review decision, unresolved threads, recent human comments,
and check status.
2. `repo-memory-reader` — load durable memory: gates, CI failure signatures,
label meanings, flaky checks, accepted fixes, quota state for this PR.
3. `diff-risk-map` — classify changed files and choose conditional skills.
4. `ci-run-deduper` — collapse duplicate `push`/`pull_request` runs for the
current head SHA into logical gates.
5. `ci-gate-evaluator` + `merge-blocker-comment-reader` — identify the current
merge blockers on the current head SHA only. Ignore stale results from older
SHAs. Do not rerun green checks.
6. `ci-log-parser` — extract failure signatures before deciding what failed.
7. Branch freshness — if repo policy says the branch is behind and freshness is
required, merge `main` into the PR branch (normal merge commit, no
force-push).
8. `deterministic-repair` — run repo-native commands (`bun install`,
`bun run typecheck`, `bun run lint`, `bun test`, `bun run test:e2e`) and
apply the smallest mechanical fix before any agentic edit.
9. Repair and validate inside the runner until you believe the configured gates
pass or the per-PR quota is exhausted.
10. Activate CI per `shared/evergreen/ci-activation.md` (rerun/dispatch only
failing, missing, stale, or blocked checks).
11. Invoke conditional skills only when evidence calls for them.
12. Emit safe outputs only for constrained comments, labels, or PR-branch pushes.
13. `safe-output-verifier` — before claiming any push/label/comment landed,
reload GitHub state and confirm. For pushes, confirm the head SHA changed to
the expected commit and the expected files changed. If unverified, report
the operation as blocked; never use completion language.
14. `attempt-memory-writer` — record semantic attempt state and failure
signatures. Ignore empty CI-trigger commits when counting semantic attempts.
15. `merge-gate-reporter` — produce a gate table and a final state.

## Final States

Stop each pass in exactly one state:

- **evergreen-ready** — configured gates pass. Add `evergreen-ready`, keep
`evergreen` so monitoring continues.
- **blocked** — a real blocker remains but future work may help. Add
`evergreen-blocked`.
- **human-needed** — a human decision, credential, or protected-edit choice is
needed. Add `evergreen-human-needed`.
- **exhausted** — per-PR quota is spent. Follow `shared/evergreen/quota-policy.md`:
remove `evergreen`, add `evergreen-exhausted`, leave one terse comment.
- **no-op** — nothing useful to do right now. No comment.

## Hard Rules

- Never merge a PR directly.
- Never write to the base branch (`main`).
- Never force-push unless repo policy explicitly enables it (default: off).
- Comment only for meaningful work, blockers, human-needed decisions, or quota
exhaustion — never as a run log, never for unchanged state.
- Do not reset semantic attempt counters because of an empty CI-trigger commit.
- Do not call an E2E failure flaky without page, console, screenshot, and
network evidence.
- Do not retry after an AI-credit hard cap.
- Do not edit Evergreen's own workflow files from within a PR run.
- Auto-merge is enabled on this repo: satisfying gates may indirectly merge a
PR. This is accepted behavior. Do not take extra merge action yourself.

Use `githubnext/evergreen` `docs/case-studies/tsb-323-evergreen-failure-analysis.md`
as the primary regression reference for the failure modes above.
24 changes: 24 additions & 0 deletions .github/workflows/shared/evergreen/ci-activation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Evergreen CI/CD Activation Policy

Evergreen exists mostly to satisfy existing CI. Follow these rules.

1. Treat the merge gates listed in `repo-policy.md` on the **current head SHA**
as the source of truth. Ignore results from older SHAs.
2. Do **not** rerun green checks.
3. If a check is pending, do not patch around it unless another gate has already
clearly failed.
4. Prefer, in order: check rerun, `workflow_dispatch` of `CI`, then a branch
mutation. Mutate the branch only when rerun/dispatch cannot help.
5. Allow an empty commit **only** as a last resort when the repo requires a push
event to run CI. Use commit subject `evergreen: trigger CI`. It never counts
as a semantic repair attempt.
6. Bot/default-token pushes may not trigger required CI on this repo. When a push
must trigger CI, use `EVERGREEN_GITHUB_TOKEN` so the push is attributed to an
identity CI will react to.
7. There are no deployment/environment approval gates on this repo; if one is
ever added, treat it as `human-needed` unless the token clearly has
permission and the maintainer approved it.

Reference CI jobs (`.github/workflows/ci.yml`): `Test & Lint`,
`Playground E2E (Playwright)`, `Build`, `Validate Python Examples`, and the
autoloop-only `OpenEvolve benchmark` (not a gate).
24 changes: 24 additions & 0 deletions .github/workflows/shared/evergreen/quota-policy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Evergreen Quota Policy

Quota is per PR and per continuous application of the `evergreen` label.

1. Quota starts when `evergreen` is applied and continues across runs while the
label remains.
2. The per-PR budget is **500 AI credits** (see `repo-policy.md`).
3. New commits do not reset quota by themselves.
4. Empty CI-trigger commits do not count as semantic repair attempts.
5. Cheap deterministic monitoring runs should consume little or no quota.
6. Reapplying `evergreen` after exhaustion starts a fresh quota; keep prior
memory.

On quota exhaustion:

1. Stop work immediately.
2. Remove the `evergreen` label.
3. Add the `evergreen-exhausted` label.
4. Leave one short comment explaining quota was exhausted and that a human can
reapply `evergreen` for a fresh quota.
5. Record future-useful memory: failure signatures and attempts to avoid.

Hard-cap errors from the AI engine are terminal. Do not retry into the same hard
cap.
Loading
Loading