10 Commits

Author SHA1 Message Date
4331b0659f add automated review
All checks were successful
Build and Release Resume PDF / date-fetch (push) Successful in 16s
Check flake.lock / Check health of `flake.lock` (push) Successful in 12s
Check Nix flake / Perform Nix flake checks (push) Successful in 59s
Build and Release Resume PDF / build (push) Successful in 1m27s
2026-03-27 16:49:38 -04:00
3c72938f98 move pdfs to lfs
All checks were successful
Check flake.lock / Check health of `flake.lock` (push) Successful in 18s
Check Nix flake / Perform Nix flake checks (push) Successful in 1m39s
2026-03-27 16:18:41 -04:00
311f022b66 ignore pdfs 2026-03-27 16:17:36 -04:00
e214c40d4d ignore direnv
All checks were successful
Check flake.lock / Check health of `flake.lock` (push) Successful in 6s
Check Nix flake / Perform Nix flake checks (push) Successful in 43s
2026-03-27 16:15:14 -04:00
213aa63aa1 rename main to resume
All checks were successful
Check flake.lock / Check health of `flake.lock` (push) Successful in 8s
Check Nix flake / Perform Nix flake checks (push) Successful in 1m1s
2026-03-27 16:13:07 -04:00
e38ed451df remove generated pdfs, rename tex file
Some checks failed
Build and Release Resume PDF / date-fetch (push) Successful in 2s
Check flake.lock / Check health of `flake.lock` (push) Successful in 7s
Check Nix flake / Perform Nix flake checks (push) Successful in 47s
Build and Release Resume PDF / build (push) Failing after 1m55s
2026-03-27 16:10:57 -04:00
e6c33a2eab remove generated pdfs, rename tex file
Some checks failed
Build and Release Resume PDF / date-fetch (push) Successful in 2s
Check flake.lock / Check health of `flake.lock` (push) Successful in 8s
Check Nix flake / Perform Nix flake checks (push) Successful in 51s
Build and Release Resume PDF / build (push) Failing after 1m44s
2026-03-27 16:08:58 -04:00
41befd6626 substring git sha
All checks were successful
Build and Release Resume PDF / date-fetch (push) Successful in 3s
Check flake.lock / Check health of `flake.lock` (push) Successful in 8s
Check Nix flake / Perform Nix flake checks (push) Successful in 45s
Build and Release Resume PDF / build (push) Successful in 1m37s
2026-03-27 16:05:39 -04:00
f3ae240c68 remove magic cache
Some checks failed
Build and Release Resume PDF / date-fetch (push) Successful in 3s
Check flake.lock / Check health of `flake.lock` (push) Successful in 7s
Build and Release Resume PDF / build (push) Has been cancelled
Check Nix flake / Perform Nix flake checks (push) Has been cancelled
2026-03-27 16:03:55 -04:00
1614e9aed0 add magic cache
Some checks failed
Build and Release Resume PDF / date-fetch (push) Successful in 2s
Check flake.lock / Check health of `flake.lock` (push) Successful in 8s
Check Nix flake / Perform Nix flake checks (push) Successful in 58s
Build and Release Resume PDF / build (push) Failing after 1m34s
2026-03-27 16:00:46 -04:00
18 changed files with 239 additions and 57 deletions

View File

