Team RJMD · CTPHacks
A coding coach that asks instead of answers. Chrome MV3 side panel.
Working name. Rename in
extension/manifest.jsonandpackage.jsonif the team picks another.
npm install
npm run devThen chrome://extensions → Developer mode → Load unpacked → select dist/.
main must always load unpacked. A commit that breaks that gets reverted.
| Folder | Track | Owner |
|---|---|---|
extension/ |
A — plumbing | |
panel/ |
B — panel UI | |
server/ |
C — coaching brain | |
visuals/ |
D — visuals & story | |
shared/ |
four owners. Changes are announced and merged alone. | |
fixtures/ |
seed data so B and D build with the backend deleted |
If you need something in someone else's folder, ask them for it. Don't edit it.
shared/contracts.ts is the interface boundary. Every message, request, and
response in the app is one of its types. shared/profile.ts holds the only
logic that may mutate a learner profile.
panel/state/useCoach.ts exports USE_FIXTURES. It is true until CP3.
While it is true the panel renders entirely from fixtures/ — no service
worker, no adapter, no backend.
Paste (A5) is the default demo path, not the fallback. The LeetCode adapter is the upgrade. Never let the demo depend on scraping Monaco.
POST /coach always returns HTTP 200 with a valid CoachResponse. On model
error, timeout, or validation failure it returns the hardcoded fallback. The
extension has no error branch for it.
Runs on Gemini. Two calls per turn, deliberately:
- Diagnose — Gemini picks one id from our frozen taxonomy.
- Our code increments the count and picks the hint level + modality.
- Coach — Gemini writes the words under those constraints.
- Our code validates and silently falls back if it misbehaved.
The model never decides how hard to push. That is the product.
npm testnpm run dry-runnpm run evaldry-run walks six attempts on the same misconception with no API key and no
network, and prints what the machine chose each time. Use it to rehearse the
escalation beat before demoing it.
eval runs 10 hand-written explanations through the real model and scores the
diagnosis. Currently 10/10. Add -- --live to run it against the deployed
endpoint instead of the local handler.
The Gemini free tier allows 15 requests per minute, and every learner turn
costs two (diagnose, then coach). That is roughly 7 turns a minute across
everyone using it at once. On a 429 the coach falls back to the hand-written
responses in server/lib/fallbacks.ts — it stays in character and the demo
keeps working, which is the entire reason those are written as product. Do not
run npm run eval while someone is demoing.
api/coach.js is generated and committed. Vercel discovers functions by
scanning the repo, and its edge bundler rejects the .ts import specifiers the
test runner needs — so scripts/build-api.mjs bundles the whole handler graph
into one file. Run npm run build before pushing any change under server/
or shared/, or the deployed coach will be stale.
Set GEMINI_API_KEY and COACH_MODEL in the Vercel dashboard — never in the
repo. Then put the deployed URL into COACH_ENDPOINT in shared/contracts.ts
and the matching origin in extension/manifest.json under host_permissions.
visuals/analogies.ts is done — six analogies, with a test that fails if any of
them reaches for the vocabulary of the thing it explains.
visuals/videos.ts is half done. The why lines are written; the video IDs
and timestamps are not, and cannot be — someone has to watch the clips and scrub
to the right moment. Instructions are at the top of the file. An entry with an
empty youtubeId counts as absent, and the coach routes around the video rung
rather than rendering a dead player, so shipping it half-filled is safe.
Every stub is tagged TODO(<task id>) matching the task breakdown. Grep for
your track letter:
grep -rn "TODO(A" extension/