name: "Daily Resume Review" on: workflow_dispatch: schedule: - cron: "15 7 * * *" concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: false jobs: review: name: "Run AI resume review and open PR" runs-on: ubuntu-latest steps: - name: Checkout repository uses: actions/checkout@v4 - name: Install nix uses: https://github.com/DeterminateSystems/nix-installer-action@main - name: Build resume PDF id: build run: | set -euo pipefail if nix build .#default > build.log 2>&1; then echo "build_status=success" >> "$GITHUB_OUTPUT" else echo "build_status=failed" >> "$GITHUB_OUTPUT" fi - name: Prepare review context id: context run: | set -euo pipefail mkdir -p archive/reviews review_date="$(date +'%Y-%m-%d')" review_path="archive/reviews/${review_date}-automated-review.md" python - <<'PY' import json import os from pathlib import Path prompt = Path('.github/prompts/resume-review.prompt.md').read_text(encoding='utf-8') resume = Path('resume.tex').read_text(encoding='utf-8') build_log = Path('build.log').read_text(encoding='utf-8', errors='replace') if Path('build.log').exists() else '' payload = { "model": os.getenv("OPENAI_MODEL", "gpt-5"), "input": [ { "role": "system", "content": [ { "type": "input_text", "text": "You are an autonomous resume review agent. Follow the provided prompt exactly." } ] }, { "role": "user", "content": [ { "type": "input_text", "text": ( "Use the following prompt as your full instruction set:\n\n" f"{prompt}\n\n" "Build status from CI:\n" f"- nix build result: {os.getenv('BUILD_STATUS', 'unknown')}\n\n" "Build log:\n" "```text\n" f"{build_log[-15000:]}\n" "```\n\n" "Resume source:\n" "```tex\n" f"{resume}\n" "```\n" ) } ] } ] } Path('review-request.json').write_text(json.dumps(payload), encoding='utf-8') PY echo "review_date=${review_date}" >> "$GITHUB_OUTPUT" echo "review_path=${review_path}" >> "$GITHUB_OUTPUT" env: BUILD_STATUS: ${{ steps.build.outputs.build_status }} - name: Run review agent id: review run: | set -euo pipefail api_base="${OPENAI_BASE_URL:-https://api.openai.com/v1}" curl -sS "${api_base}/responses" \ -H "Authorization: Bearer ${OPENAI_API_KEY}" \ -H "Content-Type: application/json" \ -d @review-request.json \ > response.json python - <<'PY' import json from pathlib import Path response = json.loads(Path('response.json').read_text(encoding='utf-8')) text = response.get('output_text', '').strip() if not text: chunks = [] for item in response.get('output', []): for content in item.get('content', []): if content.get('type') == 'output_text': chunks.append(content.get('text', '')) text = '\n'.join(chunks).strip() if not text: raise SystemExit('Agent response did not contain output text.') review_path = Path('${{ steps.context.outputs.review_path }}') review_path.write_text(text + '\n', encoding='utf-8') PY - name: Check whether review changed id: review_guard run: | set -euo pipefail current_review="${{ steps.context.outputs.review_path }}" previous_review="$(ls -1 archive/reviews/*-automated-review.md 2>/dev/null | grep -vx "$current_review" | sort | tail -n1 || true)" if [ -z "$previous_review" ]; then echo "create_pr=true" >> "$GITHUB_OUTPUT" echo "reason=no_previous_review" >> "$GITHUB_OUTPUT" exit 0 fi if cmp -s "$current_review" "$previous_review"; then rm -f "$current_review" echo "create_pr=false" >> "$GITHUB_OUTPUT" echo "reason=review_unchanged" >> "$GITHUB_OUTPUT" else echo "create_pr=true" >> "$GITHUB_OUTPUT" echo "reason=review_changed" >> "$GITHUB_OUTPUT" fi - name: Print guard decision run: | echo "create_pr=${{ steps.review_guard.outputs.create_pr }}" echo "reason=${{ steps.review_guard.outputs.reason }}" - name: Write PR body if: steps.review_guard.outputs.create_pr == 'true' run: | cat > pr_body.md <<'EOF' This PR contains the latest automated daily resume review. Review file: - ${{ steps.context.outputs.review_path }} Generated by `.github/workflows/daily-resume-review.yml` using: - Prompt: `.github/prompts/resume-review.prompt.md` - Source: `resume.tex` EOF - name: Create Pull Request id: create-pull-request if: steps.review_guard.outputs.create_pr == 'true' uses: https://nayeonie.com/ahuston-0/create-pull-request@main with: token: ${{ secrets.GH_TOKEN_FOR_UPDATES }} add-paths: ${{ steps.context.outputs.review_path }} body-path: pr_body.md author: '"github-actions[bot]" ' title: 'automated: Daily resume review (${{ steps.context.outputs.review_date }})' commit-message: 'automated: Daily resume review (${{ steps.context.outputs.review_date }})' branch: automated/daily-resume-review delete-branch: true pr-labels: | automated review permissions: pull-requests: write contents: write