Inspiration
A great job application takes real effort: read the posting closely, honestly weigh your fit, and write materials that speak to this role, not a template. Do it right and it takes an hour. Do it at scale and the quality collapses — which is exactly why most applications get filtered out before a human ever reads them.
That's not a chatbot problem. It's a plan-and-execute problem: parse, assess, draft, log, follow up — six steps, zero shortcuts, every time. So we built the agent that runs the whole pipeline itself.
What it does
Give JobPilot one thing: a job posting and your profile. That's the whole interaction. No back-and-forth, no "what should I do next?" — it plans the job and finishes it:
- Parses the posting into structured requirements — company, title, seniority, must-have and nice-to-have skills.
- Scores your fit, 0–100, and names the specific gaps holding you back.
- Writes materials that aren't generic — tailored resume bullets and a cover letter grounded in the actual posting, not filler.
- Saves the application as a real, persisted record via a
save_applicationtool call. - Schedules the follow-up it just decided you need, via
create_followup. - Reports back — one clean summary: score, gaps, materials, next date.
Every application it's ever run stays visible on the same page, backed by the same Firestore store it wrote to. That's the point: you can watch what it did, not just read what it says it did.
How we built it
- Google ADK is the backbone —
Agent,Runner,InMemorySessionService— orchestrating the full run. The model reasons (parsing, scoring, drafting); it does not get to narrate side effects. Persistence and scheduling are real function tools it must call, not sentences it gets to write. - Gemini 3.7 Flash drives every reasoning and generation step.
- FastAPI serves a single demo page and two endpoints
(
POST /api/runinvokes the ADKRunner;GET /api/applicationsreads persisted state back) — the only thing deployed to Cloud Run. - Firestore (native mode) is the system of record.
- We verified the installed ADK package's actual
Runner/Agent/ session-service signatures against the running code before writing the orchestration layer — not just against docs — which caught mismatches while they were still cheap to fix.
Challenges we ran into
The hard part isn't getting an LLM to talk about a six-step plan — it's making it finish one, unattended, with real consequences at each step. That meant drawing a hard line: reasoning stays with the model, every side effect goes through an explicit, auditable tool. Getting the instruction tight enough that it executes end-to-end in a single pass — no stalling for confirmation between steps — took real iteration.
What we learned
An agent framework is only as trustworthy as the boundary between "the model reasoned about this" and "the model actually did this." Free-form text generation for judgment calls, narrow tool calls for anything that touches real state — that boundary is what turns a chat transcript into an agent you can actually rely on.
What's next
Batch runs across multiple postings in one pass, a gap-driven learning resource recommender, and calendar integration for the follow-ups it already schedules.
Built With
- agentic-ai
- css
- docker
- fastapi
- gemini-3.7-flash
- gemini-api
- google-adk
- google-cloud
- google-cloud-firestore
- google-cloud-run
- html
- javascript
- llm-agents
- python
- uvicorn
- vertex-ai
Log in or sign up for Devpost to join the conversation.