Project Info
Inspiration
Suspicious messages are one of the most common ways people encounter scams, phishing, impersonation, and social engineering. Not to mention, there is a huge vunerability group: old people using outdated email handlers like Yahoo, in which there is a lot of evidence showing that it cannot reliably filter scams itself. But building better classifiers for these messages is hard because the best examples often come from real emails, texts, DMs, and marketplace posts that may contain sensitive personal information.
What it does
Trustfall helps collect privacy-protected, real human judgments on suspicious and legitimate messages without storing raw private message text, and trains models based on this collected data to improve its general judgement.
How we built it
Next.js App Router, Prisma, SQLite locally, browser-side .eml parsing, server-side redaction, Terac callback integration, train/eval exports, and a Qwen baseline workflow.
Challenges we ran into
The hardest part was balancing usefulness and privacy. Scam and phishing messages are valuable because they are realistic, but realism can also mean they contain names, phone numbers, links, codes, addresses, or other sensitive details. We had to design the workflow so the browser, the API, and the participant review step all reduce privacy risk before data is stored. Another challenge was separating collection from labeling. We did not want workers to label their own submissions, and we wanted Wave 2 to depend on messages collected from other participants. That required thinking carefully about task ordering, label counts, and how to prioritize messages with fewer labels. We also had to keep the project lightweight enough for a hackathon while still making the data pipeline auditable. Instead of adding a large external dataset or synthetic labels, we focused on making a clean Terac-only workflow with deterministic exports and a baseline evaluation path.
Accomplishments we're proud of
We are proud that Trustfall treats privacy as a core product feature, not an afterthought. Raw message text is only held while the participant is filling out the form, and stored records are redacted before they can be used downstream. We are also proud of the two-wave workflow. It creates a cleaner separation between message collection and human labeling, which makes the resulting dataset more trustworthy. The app includes practical details like .eml parsing, attachment stripping, redacted previews, participant attestations, label-count prioritization, admin visibility, and train/eval exports. Most importantly, the system is designed around real Terac-collected human labels. That makes the project more realistic than a demo built on public or synthetic data, and it gives us a foundation for measuring whether fine-tuning actually improves over a base model on held-out examples.
What we learned
We learned that data collection UX matters just as much as model training. If the contribution flow feels unsafe or confusing, people will not provide high-quality examples. Showing a redacted preview before submission gives participants more control and makes the privacy model easier to understand. We also learned that “human-labeled data” is not automatically trustworthy. You need clear task separation, duplicate labels, export rules, and held-out evaluation to make the data useful for training. Building the workflow forced us to think about provenance, consent, privacy, and evaluation as one connected system. Finally, we learned that a small, focused dataset collected under the right constraints can be more valuable than a large dataset with unclear provenance.
What's next
Next, we want to complete the full fine-tuning loop: collect more Terac-labeled examples, train on the sanitized human-labeled training split, and compare the fine-tuned model against the Qwen baseline on held-out evaluation messages. We also want to improve the labeling interface with clearer rubrics, disagreement tracking, confidence scores, and adjudication for messages where human labels conflict. On the privacy side, we want to add stronger redaction checks, better preview highlighting, and support for more message formats. Longer term, Trustfall could become a general-purpose human-data collection layer for safety-focused classifiers: phishing, scams, marketplace fraud, impersonation, spam, and other high-risk communication patterns where realistic examples matter but privacy cannot be compromised.
Trustfall Terac workflow
Trustfall collects privacy-protected, real human judgments about suspicious and legitimate messages during a Terac event. It is a small Next.js App Router project using Prisma and SQLite locally.
Only Terac-collected labels should be used for training. Do not add public datasets, Kaggle, Hugging Face, or AI-generated labels to the training set.
Run locally
npm install
cp .env.example .env
npx prisma migrate dev --name init
npm run dev
Visit http://localhost:3000/terac?mode=collect&teracSubmissionId=test123 for Trustfall Wave 1: Message Collection. Workers submit one suspicious and one normal message, review browser-redacted previews, and return directly to Terac—no labeling is part of this wave. Wave 2 labeling remains separate and requires messages from other participants.
Wave 1 defaults to a local .eml upload: the browser parses it, strips attachments and raw headers, and sends only the worker-approved sanitized preview to the API. Use the visible paste-text fallback for SMS, DMs, marketplace posts, and other non-email messages. Run npm run test:sanitization to check .eml parsing and redaction behavior.
Visit http://localhost:3000/terac?mode=label&teracSubmissionId=test-label-1 for Trustfall Wave 2: Message Labeling. Each worker receives LABELS_PER_PARTICIPANT redacted messages (8 by default), prioritized by fewest existing labels. Labeling cannot begin until enough Wave 1 messages exist.
The admin overview is at /admin/data. Downloadable exports are at /api/export/train and /api/export/eval; only messages with two or more human labels are included. The deterministic ID hash assigns 80% to train and 20% to holdout evaluation.
Privacy model
Raw message text is only held in the browser while the user is filling the form. Before any write, the server replaces links, email addresses, phone numbers, and 4+ digit codes. It never stores unredacted input. Participants must also attest that they removed private information and have a right to share the message.
Terac callback
Set TERAC_CALLBACK_BASE_URL to Terac’s completion callback origin or URL. /api/terac/callback?teracSubmissionId=… then redirects there with teracSubmissionId and result=completed. Without it, the app redirects to the local completion screen.
Terac Wave 1 pilot API
Set TERAC_API_KEY only in .env or your deployment secret store; never expose it to the browser. GET /api/terac/pilot lists projects (read-only). POST /api/terac/pilot supports create_project and create_wave1_draft, but only after setting TERAC_PILOT_WRITE_ENABLED=true. The integration deliberately does not expose Terac's launch endpoint: creating a draft is safe for review, while launch begins recruitment and may incur cost.
Pre-training Qwen baseline
Run this locally after real Wave 1 data is collected (never in Vercel): python3 -m pip install -r requirements-baseline.txt && npm run baseline:qwen. It reads only sanitized, non-synthetic messages and writes immutable JSONL predictions to baseline_before_training/; it does not train, modify, or export source records.
Vercel
Set DATABASE_URL to a production-compatible Prisma database (SQLite is for local development; use a hosted relational database adapter before production deployment) and TERAC_CALLBACK_BASE_URL in Vercel project settings. Run prisma generate during build if your deployment environment does not do it automatically.
Analysis
View
Metric
- 2
- 1
Figures cover GitHub contributors during the hackathon window. A co-authored commit counts in full for each author, so per-member totals add up to more than the whole-team figures.
Technology
- CSSIn code
- JavaScriptIn code
- Next.jsIn code
- PythonIn code
- ReactIn code
- SQLIn code
- Tailwind CSSIn code
- TypeScriptIn code
- Node.jsClaimed
- VercelClaimed
8 of 10 appear in the indexed code. 2 claimed on Devpost could not be matched to code, which may simply mean the tool leaves no trace in the repository.
AI coding agents
- Claude CodeCommits
Detected from committed agent config files and commit authorship. Absence of a signal is not proof an agent was unused.
Codebase size
Source size
185 KB
Source files
64
Counts recognized source files only; vendored directories, binaries and lockfiles are excluded, so this is smaller than the repository on disk.
Repository
lukejun001/Trustfall
85 files · 4.9 MB · @ 08d2470
Structure
Interface
10 files · 12%Screens, components and styles rendered to the user.
API & routing
9 files · 11%Request entry points: routes, handlers and controllers.
Application logic
12 files · 14%Domain rules, services and shared utilities.
Data & schema
13 files · 15%Schema definitions, migrations and data access.
Supporting
Layers are inferred from where files sit in the tree, not from reading the code. A project that names its directories unconventionally will read oddly here — open the file browser to check anything the diagram implies.
Languages
- TypeScript41%
- Python31%
- Markdown20%
- SQL7%
- CSS0%
- JavaScript0%
Share of indexed source by file size. Binary and vendored files are excluded.
Dependencies
package.json
npm · 16- @prisma/client
- next
- react
- react-dom
- zod
- +11 more
Declared in the repository’s manifests at the indexed commit. A declared package is not proof it is used, and runtime dependencies are listed first.
This project’s features have not been analysed yet.
Export this project's context (description, README, evidence, key source files) to chat with an AI agent elsewhere.