This is a submission for the Hacktoberfest Open-Source AI Challenge Week 2: Side Hustle
Built by @noahosmont and @nullcoder00. I did the backend and the agents; NullCoder built the entire frontend.
What I Built
Every placement season, a lot of students in India get some version of this message. (This one is a composite I wrote; the pattern is the real part.)
"Congratulations! You have been selected for our internship. Please pay a βΉ1,999 registration fee to confirm your seat. Share your Aadhaar and the OTP you receive for verification. Offer valid for 24 hours only."
It comes from a Gmail address, for a company whose website is a month old. And it works, because a student chasing their first rΓ©sumΓ© line is the person least likely to stop and check.
TrustIntern is an investigation desk for internship offers. Paste in the company, the recruiter's email, the website and the message, optionally attach the offer letter (PDF or screenshot), and TrustIntern:
- runs fixed checks (email domain vs. company, domain age via RDAP, the website, the wording),
- sends research agents after the company, the recruiter and public complaints, with a Gemma 4 planner deciding which ones to launch,
- has Gemma 4 vision read the offer letter or screenshot,
- returns a risk score you can recompute by hand, every point tied to a specific piece of evidence.
Every report says: "Heuristic indicator score, not a probability of fraud." It shows evidence and calls nobody a scammer.
The side hustle
Who pays? Not students, on purpose.
- Students: free. With local Gemma, a check costs almost nothing.
- Colleges and placement cells: paid. Bulk checks of the offers circulating in student WhatsApp groups.
- Job boards: paid API. Screen listings and recruiter accounts before they go live.
- Postmortem report: one-off paid. An evidence-backed write-up for someone who has already been scammed, to attach to a complaint. This idea came from my first tester (below).
Demo
π Live: https://trustintern.charancodes.com
In the recording I typed in a fresh fake offer from "Global Talent Solutions Ltd" (Gmail recruiter, βΉ1,999 "refundable registration fee" via UPI within 24 hours, Aadhaar plus OTP). It scored 80/100: Upfront fee +25, Email domain mismatch +20, Sensitive data request +20, Urgency or guarantee +10, Personal email provider +5. The fake domain didn't resolve, so the website and domain-age checks say Not checked instead of guessing. The built-in "Consistent offer" sample scored 0/100.
Here's the built-in Suspicious sample (a fictional "Aurora Tech Pvt Ltd"). The run streams live over SSE: checkers, then spawned agents, then findings.
The finding leads with the number, then shows the arithmetic:
90 = 25 upfront fee
+ 20 email domain mismatch
+ 20 sensitive data request
+ 10 company not in domain
+ 10 urgency or guarantee
+ 5 personal email provider
Each chip is tied to the sentence that triggered it. Nothing is subtracted; the total caps at 100.
And it all downloads as a PDF:
Code
compteccharan
/
TrustIntern
TrustIntern is an AI-powered platform that evaluates the authenticity and scam risk of internship and job opportunities by analyzing company details, recruiters, websites, communications, documents, and digital evidence to generate an explainable risk assessment.
TrustIntern π΅οΈ
An investigation desk that tells students whether an internship offer is a scam, and shows its working.
TrustIntern looks at the company name, recruiter email, website, message text, and an offer-letter PDF or screenshot. It runs a small team of research agents and returns an explainable risk score: every point is tied to a specific piece of evidence. Reports download as a PDF.
Heuristic indicator score, not a probability of fraud.
Live demo: https://trustintern.charancodes.com
How it works
- Fixed checkers look at the email domain, domain age (RDAP), website and message text.
- Gemma 4 plans which research agents to launch: company, recruiter, complaints, domain, document, follow-up. Only allowlisted agent types run; at most 8 agents and depth 2.
- Gemma 4 vision reads the offer letter (PDF or screenshot) and flags inconsistencies.
-
Deterministic scoring (
backend/app/scoring.py) adds up fixed indicator points: upfront fee 25, domain mismatch 20, sensitiveβ¦
MIT licensed. The API contract, including the scoring rules, lives in backend/CONTRACT.md.
How I Built It
ββββββββββββββββββββββββββββββββββββββββββββ
Student ββΆ β Investigation desk (Vite + React, jsPDF)β
βββββββββββββββββ¬βββββββββββββββββββββββββββ
β POST run Β· SSE event stream
βββββββββββββββββΌβββββββββββββββββββββββββββ
β FastAPI (Vercel services: /api β py) β
β β
β 1. Fixed checkers βββ β
β domain, RDAP, β evidence ledger β
β wording, site βΌ β
β 2. Planner βββΆ allowlisted agents β
β Gemma 4 company Β· recruiter Β· β
β (fallback: complaints Β· domain Β· β
β heuristics) document Β· follow-up β
β max 8 agents, depth 2 β
β 3. Gemma 4 vision: offer PDF/screenshot β
β β β
β 4. scoring.py βββββββ deterministic, β
β (Gemma never recomputable β
β touches this) β
ββββββββββββββββββββββββββββββββββββββββββββ
Gemma 4: local gemma4:e2b via Ollama
hosted demo β Gemma 4 via Google's Gemini API
Stack: FastAPI, Python agents (requests, BeautifulSoup, pypdf, pypdfium2), Gemma 4, React 18 + Vite, jsPDF, Vercel, GitHub Actions CI.
Gemma 4 does the thinking, rules do the math
-
Planner. Gemma reads what the fixed checkers found and picks which research agents to launch next, but only from an allowlist: in
registry.py, "Unknown types from the planner are never executed." - Multimodal reader. Scam offers arrive as WhatsApp screenshots more often than tidy PDFs, so Gemma 4 vision reads either and pulls out claims to compare against everything else.
Locally I run gemma4:e2b through Ollama on my laptop. The hosted demo can't reach my laptop, so it uses Gemma 4 through Google's Gemini API (gemma-4-26b-a4b-it). If no model is reachable, a heuristic planner takes over and the investigation still finishes.
The one rule I never let bend, from CONTRACT.md's "Scoring boundary (non-negotiable)":
Gemma / OSINT never invent indicator points.
gemma_client.py says it in four words: "Never scores." Run the Suspicious sample with live lookups off and you get 90 every time, pinned by tests.
The Agent Sessions Behind It
I built TrustIntern in one day, inside a 5.5-hour hackathon plan, by directing Cursor agents, subagents and parallel workers. I saved the sessions with DevRelay; they're public on my DEV profile.
It started with me demanding "this plan must win me an hackathon , so plan the best , i need the best plan." The agent's reply changed the whole project:
"The current plan would finish. It would not win. The score a judge can recompute, with the exact sentence beside each point, is the part other teams will not have."
I split the work ("build just the backend , another member builds the frontend"), the agent turned the split into a contract ("Backend owns the number"), and after I locked the plan, each worker agent got it with one instruction in capitals: "Do NOT edit the plan file."
Later I got suspicious of my own project: "is there really multimodal ai , and is it using an open source or gemma ai ?" The agent checked honestly. Gemma only ever saw a PDF page, so it wired screenshots into the same Gemma 4 vision call, noting "Points still come only from scoring.py."
Then Gemma moved onto my own machine ("i need to use gemma 4 locally and run this project"):
And the deploy prompt opened with guardrails: "Do not print secrets. Do not commit or push git. Do not read or upload backend/.env."
What Entire Gave Me
Entire ties agent work to git. In this repo it gave me three things.
1. A second reviewer on every PR. Six trail runners in .entire/runners/ (Risk, Security, Drift, Confidence, Review, Summary) score every push. I pasted Entire's gates screen into the chat with "set up runners ig", and the agent noticed "The PR had no CI checks β I'll add GitHub Actions for build, lint, and test so Entire's gates can actually run."
| Trail | Confidence | Risk | Drift | Security |
|---|---|---|---|---|
| #3: React investigation desk | 58% (β from 48%) | 15% | 28% | 14% (β from 18%) |
| #4: Gemma vision reads offer screenshots | 62% | 40% | 32% | 14% |
On trail #3, confidence rose from 48% to 58% and security risk fell from 18% to 14% as I iterated. On trail #4, the risk runner was blunt: the vision feature "falls back to phrase rules when no Gemini key is set, but the new worker branches are untested."
The runner flagged had_image; here's the fix. The best catch was a medium finding on backend/app/agents/planner.py:141:
"The Gemma planner summary only sets
had_pdfand never reports that an image was uploaded. β¦ It can then decide not to spawn the vision agent, and the screenshot is never read. Addhad_imageto this summary and mention it in the planner prompt."
An AI reviewer caught a blind spot in code an AI author wrote, in the exact feature I built for the Gemma category. Humbling. PR #6 (merge 2c57d43) adds had_image to the planner summary and prompt, makes the sync endpoint reject images with a 422 instead of quietly ignoring them (the runner's other, low finding), and adds three tests. CI passed 3/3. Still open: trail #3's note about sanitizing source_url links against javascript: URLs.
2. Commits that point back to their sessions. Commit linking is set to always: 13 commits carry an Entire-Checkpoint: trailer, stored as git refs (refs/entire/checkpoints/*).
3. entire search to explain why code exists. When I forget why something is the way it is, I search the agent history instead of the code:
$ entire search --json --compact fallback
β 1821b7f Add spawn planner with Gemma path and heuristic fallback.
$ entire search --json --compact vision
β eed6eba Let Gemma vision read an offer screenshot as well as a PDF.
β 5c8fe31 Switch Gemma to local Ollama and ship PDF reports on Vercel.
$ entire search --json --compact contract
β session DevRelay and Multi-Agent OSINT Backend (CONTRACT.md, scoring.py β¦)
β d746742 Document multi-agent SSE API and scoring boundary in CONTRACT.
Why this code exists
| Decision | Prompt or agent line behind it | Commit | Entire checkpoint |
|---|---|---|---|
A score a human can recompute (scoring.py) |
"The current plan would finish. It would not win." | c774cb1 |
01M51PZKS97NZCBGCMEJBJK7AD |
Backend owns the number (CONTRACT.md) |
"Backend owns the number." | d746742 |
01M51SNG0N6DDK13D395RD7R4G |
Gemma plans, heuristics as fallback (planner.py) |
"LLM planner (Gemma or similar) β¦ with heuristic spawn as fallback when the model is down" | 1821b7f |
01M51SNA38QJYPVJ0HX2JR7N5F |
Gemma 4 client that never scores (gemma_client.py) |
"use gemma for the multi modal orchestration :0 btw sse it is ( its cool )" | a101431 |
01M51SN923AZNDRW7RS1HWQ9NH |
OSINT via PullPush + Wikipedia (_fetch.py) |
"DuckDuckGo and Reddit's own API are blocked from this network. Switching OSINT to PullPush (Reddit archives) and Wikipedia" | 62cbf5f |
01M51SNB26MCRMCN70Y2DRMBY2 |
CI so Entire's gates can run (ci.yml) |
"The PR had no CI checks β I'll add GitHub Actions for build, lint, and test" | 613fdac |
01M51YCYAVYW1TQ8X1BQT1T8WV |
Screenshots go to Gemma vision too (document_mm.py) |
"is there really multimodal ai , and is it using an open source or gemma ai ?" | eed6eba |
none (no trailer) |
Planner told about images (planner.py) |
Runner: "Add had_image to this summary and mention it in the planner prompt."
|
0c41d59 |
none (no trailer); trail #6 |
Any checkpoint ID above opens with entire checkpoint explain <id>. Honest note: my capture hooks were Windows-only one-liners that went quiet after setup, so the checkpoints carry the commit links and file lists, while the full conversations live in the DevRelay sessions above. Next build: check the hooks in minute one.
Does It Actually Work?
Demo samples are easy to pass, so I had my agent run TrustIntern's real scoring code (analyze_opportunity from the repo, live lookups off, the same mode the tests use) on 12 publicly reported scam offers and 11 real internship postings, filling in only the fields each source actually published. Threshold: above 30 counts as a flag ("Needs verification" or "High").
| Scam report (source) | Text | Score | What fired |
|---|---|---|---|
| "Clinchbridge" βΉ1,550 enrollment fee | quoted excerpt | 25 | Upfront fee |
| TikTok Shop "recruiter" text | verbatim | 0 | nothing |
| "Indeed" task-scam text | verbatim | 0 | nothing |
| GT Ventures Teams "interview" text | verbatim | 0 | nothing |
| TopUSAJobs WhatsApp message | verbatim | 20 | Sensitive data (SSN) |
| "Infosys" βΉ275 onboarding fee | example on an awareness site | 0 | nothing |
| βΉ1,594 "internship fees" offer letter | news description | 25 | Upfront fee |
| "InnovateMetrics" βΉ1,450 enrollment fee | victim's account | 25 | Upfront fee |
| βΉ1,596 "to confirm my enrollment" | victim's account | 0 | nothing |
| βΉ6,000 "registration fees" | victim's account | 25 | Upfront fee |
| "Circumvent Pharmaceuticals" fake check | victim's account | 0 | nothing |
| βΉ35,000 "refundable" security deposit | victim's account | 25 | Upfront fee |
The real postings were intern listings from Stripe, Airbnb, Figma, Duolingo, Coinbase, Pinterest, Lyft, Samsara, Affirm, Databricks and Robinhood, pulled as full text from their public Greenhouse job boards. 10 of 11 scored 0. Airbnb scored 20, because its own anti-fraud notice says it will never ask for your "bank account details", and my sensitive-data rule has no idea what "never" means.
The honest scoreboard:
- Flags (above 30): 0 of 12 scams. Not one crossed the line on its own.
- Something fired: 6 of 12 scams (5 fee demands, 1 SSN request).
- False alarms (above 30): 0 of 11 real postings; 1 of 11 got a non-zero score.
So the rules are careful, and on these inputs too careful. The misses have clear causes:
- Most of the points need fields the public reports don't have. Domain mismatch, personal email and company-not-in-domain are worth 35 points together, and only 1 of the 12 sources published a recruiter email. With message text alone, the ceiling is 55.
- My phrase list is narrow. "Onboarding fee", "βΉ1,596 to confirm my enrollment" and fake-check or task-scam scripts slip through.
- Small, messy sample. It's 23 items, 7 of the 12 scam texts are retellings or examples rather than the original message, and the real postings are US tech listings, not the Indian SME offers students actually get.
Next: widen the fee phrases, handle "we will never ask" sentences, and add task-scam and fake-check patterns, then rerun this same set so the numbers can move in public.
Why Does Open Innovation Matter?
- Privacy. Offer letters carry names, addresses and sometimes ID numbers. With Gemma 4 on Ollama, they never leave my laptop.
- Cost. A free tier for students only works if a check costs close to nothing. An open-weight model on my own hardware makes that possible.
-
Swappable models. The planner talks to "a Gemma", not one vendor: local
gemma4:e2b, Gemma 4 via the Gemini API, or no model at all. -
Auditable scoring. The most important part isn't AI. It's open, deterministic rules anyone can read in
scoring.pyand recompute. The test above only works because the scoring is open: anyone can rerun it and see exactly which rule missed.
First User
I gave an early version to an early tester. Their feedback, lightly cleaned up:
"This would stop internship scams, at least the basic ones, from affecting unsuspecting users. And it could become a postmortem report for the wiser."
No paying customers yet; this was a free beta. But the postmortem idea went straight into the pricing plan: people who already got burned are the most motivated to want an evidence-backed report.
What's Next
- Fix the misses from the test above, then rerun it.
- Postmortem report mode: a timeline of what happened, formatted for a complaint.
- A WhatsApp or Telegram forwarder, so students can check an offer where it arrives.
- Bulk verification for placement cells.
- Sanitize
source_urllinks, and fix my Entire hooks so the next build's checkpoints carry full transcripts.
Prize Categories
-
Best Use of Gemma: Gemma 4 plans the investigation and reads offer PDFs and screenshots (local
gemma4:e2bvia Ollama; Gemma 4 via the Gemini API in the hosted demo), and is deliberately kept out of the scoring. -
Best Use of Entire: six trail runners gating PRs (one caught the
had_imagebug, fixed in PR #6), 13 commits linked to checkpoints, a "why this code exists" table,entire searchused to explain decisions, and the agent sessions shared above.
Credits
Huge shoutout to my teammate NullCoder (@nullcoder00), who built the entire frontend. If TrustIntern looks good, that's him. I just taught the bots to argue with scammers. π







