Inspiration
In the San Joaquin Valley, only 26% of ninth graders are on a path to a bachelor's degree, compared with 35% in the rest of California, and the Valley has the lowest share of adults ages 25–54 with a bachelor's degree of any California region: 19%, vs. 40% statewide (PPIC, 2024).
People here don't lack ambition. The path breaks at the hand-offs: community college to transfer, certificate to a job that pays, job to promotion. And the tools people get are a résumé, a GPA and a personality quiz. None of them let you try a job before you bet years on it, and none of them account for the things that actually decide what's possible: your hours, your budget, your commute, your kids.
We wanted one loop where every path counts equally (welding, nursing, diesel, electrician, software, farm operations, robotics, logistics) and where what you can do matters more than what's on paper.
What it does
Try. Pick one of eight local careers, or search any occupation. You play a workday of realistic moments: a pallet that won't scan, a patient who won't take their meds, a combine that throws a code at harvest. Three AI coworkers react to every choice in parallel. Don't like the options? Answer in your own words and the AI scores what you wrote. An adaptive selector picks the next moment that teaches it the most about you, and each moment is rewritten for you (your city, your coworkers, your earlier choices).
Prove. At the end of the day you get a work-style profile across O*NET 31.0's 21 work styles, your top career fits from a trained model, and real local pay.
Plan. A constraint solver builds routes (community college transfer, certificate, apprenticeship, or straight to work) that fit your real week. Type a rule in plain English ("no classes before 5pm, I work weekends"), confirm the constraints it becomes, and approve or reject the plan. A rejection becomes a new constraint and it re-solves. Pick your city and it shows the nearest campuses and drive times.
Learn. A graph neural network picks courses and jobs for you, each with a one-line reason ("Builds hydraulics → used by Diesel Technician").
Live in your area. A web-research agent runs three searches at once with Tavily (what the job is like, openings near you, training near you), ranks the sources and writes a short summary where every claim cites a source. Any sentence with a number that isn't in a cited source gets dropped.
Connect. Employers post a job (instructions hidden in a posting get flagged), then browse blind talent cards: demonstrated skills, sim performance, progress and availability. No name, photo or contact. They can request contact, but nothing is revealed until the learner accepts in their own inbox. Employers also get a fairness audit (four-fifths rule) and a skill-gap report that hides groups smaller than five.
Belong. Peer circles by life stage, a practice coach (practice, not therapy) that routes any crisis message to the 988 Lifeline, and EQ practice for things like asking for a raise, with rubric feedback.
How we built it
- Frontend: Next.js 16 (App Router, TypeScript), Tailwind CSS v4, shadcn/ui on Radix, Motion for animation, plus components from Cult UI, Watermelon UI and Skiper UI. It's a static export on Netlify that finds the API at runtime.
- Agents: FastAPI + LangGraph, five graphs, each streaming its steps live over Server-Sent Events ("Behind the scenes"):
- Sim: an interrupt waits for your choice; a
Sendfan-out runs three coworker nodes in parallel; a conditional edge throws a "crunch" moment when stress spikes. - Pathway: plain-English rules → solver → human approval loop.
- Employer: parse posting → search → fairness check → consent interrupt → gap report.
- Coach: safety check first, always.
- Research: parallel Tavily searches → rank → cited summary.
- Sim: an interrupt waits for your choice; a
- LLM: OpenAI
gpt-6-lunawith Pydantic structured outputs, a disk cache, and a deterministic offline mock so the demo never depends on Wi-Fi. - Models (PyTorch, PyTorch Geometric, scikit-learn, OR-Tools). Every number below comes from a script we ran:
- Career fit: a small MLP on O*NET work-style profiles. Top-1 71.3% vs. 70.3% for a cosine-similarity baseline (42 occupations); 93.4% vs. 92.3% on the 8 core careers.
- Adaptive selector: a Bayesian player model. The chance a player who fits career \(k\) picks choice \(c\) is \( P(c \mid k) \propto \exp\big(\beta\, \Delta_c \cdot (\theta_k - 0.5)\big) \), and the next moment maximizes expected information gain $$ \mathrm{IG}(e) = H(p) - \mathbb{E}_{c}\big[\,H(p \mid c)\,\big]. $$
- Graph recommender: a heterogeneous GNN (HeteroConv + GraphSAGE, BPR loss) vs. matrix factorization and popularity.
- Planner: OR-Tools CP-SAT vs. a greedy scheduler on 200 synthetic constraint sets. Same feasibility (48.1%), but CP-SAT finishes 0.83 months sooner on average when both find a plan; p95 solve time 190 ms.
- Claim verifier: caught 100% of 563 injected wrong numbers with 0 false positives across 741 test cases.
- Data: O*NET 31.0 (CC BY 4.0), CA EDD wage data for Stockton–Lodi (2026 Q1), Delta College and Modesto Junior College program maps, and 2,000 synthetic learners (no real people) to train the graph model.
- Storage and auth: Supabase (Postgres) mirroring SQLite, signed per-tab sessions (each browser tab can hold a different account), and a sign-up flow with location.
- Testing: 231 API tests and a 25-step end-to-end run across four accounts.
Challenges we ran into
- The venue network fought us. A filter blocked npm's registry, GitHub, Cloudflare tunnels and even
*.netlify.app. We installed through the Yarn mirror, downloaded PyTorch with resumable transfers, and made the static site discover the API at runtime so it can reach the agents on a laptop. - The data changed under us. O*NET 31.0 replaced the classic 16 work styles with 21 on a new scale, so we rebuilt the model around the real taxonomy instead of the one in our plan.
- Keeping AI output trustworthy. We used structured outputs everywhere a result drives a decision, a verifier for every generated number, and sanitizing for any text from employers, users or the web. Personalization rewrites the words of a moment without touching the math behind its choices.
Accomplishments that we're proud of
- A real two-sided product: a learner in one browser tab and an employer in another, with consent that actually gates what each side sees.
- Judges can watch the agents work live: three coworkers running in parallel, the web-research agent reading sources, the solver re-planning.
- Any career is playable, with moments researched and written on the spot.
- Every number on screen traces to a script we ran or a source we cite, including the ones where we lose.
What we learned
- Use a solver for guarantees and an LLM for language. Each is bad at the other's job.
- Baselines are strong: cosine similarity came within a point of our MLP. Measure before you celebrate.
- Fairness has to be measured, not assumed, even on synthetic data.
- Less is more on screen: one purpose per page, fewer words, motion that explains instead of decorating.
What's next for Foothold
- A hosted API so it doesn't depend on a laptop.
- Pilots with Valley high schools and community colleges using real, consented learner data.
- A counselor and parent view.
- Full program data from ASSIST and college catalogs.
- Spanish.
- A real fairness study with employer partners.
Built With
- cloudflare
- fastapi
- langgraph
- motion
- netlify
- networkx
- nextjs
- openai
- or-tools
- postgresql
- pydantic
- python
- pytorch
- pytorch-geometric
- radix-ui
- react
- scikit-learn
- server-sent-events
- shadcn-ui
- sqlite
- supabase
- tailwindcss
- tavily
- typescript
Log in or sign up for Devpost to join the conversation.