This is a submission for the Hacktoberfest Weekend Challenge: Build for a Friend
What I Built
My friend Pranshu is job hunting. Like everyone, he's staring at a job post with twenty requirements and a two-page resume, wondering which line actually proves what. The AI tools he could use either rewrite everything with confident claims that aren't his, or hand back a "92% match" that explains nothing.
So I built ProofPrep, a resume coach with one rule: no claim without a quote.
- Add details: Upload a resume, paste the job post.
- Check the evidence: Each requirement becomes a card with the exact resume line behind it, highlighted. No line? The card says "no evidence found" (not "you can't do this", because a missing line is not a missing skill). He accepts, rejects, or adds context in his own words.
- *Improve the resume:. Rewrites use only facts he approved, new numbers or tools get flagged "Check this detail", and new bullets go where they fit, not into the Volunteering section. Export a clean PDF.
- Practice the interview: Questions come only from approved facts. Pick one bullet and get grilled on it from three angles, like an interviewer who actually read your resume.
No score. No hiring odds. Nobody gets a number to be scared of.
What Pranshu said:
Being in control of every edit to my resume, and getting interview prep built around my specific bullet points, gives me the confidence to stand behind my own work.
His feedback also reshaped the app: longer job posts, a Full Stack posting that exposed a bad evidence match (now fixed with per-requirement search), step-by-step guidance, and a spelling slip I'd rather not discuss ("practise").
Demo
Code
ProofPrep
Help a friend get shortlisted and interview-ready for one specific job, using only what their resume can actually prove. Everything runs on your own laptop through Ollama; no API keys, no cloud, no cost.
ProofPrep reads a resume and a job description, links each job requirement to a verbatim quote from the resume (or says plainly that it found none), lets the candidate accept, reject or add context to every suggestion, proposes resume edits grounded only in approved facts, exports the approved version as a PDF, and runs adaptive mock interviews built from the same approved facts.
It never produces a score, a match percentage or a hiring probability. A missing resume line is treated as "not shown", never as "can't do it".
Run it
Requirements: Node 22+, Ollama, ~6 GB of disk for two small models.
ollama pull qwen3:4b-instruct-2507-q4_K_M # evidence…How I Built It
Two small open models through Ollama, each doing the job it's actually good at:
- Qwen3 4B finds evidence and writes grounded rewrites.
- Gemma 3 4B writes interview questions, feedback and follow-ups.
I didn't plan two models. I started with Gemma for everything, then measured both on the same real resume and job post:
Gemma happily treated unrelated tech lines as proof of "collaboration" and made up four quotes. My app rejected all four. So Gemma got the job where a draft is fine (interview practice), and Qwen got the job where accuracy matters. (One resume, one run, pipeline tuned on it. A measurement, not a benchmark.)
The guardrails don't rely on the model behaving:
- JSON schemas stop the model skipping a requirement or citing a line it wasn't shown.
- Every "supported" verdict needs a verbatim quote, and the app checks it exists. A fake quote becomes "could not assess". A half-fake one is cut back to the real part.
- Rewrites can't add facts without a flag.
- A Mastra workflow runs the four human decision points with real suspend/resume. Close the tab, restart the server, and it picks up where it stopped.
Plus React + Vite + TypeScript, node:sqlite, pdf.js, and browser print-to-PDF. 26 mocked tests cover the software's guarantees; they say nothing about model accuracy, which is what the eval script is for.
Why Does Open Innovation Matter?
- A resume is personal, and it never leaves the laptop. Extraction, both models, storage and export all run locally, no external fonts or CDNs. After the one-time model download, it works with the Wi-Fi off. A closed API can't give me "nothing is sent anywhere".
- Free inference meant I could measure. I re-ran the pipeline over and over and compared two models on identical input. A metered API would have made me ration that.
- I could swap models per task. The best result came from not picking one model. Both are one ollama pull away, and env variables swap either.
- Where closed would win: raw judgment. A 4B model on a laptop is slower and less sharp than a frontier API, and a long job post takes a few minutes. So I built around it with schemas, quote checks and a human in the loop. (No fine-tuning here. The gains came from model choice and pipeline design.)
My Agent Session
This session is being continued from a previous conversation that ran out of context. The summary below covers the earlier portion of the conversation.
Summary:
1. Primary Request and Intent
Project: ProofPrep, Pranshu's Hacktoberfest 2026 DEV challenge entry ("Build for a Friend"; deadline Oct 5, 2026 12:29 PM IST). It is a local-first app that:
- links job-description requirements to verbatim resume quotes;
- lets the candidate accept, reject, or add context to each match;
- proposes grounded resume edits;
- exports a PDF;
- runs adaptive mock interviews.
Models: Qwen3 4B (qwen3:4b-instruct-2507-q4_K_M) for evidence analysis and tailoring, Gemma 3 4B for interview questions and feedback.
Constraints:
- ₹0 budget; Ollama only.
- Never invent qualifications or metrics.
- No ATS score or hiring probability.
- A missing resume line does not mean the candidate lacks the skill.
- Distinguish passing mocked tests from real model accuracy.
- Make edits and run checks directly instead of asking the user to copy patches.
Requests handled this session (all done, committed to the device):
- Friend-feedback round: JD limit, practise→practice, Full Stack evidence cross-check and pipeline fixes, simple UI with help and guides, disclaimers removed, premium UI with animations.
- The resume text inserted at the end of the Volunteering section (new bullets), improved PDF export template, and bullet-drill question quality.
- The model deciding where a new bullet goes, or which line to replace.
- A fix for random bold/large text in the PDF export.
CURRENT request (latest user message, implemented but not yet verified or committed): "now create me a very nice asthetic premium looking start page, like the home screen, which visually draws the judges. and also if you could add a dark and light mode toggle on the top left. and remove the private on this computer part next to the ready status, just keep the ready status. i dotn want anything which shows on the project that this is running locally."
2. Key Technical Concepts
- Ollama
/api/chatwith JSON-schemaformat. num_ctx is now 8192; per-call timeout 180s, total 900s. Pipelineevidence-review-v6. - Pipeline:
- Chunked JD requirement extraction (verbatim quotes, up to 40).
- Per-requirement resume search (schema
selectionSchemaFor([r.id], sourceIds)). - Per-requirement review (
reviewSchemaFor). -
verifiedQuote: contiguous match with 2+ words, or one 5+ letter term when the line has ≤14 words. If the full quote fails, salvage the longest contiguous fragment of 2+ words and warn.
-
LIMITS = {resume: 12000, jobDescription: 12000}(server andsrc/lib/api.ts). Server body limits 160000. - node:sqlite (DB migration
UPDATE applications SET stage='practice' WHERE stage='practise'); Mastra workflow with suspend/resume (zod resumeSchema strips unknown keys, so new fields must be added to the schema). - Tailoring:
-
ungroundedTermsflags new numbers/tools/names ("Check this detail", unchecked by default). - No-op rewrites are dropped.
- Shared
applyEdits(resume, accepted)is used by both the/versionsroute and the workflow's approve-edits step.
-
- Placement (
choosePlacement): the model picks a bullet ID from an enum withinsert_afterorreplace. Replace is downgraded if word overlap < 0.35. FallbackfallbackPlacementuses word overlap with bullet text plus entry name.bulletOptions(resume)lists content bullets (excluding "Built using" lines) with their entry and section. - Extraction (
extract.mjs): pdf.js lines, blank lines stripped for PDFs,joinWrappedmerges wrapped bullet lines (lowercase start, mid-phrase endings, digit continuation after an unfinished bullet). - Interview focus mode: three separate per-angle calls with a single-question schema
{question, probes}. Each call sees only the focus fact and previous questions ([...asked]copy), with overlap and repeat checks and a template fallback. - Print export:
src/lib/resumeHtml.ts(resumeToHtml,RESUME_CSS, internaljoinWrapped) renders name header, contact lines, section headings with rules, entry titles with right-aligned dates, bullets, skills rows, "Built using" tech lines, summary paragraphs, and split " • " runs (volunteering). - Frontend: React 19 + Vite 7 + TS, plain CSS with tokens, hash routing, animations that respect
prefers-reduced-motion, no external fonts/CDNs. Theme viadata-themeon<html>. - Operational:
- The commit tool can re-send cached files, so stage under a fresh
/mnt/user-data/outputs/<dir>/each time and verify withdevice_list_dir. - Device path base is
C:\Users\[user]\OneDrive\Documents\proofprep(Windows, backslashes). - There is no
device_bash; deletions are impossible, so the stalesrc\screens\Practise.tsxstays on the device and the user was told to delete it. - Playwright uses an explicit
executablePath. -
/tmp/e2e/restart.shrestarts fake-ollama (port 11997) and the server (port 3001).
- The commit tool can re-send cached files, so stage under a fresh
3. Files and Code Sections (all under [REDACTED]/proofprep, mirrored to the device)
Committed to device (r2–r5): server/analysis.mjs, analysis.test.mjs, index.mjs, db.mjs, tailor.mjs, interview.mjs, workflow.mjs, extract.mjs, src/App.tsx (older version), src/styles.css (older), src/components/Guide.tsx (older), src/lib/api.ts, src/lib/resumeHtml.ts, src/screens/{Applications,Inputs,ApplicationShell,Review,Tailor,Practice}.tsx, dist/index.html + assets (last committed: index-AELXCRA8.js, index-DI4i5nkp.css), README.md, HANDOFF.md. The last full device state corresponds to r5; round-4 changes below are NOT yet on the device.
Key code in server/tailor.mjs:
- bulletOptions(resume) returns [{id, text, entry, section}].
- choosePlacement({callModel, resume, text, bullets, signal}) returns {action, lineId, reason, by:'model'|'rules'}.
- applyEdits handles rewrites (keeping the bullet marker), placed items (insert after the chosen bullet, past wrapped continuation lines, or replace), and legacy additions with section/anchor via insertIntoSection.
- The /tailor route adds placement/placements to new-bullet proposals.
Current-round changes (uncommitted, built OK):
- src/App.tsx (rewritten):
- Hash routing: #/ → <Landing/>, #/applications → <Applications/>, #/new → <Applications newApp/>, #/app/:id/:tab → ApplicationShell.
- useTheme() stores pp-theme in localStorage (try/catch) and sets documentElement.dataset.theme plus the theme-color meta.
- Topbar order: theme-toggle button (sun/moon icon, left), brand link #/, spacer, status pill (Ready / Engine offline / Server unreachable / Checking…), an "Applications" ghost link when not on landing, and a "How it works" button.
- <HelpDrawer open onClose />, with no health prop.
- The topbar gets class on-landing (transparent) on the landing page.
- src/screens/Landing.tsx (new). Sections:
- Hero with pill "Evidence-first interview prep", headline "Walk into the interview knowing what your resume can prove." (gradient text), lead copy, CTAs "Get started" (#/new) and "See how it works" (scrolls to #how), and trust list.
- A floating product-preview stack (pv-main evidence card, pv-q interview question card, "Quote verified" and "Step 2 of 4" badges).
- 4-step cards, a 6-feature grid, a "paper" resume export showcase, a gradient CTA band, and a footer.
- useReveal() IntersectionObserver adds .in to .reveal elements.
- src/styles.css:
- Added the :root[data-theme="dark"] token set and new light tokens (--topbar --field --field-focus --mark --glow-a/b --info-line --info-ink --warn-line --warn-ink --bad-line --bad-ink --diff-add --diff-del --card-edge, color-scheme).
- Replaced hard-coded colors with tokens.
- Added .df/.df-add/.df-del, a select style and .theme-toggle.
- Appended the landing CSS block (.landing, .lp-bg orbs and grid, .lp-hero, .lp-copy h1, .grad-text, .pv-*, .lp-steps/.lp-step, .lp-grid/.lp-feature, .lp-showcase, .paper*, .lp-cta, .lp-foot, responsive and reduced-motion rules, .reveal).
- src/components/Guide.tsx:
- Icon union extended with sun/moon/lock/pdf/save.
- HelpDrawer signature is now ({ open, onClose }: { open: boolean; onClose: () => void; health?: unknown }).
- FAQ item "Is my information shared?" replaces "Where is my data?".
- The "Under the hood" section is removed.
- Practice step text: "Sessions are saved automatically."
- src/screens/Applications.tsx:
- The big hero is replaced by a compact page-head (title, "Home" link, "New application" / "Start your first application" button).
- Cancel and links use #/applications.
- The how-cards still show when the list is empty.
- ApplicationShell.tsx, Tailor.tsx, Practice.tsx: go('#/') → go('#/applications'), href="#/" → href="#/applications".
- ApplicationShell.tsx banner: "The analysis engine isn’t running yet. Start it and this button will unlock."
- Tailor.tsx: diff spans use className={w.k === 'same' ? '' :df df-${w.k}}; the inline select style was removed.
- index.html: added <meta name="theme-color" content="#f6f7f4" /> and an inline pre-paint script that sets data-theme from localStorage or prefers-color-scheme.
- Remaining intentional mentions: the Practice screen error banner "The interview model isn’t installed yet. Run ollama pull …" (error state only), and the Inputs text "The AI engine isn’t running yet; you can save now and continue later." (error state).
Test state: server/analysis.test.mjs has 26 passing tests as of the last run (the landing and theme changes touch only the frontend). tsc passed and npm run build succeeded after the landing work, producing dist/assets/index-C1Xdu2hq.css and index-vzBLN0xC.js.
4. Errors and fixes
- Playwright browser not found: use
executablePath: '/opt/pw-browsers/chromium-1194/chrome-linux/chrome'. -
getByRole('button', {name:/How it works/})failed becausearia-label="Open help"overrides the name: usegetByLabel('Open help'). - Re-ran E2E when the DB wasn't fresh:
restart.shremoves/tmp/e2e/test.sqlite*. - Fake model hard-coded to an old JD: rewrote its requirements, selection and review responses to be JD- and schema-aware.
- Review test expected old behaviours: updated tests (the 3-word rule changed, call counts changed from 5 to 7, the extra-keys test changed).
-
previousQuestionsmutation made the interview test see [3,3,3]: pass a copy[...asked]. - New bullets still landed in Volunteering via the UI: the Mastra workflow had its own duplicate apply logic. Refactored to a shared
applyEditsand extended the zod resume schema withsection,anchorand thenplacement. - Placement was stripped by zod: added
placement: z.object({action: z.enum([...]), lineId: z.string()}).nullable().optional()to the schema. - PDF export showed bold/large wrapped fragments: added
joinWrappedand the sentence-end fragment rule to resumeHtml.ts. - First fallback test expectation (S8) was wrong; corrected to S7.
- Edit-tool "file changed on disk" notices were from my own edits and were not a problem.
5. Problem Solving
Solved and committed: the pipeline limits and false negatives (mock-verified only), rename, UI redesign, placement, PDF template, drill questions, and wrapped-line merging at extraction. Not verifiable from the cloud: real Qwen/Gemma accuracy on the new search and placement, and the real drill output; the user must rerun with the real models and re-upload the PDF so extraction merges wrapped lines. Ongoing: verification and delivery of the landing page, dark mode and de-"local" copy (see sections 7 and 8).
6. All user messages
- (Earlier, summarized) Handoff-continuation request; "what do u need me to do now"; eval outputs; Gemma prize screenshot and "wait a second what is qwen?…"; "lets go with option 2. i cant miss the prized category…"; storage complaint about gemma3n:e4b; pasted eval outputs; "whats the final decision then?…"; honest write-up angle plus UI/architecture question; stack choices (React+Vite+TS, Mastra yes, print-to-PDF); DB questions; then the six-item friend-feedback message (JD limit; practise→practice; cross-check Full Stack evidence; easier UX with instructions; remove local/model disclaimers; premium UI with animations).
- "the UI is better now. there is somthing more to work on: 1. i have attached the screenshot. it basically added the suggested edits at the end of the resume in the which has the volunteering section which does not make any sense 2. the resume template which is used when the user clicks on "export pdf" is not good looking at all like can you make it better in layout wise and format wise. there is no formatting, no spacing. so improve that. 3. the bullet point specific practice, the first question is relatable to the correct bullet point but the other 2 questions are just repeating and also not relatable."
- (Two screenshots) "if a new line is added as an edit, then i just adds at the last of the section, which is not good, can we do something where the model decides automatically where in the resume the line would look nice and appealing or replacing a line with the suggested edit, like think on its own?"
- (Screenshot) "i love the foprmaatting of the resume but as u can see it is randomly highlighting words and increasing font sizes creating confusion between project titles and normal text. fix this"
- (Screenshot of the home screen) "now create me a very nice asthetic premium looking start page, like the home screen, which visually draws the judges. and also if you could add a dark and light mode toggle on the top left. and remove the private on this computer part next to the ready status, just keep the ready status. i dotn want anything which shows on the project that this is running locally."
7. Pending Tasks
(All for the latest request.)
- Visual verification: restart /tmp/e2e/restart.sh, write a Playwright script that screenshots the landing page in light and dark, the #/applications and #/new pages, an inner page in dark mode (review/tailor), and the help drawer; check the toggle works and persists, and no console errors.
- Fix any layout or dark-mode contrast issues found (e.g., banners, chips, stepper, nextbar, drawer, textareas, diffs, .guide/.hero unchanged gradients).
- Grep the UI for leftover "local/computer/private/Ollama" text (the error-state mentions are the only intended ones) and confirm the status pill shows only "Ready".
- Run node --test server/analysis.test.mjs (expect 26 pass) and npx tsc --noEmit -p .; npm run build.
- Stage changed files under a fresh /mnt/user-data/outputs/r6/ and device_commit_files to C:\Users\[user]\OneDrive\Documents\proofprep\…:
- index.html
- src/App.tsx
- src/styles.css
- src/components/Guide.tsx
- src/screens/Landing.tsx (new)
- Applications.tsx
- ApplicationShell.tsx
- Tailor.tsx
- Practice.tsx
- dist/index.html
- dist/assets/index-vzBLN0xC.js and index-C1Xdu2hq.css (or whatever the final build names are)
Verify sizes with device_list_dir.
- Then tell the user, concisely, what changed (landing page, theme toggle top-left, status shows only "Ready", local mentions removed), what couldn't be verified, and to restart with node server\index.mjs. Optionally update the README layout/limits notes.
8. Current Work
Immediately before this summary request I had finished writing and building the landing page, theme toggle and copy changes: npx tsc --noEmit -p . passed and npm run build produced dist/assets/index-C1Xdu2hq.css (29.95 kB) and dist/assets/index-vzBLN0xC.js (284.47 kB). I had sent the user a progress message ("Building the new landing page, dark/light toggle (top left) and removing every 'runs on this computer' mention. Writing the page styles now, then I'll screenshot both themes."). The next step was screenshot verification in both themes.
9. Optional Next Step
Continue exactly where I left off: verify the new landing page and dark mode visually. Restart the stand-in stack (bash /tmp/e2e/restart.sh), then run a Playwright script (explicit chromium executablePath) that screenshots the landing page (#/) in light and dark, the applications and inner pages in dark, and the help drawer; fix any contrast or layout problems; run tests, tsc and build; stage under a fresh dir (r6); commit to the device; verify sizes; and report to the user. This follows the user's latest request: "now create me a very nice asthetic premium looking start page… add a dark and light mode toggle on the top left… remove the private on this computer part next to the ready status, just keep the ready status. i dotn want anything which shows on the project that this is running locally."
If you need specific details from before compaction (like exact code snippets, error messages, or content you generated), read the full transcript at: /root/.claude/projects/-home-claude/d18c25d3-a4ac-5dcb-ab3f-1fa309353fde.jsonl
Continue the conversation from where it left off without asking the user any further questions. Resume directly — do not acknowledge the summary, do not recap what was happening, do not preface with "I'll continue" or similar. Pick up the last task as if the break never happened.
$ bash /tmp/e2e/restart.sh >/dev/null 2>&1; sleep 2; cat > /tmp/e2e/shots.mjs <<'EOF'
import { chromium } from 'playwright';
const b = await chromium.launch({ executablePath: '/opt/pw-browsers/chromium-1194/chrome-linux/chrome' });
const errs=[];
for (const theme of ['light','dark']) {
const ctx = await b.newContext({ viewport:{width:1360,height:860}, colorScheme: theme });
const p = await ctx.newPage(); p.on('console',m=>m.type()==='error'&&errs.push(m.text())); p.on('pageerror',e=>errs.push(String(e)));
await p.goto('http://localhost:3001/#/'); await p.waitForTimeout(1500);
await p.screenshot({path:`/tmp/e2e/land-${theme}.png`});
await p.evaluate(()=>window.scrollTo(0,1000)); await p.waitForTimeout(900);
await p.screenshot({path:`/tmp/e2e/land2-${theme}.png`});
await p.goto('http://localhost:3001/#/applications'); await p.waitForTimeout(800);
await p.screenshot({path:`/tmp/e2e/apps-${theme}.png`});
console.log(theme, await p.locator('.status').innerText());
}
const ctx = await b.newContext({ viewport:{width:1360,height:860}, colorScheme:'light' });
const p = await ctx.newPage(); await p.goto('http://localhost:3001/#/'); await p.waitForTimeout(800);
await p.getByLabel(/Switch to dark/).click(); await p.waitForTimeout(400);
console.log('theme after click', await p.evaluate(()=>document.documentElement.dataset.theme));
await p.reload(); await p.waitForTimeout(500);
console.log('persisted', await p.evaluate(()=>document.documentElement.dataset.theme));
await p.getByLabel('Open help').click(); await p.waitForTimeout(400);
await p.screenshot({path:'/tmp/e2e/help-dark.png'});
console.log('errors', errs);
await b.close();
EOF
cp /tmp/e2e/shots.mjs ./shots.tmp.mjs && node shots.tmp.mjs; rm shots.tmp.mjs
node:internal/modules/run_main:123
triggerUncaughtException(
^
Error [ERR_MODULE_NOT_FOUND]: Cannot find package 'playwright' imported from /home/claude/proofprep/shots.tmp.mjs
Did you mean to import "playwright/index.js"?
at Object.getPackageJSONURL (node:internal/modules/package_json_reader:314:9)
at packageResolve (node:internal/modules/esm/resolve:767:81)
at moduleResolve (node:internal/modules/esm/resolve:853:18)
at defaultResolve (node:internal/modules/esm/resolve:983:11)
at #cachedDefaultResolve (node:internal/modules/esm/loader:731:20)
at ModuleLoader.resolve (node:internal/modules/esm/loader:708:38)
at ModuleLoader.getModuleJobForImport (node:internal/modules/esm/loader:310:38)
at ModuleJob._link (node:internal/modules/esm/module_job:182:49) {
code: 'ERR_MODULE_NOT_FOUND'
}
Node.js v22.22.0
$ cd /tmp/e2e && ls; ls node_modules 2>/dev/null | head; npm ls -g 2>/dev/null | grep -i playwright
1-empty.png
10-print.png
11-tailor-wf.png
12-done-wf.png
2-inputs.png
3-review.png
4-decided.png
5-list.png
6-practise-setup.png
7-practise-feedback.png
8-tailor.png
9-version.png
fake-ollama.mjs
fake.log
node_modules
package-lock.json
package.json
pdftest.mjs
peek.mjs
restart.sh
resume-export.pdf
resume-out.pdf
resume-out.png
resume.html
resumeHtml.mjs
server.log
shot.mjs
shot2.mjs
shot3.mjs
shot4.mjs
shots.mjs
shotv2.mjs
shotv3.mjs
test.sqlite
test.sqlite-shm
test.sqlite-wal
v2-1-home.png
v2-2-inputs.png
v2-3-working.png
v2-4-review.png
v2-5-decided.png
v2-6-tailor.png
v2-7-suggest.png
v2-8-help.png
v3-1-suggest.png
v3-2-version.png
v3-3-drill.png
playwright
playwright-core
+-- @playwright/mcp@0.0.68
+-- playwright@1.56.0 -> ./../../../../opt/npm-tools/node_modules/playwright
Shell cwd was reset to /home/claude
$ cd /tmp/e2e && node shots.mjs
light Ready
dark Ready
theme after click dark
persisted dark
errors []
Shell cwd was reset to /home/claude
/tmp/e2e/land-light.png
[screenshot omitted]
/tmp/e2e/land-dark.png
[screenshot omitted]
/tmp/e2e/land2-dark.png
[screenshot omitted]
/tmp/e2e/apps-dark.png
[screenshot omitted]
$ cd /home/claude/proofprep && grep -n "on-landing\|\.topbar" src/styles.css | head -20
30:html { transition: background-color .3s; } body, .card, .topbar, .btn, textarea, input, .evidence, .stat, .stepper li, .drawer { transition-property: background-color, border-color, color, box-shadow, transform; transition-duration: .25s; }
58:.topbar { position: sticky; top: 0; z-index: 20; background: var(--topbar); backdrop-filter: saturate(1.4) blur(14px); border-bottom: 1px solid rgba(207, 213, 200, .7); }
59:.topbar-inner { max-width: 1120px; margin: 0 auto; padding: 12px 24px; display: flex; align-items: center; gap: 14px; }
245:.topbar.on-landing { background: transparent; backdrop-filter: none; border-bottom-color: transparent; }
Quick fix: the landing topbar is transparent, so content slides under it when scrolling. I'll make it solid once the page scrolls.
$ python3 - <<'EOF'
p='src/styles.css'; s=open(p).read()
s=s.replace(".topbar.on-landing { background: transparent; backdrop-filter: none; border-bottom-color: transparent; }",".topbar.on-landing:not(.scrolled) { background: transparent; backdrop-filter: none; border-bottom-color: transparent; }")
open(p,'w').write(s)
p='src/App.tsx'; s=open(p).read()
s=s.replace(" const [help, setHelp] = useState(false);\n"," const [help, setHelp] = useState(false);\n const [scrolled, setScrolled] = useState(false);\n useEffect(() => { const on = () => setScrolled(window.scrollY > 24); on(); window.addEventListener('scroll', on, { passive: true }); return () => window.removeEventListener('scroll', on); }, []);\n",1)
s=s.replace("`topbar ${landing ? 'on-landing' : ''}`","`topbar ${landing ? 'on-landing' : ''} ${scrolled ? 'scrolled' : ''}`")
open(p,'w').write(s)
EOF
npx tsc --noEmit -p . && npm run build 2>&1 | tail -4 && node --test server/analysis.test.mjs 2>&1 | grep -E "^# (pass|fail)"; bash /tmp/e2e/restart.sh >/dev/null 2>&1; sleep 2; cd /tmp/e2e && node shots.mjs
dist/index.html 0.96 kB │ gzip: 0.58 kB
dist/assets/index-DdfmYWHq.css 29.97 kB │ gzip: 7.29 kB
dist/assets/index-CtBvIRZT.js 284.67 kB │ gzip: 88.51 kB
✓ built in 3.49s
# pass 26
# fail 0
light Ready
dark Ready
theme after click dark
persisted dark
errors []
Shell cwd was reset to /home/claude
/tmp/e2e/land2-light.png
[screenshot omitted]
$ cd /home/claude/proofprep && grep -rniE "local|this computer|private|ollama" src --include=*.tsx | grep -v "localStorage" | head; rm -rf /mnt/user-data/outputs/r6; mkdir -p /mnt/user-data/outputs/r6/src/screens /mnt/user-data/outputs/r6/src/components /mnt/user-data/outputs/r6/dist/assets; for f in index.html src/App.tsx src/styles.css src/components/Guide.tsx src/screens/Landing.tsx src/screens/Applications.tsx src/screens/ApplicationShell.tsx src/screens/Tailor.tsx src/screens/Practice.tsx dist/index.html dist/assets/index-DdfmYWHq.css dist/assets/index-CtBvIRZT.js; do cp $f /mnt/user-data/outputs/r6/$f; done; ls -R /mnt/user-data/outputs/r6 | head -30
src/App.tsx:40: const tick = () => api.health().then(h => alive && setHealth(h)).catch(() => alive && setHealth({ backend: 'unreachable', ollama: 'unavailable', roles: [] }));
src/App.tsx:46: const ready = health?.ollama === 'connected';
src/screens/Tailor.tsx:62: <div><h2>Your improved resume</h2><p className="small muted">Saved {new Date(preview.created_at).toLocaleString()} · {preview.note}. Your original is kept.</p></div>
src/screens/Tailor.tsx:66: {(app.resumeVersions?.length ?? 0) > 1 && <details style={{ marginTop: 8 }}><summary>Earlier versions</summary><div className="list" style={{ marginTop: 6 }}>{app.resumeVersions!.map(v => <div key={v.id} className="row between small"><span>{new Date(v.created_at).toLocaleString()} · {v.note}</span><button className="btn small" onClick={() => setPreview(v)}>View</button></div>)}</div></details>}
src/screens/Tailor.tsx:72: <button className="btn primary" disabled={busy || !decided || health?.ollama !== 'connected'} onClick={propose}>{busy && !proposals ? <><span className="spinner" /> Writing suggestions…</> : proposals ? 'Try again' : 'Suggest edits'}</button>
src/screens/Practice.tsx:90: {model && !model.available && <div className="banner warn" style={{ marginTop: 12 }}>The interview model isn’t installed yet. Run <span className="kbd">ollama pull {model.model}</span> and refresh.</div>}
src/screens/Practice.tsx:109: {past.map(s => <div key={s.id} className="row between"><span className="small">{new Date(s.created_at).toLocaleString()} · {s.turns} question{s.turns === 1 ? '' : 's'}{s.focus ? ' · focused' : ''}</span><button className="btn small" onClick={() => sessionApi.get(s.id).then(setSession)}>Open</button></div>)}
src/screens/Applications.tsx:42: <div style={{ flex: 1 }}><div className="title">{a.title}</div><div className="meta">{STAGE_LABEL[a.stage]} · updated {new Date(a.updated_at).toLocaleString()}</div></div>
src/screens/ApplicationShell.tsx:63: <button className="btn primary big" disabled={health?.ollama !== 'connected'} onClick={analyze}>{app.analysis ? 'Start over' : 'Find my evidence'} <Icon name="arrow" size={18} /></button>
src/screens/ApplicationShell.tsx:66: {health?.ollama !== 'connected' && !analyzing && <div className="banner warn" style={{ marginTop: 12 }}>The analysis engine isn’t running yet. Start it and this button will unlock.</div>}
/mnt/user-data/outputs/r6:
dist
index.html
src
/mnt/user-data/outputs/r6/dist:
assets
index.html
/mnt/user-data/outputs/r6/dist/assets:
index-CtBvIRZT.js
index-DdfmYWHq.css
/mnt/user-data/outputs/r6/src:
App.tsx
components
screens
styles.css
/mnt/user-data/outputs/r6/src/components:
Guide.tsx
/mnt/user-data/outputs/r6/src/screens:
ApplicationShell.tsx
Applications.tsx
Landing.tsx
Practice.tsx
Tailor.tsx
Header is fixed. Committing to the device.
{"files":[{"devicePath":"C:\\Users\\[user]\\OneDrive\\Documents\\proofprep\\index.html","stagedPath":"/mnt/user-data/outputs/r6/index.html"},{"devicePath":"C:\\Users\\[user]\\OneDrive\\Documents\\proo...
{
"written": [
"C:Users[user]Documents\\proofprep\\index.html",
"C:Users[user]Documents\\proofprep\\src\\App.tsx",
"C:Users[user]Documents\\proofprep\\src\\styles.css",
"C:Users[user]Documents\\proofprep\\src\\components\\Guide.tsx",
"C:Users[user]Documents\\proofprep\\src\\screens\\Landing.tsx",
"C:Users[user]Documents\\proofprep\\src\\screens\\Applications.tsx",
"C:Users[user]Documents\\proofprep\\src\\screens\\ApplicationShell.tsx",
"C:Users[user]Documents\\proofprep\\src\\screens\\Tailor.tsx",
"C:Users[user]Documents\\proofprep\\src\\screens\\Practice.tsx",
"C:Users[user]Documents\\proofprep\\dist\\index.html",
"C:Users[user]Documents\\proofprep\\dist\\assets\\index-DdfmYWHq.css",
"C:Users[user]Documents\\proofprep\\dist\\assets\\index-CtBvIRZT.js"
],
"rejected": [
]
}
{
"path": "C:\\Users\\[user]\\OneDrive\\Documents\\proofprep\\dist\\assets"
}
{
"entries": [
{
"name": "index-AELXCRA8.js",
"type": "file",
"size": 275784,
"mtimeMs": 1791127697281
},
{
"name": "index-BBGxOmYZ.js",
"type": "file",
"size": 274989,
"mtimeMs": 1791126187494
},
{
"name": "index-BeeFCv8x.css",
"type": "file",
"size": 8063,
"mtimeMs": 1791119902999
},
{
"name": "index-CtBvIRZT.js",
"type": "file",
"size": 284667,
"mtimeMs": 1791128190976
},
{
"name": "index-Cv7tOCA4.js",
"type": "file",
"size": 243238,
"mtimeMs": 1791119108988
},
{
"name": "index-D5p6C__x.js",
"type": "file",
"size": 250465,
"mtimeMs": 1791119416337
},
{
"name": "index-dc2utrbl.js",
"type": "file",
"size": 258657,
"mtimeMs": 1791119606840
},
{
"name": "index-DdfmYWHq.css",
"type": "file",
"size": 29966,
"mtimeMs": 1791128190384
},
{
"name": "index-DfyPOuf7.js",
"type": "file",
"size": 261302,
"mtimeMs": 1791119904288
},
{
"name": "index-DI4i5nkp.css",
"type": "file",
"size": 18784,
"mtimeMs": 1791123738865
},
{
"name": "index-gVTMbngN.js",
"type": "file",
"size": 273304,
"mtimeMs": 1791125646181
},
{
"name": "index-Il7CKm3s.js",
"type": "file",
"size": 269033,
"mtimeMs": 1791123739507
}
]
}
The new start page, the dark/light toggle and the "Ready"-only status are all in your project folder. I checked them in headless Chromium against a stand-in for the AI engine, not your real models. There were no console errors, and the 26 server tests still pass.
- Start page: the app now opens on a new home page with a headline, "Get started" and "See how it works" buttons, and floating preview cards of an evidence match and an interview question. Below that are a four-step section, six feature cards, a resume-export showcase and a closing call to action. It animates in and respects reduced-motion settings. "Applications" is now a separate page, and "Home" and the logo return to the start page.
- Theme toggle: a sun/moon button sits at the top left, before the logo. It remembers your choice and defaults to your system setting. I checked that it persists after a reload. The whole app follows the theme, including the applications list, the help drawer and the diffs.
- Status pill: it now just says "Ready", with no "private on this computer". I removed the other "runs locally" wording from the help text and banners too. The only mentions left are error messages when the AI engine is off or a model isn't installed, such as "run ollama pull…".
I screenshotted the start page and the applications list in both themes, plus the help drawer in dark. I did not screenshot the review, tailor and practice pages in dark mode. They use the same theme colours, but look through them once.
To see it, close the old server and run node server\index.mjs again, then hard-refresh. The old src\screens\Practise.tsx is still there and still needs deleting by hand.
yes i love the design, the colors and the project is alos working fine. now lets think about the przied categories what about that
{
"path": "/areas/proofprep.md"
}
[updated: 2026-10-04T13:21:50.781822+00:00] [size: 851 of 49152 bytes — 48301 free] [version: d5a85a65bba9] (pass as if_version on your next write or edit of this path)
---
name: proofprep
description: ProofPrep — Pranshu's Hacktoberfest 2026 "Build for a Friend" app (resume/JD evidence matching, local inference); read when ProofPrep or the Hacktoberfest submission comes up
sources: [cowork]
aliases: [ProofPrep, Hacktoberfest project]
---
- [stated] Building ProofPrep for Hacktoberfest 2026's "Build for a Friend" challenge; aiming for the "Best Use of Gemma" prize category and does not want to miss it
- [stated] Decided on a two-model split: Qwen for evidence judging, Gemma for interview practice; write-up angle is "measured Gemma, found where it's reliable, designed around it"
- [stated] Chose React + Vite + TypeScript frontend, Mastra workflow included, browser print-to-PDF export
- [stated] Constraint: ₹0 budget, local Ollama inference only; limited disk space for extra model downloads
FINAL WRITE
{
"query": "select:WebSearch,WebFetch",
"max_results": 2
}
{
"query": "DEV Hacktoberfest 2026 challenge \"Build for a Friend\" prize categories Gemma"
}
Web search results for query: "DEV Hacktoberfest 2026 challenge "Build for a Friend" prize categories Gemma"
Links: [{"title":"Hacktoberfest Weekend Challenge: Build for a Friend - DEV Challenge — DEV Community","url":"https://dev.to/challenges/hacktoberfest-weekend-2026-10-01"},{"title":"Join the Hacktoberfest Weekend Challenge: Build for a Friend! $2,450 in Prizes Across 17 Winners. Submissions Due October 5 at 6:59 AM UTC. - DEV Community","url":"https://dev.to/devteam/join-the-hacktoberfest-weekend-challenge-build-for-a-friend-2450-in-prizes-across-17-winners-1aj5"},{"title":"Hacktoberfest 2026 Challenge - DEV Community","url":"https://dev.to/t/hf26challenge"},{"title":"20 Hacktoberfest Ideas That Wins You TheWeekend Challenge - DEV Community","url":"https://dev.to/unicodeveloper/20-hacktoberfest-ideas-that-wins-you-theweekend-challenge-4m5m"},{"title":"GitHub - rcortez056-spec/hacktoberfest-2026-build-for-a-friend: Privacy-first local agent workforce and schema specifications for Hacktoberfest 2026 · GitHub","url":"https://github.com/rcortez056-spec/hacktoberfest-2026-build-for-a-friend"},{"title":"I built a local Gemma 3 bot to help my friend remember her iron tablets - DEV Community","url":"https://dev.to/sanyam26362/i-built-a-local-gemma-3-bot-to-help-my-friend-remember-her-iron-tablets-5677"},{"title":"My Friend Answers the Same 5 Questions Every Event, So I Built a Bot That Won't Guess - DEV Community","url":"https://dev.to/ghanshyam_jha/my-friend-answers-the-same-5-questions-every-event-so-i-built-a-bot-that-wont-guess-bh6"},{"title":"Buddy: A Private AI Companion Built for a Friend with Local Gemma - DEV Community","url":"https://dev.to/himanshurane/buddy-a-private-ai-companion-built-for-a-friend-with-local-gemma-1pj4"},{"title":"Hacktoberfest 2026 is here - DEV Community","url":"https://dev.to/vashii17/hacktoberfest-2026-is-here-1afa"},{"title":"DeushChat - A German Friend - DEV Community","url":"https://dev.to/khizerans04/deushchat-a-german-friend-5pm"}]
REMINDER: You MUST include the sources above in your response to the user using markdown hyperlinks.
{"url":"https://dev.to/challenges/hacktoberfest-weekend-2026-10-01","prompt":"List every prize category with amounts, number of winners, eligibility/judging criteria, required submission format/templa...
# Hacktoberfest Weekend Challenge: Prize Categories
## Overall Prize
- **Amount:** $250 USD + DEV++ membership + exclusive winner badge
- **Winners:** 1
- **Eligibility:** Open to all valid submissions
- **Judging Criteria:** Writing Quality (weighted most heavily), Relevance to Prompt/Theme, Creativity, Technical Execution
- **Deadline:** October 5, 2026, 6:59 AM UTC
## Featured Categories ($200 each)
### Best Use of Render
- **Amount:** $200 USD + exclusive badge
- **Winners:** 1
- **Eligibility:** "Use Render as your project's AI runtime, to host an agent's front end, or to run Hermes or OpenClaw"
- **Judging Criteria:** Use of partner technology + standard criteria
### Best Use of TabPFN
- **Amount:** $200 USD + exclusive badge
- **Winners:** 1
- **Eligibility:** "Use TabPFN...to forecast, predict, classify, or spot anomalies from historical data"
- **Judging Criteria:** Use of partner technology + standard criteria
### Best Use of Tinker
- **Amount:** $200 USD + exclusive badge
- **Winners:** 1
- **Eligibility:** "Use Thinking Machines' Tinker to fine-tune a model...and show a clear improvement"
- **Judging Criteria:** Use of partner technology + standard criteria
### Best Use of Arduino
- **Amount:** $200 USD + exclusive badge
- **Winners:** 1
- **Eligibility:** "Anyone building with an Arduino UNO Q"
- **Judging Criteria:** Use of partner technology + standard criteria
### Best Use of DigitalOcean
- **Amount:** $200 USD + exclusive badge
- **Winners:** 1
- **Eligibility:** "Build or deploy your project on DigitalOcean"
- **Judging Criteria:** Use of partner technology + standard criteria
### Best Use of Gemma
- **Amount:** $200 USD + exclusive badge
- **Winners:** 1
- **Eligibility:** "Use Gemma, Google's open-weight model"
- **Judging Criteria:** Use of partner technology + standard criteria
## Partner Categories ($100 each)
### Best Use of Backboard
- **Amount:** $100 USD + exclusive badge
- **Winners:** 1
- **Eligibility:** "Build with R-CLI...compare open-weight models...or give an open-source project's assistant memory and RAG"
### Best Use of ElevenLabs
- **Amount:** $100 USD + exclusive badge
- **Winners:** 1
- **Eligibility:** "Give an open-source agent a voice, transcribe audio...or generate narration"
### Best Use of Entire
- **Amount:** $100 USD + exclusive badge
- **Winners:** 1
- **Eligibility:** "Share the agent sessions...or search past agent work"
### Best Use of GitHub Copilot
- **Amount:** $100 USD + exclusive badge
- **Winners:** 1
- **Eligibility:** "Build with Copilot's coding agent...automate your project...or review contributors' PRs"
### Best Use of Mastra
- **Amount:** $100 USD + exclusive badge
- **Winners:** 1
- **Eligibility:** "Orchestrate an agent...add memory and tools...or build a workflow"
### Best Use of MongoDB Atlas
- **Amount:** $100 USD + exclusive badge
- **Winners:** 1
- **Eligibility:** "Use Atlas as your data layer"
### Best Use of Sentry Agent Tracing
- **Amount:** $100 USD + exclusive badge
- **Winners:** 1
- **Eligibility:** "Show your agent's work...include traces or screenshots"
### Best Use of SerpApi
- **Amount:** $100 USD + exclusive badge
- **Winners:** 1
- **Eligibility:** "Give an agent live web search...ground a RAG app...or track news"
### Best Use of Temporal
- **Amount:** $100 USD + exclusive badge
- **Winners:** 1
- **Eligibility:** "Make your agent durable...wrap it in a Temporal workflow"
### Best Use of Tiger Data
- **Amount:** $100 USD + exclusive badge
- **Winners:** 1
- **Eligibility:** "Store embeddings...run hybrid search...or let an agent manage a database"
## Submission Requirements
- Use provided template with tags: #devchallenge, #weekendchallenge, #hf26challenge
- Include: project description, demo, code, technical approach, open innovation rationale
- Optional: DevRelay agent session
- Team submissions: list member DEV handles; one post per team
## Completion Badge
- **Eligibility:** All valid submissions
- **Requirement:** Meet submission format and deadline
$ date -u; TZ=Asia/Kolkata date
Sun Oct 4 15:42:58 UTC 2026
Sun Oct 4 21:12:58 IST 2026
I checked the official challenge page. It's 21:13 IST now and the deadline is 12:29 PM IST tomorrow, so you have about 15 hours.
Categories ProofPrep can enter
- Best Use of Gemma ($200). This is your main target. The rule is just "use Gemma, Google's open-weight model", and Gemma 3 writes your interview questions and feedback. It is judged on partner-technology use plus the standard criteria. Your honest angle fits well: you measured where Gemma is reliable and gave it only the jobs it handles well.
- Best Use of Mastra ($100). You use a real Mastra workflow with suspend and resume, so the human approves before the workflow continues. That matches "build a workflow". It costs almost nothing extra: one paragraph in the write-up plus a screenshot of the workflow.
- Overall ($250). Writing quality is weighted most heavily, then relevance, creativity and technical execution. The honest, measured write-up is your best chance here, and the new design helps with the screenshots.
Categories I'd skip
- ElevenLabs (voice) and Backboard (compare open-weight models) sound close, but they need those partners' tools. You'd have to build something new tonight, which isn't worth the risk.
- Sentry is possible if you show agent traces. It's a stretch, so only try it if you have time left.
- Render, DigitalOcean, TabPFN, Tinker, Arduino and the rest don't fit.
What I'd do tonight
- Pick one primary category in the post. The submission template asks for a "technical approach", so lead with Gemma. Mention Mastra in its own short section.
- Put your own numbers in the write-up. Include your Gemma versus Qwen results, why you split the work, and what you tested on the real models versus the mocks. I only verified the pipeline against a stand-in model, so don't claim real-model accuracy I haven't seen.
- Run one real end-to-end pass with your actual resume and a real job post. Use that for the demo video and screenshots. If the real output has a flaw, your write-up should say so.
-
Use the exact tags. They are
#devchallenge,#weekendchallengeand#hf26challenge, with the template sections, code link and demo. - Submit by about 9 AM IST to leave a buffer.
I don't know whether one post can win several categories at once. The page doesn't say, so check the rules or ask the DEV team before counting on it.
Want me to draft the post (Gemma-first, with a Mastra section), or run through the demo and screenshot plan first?
Sources: Hacktoberfest Weekend Challenge: Build for a Friend
whats sentry and how long it will take to integrate, like tell me what would sentry do in this project?
{
"query": "Sentry AI agent monitoring Node.js tracing Vercel AI SDK custom gen_ai spans setup"
}
Web search results for query: "Sentry AI agent monitoring Node.js tracing Vercel AI SDK custom gen_ai spans setup"
Links: [{"title":"Set Up Agent Tracing","url":"https://docs.sentry.io/platforms/javascript/guides/node/agent-tracing/"},{"title":"Instrument AI Agents","url":"https://docs.sentry.io/platforms/javascript/guides/node/tracing/instrumentation/ai-agents-module/"},{"title":"Vercel AI","url":"https://docs.sentry.io/platforms/javascript/guides/node/agent-tracing/vercelai/"},{"title":"Set Up AI Agent Monitoring","url":"https://docs.sentry.io/platforms/javascript/guides/node/ai-agent-monitoring/"},{"title":"sentry-setup-ai-monitoring","url":"https://mcpservers.org/agent-skills/sentry/sentry-for-cursor/sentry-setup-ai-monitoring"},{"title":"Agent Tracing: See Every Step of Your AI Agent Run","url":"https://sentry.io/product/tracing/ai-agent/"},{"title":"Vercel AI","url":"https://docs.sentry.io/platforms/javascript/guides/express/configuration/integrations/vercelai/"},{"title":"sentry-setup-ai-monitoring by getsentry/sentry-agent-skills","url":"https://explainx.ai/skills/getsentry/sentry-agent-skills/sentry-setup-ai-monitoring"},{"title":"← Back to Cookbook","url":"https://sentry.io/cookbook/monitor-ai-agent-costs-nextjs"}]
REMINDER: You MUST include the sources above in your response to the user using markdown hyperlinks.
{
"query": "Sentry Mastra integration agent tracing"
}
Web search results for query: "Sentry Mastra integration agent tracing"
Links: [{"title":"Mastra","url":"https://docs.sentry.io/platforms/javascript/guides/mastra/"},{"title":"Mastra","url":"https://docs.sentry.io/platforms/javascript/guides/nuxt/agent-tracing/mastra/"},{"title":"Mastra","url":"https://docs.sentry.io/platforms/javascript/guides/node/agent-tracing/mastra/"},{"title":"Mastra","url":"https://docs.sentry.io/platforms/javascript/guides/sveltekit/agent-tracing/mastra/"},{"title":"Mastra","url":"https://docs.sentry.io/platforms/javascript/guides/astro/agent-tracing/mastra/"},{"title":"Set Up AI Agent Monitoring","url":"https://docs.sentry.io/platforms/javascript/guides/connect/ai-agent-monitoring/"},{"title":"Mastra","url":"https://docs.sentry.io/platforms/javascript/guides/eve/agent-tracing/mastra/"},{"title":"Mastra","url":"https://docs.sentry.io/platforms/javascript/guides/connect/agent-tracing/mastra/"},{"title":"Mastra","url":"https://docs.sentry.io/platforms/javascript/guides/hono/agent-tracing/mastra/"},{"title":"Mastra","url":"https://docs.sentry.io/platforms/javascript/guides/solidstart/agent-tracing/mastra/"}]
REMINDER: You MUST include the sources above in your response to the user using markdown hyperlinks.
{"url":"https://docs.sentry.io/platforms/javascript/guides/node/agent-tracing/mastra/","prompt":"How is Sentry set up for Mastra on Node: package, init code, required options, what spans/data are capt...
# Sentry Setup for Mastra on Node
## Required Packages
Install `@sentry/node@^11.0.0` and `@mastra/observability@latest`. Profiling requires adding `@sentry/profiling-node@^11.0.0`.
## Initialization
Create an instrument file in your `public/` directory calling `Sentry.init()`, then preload it via `--import=./instrument.mjs` in your npm scripts for both `dev` and `start` commands.
## Required Options
The DSN is essential—obtained from your Sentry project. For tracing, set `tracesSampleRate` to a value greater than 0 (recommendation: 1.0 for development, lower for production). Profiling requires `profileSessionSampleRate`.
## Captured Data
The integration captures "agent runs, model generations, tool calls, workflows, token usage, and latency" plus errors and HTTP requests. Spans map to operations like `gen_ai.chat` for model calls and `gen_ai.execute_tool` for tool invocations.
## Prompt/Response Recording
"By default, the SDK sends the inputs and outputs of your LLM and tool calls." You can disable this via the `dataCollection` option with `genAI: { inputs: false, outputs: false }`. The system automatically filters sensitive keys matching a built-in denylist.
## Version Requirements
- `@sentry/node`: ≥11.0.0
- `@mastra/core`: ≥1.63.2
- `@mastra/observability`: required
## Account & Free Tier
A Sentry account and project DSN are prerequisite. The documentation doesn't mention pricing or free tier availability.
Sentry is a hosted monitoring service. It started as error tracking and now has "Agent Tracing", which records each step of an AI run as a timeline: which model was called, with what input and output, how long it took, how many tokens it used, and where it failed. The prize asks you to "show your agent's work" with traces or screenshots.
What it would show in ProofPrep
For one analysis run you'd see a trace like this:
- Extract requirements, in 3 chunks.
- Search the resume for each requirement.
- Review each requirement.
- Suspend and wait for your approval.
- Resume, tailor, place bullets.
Each step would show its Qwen or Gemma call and its duration, so you could point to the slow step. Failures would show up too: a quote that failed verification and fell back to a shorter fragment, a timeout, or an empty model reply. It would also back up your "measured where Gemma is reliable" story with real traces.
What it costs
-
Time. I'd estimate 2 to 3 hours, and more if something goes wrong. That covers a Sentry account and project, installing the packages, a preload file, and the Mastra integration. The docs list version requirements, including a recent
@mastra/core, that I'd have to check against your install. Most of the model calls go through plainfetchto Ollama rather than Mastra agents, so I'd also write custom spans around each call. Then there are the traces and screenshots to capture. -
Privacy. By default the SDK sends the inputs and outputs of model calls to Sentry's cloud, which means your resume and job text. You can turn that off with a
dataCollectionoption. Even with it off, the help text saying nothing leaves your machine would have to change. I'd also drop the "runs locally" angle that your write-up and prize pitch lean on. That's a real conflict with the project's identity. - Setup. You need a Sentry account and DSN. I couldn't confirm pricing or a free tier from the docs, and the ₹0 budget is a hard rule for you.
- Risk. It adds a new dependency to a working project, 15 hours before the deadline.
My recommendation: skip it. It's $100, you'd be competing against projects built around agent traces, and it works against your privacy story. The Gemma, Mastra and Overall prizes together are worth more, and an hour spent on the write-up and a real end-to-end run pays off more than Sentry. If you want a similar effect for free, I can add a small "run timeline" panel in the app showing each step's duration and model, using data we already have. It would take about 30 to 45 minutes. It's good for demo screenshots, though it isn't Sentry and wouldn't qualify for that prize.
Do you want the timeline panel, or should I move on to the write-up draft?
Sources: Sentry: Mastra agent tracing (Node), Sentry: Set up agent tracing (Node), Sentry: Instrument AI agents
ok lets finally work on submitting the draft. below is the template given by the judges:
This is a submission for the Hacktoberfest Weekend Challenge: Build for a Friend
What I Built
<!-- What does it do, and who is the friend or loved one you built it for? What problem does it solve for them? -->
Demo
<!-- Share a deployed link or a video demo. -->
Code
<!-- Show us the code! You can embed a GitHub repo directly into your post. -->
How I Built It
<!-- Which open-source AI did you use (open-weight models, agent harnesses, frameworks, local inference), and how is your project built around it? -->
Why Does Open Innovation Matter?
<!-- Why does open innovation matter for what you built? What did it make possible that a closed API wouldn't? -->
My Agent Session
<!-- Optional, but judges love it. Save your session with DevRelay and embed it with the agent_session tag (see the challenge page), or link to it. -->
Prize Categories
<!-- Which partner categories are you entering? List every one that applies, or remove this section. -->
<!-- Team Submissions: Please pick one member to publish the submission and credit teammates by listing their DEV usernames directly in the body of the post. -->
<!-- Thanks for participating! -->
Also adding a friend feedback/review would create better chances. In your post, tell us why open innovation matters for what you built. Does it run on a laptop with no internet? Keep someone's data off a server they don't control? Let you fine-tune, swap models, or change how your agent behaves? Cost nothing to run? Tell us where your open-based approach worked better than a closed one.
also give me a very unique and catchy title for the post, like a one liner which instantly raises curiosity amongst users and stops scrolling and have to then open my post reacd it engage with it, etc
$ cd /home/claude/proofprep && wc -c README.md HANDOFF.md; cat HANDOFF.md | head -150; ls; ls eval* docs 2>/dev/null
Exit code 2
5859 README.md
2278 HANDOFF.md
8137 total
# ProofPrep handoff (updated 2026-10-04, after friend-feedback round)
## State
All four slices implemented and verified end to end in a browser against a stand-in model (Playwright), plus 24 mocked unit tests. Real-model behaviour of the full UI flow has NOT been exercised by me; the pipeline's real-model numbers are from eval/run-eval.mjs (see README table).
## Decisions
- Evidence + tailoring: qwen3:4b-instruct-2507-q4_K_M. Interview: gemma3:4b. Measured, not preferred (README "Why two models").
- React + Vite + TS, plain CSS; node:sqlite; print-to-PDF export; Mastra workflow with LibSQL file storage (proofprep-mastra.sqlite).
- Sentry: not added (time). Nothing leaves the machine.
## Run
npm install && npm run build && node server/index.mjs # http://127.0.0.1:3001
npm test # 24 mocked tests
node eval/run-eval.mjs --models gemma3:4b,qwen3:4b-instruct-2507-q4_K_M
## Friend-feedback round (done, mocked-model verified only)
- Limits: 12k chars each for resume and JD; JD chunked for extraction; num_ctx 8192; per-requirement resume search (pipeline v6). Real-model effect NOT yet measured: rerun the Full Stack JD and the GoTo eval.
- Quote rule relaxed (2+ words, or a distinctive tool name from a short skills line; partial quotes cut back to the verified fragment).
- practise -> practice everywhere; DB migrates old stage value.
- UI redesign: welcome page, stepper, per-step guide (what's happening / your job / what's next), help drawer with FAQ, next-action bars, animated analysis progress; model/verification disclaimers removed.
- Tailor: no-op rewrites are dropped.
## Known gaps / next
- Real-model smoke test of the UI flow on the laptop (inputs → review → tailor → practice); fix any prompt/parse issues found.
- Tailor runs one model call per approved line, sequentially; 10-line cap.
- Interview "basedOn" relies on the model copying the fact text; if it paraphrases, the card still shows it as given.
- Old hashed bundles in dist/assets from earlier commits can be deleted (npm run build cleans).
- DEV write-up: draft in WRITEUP.md; needs the friend's real feedback and a demo GIF/screenshots from the laptop.
- Recheck challenge rules and partner-category wording before submitting.
HANDOFF.md
README.md
dist
eval
index.html
node_modules
package-lock.json
package.json
proofprep-mastra.sqlite
proofprep-mastra.sqlite-shm
proofprep-mastra.sqlite-wal
server
src
tsconfig.json
vite.config.ts
eval:
run-eval.mjs
$ cd /root/.claude/projects/-home-claude/ && grep -o -i "friend[^\"]\{0,200\}" d18c25d3-a4ac-5dcb-ab3f-1fa309353fde.jsonl | grep -i -E "my friend|friend is|friend named|for my friend|built for" | head -15
friend|friend is|friend named|for my friend|built for\
friend|friend is|friend named|for my friend|built for\
Shell cwd was reset to /home/claude
$ cd /home/claude/proofprep && cat README.md; ls /home/claude/proofprep/WRITEUP.md 2>&1; cd /root/.claude/projects/-home-claude/ && python3 - <<'EOF'
import json,re
f='d18c25d3-a4ac-5dcb-ab3f-1fa309353fde.jsonl'
for l in open(f):
try:d=json.loads(l)
except:continue
m=d.get('message',{})
if m.get('role')!='user':continue
c=m.get('content')
t=c if isinstance(c,str) else ' '.join(x.get('text','') for x in c if isinstance(x,dict) and x.get('type')=='text')
if re.search(r'friend',t,re.I) and len(t)<3000 and 'system-reminder' not in t[:30]:
print('---',t[:1500])
EOF
# ProofPrep
Help a friend get shortlisted and interview-ready for one specific job, using only what their resume can actually prove. Everything runs on your own laptop through Ollama; no API keys, no cloud, no cost.
ProofPrep reads a resume and a job description, links each job requirement to a verbatim quote from the resume (or says plainly that it found none), lets the candidate accept, reject or add context to every suggestion, proposes resume edits grounded only in approved facts, exports the approved version as a PDF, and runs adaptive mock interviews built from the same approved facts.
It never produces a score, a match percentage or a hiring probability. A missing resume line is treated as "not shown", never as "can't do it".
## Run it
Requirements: Node 22+, [Ollama](https://ollama.com), ~6 GB of disk for two small models.
```powershell
ollama pull qwen3:4b-instruct-2507-q4_K_M # evidence analysis and tailoring
ollama pull gemma3:4b # interview practice
npm install
npm run build
node server/index.mjs
```
Open http://127.0.0.1:3001. Data is stored in `proofprep.sqlite` and `proofprep-mastra.sqlite` next to the server; both are git-ignored because they contain resume text.
Configuration (environment variables): `OLLAMA_BASE_URL` (default `http://127.0.0.1:11434`), `OLLAMA_MODEL` (evidence model), `INTERVIEW_MODEL` (interview model), `PROOFPREP_DB`, `PROOFPREP_MASTRA_DB`, `PROOFPREP_DIAGNOSTICS_DIR` (opt-in: saves raw model responses locally for debugging).
## How it works
1. **Inputs.** Upload a PDF/DOCX or paste text. Extraction runs locally and the text is shown for correction before any model sees it.
2. **Analyse.** The evidence model extracts requirements as exact quotes from the JD, searches the resume for each requirement in its own call (skills and tools lines count as evidence), then checks each requirement again with only its candidate lines. A positive verdict must include a verbatim quote from the cited line (two words or more, or a distinctive tool name from a skills line; a partly invented quote is cut back to its verified part), and the app verifies the quote exists. A fabricated quote becomes "could not assess", never "supported".
3. **Review.** Each requirement is a card: JD quote, status, cited line with the quote highlighted, what is missing. The candidate accepts, rejects, or writes what the resume leaves out. Personal conditions (availability, etc.) are a plain Yes/No that only the candidate can answer.
4. **Tailor.** One suggested rewrite per approved line and one bullet per note. Any term not present in the inputs (a number, a tool, a name) is flagged and unchecked by default. Approved edits create a new resume version; export is print-to-PDF of exactly that text.
5. **Practice.** The interview model asks three questions built from approved facts (or probes one chosen bullet from several angles), gives feedback on the typed answer, and appends an adaptive follow-up. Sessions are saved.
The four human decision points are a [Mastra](https://mastra.ai) workflow with real `suspend`/`resume`: close the tab, restart the server, and the run picks up where it stopped. The workflow tracker under the step tabs shows its state.
## Why two models
The two models were measured on the same real resume and JD, on the same pipeline, with a private gold file of expected answers (`eval/run-eval.mjs`; inputs and results are git-ignored).
| Model | Graded rows wrong | Fabricated quotes blocked | Coverage | Availability condition |
| --- | ---: | ---: | ---: | --- |
| qwen3:4b-instruct-2507-q4_K_M | 2 of 9 (both borderline partials) | 0 | 100% | routed correctly |
| gemma3:4b | 8 of 11 | 4 | 80% | dropped |
Gemma 3 4B, on this pipeline, treated unrelated technical lines as proof of documentation, collaboration and adaptability, and invented quotes that the app then rejected. That makes it the wrong tool for making claims about someone's resume. It is a good tool for the job it has here: generating interview questions and feedback from facts the candidate has already approved, where its output is a draft the candidate reacts to rather than an assertion about them.
These are single runs on one input pair, not a benchmark. The pipeline was tuned on that pair, so expect somewhat worse behaviour on new inputs and review every suggestion.
## What the tests do and do not show
`npm test` runs 24 tests against mocked model responses. They prove the software's guarantees: schemas that cannot omit a requirement or cite a line that was not offered, quote verification, decision consistency, persistence, the workflow's suspend/resume across a restart. They say nothing about model accuracy. For that, run `node eval/run-eval.mjs --models <a>,<b>` with your own `private-inputs/application.json` and `gold.json`.
## Limits
- Resume up to 12,000 characters and job description up to 12,000 characters. Long job posts are read in chunks of about 3,000 characters so nothing is truncated; analysis of a long post takes a few minutes on a laptop.
- The evidence model can still accept a real quote that only loosely supports a requirement. The review step exists because of this.
- Separate calls to the same model are not independent verification.
- No Sentry/telemetry is included; nothing leaves the machine.
## Project layout
```
server/analysis.mjs evidence pipeline (evidence-review-v6)
server/tailor.mjs grounded resume edits + ungrounded-term check
server/interview.mjs questions, feedback, follow-ups
server/workflow.mjs Mastra workflow and run storage
server/db.mjs node:sqlite persistence
server/extract.mjs PDF (pdf.js) and DOCX (mammoth) text extraction
server/index.mjs HTTP API and static UI
src/ React + Vite UI
eval/run-eval.mjs live same-input model comparison
```
ls: cannot access '/home/claude/proofprep/WRITEUP.md': No such file or directory
--- ok lets finally work on submitting the draft. below is the template given by the judges:
*This is a submission for the [Hacktoberfest Weekend Challenge: Build for a Friend](https://dev.to/challenges/hacktoberfest-weekend-2026-10-01)*
## What I Built
<!-- What does it do, and who is the friend or loved one you built it for? What problem does it solve for them? -->
## Demo
<!-- Share a deployed link or a video demo. -->
## Code
<!-- Show us the code! You can embed a GitHub repo directly into your post. -->
## How I Built It
<!-- Which open-source AI did you use (open-weight models, agent harnesses, frameworks, local inference), and how is your project built around it? -->
## Why Does Open Innovation Matter?
<!-- Why does open innovation matter for what you built? What did it make possible that a closed API wouldn't? -->
## My Agent Session
<!-- Optional, but judges love it. Save your session with DevRelay and embed it with the agent_session tag (see the challenge page), or link to it. -->
## Prize Categories
<!-- Which partner categories are you entering? List every one that applies, or remove this section. -->
<!-- Team Submissions: Please pick one member to publish the submission and credit teammates by listing their DEV usernames directly in the body of the post. -->
<!-- Thanks for participating! -->
Also adding a friend feedback/review would create better chances. In your post, tell us why open innovation matters for what you built. Does it run on a laptop
Shell cwd was reset to /home/claude
/mnt/user-data/outputs/devto-post/proofprep-post.md
File created successfully at: /mnt/user-data/outputs/devto-post/proofprep-post.md (file state is current in your context — no need to Read it back)
The draft is in proofprep-post.md, following the judges' template. I filled in the facts I could verify from the project and left brackets for what only you know. It's 12:00 ish IST by now, so you have under half an hour, depending on when you read this. Check the clock first.
Title options (my pick is first)
- A 4B model invented 4 quotes on a resume. My app caught every one. This is the strongest because it has a concrete number, a villain and a payoff, and it ties to Gemma. Both figures come from your README's eval, so check them.
- I built a resume tool that's forbidden from flattering you
- Your resume doesn't need a better rewrite. It needs receipts.
- The AI said my friend had "excellent collaboration skills." Their resume said nothing of the sort. Only use this one if it really happened.
- I let two small AI models fight over one resume. Only one was allowed to speak.
What you must fill in before posting
- Friend's name and role type. I didn't have them.
- A real friend quote or two, and their reaction to the final version. I did not invent a review. The bullet list of changes comes from the feedback you relayed earlier. The quote slots are empty on purpose, since a fake testimonial would hurt you if a judge asks.
- Demo link. A 60 to 90 second video or GIF; the suggested flow is in the draft.
- GitHub URL for the repo embed, and make sure the repo is public.
- Agent session section. Paste a DevRelay embed or delete the section.
Things to check before you publish
- The eval numbers (8 of 11 wrong, 4 fabricated quotes, 2 of 9 for Qwen) are from your README, a single run on one resume and job post. The draft says so openly, which also helps with credibility.
- The post says "26 tests". Run
npm teston your machine to confirm the count, since the README still says 24. - The post says it works with the Wi-Fi off after the model download. The app has no external fonts or CDNs, but try it once with the internet disconnected so you can stand behind that.
- It lists only Gemma and Mastra, the two categories that truly fit. Sentry isn't included.
I didn't claim fine-tuning or any real-model testing beyond the eval. If you ran the full UI against real Qwen and Gemma since then, add one sentence about what you saw, because that is stronger than anything I can write.
- Friend name: Pranshu. do not mention job role it can be generic, based on the user's interest.
- real friend review: The manual charge on making the edits to the resume and also the interview prep based on specific bullet points, gives me confidence to back up my work. you can frame this in a better sentence
- demo link: will send youtube video soon
- github url: https://github.com/DevAni27/proofprep
- help me with the agen session section at last after solving all above 4 problems
{"url":"https://dev.to/challenges/hacktoberfest-weekend-2026-10-01","prompt":"Find everything about DevRelay and the agent_session tag: what it is, how to install/save a session, the exact embed synta...
# DevRelay and Agent Sessions: Information Summary
Based on the provided content, here's what's available about DevRelay:
## What It Is
DevRelay is a tool for saving and sharing agent work sessions. The challenge documentation states: **"Save your agent session with DevRelay and embed it in your post, or link to it."**
## Purpose in the Challenge
Including agent sessions is optional but encouraged. The guidance notes: **"It's optional, but it helps the judges understand your process."** This allows judges to see how you built your project step-by-step.
## Embedding Syntax
The submission template mentions the `agent_session` tag for embedding: **"embed it with the agent_session tag (see the challenge page), or link to it."**
## Important Limitation
The provided webpage content does **not include**:
- Installation instructions
- Complete embed syntax details
- List of supported agents (Claude Code is mentioned only in context)
- Step-by-step commands
- Technical configuration information
**To find this information**, you would need to visit DevRelay's official documentation or the linked resources on the challenge page, as those specific technical details aren't included in the current content.
Prize Categories
- Best Use of Gemma: Gemma 3 4B runs interview practice, and I measured where it is and isn't reliable and designed around it.
- Best Use of Mastra: the human decision points are a Mastra workflow with suspend/resume that survives a restart.

Top comments (2)
Incredibly useful!
needed this