Inspiration

What it does

RepUp — Duolingo for Developers

Inspiration

As developers, we all know we should code every day. we know consistent practice is what separates good engineers from great ones. But knowing something and doing it are very different things — life gets in the way, motivation fluctuates, and there's no feedback loop that makes daily coding feel rewarding.

I looked at how Duolingo turned language learning — something most people give up on — into a daily habit for millions of people. The answer wasn't better content. It was streaks, XP, leaderboards, and a tiny dopamine hit every time you showed up. I wanted to bring that same psychology to software development.

That was the spark for RepUp.

What I Built

RepUp is a Chrome extension that sits inside your browser and turns your existing GitHub workflow into a game. It tracks your real coding activity, rewards you for showing up every day, and adds a layer of AI-powered tooling that makes you a better developer while you're at it.

The core features are:

  • Daily streaks and XP based on real GitHub activity — commits, pull requests, README updates, and issue comments all count
  • A daily coding challenge — a new bugfix puzzle every day in a randomly selected language, graded by Gemini AI with a speed bonus for fast solvers
  • A global leaderboard showing who solved the challenge fastest and most accurately
  • An AI code review sidebar injected directly into GitHub that analyzes any file or PR diff using Gemini 2.5 Pro, flagging bugs, security vulnerabilities, performance issues, and code smells in real time
  • A decoration shop where you spend XP on cosmetic themes
  • A todo list and repo bookmarks for managing your dev workflow without leaving the extension

How I Built It

The project is split into three layers.

The Chrome extension is built in React with Tailwind CSS and compiled as a Manifest V3 extension. The AI code review sidebar is injected into GitHub pages using a content script and isolated inside a Shadow DOM so it can't interfere with GitHub's styling. Because GitHub sets a strict connect-src Content Security Policy that blocks cross-origin fetches from content scripts, I route all backend requests through the background service worker which has its own extension-level CSP.

The backend is a Python FastAPI server deployed on Google Cloud Run. It has three main responsibilities: generating the daily coding challenge using Gemini, grading user submissions, and streaming code review results back to the extension as NDJSON. The review endpoint streams section by section (bugs → security → performance → smells → grade) so results appear progressively rather than making the user wait for a single response.

The data layer uses Firebase Firestore for user profiles, XP, streaks, and submissions, and Firebase Authentication with GitHub OAuth for login.

$$\text{Total XP} = \text{score} + \begin{cases} 50 & \text{if elapsed} \leq 120s \ 30 & \text{if elapsed} \leq 300s \ 15 & \text{if elapsed} \leq 600s \ 5 & \text{otherwise} \end{cases}$$

Speed bonuses are calculated server-side so they can't be manipulated by the client.

Challenges I Faced

GitHub's Content Security Policy was the first major wall I hit. Content scripts in Chrome MV3 inherit the host page's CSP, which means any fetch() call from my review script to my backend was blocked by GitHub's connect-src directive. The fix was to proxy all backend requests through the background service worker via a long-lived chrome.runtime.Port, which has its own extension CSP and is exempt from the page's restrictions.

Chrome's aggressive service worker lifecycle was another constant battle. Chrome MV3 kills background service workers after a short idle period, which meant long-running code reviews would fail mid-stream with "Extension context invalidated." I solved this by adding a keepalive ping every 20 seconds using chrome.runtime.getPlatformInfo while a review is in progress.

GitHub's SPA navigation meant that switching between files didn't trigger a page reload, so my content script couldn't just listen for DOMContentLoaded. I patched history.pushState and history.replaceState, added a popstate listener, watched <title> mutations with a MutationObserver, and added a 500ms polling interval as a final fallback to catch any navigation that slipped through all other detection methods.

Keeping the leaderboard fair required me to calculate the speed bonus server-side and ignore whatever the client reported. I also set incorrect submissions to a total score of 0 so they can't appear on the leaderboard, while still awarding one-third of the correctness score as partial XP so a near-miss never feels completely worthless.

What I Learned

  • Shadow DOM is genuinely powerful for injecting UI into third-party pages without style conflicts
  • Chrome MV3's service worker lifecycle is far more aggressive than documented and requires explicit keepalive strategies for long-running operations
  • Streaming NDJSON from a FastAPI backend feels much more responsive than waiting for a single JSON response, even when the total latency is the same
  • Gamification mechanics only work if the underlying activity is real — tying XP to actual GitHub commits rather than arbitrary in-app actions was the right call

What's Next

  • Team leaderboards and clan XP
  • A shareable public profile page with embeddable GitHub README stats card
  • Bug pattern analysis — after enough reviews, identify what types of mistakes I personally keep making
  • Cross-repo issue board aggregating all my open issues in one view ## How we built it

Challenges we ran into

Accomplishments that we're proud of

What we learned

What's next for RepUp

Built With

  • artifact-registry-apis-github-rest-api
  • chrome-extension-(manifest-v3)
  • chrome-identity-api
  • chrome-side-panel-api-dev-tools-node.js
  • chrome-storage-api
  • craco
  • fastapi
  • firebase-authentication
  • git
  • github-oauth-cloud-&-hosting-google-cloud-run
  • google-cloud-build
  • here's-your-full-tech-stack:-frontend-react
  • shadow-dom-backend-python
  • tailwind-css
  • uvicorn-ai/ml-google-gemini-2.5-pro-(via-gemini-api)-database-&-auth-firebase-firestore
  • yarn
Share this project:

Updates