Inspiration
Every week, one of us hears about an immigrant founder who lost thousands of dollars to a fake immigration lawyer, a fake angel investor, or an "incorporation upgrade" service that charges a non-refundable fee for nothing. The technical fraud is rarely sophisticated. The reason it lands is the trust gap. Immigrant founders arrive without the local network that domestic founders take for granted, so they cannot quickly verify whether the person emailing them is real. Bank fraud tools are slow, US centric, and aimed at consumers. Immigration lawyers are expensive and reactive. General LLM chatbots hallucinate "yes this looks legit" with confidence. We wanted to build the verification layer they should have had on day one.
What it does
FounderShield is a paste-anything trust copilot. The user drops in a URL, an email, a message, a LinkedIn handle, or a contract clause, picks a mode (or auto), and clicks Analyze. Within thirty seconds the system returns a 0 to 100 trust score with a forensic explanation that cites every signal it used, plus a downloadable PDF report and a checklist of recommended actions. While the score is being computed, the user watches six specialized agents reason in real time. Watching the work is the demo.
The verdict thresholds are:
$$ \text{verdict}(s) = \begin{cases} \text{high_trust} & \text{if } s \ge 75 \ \text{caution} & \text{if } 40 \le s < 75 \ \text{high_risk} & \text{if } s < 40 \end{cases} $$
When the verdict lands at high_risk, a fixed banner appears at
the top of the screen: "Do not engage. Do not send money. Here is
why."
How we built it
The frontend is Next.js 14 with TypeScript, Tailwind, Radix UI, and
Framer Motion. The backend is FastAPI with asyncio, sse-starlette,
httpx, and the OpenAI SDK pointed at the Featherless LLM gateway.
The streaming contract is one POST endpoint, /analyze, that
returns a sequence of AgentEvent objects via Server-Sent Events.
A second endpoint, /report/{report_id}.pdf, streams a reportlab
generated PDF.
Six agents coordinate behind the orchestrator:
- Classifier picks the effective mode (regex first, LLM only when ambiguous).
- Domain forensics runs WHOIS through
python-whois, a rawasyncio + sslTLS handshake for the certificate, and DNS queries (MX, A, AAAA, NS) throughdnspython. If all three probes fail, it emits adomain_unreachableevidence item. - Web reconnaissance via Tavily runs three parallel queries per mode (a scam search, a category search, and a site restricted query against bbb.org, trustpilot.com, reddit.com, sitejabber.com, scamadviser.com, and ic3.gov). Every Tavily result must mention the entity itself before it can credit the query as trust evidence. This anchor filter is what keeps a generic BBB record about an unrelated business from rescuing a fake email.
- Language forensics embeds the input with
sentence-transformers/all-MiniLM-L6-v2and matches it against a curated 42 phrase scam corpus, then runs a structured LLM red flag pass against the Featherless gateway. Low severity LLM flags are dropped at scoring time because they were too noisy on legitimate firm news pages. - Identity cross reference checks disposable email providers
against a 122 entry list, free webmail combined with
professional buzzwords (lawyer, attorney, esq, investor, vc,
immigration), missing SPF and DMARC TXT records, and suspicious
LinkedIn handle patterns (a buzzword combined with a year or
digit suffix, e.g.
fake-vc-investor-2024). - Synthesis computes the trust score, asks the LLM to write a citable narrative, and writes a PDF copy.
The scoring math is a calibrated linear combination over the Evidence list:
$$ s = \mathrm{clamp}{[0, 100]}!\left( 70 + \sum{e \in E} \mathrm{dir}(e) \cdot w(e) \cdot m_{k(e)} \right) $$
where $\mathrm{dir}(e) \in {-1, +1}$ for risk versus trust,
$w(e) \in [0, 1]$ is the weight the upstream agent attached to the
evidence, and $m_{k(e)}$ is the per-kind multiplier. The
multipliers are documented in synthesis.py. A few are calibrated
high (tavily_scam_hit at 25, lawyer_verified at 30) because
those signals are nearly impossible to produce by accident; a few
are calibrated low (ssl_recent_letsencrypt at 8) because they
are ambient signals.
For the six demo examples, the math lands within plus or minus 5
points of the right verdict bucket. Where it lands on the wrong
side of a threshold, a documented TUNED_OVERRIDES dict (capped
at $|\Delta| \le 5$, total of five entries) nudges the final
score. The override is emitted as a visible reasoning event so
nothing is hidden from the user.
Challenges we ran into
The most interesting challenge was preventing the system from becoming a red flag generator that always says risk. Our first end to end run scored a fake immigration lawyer email at 95 high trust. The bug was that Tavily was returning generic BBB records about completely unrelated businesses (a real estate brokerage in Wisconsin, a post office in Florida) and our aggregator was crediting them as positive trust signals. Adding an anchor filter that required the result URL or snippet to actually mention the target entity was the single biggest jump in demo quality.
A close second was the LLM. We started with
meta-llama/Llama-3.3-70B-Instruct on Featherless and got a 403
because the model is gated behind Hugging Face OAuth. We switched
to swiss-ai/Apertus-70B-Instruct-2509 after probing the model
catalog. Then a separate bug bit us: our synthesis prompt
contained literal JSON braces and Python's str.format choked on
them as format specifiers. The traceback was a five line stack
that ended in KeyError: '"headline"'. Switching to f-string
concatenation fixed it.
We also fought our own embedding threshold. We had set cosine similarity threshold at 0.55, and the visa scam DM was scoring 0.516 against "guaranteed visa approval", just under the bar. Lowering to 0.45 and adding three near-miss phrases to the corpus got the visa DM into high risk territory.
Finally, the SSE client. The browser's native EventSource is GET
only, but our analyze endpoint is POST so we can carry long
contract bodies. We hand rolled a fetch + ReadableStream parser
and got bitten by CRLF versus LF separators (sse-starlette emits
CRLF on some platforms). The fix was a one line normalization
that strips \r from the buffer before splitting on \n\n.
Accomplishments that we're proud of
The biggest one is that we resisted the temptation to fake the
demo with hardcoded responses. Every score in the demo table
comes from real WHOIS, real TLS handshakes, real DNS queries,
real Tavily searches, and a real Apertus 70B narrative. The five
entries in TUNED_OVERRIDES only nudge by at most plus or minus
five points, so even if you removed them every example would
still land in the right ballpark.
We are also proud of the visible agent reasoning. Each agent
emits a start, then tool_call and tool_result pairs with
contextual icons (a calendar for WHOIS, a shield for TLS, a
sparkle for the embedding pass), then done. The trust gauge
animates from 70 toward the final score in real time, with HSL
color interpolation across rose, amber, and emerald. Watching the
work happen is, for us, the most powerful artifact in the
project.
Operationally we are proud of the test suite (147 unit tests covering scoring branches, anchor filtering, disposable email matching, and the report PDF route), the type checked TypeScript front end, and the process level LRU caches that let judges retry inputs in well under a second.
What we learned
Two things mattered above everything else in this build.
First, visible reasoning builds the same trust the system is measuring. People believe a verdict they watched the system arrive at. Hiding the chain of thought behind a single number would have collapsed the project into yet another opaque LLM "yes this looks legit" tool.
Second, the report has to be actionable, not just a red flag, or people will not act on it. We spent real time on the synthesis prompt so the summary cites evidence with precise numbers ("the domain was registered eleven days ago", not "the domain is recent"), and on the recommended actions checklist so the user has a concrete next step.
A smaller lesson: anchor filtering is the unsung hero of any web search based verification system. The default of "trust whatever came back" is dangerously wrong because search engines will always return something.
What's next for Founder Shield AI
In the next two weeks we want to ship:
- Persistent reports so users can share a permanent URL with their cofounder or attorney instead of a session scoped report id. This is the number one piece of feedback we expect.
- Browser extension that flags suspicious links and attachments inline in Gmail and LinkedIn before the user clicks. The trust score is more useful at the moment of decision than after.
- Bilingual UI starting with Spanish, Mandarin, Hindi, and Portuguese, since the target user is by definition multilingual.
- Lawyer verification API that integrates state bar admission
databases directly instead of relying on Tavily's web crawl, so
the
lawyer_verifiedevidence becomes a structured lookup. - Tunable risk profile per user. A first time founder has different tolerances than a serial founder; the verdict thresholds should reflect that.
Longer term, we believe the same architecture (parallel evidence collection, transparent scoring, citable narrative) is the right shape for a much larger problem: any high stakes decision where the user does not have the trust network to verify on their own. Immigration scams are the wedge. The verification layer is the product.
Built With
- apertus-70b-instruct
- asyncio
- eslint
- featherless
- featherless.ai
- githubfastapi
- httpx
- hugging-face
- icann-whois
- inter
- javascript
- pip
- pnpm
- pydantic
- python
- render
- setuptools
- sse-starlette
- tavily
- typescript
- uvicorn
- vercel
Log in or sign up for Devpost to join the conversation.