Skip to content

Contribution Check #423

Contribution Check

Contribution Check #423

Agentic Workflow file for this run

---
name: "Contribution Check"
on:
schedule: "every 4 hours"
workflow_dispatch:
permissions:
contents: read
issues: read
pull-requests: read
env:
TARGET_REPOSITORY: ${{ vars.TARGET_REPOSITORY || github.repository }}
engine:
id: copilot
agent: contribution-checker
tools:
mount-as-clis: true
github:
toolsets: [pull_requests, repos, issues]
allowed-repos: all
min-integrity: none
safe-outputs:
create-issue:
title-prefix: "[Contribution Check Report]"
labels:
- contribution-report
close-older-issues: true
group-by-day: true
expires: 1d
add-labels:
allowed: [spam, needs-work, outdated, lgtm]
max: 4
target: "*"
target-repo: ${{ vars.TARGET_REPOSITORY }}
add-comment:
max: 10
target: "*"
target-repo: ${{ vars.TARGET_REPOSITORY }}
hide-older-comments: true
steps:
- name: Fetch and filter PRs
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
# Fetch open PRs from the target repository opened in the last 24 hours
SINCE=$(date -d '24 hours ago' '+%Y-%m-%dT%H:%M:%SZ' 2>/dev/null \
|| date -v-24H '+%Y-%m-%dT%H:%M:%SZ')
echo "Fetching open PRs from $TARGET_REPOSITORY created since $SINCE..."
ALL_PRS=$(gh pr list \
--repo "$TARGET_REPOSITORY" \
--state open \
--limit 100 \
--json number,createdAt \
--jq "[.[] | select(.createdAt >= \"$SINCE\")]" \
2>/dev/null || echo "[]")
TOTAL=$(echo "$ALL_PRS" | jq 'length')
echo "Found $TOTAL open PRs created in the last 24 hours"
# Cap the number of PRs to evaluate at 5
MAX_EVALUATE=5
EVALUATED=$(echo "$ALL_PRS" | jq --argjson max "$MAX_EVALUATE" '[.[0:$max][] | .number]')
EVALUATED_COUNT=$(echo "$EVALUATED" | jq 'length')
SKIPPED_COUNT=$((TOTAL - EVALUATED_COUNT))
# Write results to workspace root
jq -n \
--argjson pr_numbers "$EVALUATED" \
--argjson skipped_count "$SKIPPED_COUNT" \
--argjson evaluated_count "$EVALUATED_COUNT" \
'{pr_numbers: $pr_numbers, skipped_count: $skipped_count, evaluated_count: $evaluated_count}' \
> "$GITHUB_WORKSPACE/pr-filter-results.json"
echo "✓ Wrote pr-filter-results.json: $EVALUATED_COUNT to evaluate, $SKIPPED_COUNT skipped"
cat "$GITHUB_WORKSPACE/pr-filter-results.json"
# Pre-fetch CONTRIBUTING.md once so all subagent calls can reuse it
CONTRIBUTING_FETCHED=false
for CONTRIBUTING_PATH in "CONTRIBUTING.md" ".github/CONTRIBUTING.md" "docs/CONTRIBUTING.md"; do
if gh api "repos/$TARGET_REPOSITORY/contents/$CONTRIBUTING_PATH" \
--jq '.content' 2>/dev/null | base64 -d > "$GITHUB_WORKSPACE/contributing-guidelines.md" 2>/dev/null; then
echo "✓ Pre-fetched contributing guidelines from $CONTRIBUTING_PATH"
CONTRIBUTING_FETCHED=true
break
fi
done
if [ "$CONTRIBUTING_FETCHED" = "false" ]; then
echo "# No CONTRIBUTING.md found" > "$GITHUB_WORKSPACE/contributing-guidelines.md"
echo "ℹ No CONTRIBUTING.md found in $TARGET_REPOSITORY (checked root, .github/, docs/)"
fi
features:
mcp-cli: true
---
## Target Repository
The target repository is `${{ env.TARGET_REPOSITORY }}`. All PR fetching and subagent dispatch use this value.
## Overview
You are an **orchestrator**. Your job is to dispatch PRs to the `contribution-checker` subagent for evaluation and compile the results into a single report issue in THIS repository (`${{ github.repository }}`).
You do NOT evaluate PRs yourself. You delegate each evaluation to `.github/agents/contribution-checker.agent.md`.
## Pre-filtered PR List
A `pre-agent` step has already queried and filtered PRs from `${{ env.TARGET_REPOSITORY }}`. The results are in `pr-filter-results.json` at the workspace root. Read this file first. It contains:
```json
{
"pr_numbers": [18744, 18743, 18742],
"skipped_count": 10,
"evaluated_count": 3
}
```
If `pr_numbers` is empty, create a report stating no PRs matched the filters and skip dispatch.
Do **not** emit one `noop` per PR slot or placeholder. If you need a noop, emit exactly **one** consolidated noop for the entire run.
## Step 1: Dispatch to Subagent
For each PR number in the comma-separated list, delegate evaluation to the **contribution-checker** subagent (`.github/agents/contribution-checker.agent.md`).
### How to dispatch
Read the contents of `contributing-guidelines.md` from the workspace root. This file was pre-fetched in the `pre-agent` step and contains the target repository's contributing guidelines. Include it verbatim in every subagent dispatch prompt to avoid redundant fetches.
Call the contribution-checker subagent for each PR with this prompt:
```
The CONTRIBUTING.md content for this repository is attached below.
Skip Step 1 — do not fetch CONTRIBUTING.md again.
<contributing-guidelines>
{contents of contributing-guidelines.md}
</contributing-guidelines>
Evaluate PR ${{ env.TARGET_REPOSITORY }}#<number> against the contribution guidelines.
```
The subagent accepts any `owner/repo#number` reference — the target repo is not hardcoded.
The subagent will return a single JSON object with the verdict and a comment for the contributor.
### Parallelism
- Dispatch **multiple PRs concurrently** when possible — the subagent evaluations are independent of each other.
- Each subagent call is stateless and self-contained. It fetches its own PR data.
### Collecting results
Gather all returned JSON objects. If a subagent call fails, record the PR with verdict `` and quality `triage:error` in the report.
### Posting comments
For each PR where the subagent returned a non-empty `comment` field and the quality is NOT `lgtm`, call the `add_comment` safe output tool to post the comment to the PR in the target repository. Pass the PR number and the comment body from the subagent result. The `add_comment` tool is pre-configured with `target-repo` pointing to the target repository — you do NOT need to specify the repo yourself.
Do NOT post comments to PRs with `lgtm` quality — those are ready for maintainer review and don't need additional feedback.
## Step 2: Compile Report
Create a single issue in THIS repository. Use the `skipped_count` from `pr-filter-results.json`. Build the report tables from the JSON objects returned by the subagent (use `number`, `title`, `author`, `lines`, and `quality` fields).
Follow the **report layout rules** below — they apply to every report this workflow produces.
### Report Layout Rules
Apply these principles to make the report scannable, warm, and actionable:
**Report Formatting**: Use h3 (###) or lower for all headers in the report. Wrap long sections (>10 items) in `<details><summary>Section Name</summary>` tags to improve readability.
1. **Lead with the takeaway.** Open with a single-sentence human-readable summary that tells the maintainer what happened and what needs attention. No jargon, no counts-only headers. Example: *"We looked at 10 new PRs — 6 look great, 3 need a closer look, and 1 doesn't fit the project guidelines."*
2. **Group by action, not by data.** Organize results into clear groups that answer "what should I do?" rather than listing raw rows. Use these groups (omit any group with zero items):
- **Ready to review** 🟢 — PRs that passed all checks
- **Needs a closer look** 🟡⚠️ — PRs that need discussion or focus work
- **Off-guidelines** 🔴 — PRs that don't align with CONTRIBUTING.md
3. **One table per group.** Keep tables short and focused. Columns:
- PR (linked), Title (truncated to ~50 chars), Author, Lines changed, Quality signal
- Do NOT include boolean checklist columns (on-topic, focused, deps, tests) — those are for the subagent, not the reader. The verdict emoji and quality signal are enough.
4. **Use whitespace generously.** Separate groups with blank lines and horizontal rules (`---`). Let each section breathe.
5. **End with context, not noise.** Close with a small stats line: `Evaluated: {n} · Skipped: {n} · Run: {run_link}`. Keep it quiet — one line, not a table.
6. **Tone: warm and constructive.** These reports help maintainers prioritize, not gatekeep. Use encouraging language for aligned PRs ("looking good", "ready for eyes"). Be matter-of-fact for off-guidelines PRs — no shaming.
### Example Report
```markdown
### Contribution Check — {date}
We looked at 4 new PRs — 1 looks great, 2 need a closer look, and 1 doesn't fit the contribution guidelines.
---
### Ready to review 🟢
| PR | Title | Author | Lines | Quality |
|----|-------|--------|------:|---------|
| #4521 | Fix CLI flag parsing for unicode args | @alice | 125 | lgtm ✨ |
---
### Needs a closer look 🟡
| PR | Title | Author | Lines | Quality |
|----|-------|--------|------:|---------|
| #4515 | Refactor auth + add rate limiting | @bob | 310 | needs-work |
| #4510 | Add Redis caching layer | @carol | 88 | needs-work |
---
### Off-guidelines 🔴
<details>
<summary>Per-PR Details</summary>
| PR | Title | Author | Lines | Quality |
|----|-------|--------|------:|---------|
| #4519 | Add unrelated marketing page | @dave | 42 | spam |
</details>
---
Evaluated: 4 · Skipped: 10
```
## Step 3: Label the Report Issue
After creating the report issue, call the `add_labels` safe output tool to apply labels based on the quality signals reported by the subagent. Collect the distinct `quality` values from all returned rows and add each as a label. The `add_labels` tool is pre-configured with `target-repo` pointing to the target repository.
When you create the report issue, set a `temporary_id` (for example `aw_summary`). Then set `add_labels.item_number` to `#<temporary_id>` (for example `#aw_summary`) so labels are applied to the issue created in the same run.
Example:
```json
{"type":"create_issue","temporary_id":"aw_summary","title":"Contribution Check — 2026-04-19","body":"..."}
{"type":"add_labels","item_number":"#aw_summary","labels":["lgtm","needs-work"]}
```
For example, if the batch contains rows with `lgtm`, `spam`, and `needs-work` quality values, apply all three labels: `lgtm`, `spam`, `needs-work`.
If any subagent call failed (❓), also apply `outdated`.
## Important
- **You are the orchestrator** — you dispatch and compile. You do NOT run the checklist yourself.
- **PR fetching and filtering is pre-computed** — a `pre-agent` step writes `pr-filter-results.json`. Read it at the start.
- **Subagent does the analysis**`.github/agents/contribution-checker.agent.md` handles all per-PR evaluation logic.
- **Read from `${{ env.TARGET_REPOSITORY }}`** — read-only access via GitHub MCP tools.
- **Write to `${{ github.repository }}`** — reports go here as issues.
- **Use safe output tools for target repository interactions** — use `add-comment` and `add-labels` safe output tools to post comments and labels to PRs in the target repository `${{ env.TARGET_REPOSITORY }}`. Never use `gh` CLI or direct API calls for writes.
- Close the previous report issue when creating a new one (`close-older-issues: true`).
- Be constructive in assessments — these reports help maintainers prioritize, not gatekeep.
- `noop` is global, not per-PR. Emit at most one consolidated noop for the entire workflow run.
- If you emitted any actionable safe outputs (`create_issue`, `add_comment`, `add_labels`), do **not** emit `noop`.
{{#import shared/noop-reminder.md}}