Vibe Coding in Action: Building an AI-Powered Hiring System at Electrum

At Electrum, hiring isn’t just a task for the HR team—it’s a big part of how we build the future of electric mobility in Indonesia. As one of the first Software Engineers here, I’ve seen how the right people can speed up everything we’re trying to achieve in urban transportation.
But one quiet Wednesday afternoon, a message on LinkedIn stopped me for a moment.
"I just wanted to know if I was still being considered."
It wasn’t the first message like that. That week alone, several candidates had reached out, unsure about their application status. Some had been reviewed but got no follow-up. Others were still waiting, wondering if anyone had even seen their CV.
And that made me think: for a company that uses tech in almost every part of our product—from battery swapping to smart charging—why are we still slow in replying to candidates?
As Electrum grew, the number of applications doubled in just three months. But our internal tools, which were fine when we were small, couldn’t handle the new volume. Our HR team saw this problem early and had been asking for help. But even with their full effort, the system was stuck in a loop of manual work:
- Too Many Steps: Each application meant downloading CVs, checking them one by one, organizing files, and updating spreadsheets—necessary, but time-consuming.
- Not Enough Time for People: With so much admin work, HR had less time for real conversations and evaluating talent.
- Slow or No Replies: Even with detailed tracking, some candidates didn’t get updates. A few were left hanging with no answer at all.
When I spoke with our HR Team, one thing was clear: we all wanted the same thing—better support for candidates and each other. So we agreed on four simple goals:
- Reply to every candidate quickly and clearly.
- Free up HR from repetitive admin tasks.
- Create a system that grows with us.
- Keep the human part—judgment and empathy—at the center.
Sometimes, great projects begin with a simple question: “How can we help each other work better?”
That question turned into a real partnership between Engineering and HR. The next morning, I sketched a rough idea using AI to automate hiring pipeline. And along the way, I saw the value of what some people now call “vibe coding”—a way of building things quickly where AI helps write the code.
The Crossroads: Embracing Speed with Principles
We were at a crossroads. Applications kept coming in, and the backlog was growing every day. We couldn’t afford to wait months to build a perfect solution using traditional software development—with long planning, long reviews, and even longer timelines.
We needed to move fast. But we also needed to do it right. That’s when we tried something new: vibe coding..
What is Vibe Coding?
Start with the outcome you want—the "vibe"—and use AI tools to help generate and refine the code. You stay in control, guiding the system based on human judgment and engineering best practices.
For this project, I used Google’s Gemini models and Cursor (https://cursor.sh), an AI-powered code editor.
back to this AI-Powered Hiring System, we had to ask ourselves: Can AI really help build something as sensitive as a hiring system? Can we trust AI code with candidate data?
The answer wasn’t blind trust. It was about setting clear rules before writing a single line.
Our Guiding Principles
1. **Human-in-Command:** AI helps, but people decide. All important judgments about candidates stay with our HR team and hiring managers.
2. **Privacy First:** Candidate data is sensitive. Security and compliance aren’t optional—they’re built in from the start.
3. **Transparency is Key:** The system should make communication better. Every applicant deserves to know where they stand.
4. **Maintainability Matters:** The solution must be easy for our team to understand and manage—no AI experts required. Clean, well-structured code is a must, even if AI drafts it.
With these principles as our compass, we were ready to try this faster, AI-assisted approach to our hiring challenge.
Sketching the Solution: A Digital Hiring Crew
With our principles set and speed essential, we started designing the solution. Our goal was simple: make things better for candidates (faster updates) and for HR (less manual work, more clarity). To achieve this, we envisioned a team of digital assistants—each with a clear job, working together.
Automate your initial candidate screening pipeline with AI.
Electrum Digital Hiring is an AI-powered system designed to streamline recruitment workflows. It integrates seamlessly with Google Workspace (Gmail, Drive, Sheets) and leverages Google's Gemini AI to automate the processing, screening, and initial communication stages of hiring.
✨ Features
- 📧 Automated Email Intake: Monitors a designated Gmail inbox for new applications.
- 📄 Intelligent CV Processing: Extracts and validates CV attachments (PDF, DOC, DOCX, PPT).
- 🤖 AI-Powered Role Matching: Uses Google Gemini to match candidates to open roles defined in a Google Sheet.
- ☁️ Secure Document Storage: Uploads relevant CVs to a specified Google Drive folder.
- 📊 Centralized Tracking: Logs all application details and statuses in a Google Sheet.
- 🧠 Smart CV Screening:
- Converts CVs to Markdown for analysis.
- 🔒 Redacts Personally Identifiable Information (PII) before sending to the AI model.
- Utilizes Google Gemini for in-depth analysis, generating:
- Professional summaries.
- Key skill identification.
- Candidate rating (high, medium, low, skip).
- Justification for the rating.
- ✉️ Automated Notifications: Sends personalized rejection emails (based on templates) for candidates not moving forward.
How it works in detail:
- Intake Assistant: Watches the
digital-hiring@electrum.id
inbox, finds applications, grabs attachments (PDFs, DOCX), uploads them to Google Drive, and adds candidate info to our Google Sheet tracker. - Screening Assistant: When Intake logs a new application, this assistant fetches the CV from Drive, turns it into text (using
markitdown
), and redacts all personally identifiable information (PII) before sending it to Gemini AI for analysis. It writes a summary, lists skills that match the job, suggests a fit rating (low
,medium
,high
), and explains why—all added to the candidate’s row in the Sheet. - Notification Assistant: Makes sure no candidate is left waiting. It checks the Sheet for rejected candidates and sends them a personalized status email using templates. It marks each candidate as
NOTIFIED
to avoid duplicates.
Crafting the Code: Structure Amidst Speed
Does "vibe coding" mean forgetting about good structure?
Not at all. While AI helps us write code faster, good architecture keeps things maintainable, testable, and understandable—even after the initial rush. We needed speed, but we also needed a system that wouldn’t turn into a mess.
We followed principles from Clean Architecture. The main idea is simple: keep different responsibilities separate, so each part of the code does one job and doesn’t get tangled up with the rest. This is especially important with AI in the mix—structure gives boundaries, so AI-generated code fits where it should and follows our business rules.
How We Structured the Code
To make this separation clear, here’s how the layers interact:
What this means:
- Domain Layer: The core, with business objects (
Candidate
,Email
, etc.) and rules. It doesn’t depend on anything else. - Services Layer: Holds the main application logic. It knows what to do, but not how to get or store data.
- Repositories Layer: Defines interfaces for data access, but doesn’t implement them.
- Infrastructure Layer: Connects to external systems like Gmail, Google Sheets, and Gemini AI.
Detailed Class Diagram: How the Core Components Connect
To make things clearer, here’s a class diagram showing how our domain models, repositories, services, and infrastructure come together—especially in the screening flow:
Why Does This Matter?
Good architecture makes AI copilots more effective. Clear separation of concerns means less hallucination, easier code navigation, and better suggestions. When the codebase is predictable and modular, it becomes easier to reason about, easier to change, and easier to track—whether you're human or AI.
In the end, good structure isn’t just for the code—it’s for the people (and tools) that work with it, too.
The Vibe: A Conversation with Code
I started treating coding like a conversation. Instead of working alone, I’d write a prompt, describe what I needed, and let AI (using Cursor and Gemini) take the first shot. Sometimes the results were spot-on. Other times, I’d nudge the AI, clarify my intent, or ask for a tweak. It felt less like typing alone, and more like pair programming with a super-fast assistant.
Ever wondered what it’s like to have a coding partner who never gets tired? Here’s a real example. I asked Cursor:
"Write a Python class to wrap the Gmail API for fetching unread emails, downloading attachments, and sending replies. Include retries and error handling. Use googleapiclient."
The AI came back with something like:
class GmailClient:
def fetch_new_emails(self) -> List[Dict[str, str]]:
# ...fetch unread emails...
def get_email_details(self, message_id: str) -> Tuple[str, str, str, List[Dict[str, str]]]:
# ...get subject, snippet, from, attachments...
def download_attachment(self, message_id: str, attachment_id: str) -> bytes:
# ...download attachment...
def send_email(self, to_email: str, subject: str, body: str, ...):
# ...send email...
def reply_to_email(self, original_message_id: str, body: str, ...):
# ...reply to email...
I repeated this for Drive and Sheets, asking AI to generate classes that handled file uploads, downloads, reading and writing rows—always including retry logic for reliability.
This is the heart of vibe coding: let AI handle the repetitive stuff, so engineers can focus on what really matters—solving real problems for real people.
Protecting Privacy: The PII Redaction Shield
When we built the Screening Assistant, privacy was our first priority. Candidate CVs are full of sensitive details—names, emails, phone numbers, sometimes even home addresses. If we want people to trust our process, we have to protect their data as carefully as we protect our own.
So, how do you use AI to help with hiring without ever risking someone’s personal information? For us, the answer was simple: don’t let any PII leave our system. Ever.
Before sending any CV to Gemini, our system automatically detects and removes sensitive information:
- Names and personal identifiers
- Email addresses
- Phone numbers
- Physical addresses
- Personal URLs (like LinkedIn or GitHub)
- Entire "Personal Information" sections
We use pattern recognition to catch common PII formats, applying multiple detection methods to be thorough. Here’s a simplified version of our redaction code:
def redact_pii(cv_markdown: str) -> str:
"""Remove personally identifiable information from CV text."""
# Start with the original text
redacted = cv_markdown
# Apply various redaction patterns
redacted = redact_emails(redacted)
redacted = redact_phones(redacted)
redacted = redact_header_names(redacted)
redacted = redact_urls(redacted)
return redacted
A typical redacted CV might look like this when passed to the AI:
[CANDIDATE NAME]
[PERSONAL INFORMATION REDACTED]
PROFESSIONAL EXPERIENCE
Senior Software Engineer | TechCorp Inc.
2019–Present
- Led development of scalable payment processing service
- Reduced infrastructure costs by 35% through optimized cloud usage
- Mentored 3 junior engineers in backend development best practices
SKILLS
Java, Kotlin, Spring Boot, Kubernetes, AWS, CI/CD, Microservices
EDUCATION
B.Sc. Computer Science, University of Technology
Contact: [EMAIL] | [PHONE] | [PERSONAL URL]
This way, the AI can still evaluate skills and experience—but never sees anything personal.
How We Guide LLM: The Screening Prompt
Once privacy was protected, the next step was getting useful, fair results from an LLM. We chose Gemini, Google’s large language model, for a few simple reasons: it performs well in structured evaluations, integrates smoothly with our existing Google Workspace stack, and crucially—didn’t require us to manage yet another set of API keys or billing accounts. No extra overhead, no surprise invoices. Just clean, secure access through the tools we already use.
But like any LLM, Gemini doesn’t just “know what to do.” The quality of its output depends heavily on the clarity of the input. Good AI responses come from good prompts—not hope.
So how do you make an LLM think like a thoughtful recruiter? We focused the prompt on what actually matters: skills, experience, and fit for the role—nothing personal or irrelevant.
Here’s the prompt:
You are a senior technical recruiter and professional resume screener.
Use **only** the information provided in the **Job Description** and **Candidate CV**.
Evaluate the candidate holistically on skills, experience, and potential fit.
Ignore all personal or demographic attributes.
## Input
- **Job Description** (Markdown):
{job_description}
- **Candidate CV** (Markdown):
{cv_markdown}
## Evaluation Guidelines
1. **Read both documents carefully.**
2. Judge the candidate’s readiness for *this* role, paying close attention to:
- Relevant technical skills, tools, and domains.
- Depth and breadth of professional experience.
- Scale and complexity of past projects.
- Demonstrated ownership, collaboration, and impact.
- Evidence they can thrive in an environment similar to the JD.
3. **Think like an expert recruiter**—don’t just match keywords.
Ask yourself: *Would this person realistically succeed in the role described?*
4. **Rating scale**
- **high** — >75% of critical requirements; strong recommend.
- **medium** — ~50–75%; some gaps but clear potential.
- **low** — <50%; lacks key skills or depth.
- **skip** — Profile largely irrelevant; do not advance.
## Output Requirements
Return **valid JSON only** (no extra keys, no line breaks inside values):
{
"summary": "Single-paragraph (≤150 words) highlighting role focus, standout skills, and approximate years of experience.",
"skills_matched": ["skill1", "skill2", "..."],
"rating": "high | medium | low | skip",
"reason": "Specific, factual justification for the rating—note main strengths and critical gaps."
}
### Error Handling
- If the CV is missing, blank, or unreadable, return:
`{"error": "CV_UNREADABLE"}`
- If the Job Description is missing, blank, or unreadable, return:
`{"error": "JD_UNREADABLE"}`
- If output cannot be generated, respond with the single word:
`INVALID`
### Additional Notes
- Stay concise; total output ≤500 tokens.
- Do **not** include line breaks or quotation marks inside JSON field values.
- Prioritize demonstrated achievements over buzzwords.
cv_screening_prompt_v0
This prompt helps the model give us a clear, structured summary, a list of matched skills, a fit rating, and a reason—all in valid JSON. If something’s missing or unreadable, Gemini returns a specific error.
This way, our HR team gets consistent, actionable insights—and every candidate is evaluated on what matters most: their skills and experience.
The Transformation: From Silence to Satisfaction
Before we built our digital hiring crew, things were tough. HR inboxes overflowed, candidates waited in silence, and everyone felt the strain. Sometimes, it felt like applications just vanished into a black hole.
Today, the new system is actively rolling out for applicants to our Digital division—and so far, the results are promising. If everything continues to run smoothly, we plan to expand it to support other roles and email channels across Electrum.
Here’s what we’ve already seen:
- Faster Processing: Applications that once piled up are now handled quickly and efficiently.
- Consistent Communication: We reached our goal—100% of applicants receive updates. No one is left in the dark.
- More Time for People: HR reclaimed 10–20 hours per week. Instead of chasing files, they focus on interviews, building relationships, and prioritizing the most promising candidates.
- AI as a Partner: We continuously review and refine the prompt based on real results. HR and hiring managers found the AI-generated summaries helpful for early screening—but final decisions always stayed human.
and here are the lessons that stood out most from this projects:
- Set Boundaries Early: Our shared principles—Human-in-Command, Privacy First, Transparency, Maintainability—built trust and accountability from day one.
- Clear AI Instructions Matter: Good results from AI don’t come from vague prompts. HR’s input shaped what makes a useful candidate summary and what information really supports their decision-making.
- Humans + AI: Stronger as a Team: The best results came from collaboration. AI handled the routine; people brought judgment, empathy, and quality control.
- Speed Doesn’t Replace Craftsmanship: Using an AI copilot doesn’t mean forgetting clean code, good architecture, or engineering best practices. In fact, structure matters even more—because it gives AI-generated code a place to fit, and keeps the system understandable and maintainable for the humans who come after.
What’s Next: From Screening to Signals
This system is just the beginning. There’s still plenty we want to improve—because great hiring doesn’t stop at reading CVs.
One of our next goals is to enrich candidate insights by bringing in signals from beyond the resume. We’re exploring agents that can:
- 🔍 Find public GitHub activity, so hiring managers can quickly see real-world contributions, repos, and code quality.
- 📝 Scan Medium or blog posts, if available, to understand how candidates think, communicate, and solve problems.
- 🤖 Auto-link relevant signals to the candidate’s row in our tracker, giving HR more context without extra digging.
These agents will work in tandem with our screening assistant—giving our team more meaningful data, not just more noise. And always, with privacy and consent at the core.
Conclusion: Fast Doesn’t Mean Careless—And AI Isn’t the Opposite of Craft
This journey started with a quiet message from a candidate—and turned into a real example of how AI can help solve meaningful problems, when guided by the right people, principles, and mindset.
We didn’t just build faster—we built with care. We used AI not to cut corners, but to remove friction. We made room for good architecture, clean code, and thoughtful prompts, so the system could evolve without becoming fragile. The result wasn’t just a better hiring process—it was a better way of working together.
At the end of the day, this wasn’t just about tech or automation. It was about collaboration—people supporting people, and humans working alongside AI, each contributing in ways that play to their strengths.
Have you tried building with Vibe Coding or AI in a real team setting? I’d love to hear what worked (or didn’t) for you.
We’re Hiring – Join Us in Shaping the Future of Mobility
We’re growing our Digital team and hiring across multiple roles:
- 💻 Senior Software Engineer (Go)
- 📊 Senior/Staff Data Engineer
- 🧪 Software QA Engineer
- 🧭 Senior Product Manager
If’re excited about solving real problems with great people (and a little help from AI), we’d love to hear from you. Send your CV to 👉 digital-hiring@electrum.id
Until next time,
Andi Pangeran