all projects
01 2026 - now Full-stack · AI

An AI civic assistant for Nigerians that answers questions about your rights, grounded in real law, with sources you can open yourself.

For most people, the law is unreadable. Knowing your rights in Nigeria means either wading through statutes written for lawyers or trusting a stranger online who might be wrong. VeraCivic answers a plain-language question, like "can the police search my phone?" with a grounded answer drawn from the actual Constitution and Acts and a citation you can open and check yourself.

It's built as a LangGraph ReAct agent with six retrieval tools over a Qdrant vector store: an authoritative law corpus (Constitution and Acts) alongside a rolling news index refreshed every 15 minutes. The model's own memory is never treated as a source; every claim is grounded in retrieved evidence. Before an answer reaches a user it passes a faithfulness gate (claim extraction plus verification, with a ≥0.7 grounded-score threshold), backed by eval suites covering in-scope civic questions, out-of-corpus negatives, and adversarial red-team prompts, plus prompt-injection hardening that fences all untrusted web and news content as data.

The design has a spine: the safety and danger path, covering emergencies, abuse, and life-safety resources, is always free, unmetered, and never behind a login. I built and shipped the whole thing solo, with a freemium model in flight.

  • LangGraph ReAct agent with 6 retrieval tools over a Qdrant vector store (FastEmbed/BGE embeddings); multi-provider by design, with Gemini 2.5 as default and Anthropic Claude swappable via config.
  • Citation-grounded answer generation behind a faithfulness eval harness (claim extraction plus verification, ≥0.7 grounded-score gate); the model's memory is never a source.
  • Prompt-injection hardening that fences all untrusted web and news content as data, with eval suites for in-scope questions, out-of-corpus negatives, and adversarial red-team prompts.
  • Safety and danger path always free, unmetered, and never behind login; freemium billing (Paystack) in flight.
#Python#LangGraph#RAG#Qdrant#Agent Evals#Next.js#TypeScript
read case study →
02 2026 Creator, Python

An open-source, evidence-grounded evaluator for AI agents, published on PyPI. It grades an agent against its real tool outputs, not LLM-judge vibes.

attest is an open-source tool for evaluating AI agents. Most ways of grading an agent ask another model, "Is this answer good?" which is surprisingly easy to fool. Research has shown that simply rewriting an agent's reasoning, while leaving what it actually did unchanged, can inflate an AI judge's false-positive rate by up to 90%. attest takes the opposite approach. It never trusts what the agent says it did. It breaks the answer into individual claims and checks each one against the agent's real tool outputs, the receipts, grounding every verdict in the exact piece of evidence behind it.

It runs four checks: faithfulness, whether the answer matches what the tools returned; tool-use correctness, whether the right tools were called and errors handled; prompt injection, whether hidden instructions in tool data hijacked the agent; and role adherence, whether the agent stayed within its defined job or got talked out of it. It works across Anthropic, OpenAI, and Gemini behind one interface and returns a single typed report with per-check scores.

I designed and published it as a pip-installable package, agent-attest, with automated releases; hardened its own judge against the same injection it looks for; and made it cheap to run at scale by batching the verification. I use it the way evals are meant to be used: as a test suite. A spec of expected agent behaviour, graded by attest, that turns red when the agent regresses, so a problem shows up as a failing check instead of reaching production.

  • Designed and published a pip-installable evals package (agent-attest), MIT-licensed, with automated PyPI releases via GitHub Actions Trusted Publishing.
  • Four checks: faithfulness, tool use, prompt injection, and role adherence, across Anthropic, OpenAI, and Gemini.
  • Grounded in current research (Gaming the Judge, 2026): rewriting an agent's reasoning can inflate an LLM judge's false-positive rate by up to 90%.
  • 73 offline tests, dogfooded in a real LangGraph agent's eval suite.
#Python#LLMS#Evals#Pydantic#Langchain#AI Agents#Prompt Injection#Security
read case study →
03 2026 Full-stack · AI

An LLM-powered Discord music bot that understands vibes, not just song titles — ask for "some chill vibes" and Gemini curates the queue.

Most Discord music bots are glorified search boxes — you give them an exact title, they play it. This one treats requests the way a friend would: you describe a mood, a fragment of lyrics, or a half-remembered song, and a Gemini agent figures out what you actually want.

Under the hood, each Discord server gets its own MusicAgent instance that owns the voice connection, audio player, and queue. Slash commands that are unambiguous (/skip, /pause) bypass the LLM entirely to save tokens — only the fuzzy requests go through Gemini. The agent can clarify ambiguous asks, suggest tracks for a mood, curate full playlists on demand, and politely refuse non-music requests without wasting a token on them.

It's self-hosted on purpose: YouTube blocks datacenter IPs, so the bot runs on a home server or a Raspberry Pi. A deliberate constraint that kept the scope honest.

  • Per-guild MusicAgent with isolated voice connection, queue, and audio state
  • Gemini-powered intent routing — play, clarify, suggest, curate, or reject
  • AI playlist curation: "/playlist 90s road trip" → a 10–15 track queue
  • Direct commands skip the LLM entirely to stay token-efficient
  • Channel lock, auto-leave after 5min idle, structured Pino logging with secret redaction
  • Zod env validation — fails fast at startup if anything's missing
#Typescript#Node.js#Discord.js#Gemini#yt-dlp#Vitest#Zod
read case study →
04 2025 Research + Full-stack development

A CNN-based facial emotion recognition system trained on FER2013, CK+, and AffectNet datasets, with D3.js sunburst visualisations representing emotional states.

