
careersphere
A PyCon Singapore 2026 champion project that maps a person's skills to realistic career moves using OpenAI, SkillsFuture data, live job signals, and a 3D role sphere.
the hackathon brief
Career advice has two common failure modes: it is either too generic, like “learn AI,” or too overwhelming, like a wall of 500 skills with no priority. careersphere was built for the Pycon Singapore 2026 Hackathon, which was presented in collaboration with OpenAI and AI Singapore, to answer three more useful questions:
- Where do I stand right now?
- Where can I realistically go next?
- What should I do today?
I built it with my friend Kieran Ho, and we won 1st place, champion with it. The event brief put real weight on Python, OpenAI, transparent data use, and clear next steps, so the core idea was to build a career guidance tool where the data decides and the AI interprets. A user can paste a resume, describe their background, mention constraints like salary or timeline, or simply say they are not sure what to do next. The app turns that into a grounded career map.
what we built
careersphere is a Singapore-focused career exploration app. It parses your profile, matches your skills to official SkillsFuture skills, compares you against official role requirements, and shows which roles are ready now, which are within reach, and which skills you would need to build to unlock those reachable roles.
The product flow is intentionally linear: onboarding, live analysis, sphere, where you stand, where you could go, then how to get there. Career tools can get messy quickly because there are too many directions to scan. Instead of making the user stitch together a dashboard, careersphere moves one step at a time: first understand the person, then show the landscape, then explain the realistic options, then recommend an action.
the career sphere
The visual center of the product is a 3D career sphere. You sit at the center. Every official Singapore role becomes a node. Roles closer to you are more relevant to your background; roles farther away need a bigger jump. Node color moves from green to yellow to red based on readiness.
That mattered for the demo. A sphere looks impressive, but if it is just a pretty animation it becomes decoration. The useful part is that it gives the user a map feeling: near roles feel close, distant roles feel like larger moves, and clusters make adjacent paths easier to see before the page narrows down into ranked recommendations.
data, agents, and live signals
The backend uses three main public data sources:
- SkillsFuture Skills Framework for official sectors, roles, role descriptions, required skills, and proficiency levels.
- MyCareersFuture job postings for market-facing job signals and listed skills.
- SkillsFuture Courses API for live course options tied to the user’s skill gaps.
The app also uses SkillsFuture course data for practical next steps. The SkillsFuture framework becomes a baked DuckDB snapshot with role, skill, proficiency, and embedding metadata, so request-time analysis can stay fast enough for a live web app.
In production, job freshness is handled outside the user request path. A scheduled ingest pulls the newest MyCareersFuture postings, updates the job store, rebuilds the DuckDB artifact, and ships a refreshed container with the latest baked-in snapshot. The app can then rank fresh jobs quickly without scraping or joining huge datasets while someone is waiting on the page. Course freshness stays live: when the engine identifies the skills needed for a reachable role, it can call the SkillsFuture Courses API and show current options to close those gaps.
The architecture is deliberately split. OpenAI handles language-shaped work: parsing messy profiles, extracting intent, embedding text for semantic matching, routing a constrained tool loop, and explaining computed results. Python handles the parts that should be auditable: role fit, gap ranking, job matching, course lookup, and evidence payloads.
agent as orchestrator
The most important backend design choice was making the AI act like an orchestrator, not the source of truth. A request does not go to one giant prompt that returns career advice. Instead, the model runs inside a constrained tool loop and can call only backend tools we expose.
Those tools include:
parse_profileto turn messy resume or free-text input into structured skills and evidencematch_skillsto map user evidence to SkillsFuture skillsfind_rolesandfind_reachable_rolesto retrieve grounded role candidatesrank_gapsto choose the highest-leverage skill gapfind_coursesto connect gaps to SkillsFuture coursesrank_jobsto match live or cached job postings against the user’s skills
Each tool returns structured JSON from deterministic Python code. The agent can decide the sequence and explain the results, but it cannot write arbitrary SQL, invent a role, or override the scores. That was the line that made the system feel like an actual career engine rather than a chatbot with a nicer UI.
AI with boundaries
The OpenAI path uses Structured Outputs, embeddings, and a tool-calling loop over allowlisted backend functions. The model can ask for operations like parse_profile, match_skills, find_roles, rank_gaps, find_courses, and rank_jobs, but each tool delegates to deterministic code and returns checkable JSON.
It cannot invent new SkillsFuture roles, change proficiency requirements, rank jobs without evidence, or make up salaries and courses. If the live model path fails or latency gets too high, the app falls back to the fixed deterministic orchestrator with the same response shape.
The scoring path looks roughly like this:
profile text
-> structured profile parse
-> skill matching with embeddings and deterministic fallbacks
-> official role requirement lookup
-> role fit scoring
-> gap ranking
-> course lookup
-> job ranking
-> explanation from computed JSON
live jobs and courses
careersphere does not stop at “you should learn X.” It tries to connect the recommendation to something the user can actually do next.
For jobs, the app ranks freshly ingested MyCareersFuture postings against the user’s current skills and the roles the engine selected. The result is not a generic job search page: each posting is shown because its listed skills overlap with the user’s profile, and the UI keeps matched and missing skills visible so the user can tell why it appeared.
For courses, the app connects the skills needed for a reachable role to live SkillsFuture course options. That matters because a gap is only useful if it becomes an action. If the system says Database Administration is one of the skills holding back a role, it should also be able to show relevant courses, providers, and registration links instead of leaving the user to search from scratch.
how fit is scored
The core fit calculation uses official role-skill-proficiency rows. A missing skill gets level 0; partial proficiency gets partial credit; duplicate mapped requirements keep the maximum required level.
| Signal | What It Measures | Who Decides |
|---|---|---|
| Role relevance | Whether the full profile is semantically close to the role | Embeddings + guardrails |
| Framework fit | How much of the official role requirement ladder the user covers | Deterministic Python |
| Gap priority | Which skill is close, reusable, market-visible, and future-facing | Deterministic Python |
| Explanation | How to translate the computed result into readable advice | OpenAI, from JSON |
This split was important because raw official coverage is useful but not the whole story. Some framework rows are broad or surprising in context, so the app blends role relevance with official coverage and gap penalties. The UI can then say “this role fits your background” while still showing which official skills are missing.
the shipped flow
The final demo flow starts with one input bar: paste text, describe your career, or attach a resume. Then the app asks where you want to go next and whether you want the analysis to lean future-proof. A live loader runs while the backend parses the profile, matches skills, and scores the role landscape.
After that, the app shows:
- the 3D sphere of official roles
- ready-now roles and aspirational next-move roles
- the skills needed to move from your current profile into a chosen role
- live SkillsFuture courses to close that gap
- matching jobs ranked by listed-skill coverage
- inline “why?” evidence and assumptions
For example, a non-programmer does not just get told to “learn Python.” The app can show that senior roles in their own field already require data analytics or automation, surface the adjacent skill that unlocks them, and point to live SkillsFuture courses to close that gap. That was the product thesis: build on what someone already has instead of telling them to restart from zero.
process as part of the build
The hackathon was judged half on product and half on process, and the official framing around OpenAI and AI Singapore made that feel less like a normal weekend build and more like a test of how well we could combine AI tooling with credible public-sector skills data. The repo kept a real trail: DECISIONS.md, PRD notes, data and algorithm cards, failure cases, and AI collaboration logs. That was not just submission polish. It helped us make better tradeoffs during the build.
We also kept an ai_collab_log.md that recorded what each of us added to the project as the build moved. That mattered because Kieran and I were not just splitting tickets and disappearing into separate corners. We spent a lot of time bouncing ideas off each other, arguing through product shape, checking whether recommendations felt realistic, and deciding what to cut. Both of us had built plenty of projects alone before, so the biggest shift was how much more communication the team version required. When it worked, we were genuinely more than the sum of our parts: one person’s half-formed idea would become sharper after the other person pushed on it.
The most useful process rule was simple: features where the LLM decides felt like wrappers; features where the data decides and the LLM translates felt substantial. That rule helped us cut tempting features like a resume editor and focus on the grounded recommendation loop.
We also used AI heavily while building. Codex helped with backend loops, tests, and UI iteration, but the hard part was still judgment: checking traces, reading generated code, tuning weights, deciding which recommendations felt realistic, and making the demo robust enough to run on stage.
what stuck with me
Grounding is a product feature. Career recommendations need evidence because the user has to trust the advice before acting on it. Showing the source row, missing skill, and match reason is part of the UX, not just backend hygiene.
A good visualization needs a job. The sphere worked because it framed the role landscape before the page narrowed into concrete actions. Without the ranked roles, gaps, jobs, and evidence around it, it would have been a cool graphic instead of a useful tool.
AI agents need rails. The live OpenAI tool loop was useful because it could interpret flexible input and route analysis, but it stayed inside a small tool registry. The model did language work; the backend owned facts and scores.
Hackathon speed exposes architecture quickly. AI assistance let us ship more than we could have by hand in the same time, but it also made technical debt appear faster. The useful loop was not “prompt and trust”; it was prompt, inspect, test, argue with the result, and keep the pieces that survived.