@@ -1,19 +0,0 @@
#!/usr/bin/env bash
set -e
if [[ ! -d "/home/alice/.gitprojects/resumes" ]]; then
echo "Cannot find source directory; Did you move it?"
echo "(Looking for "/home/alice/.gitprojects/resumes")"
echo 'Cannot force reload with this script - use "direnv reload" manually and then try again'
exit 1
fi
# rebuild the cache forcefully
_nix_direnv_force_reload=1 direnv exec "/home/alice/.gitprojects/resumes" true
# Update the mtime for .envrc.
# This will cause direnv to reload again - but without re-building.
touch "/home/alice/.gitprojects/resumes/.envrc"
# Also update the timestamp of whatever profile_rc we have.
# This makes sure that we know we are up to date.
touch -r "/home/alice/.gitprojects/resumes/.envrc" "/home/alice/.gitprojects/resumes/.direnv"/*.rc

1
.gitattributes vendored Normal file
View File

@@ -0,0 +1 @@
*.pdf filter=lfs diff=lfs merge=lfs -text

View File

@@ -1,28 +1,30 @@
# Project Guidelines
## Code Style
- Primary source is `main.tex`; keep edits focused there unless build config changes are required.
- Primary source is `resume.tex`; keep edits focused there unless build config changes are required.
- Follow existing LaTeX macro style: reusable `\newcommand` helpers for resume blocks (e.g., `\resumeSubheading`, `\resumeEducation`, `\resumeItem`).
- Preserve compact spacing/layout conventions (`\vspace`, custom `\titleformat`, `tabular*` alignment) unless asked to redesign formatting.
- Keep package usage consistent with current preamble and avoid adding new packages unless required for a user request.
## Architecture
- This workspace is a single-document resume project.
- `main.tex` contains both template macros and resume content.
- Files like `main.aux`, `main.fdb_latexmk`, and `main.fls` are generated build artifacts, not source-of-truth.
- `resume.tex` contains both template macros and resume content.
- Files like `resume.aux`, `resume.fdb_latexmk`, and `resume.fls` are generated build artifacts, not source-of-truth.
- `glyphtounicode` is included for text extractability/ATS friendliness via `\pdfgentounicode=1`.
## Build and Test
- Build PDF (preferred): `latexmk -pdf main.tex`
- Alternative build: `pdflatex main.tex` (run multiple times if references/layout need settling)
- Preferred reproducible build: `nix build .#default` (outputs `result/Alice_Huston_Resume_Software_Engineer.pdf`)
- Local TeX build: `latexmk -pdf resume.tex`
- Alternative build: `pdflatex resume.tex` (run multiple times if references/layout need settling)
- Clean artifacts: `latexmk -c`
- Validate by checking successful compile and reviewing resulting `main.pdf` for layout overflow/line wrapping regressions.
- Validate by checking successful compile and reviewing resulting `resume.pdf` for layout overflow/line wrapping regressions.
## Project Conventions
- Use existing macros instead of ad-hoc formatting in section bodies.
- Keep section/list structure aligned with current pattern: `\resumeSubHeadingListStart` / `\resumeSubHeadingListEnd` and `\resumeItemListStart` / `\resumeItemListEnd`.
- Keep content concise and achievement-oriented; avoid large prose blocks that break one-page layout assumptions.
- Do not manually edit generated files (`*.aux`, `*.fdb_latexmk`, `*.fls`, etc.); `.gitignore` already treats these as build outputs.
- Prefer linking to existing guidance instead of duplicating it: see `.github/prompts/resume-review.prompt.md` for the structured review workflow.
## Integration Points
- External links are rendered with `hyperref` (`hidelinks`) and should stay valid/HTTPS.

View File

@@ -12,14 +12,14 @@ Review the candidate's resume by following the steps below in order.
### Step 1 — Read the LaTeX source
Read [main.tex](../main.tex) to understand the full content and structure of the resume: sections, roles, dates, technologies, bullet text, projects, certifications, and any formatting macros.
Read [resume.tex](../../resume.tex) to understand the full content and structure of the resume: sections, roles, dates, technologies, bullet text, projects, certifications, and any formatting macros.
### Step 2 — Build the PDF
Run the following command in the terminal to compile the resume:
```
latexmk -pdf main.tex
latexmk -pdf resume.tex
```
If the build produces errors, include them as a finding under **Formatting & Layout** (e.g., "Compile error on line X — fix before submission"). Continue the review using the LaTeX source regardless.
@@ -29,11 +29,11 @@ If the build produces errors, include them as a finding under **Formatting & Lay
Clean up any stale preview files, then convert the first page of the built PDF to a PNG and view it:
```
rm -f main-preview*.png
pdftoppm -r 150 -png main.pdf main-preview
rm -f resume-preview*.png || true # ignore if no previews exist
pdftoppm -r 150 -png resume.pdf resume-preview
```
Then use #tool:view_image to view `main-preview-1.png`.
Then use #tool:view_image to view `resume-preview-1.png`.
If this step fails for any reason (conversion error, tool unavailable, file not found), note it briefly — e.g., *"PDF preview unavailable — layout assessment based on LaTeX source only"* — and proceed. Do not retry or block on this step.

View File

@@ -5,7 +5,7 @@ on:
branches:
- main
paths:
- 'main.tex'
- 'resume.tex'
- '.github/workflows/build-resume.yaml'
workflow_dispatch:
@@ -14,10 +14,14 @@ jobs:
runs-on: ubuntu-latest
outputs:
current-date: ${{ steps.get-date.outputs.current-date }}
commit-sha: ${{ steps.get-sha.outputs.commit-sha }}
steps:
- name: Get current date
id: get-date
run: echo "current-date=$(date +'%Y-%m-%d')" >> $GITHUB_OUTPUT
- name: Get first 7 characters of commit SHA
id: get-sha
run: echo "commit-sha=$(echo $GITHUB_SHA | cut -c1-7)" >> $GITHUB_OUTPUT
build:
needs: date-fetch
@@ -45,7 +49,7 @@ jobs:
uses: softprops/action-gh-release@v1
with:
files: result/Alice_Huston_Resume_Software_Engineer.pdf
tag_name: alice-huston-resume-${{ needs.date-fetch.outputs.current-date }}-${{ github.sha }}
body: "Resume PDF built from commit ${{ github.sha }}"
tag_name: alice-huston-resume-${{ needs.date-fetch.outputs.current-date }}-${{ needs.date-fetch.outputs.commit-sha }}
body: "Resume PDF built from commit ${{ github.sha }} on ${{ needs.date-fetch.outputs.current-date }}."
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -0,0 +1,189 @@
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]" <github-actions[bot]@users.noreply.github.com>'
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

5
.gitignore vendored
View File

@@ -12,3 +12,8 @@
*.fls
*.synctex.gz
*.png
# all PDFs are generated, so ignore them all
*.pdf
result
.direnv

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -46,8 +46,8 @@
buildPhase = ''
runHook preBuild
latexmk -pdf -interaction=nonstopmode -halt-on-error main.tex
mv main.pdf ${resume_final_pdf}
latexmk -pdf -interaction=nonstopmode -halt-on-error resume.tex
mv resume.pdf ${resume_final_pdf}
runHook postBuild
'';

BIN
main.pdf

Binary file not shown.

View File

@@ -249,26 +249,26 @@ to improve reliability in navigation}
% Certifications moved to Technical Skills & Certifications section above
%\section{Projects}
%\resumeSubHeadingListStart
%\resumeProjectHeading{SwitchForward}{Jun. 2020 -- Aug. 2020}
%\resumeItemListStart
%\resumeItem{A \textbf{Python}-based Telegram bot to send stock
% updates for the Nintendo Switch during a supply shortage}
%\resumeItem{Used the Gmail API to receive and parse emails from a
% Google Group tracking Nintendo Switch stock}
%\resumeItem{Sent updates to a Telegram announcements channel used by
% \textbf{5-10} users}
%\resumeItemListEnd
%
%\resumeProjectHeading{Autonomous Robot}{Aug. 2018 -- Dec. 2018}
%\resumeItemListStart
%\resumeItem{An \textbf{Arduino}-based robot designed to navigate
% through a maze}
%\resumeItem{Primarily worked on pathplanning and control in a dynamic setting}
%\resumeItem{Implemented basic error-correction to account for drift
% during navigation}
%\resumeItemListEnd
\section{Projects}
\resumeSubHeadingListStart
\resumeProjectHeading{SwitchForward}{Jun. 2020 -- Aug. 2020}
\resumeItemListStart
\resumeItem{A \textbf{Python}-based Telegram bot to send stock
updates for the Nintendo Switch during a supply shortage}
\resumeItem{Used the Gmail API to receive and parse emails from a
Google Group tracking Nintendo Switch stock}
\resumeItem{Sent updates to a Telegram announcements channel used by
\textbf{5-10} users}
\resumeItemListEnd
\resumeProjectHeading{Autonomous Robot}{Aug. 2018 -- Dec. 2018}
\resumeItemListStart
\resumeItem{An \textbf{Arduino}-based robot designed to navigate
through a maze}
\resumeItem{Primarily worked on pathplanning and control in a dynamic setting}
\resumeItem{Implemented basic error-correction to account for drift
during navigation}
\resumeItemListEnd
% Removing this project as it is not as relevant to the software
% engineering positions I am applying for
@@ -285,6 +285,6 @@ to improve reliability in navigation}
% resulting data}
%\resumeItemListEnd
%\resumeSubHeadingListEnd
\resumeSubHeadingListEnd
\end{document}