My MSc thesis project at Big Academy UAE / Euclea Business School. The research side trains and compares three CNN models from scratch — one on FER2013, one on CK+, one on AffectNet — to measure how well each generalises across datasets. No transfer learning, no pretrained weights, just standard convolutional architectures to establish honest baselines.

The applied side is a full-stack web app. Upload a photo, point your webcam, or drop a video, and the system detects faces and classifies emotions in real time. The backend runs on FastAPI with OpenCV for face detection and TensorFlow for inference. The frontend is a React app with pages for each input mode, a research overview, and an interactive emotions reference.

The point wasn't to beat state-of-the-art benchmarks — it was to understand where simple models break down across different data conditions, and to build something usable that demonstrates the findings.

  • Full research pipeline: preprocessing, training, confusion matrices, per-class metrics, and visualisation
  • React frontend with interactive emotions reference, research overview, and multiple analysis modes
  • FastAPI backend with OpenCV face detection and TensorFlow inference, deployed on Render
  • Live web app with webcam, photo upload, and video analysis — faces detected and emotions classified in real time
  • Three CNNs trained from scratch on FER2013 (59%), CK+ (100%), and AffectNet (62.5%) with cross-dataset evaluation
#Python#Deep Learning#D3.js #React.js
read case study →
05 2025 Senior Backend Developer

Multi-sided marketplace with real-time notifications (Socket.IO), Paystack payment integration, dual-order management for food delivery and e-commerce, and geospatial rider tracking.

A Node/TypeScript backend powering a four-sided marketplace: customers, two kinds of merchants, and delivery riders, all converging on one shared platform for payments, notifications, and dispatch. Each role has its own auth flow and order lifecycle, but every transaction has to stay consistent across all of them.

The interesting engineering wasn't the happy path — it was everything that breaks when money and physical goods are involved. Payment splits between merchants and the platform that have to land in the right wallets every time. Order state machines that need to survive crashed apps, dropped sockets, and payment webhooks arriving out of order or arriving twice. Ledgers that have to reconcile cleanly after a partial refund. Media buckets that slowly fill with orphaned uploads from abandoned listings.

Most of what I'm proud of in this project isn't visible to the end user. It's the recovery scripts that reconstruct orders from payment provider records when something fails midway. The scheduled cleanup crons that keep storage costs honest. The careful state transitions that make sure a rider disconnect mid-delivery doesn't leave the customer hanging or the vendor unpaid. The kind of work that only matters when things go wrong — which, in production, is constantly.

  • Multi-role auth with social SSO, email and phone verification, and role-based access control
  • End-to-end order lifecycle from cart to settlement, with deterministic recovery paths for every failure mode
  • Payment integration with automatic multi-party splits, virtual accounts, and refund flows driven by webhooks
  • Append-only transaction ledger backed by an event log for reconcilable wallet history
  • Real-time order tracking and live dispatch updates over WebSockets
  • Production hardening: scheduled media-cleanup jobs, order-recovery tooling, refund scripts, rate limiting, input validation
#Node.js #Socket.IO#Paystack#MongoDB#Express#TypeScript
read case study →
06 2022 - now Fullstack Developer

A real-time multiplayer gaming platform with matchmaking, in-game chat, and player presence — Tic-Tac-Toe and Ludo, playable in the browser. New games will be added as time goes.

Gamebase is a browser-based multiplayer platform where players sign up, get matched, and play board games against each other in real time. Currently supports Tic-Tac-Toe and Ludo, with matchmaking queues, private invites, in-game messaging, player profiles, and a report system.

Everything runs on WebSockets. Game state, turns, matchmaking, presence, and chat all flow through a single Socket.IO connection per player. The server keeps each game room in memory and persists it to MongoDB so players can reconnect after a dropped connection without losing their match. Disconnects get a grace period before the game is forfeited — if you come back in time, you pick up exactly where you left off.

The frontend is a React SPA with a space-themed auth flow and sound effects for game events. The backend is Node/Express with a full socket layer handling five separate handler modules: game logic, chat, matchmaking, Ludo lobbies, and reports.

  • Real-time multiplayer Tic-Tac-Toe and Ludo with turn-by-turn state sync over WebSockets
  • Matchmaking queues with automatic pairing and private invite links
  • Reconnection handling — dropped players get a grace period and rejoin without losing the game
  • In-game chat per room with conversation persistence in MongoDB
  • Player presence system — online, away, in-game — broadcast to all connected clients
  • Profiles with game stats, points, and match history
#React#Node.js#Express#Socket.io#Tailwindcss#Mongodb
read case study →
07 2022 Frontend Developer and Co-creator (team of 5, open-source)

Chrome DevTools panel (Manifest V3) with real-time AST visualisation, prop/state diagramming, and D3.js dependency trees

Sveltool is a Chrome extension that adds a panel to DevTools for inspecting Svelte applications. It parses the running page, extracts the component hierarchy along with each component's props and state, and renders the whole thing as an interactive tree using D3.js.

Built at Codesmith with a team of five and open-sourced under OSLabs. My work focused on the component parser, the D3 tree rendering, and the DevTools panel integration. The extension injects a content script that walks the Svelte component tree in the page context, serialises it, and sends it to the DevTools panel over Chrome's messaging API.

  • Chrome DevTools extension — adds a dedicated Sveltool panel for inspecting Svelte apps
  • Parses live Svelte component trees with props and state for each node
  • Interactive D3.js tree visualisation of the component hierarchy
  • Built and open-sourced with a team of five under OSLabs at Codesmith
#Svelte#Chrome Extension#D3.js#TypeScript
read case study →

© 2026 adepeju orefejo