Skip to content

feat(ci): add CLIO-powered issue triage and PR review #1

feat(ci): add CLIO-powered issue triage and PR review

feat(ci): add CLIO-powered issue triage and PR review #1

Workflow file for this run

name: PR Review with CLIO
on:
pull_request:
types: [opened, synchronize, reopened, review_requested]
permissions:
pull-requests: write
contents: read
packages: read
env:
CLIO_MODEL: gpt-5-mini
REGISTRY: ghcr.io
jobs:
review:
name: Analyze and Review PR
runs-on: ubuntu-latest
if: |
github.event.pull_request.user.type != 'Bot' &&
github.event.pull_request.draft != true
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Log in to GHCR
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Pull CLIO container
run: docker pull ghcr.io/syntheticautonomicmind/clio:latest
- name: Prepare workspace
run: |
mkdir -p /tmp/clio-workspace
cp -r ./* /tmp/clio-workspace/ 2>/dev/null || true
cp -r ./.clio /tmp/clio-workspace/ 2>/dev/null || true
cp -r ./.github /tmp/clio-workspace/ 2>/dev/null || true
mkdir -p /tmp/clio-workspace/.clio/sessions
mkdir -p /tmp/clio-config
- name: Configure CLIO authentication
env:
CLIO_ACCESS: ${{ secrets.CLIO_ACCESS }}
run: |
set +x
printf '{"github_token": "%s", "saved_at": %d}' "$CLIO_ACCESS" "$(date +%s)" > /tmp/clio-config/github_tokens.json
chmod 600 /tmp/clio-config/github_tokens.json
echo '{"provider": "github_copilot"}' > /tmp/clio-config/config.json
- name: Prepare PR info file
env:
PR_NUMBER: ${{ github.event.pull_request.number }}
PR_TITLE: ${{ github.event.pull_request.title }}
PR_AUTHOR: ${{ github.event.pull_request.user.login }}
PR_HEAD: ${{ github.event.pull_request.head.ref }}
PR_BASE: ${{ github.event.pull_request.base.ref }}
PR_ACTION: ${{ github.event.action }}
PR_BODY: ${{ github.event.pull_request.body }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh pr diff "$PR_NUMBER" > /tmp/clio-workspace/PR_DIFF.txt 2>/dev/null || echo "No diff available" > /tmp/clio-workspace/PR_DIFF.txt
gh pr view "$PR_NUMBER" --json files --jq '.files[].path' > /tmp/clio-workspace/PR_FILES.txt 2>/dev/null || echo "" > /tmp/clio-workspace/PR_FILES.txt
# Create PR info file using env vars (safe from shell metacharacters)
{
echo "# Pull Request #${PR_NUMBER}"
echo ""
echo "**Title:** ${PR_TITLE}"
echo "**Author:** ${PR_AUTHOR}"
echo "**Branch:** ${PR_HEAD} -> ${PR_BASE}"
echo "**Event:** ${PR_ACTION}"
echo ""
echo "## Description"
echo ""
} > /tmp/clio-workspace/PR_INFO.md
# Append body safely via printf
printf '%s\n' "$PR_BODY" >> /tmp/clio-workspace/PR_INFO.md
echo "PR info prepared"
- name: Run CLIO PR Review
id: review
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PR_NUMBER: ${{ github.event.pull_request.number }}
run: |
TASK="You are in HEADLESS CI/CD MODE. No human is present.
TASK: Review Pull Request #${PR_NUMBER}
STEPS:
1. Read .github/clio-prompts/pr-review.md for instructions
2. Read PR_INFO.md, PR_DIFF.txt, PR_FILES.txt
3. Check AGENTS.md and docs/STYLE_GUIDE.md if needed
4. WRITE your review JSON to /workspace/review.json using file_operations
CRITICAL:
- DO NOT use user_collaboration (it will hang forever)
- Write JSON to /workspace/review.json using file_operations create_file"
echo "=== Starting CLIO PR Review ==="
docker run -i --rm \
-v "/tmp/clio-workspace":/workspace:rw \
-v "/tmp/clio-config":/root/.clio:rw \
-w /workspace \
-e CLIO_LOG_LEVEL=WARNING \
-e GH_TOKEN="${GH_TOKEN}" \
ghcr.io/syntheticautonomicmind/clio:latest \
--new \
--model "$CLIO_MODEL" \
--input "$TASK" \
--exit 2>&1 | tee /tmp/clio-workspace/full_response.txt || true
echo ""
echo "=== CLIO Review Complete ==="
if [ -f /tmp/clio-workspace/review.json ]; then
echo "review.json found!"
else
echo "review.json NOT found"
fi
- name: Get review JSON
id: extract
run: |
if [ -f /tmp/clio-workspace/review.json ] && jq . /tmp/clio-workspace/review.json > /dev/null 2>&1; then
echo "Using review.json written by CLIO"
cp /tmp/clio-workspace/review.json /tmp/clio-workspace/analysis.json
echo "json_valid=true" >> $GITHUB_OUTPUT
else
echo "json_valid=false" >> $GITHUB_OUTPUT
echo '{"recommendation":"needs-review","security_concerns":[],"style_issues":[],"documentation_issues":[],"test_coverage":"unknown","breaking_changes":false,"suggested_labels":["needs-review"],"summary":"Automated analysis could not produce review.json. Manual review recommended.","detailed_feedback":[]}' > /tmp/clio-workspace/analysis.json
echo "Using fallback JSON"
fi
echo "=== Review JSON ==="
cat /tmp/clio-workspace/analysis.json
- name: Parse results
id: parse
run: |
ANALYSIS=$(cat /tmp/clio-workspace/analysis.json)
RECOMMENDATION=$(echo "$ANALYSIS" | jq -r '.recommendation // "needs-review"')
LABELS=$(echo "$ANALYSIS" | jq -r '(.labels // .suggested_labels // []) | join(",")')
echo "recommendation=$RECOMMENDATION" >> $GITHUB_OUTPUT
echo "labels=$LABELS" >> $GITHUB_OUTPUT
- name: Apply labels
if: steps.parse.outputs.labels != ''
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PR_NUMBER: ${{ github.event.pull_request.number }}
run: |
IFS=',' read -ra LABELS <<< "${{ steps.parse.outputs.labels }}"
for label in "${LABELS[@]}"; do
label=$(echo "$label" | xargs)
if [ -n "$label" ]; then
gh pr edit "$PR_NUMBER" --add-label "$label" 2>/dev/null || \
(gh label create "$label" --color "c5def5" 2>/dev/null; gh pr edit "$PR_NUMBER" --add-label "$label" 2>/dev/null) || true
fi
done
- name: Post review comment
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PR_NUMBER: ${{ github.event.pull_request.number }}
run: |
ANALYSIS=$(cat /tmp/clio-workspace/analysis.json)
RECOMMENDATION=$(echo "$ANALYSIS" | jq -r '.recommendation // "needs-review"')
SUMMARY=$(echo "$ANALYSIS" | jq -r '.summary // "Analysis complete."')
TEST_COV=$(echo "$ANALYSIS" | jq -r '.test_coverage // "unknown"')
BREAKING=$(echo "$ANALYSIS" | jq -r '.breaking_changes // false')
case "$RECOMMENDATION" in
"approve"|"approved") EMOJI="OK"; VERDICT="LGTM - Ready for Human Review" ;;
"needs-changes") EMOJI="WARN"; VERDICT="Changes Requested" ;;
"security-concern") EMOJI="STOP"; VERDICT="Security Review Required" ;;
*) EMOJI="INFO"; VERDICT="Needs Review" ;;
esac
# Build security concerns section
SEC_CONCERNS=$(echo "$ANALYSIS" | jq -r '(.security_concerns // []) | if length > 0 then "## Security Concerns\n\n" + (map("- " + .) | join("\n")) + "\n" else "" end')
# Build style issues section
STYLE_ISSUES=$(echo "$ANALYSIS" | jq -r '(.style_issues // []) | if length > 0 then "## Style Issues\n\n" + (map("- " + .) | join("\n")) + "\n" else "" end')
# Build detailed feedback section
FEEDBACK=$(echo "$ANALYSIS" | jq -r '(.detailed_feedback // []) | if length > 0 then "## Detailed Feedback\n\n" + (map("- " + .) | join("\n")) + "\n" else "" end')
# Construct comment body
COMMENT_BODY="## ${EMOJI} CLIO Automated Review: ${VERDICT}
**Summary:** ${SUMMARY}

Check failure on line 206 in .github/workflows/pr-review.yml

View workflow run for this annotation

GitHub Actions / .github/workflows/pr-review.yml

Invalid workflow file

You have an error in your yaml syntax on line 206
| Metric | Value |
|--------|-------|
| Test Coverage | \`${TEST_COV}\` |
| Breaking Changes | \`${BREAKING}\` |
${SEC_CONCERNS}
${STYLE_ISSUES}
${FEEDBACK}
---
_This is an automated review. A human maintainer will provide final approval._"
gh pr comment "$PR_NUMBER" --body "$COMMENT_BODY"
- name: Upload artifacts
if: always()
uses: actions/upload-artifact@v4
with:
name: review-artifacts
path: |
/tmp/clio-workspace/full_response.txt
/tmp/clio-workspace/review.json
/tmp/clio-workspace/analysis.json
/tmp/clio-workspace/PR_INFO.md
/tmp/clio-workspace/PR_DIFF.txt
retention-days: 7