John Huang← Back to experience

Case study

ENGINExLaunch

Capstone operations platform for GIX Launch, UW GIX's capstone program: team formation, mentor matching, progress tracking, and presentation feedback. Now one app built for 150+ students and 140+ mentors across GIX Launch and ENGINE.

  • Python
  • FastAPI
  • OR-Tools CP-SAT
  • Supabase
  • Next.js
  • GitHub Actions
  • 150+students and 140+ mentors across GIX Launch and ENGINE
  • < 10 sto a provably best team assignment, where the old heuristic timed out at 60 s
  • 938tests behind a 12-job CI pipeline
  • 46Klines of dead code removed, test coverage intact
Walkthrough on synthetic data, sped up (1:38): team formation, progress check-ins, presentation feedback

Overview

ENGINExLaunch is a capstone operations platform at the University of Washington that runs two capstone programs, GIX Launch and ENGINE, each through four agents: Team Formation, Mentor, Progress, and Presentation. GIX Launch is UW GIX's capstone program, with a mix of sponsored and student-led work.

The platform replaced a workflow that had sprawled across spreadsheets and manual handoffs, with hard constraints around team size, project capacity, and student eligibility that made naive automation risky. It also gave teachers and TAs a single place to see a team's past feedback and current progress, something that previously did not exist.

The platform grew as two codebases from a common start, one for GIX Launch and one for ENGINE, and the two diverged. I did all of the implementation on the GIX Launch side, which is what this page describes. In September 2026 we merged the two into one app: a single Next.js frontend and login serving both programs, with each program keeping its own services and matching logic. The merged platform is built for 150+ students and 140+ mentors across GIX Launch and ENGINE, on 8 backend services with 235 API endpoints.

My contribution

I joined an earlier version of the system in June 2026 and have authored 270+ commits since. I built the team-formation optimizer twice, first as a hill-climbing heuristic and then as an exact CP-SAT solver, and built out mentor matching, progress and blocker tracking, and presentation feedback around it.

On the infrastructure side, I introduced Alembic migrations and set up Supabase so the services can share one hosted Postgres database. I grew automated testing to 938 tests behind a 12-job GitHub Actions pipeline covering every service, and fixed test suites that had been writing to live student data on every run, taking the build from five failing jobs to one.

For the merge, I wrote a shared core package and a contract for each of the four agents. A contract describes what both programs' implementations already do, and CI checks every service against it. The merge also removed 46K lines of dead code with no loss of test coverage.

Implementation

Each of the four agents runs as its own FastAPI service and orchestrates its own LLM steps. The Presentation agent, for example, digests a team's deck, fans it out to a panel of reviewer personas, and has an orchestrator synthesize their critiques into one set of feedback.

Team Formation places students with an exact CP-SAT solver under lexicographic priorities, in a default order the coordinator can change: a student's own project picks first, then their track, then being placed at all, then team size, with ties broken on contribution-area fit and diversity. The coordinator also sets the team-size limits, which the solver treats as rules it cannot break. Coordinators get a per-student explanation of each placement and a drag-and-drop board to adjust it, so the output stays auditable rather than a black box.

Mentor matching embeds mentor expertise into ChromaDB and ranks mentors for each project by cosine similarity. I vectorized that computation into one normalized matrix multiplication, collapsed 137 per-row embedding calls into a single batch encode, and replaced full-table scans with SQL COUNT aggregates.

Progress turns TA check-in notes into structured accomplishments, blockers, and per-student contributions, which feed a cross-team blocker board and a teacher-reviewed feedback export.

I consolidated nine separate AI service integrations into one shared Python library used by all 8 services. That eliminated three hidden bugs in retry handling that had been stalling unrelated requests and burning through API quota.

Student names are anonymized before any AI call and were scrubbed from existing records. Uploads and search requests are limited to cap both memory use and API spend, and exported spreadsheets are sanitized against formula injection.

Architecture diagram of ENGINExLaunch: one Next.js frontend and login sits above the GIX Launch and ENGINE programs, which each run their own copy of the Team Formation, Mentor, Progress and Presentation services, with a separate database for each program and ChromaDB vectors. Both import a shared core package holding the agent contracts, one AI library and database setup
Service architecture after the merge
Pipeline diagram of team formation with a coordinator above every stage. The coordinator confirms the inputs, sets the team-size rules and the order of the priorities, and adjusts the resulting teams. The project deck, the student survey and a set of hard rules feed an exact CP-SAT solver, which works through the priorities in that order, each with up and down controls for reordering, and ends with a tie-break on contribution-area fit and diversity. It outputs the team assignment, a per-student explanation and a move log
Team formation, with a coordinator deciding at each step

Challenges

The first optimizer was a heuristic: greedy construction, hill climbing, and pairwise-exchange moves to break the deadlocks that appeared when every better destination was already at capacity. It worked, but minimum team size and project selection were repair passes bolted on around it, and the diversity figure it reported was not the quantity it optimized. I replaced it with the CP-SAT solver. Where the heuristic timed out after 60 seconds, the solver produces a provably best assignment in under 10 and returns the same result on every run. It treats those rules as constraints it cannot violate and reports the same number it maximizes.

The review screen was built around a log of moves, while an exact solver returns only a final assignment. I rebuilt the log by diffing the optimum against a deterministic baseline, so coordinators still see why each student moved.

The other challenge was merging the GIX Launch and ENGINE codebases, which had diverged for months. We moved both into one tree with one frontend and login, and deliberately did not reconcile their logic. The programs share no database, service process, or matching algorithm, so either can keep changing without touching the other.

What I learned

This project reinforced that optimization logic needs explainability as much as a good score. A provably best assignment is only useful if a coordinator can see why each student landed where they did, and change it.

The merge taught me that two programs can share one product without sharing their logic. Writing contracts around what GIX Launch and ENGINE already did, and checking them in CI, let us put both behind one frontend and login without forcing either onto the other's algorithms. Migrations, tests, and CI are what made that safe while both programs kept changing.