This is a submission for the Hacktoberfest Weekend Challenge: Build for a Friend
grill is a mock technical interviewer that has read your code. It runs in a terminal, on an open model, on your own laptop.
I built it for my friend Akash. He has spent the last year writing Rust, ships TypeScript on the side, and is looking for a full-time role. The rounds he dreads are the Rust and JavaScript deep dives.
Most interview prep tools ask the same textbook questions: what is a closure, explain ownership. Real senior interviews do not go that way. They go "walk me through your project", and then the interviewer points at one line you hoped nobody would notice and asks why.
You cannot practise that with a question bank, because the questions depend on your code. So grill does three things: Reads his repositories and finds the lines worth a question: unsafe blocks, locks, lifetimes, spawned tasks, useEffect, forEach(async ...), any, empty catch. Interviews him on them. One question about that exact code, one follow-up that presses on the weakest part of his answer, then a grade from 0 to 4 with what he missed. Remembers what he got wrong. The next session draws more from his worst topics.
Here is the scanner on four of Akash's public repositories. This is real output:
116 spots, and the top one is in miccli, his voice dictation CLI: an Arc> shared with a real-time audio callback. That is exactly the line a Rust interviewer would circle.
A session looks like this. The code and location are real scanner output; paste your own question, answer and grade from a real run in place of the placeholder lines:
About 1,300 lines of TypeScript including tests, three runtime dependencies, MIT licensed.
The open pieces: Gemma, Google's open-weight model, served by Ollama on localhost. Mastra, the open-source TypeScript agent framework, for the two agents and the tool.
A 4B model running on a laptop is not going to plan an interview, hold a rubric in its head, and remember what it asked five turns ago. So I did not ask it to. The order of steps lives in ordinary TypeScript. The model is only ever asked to do one of three things: write a question, write a follow-up, or grade an exchange.
Every one of those calls is handed the real snippet again. The model never has to recall code, so it has less room to invent it.
The scanner is a table of 38 patterns, 17 for Rust and 21 for JavaScript and TypeScript. Each one carries a topic, a weight, and the angle a good interviewer would take:
A regex hit on one line is not a question. So for every hit, the scanner walks up to the enclosing function, matches braces to find its end, and frames the whole thing. Weights are summed per function, overlapping frames are dropped in favour of the strongest, and each repository contributes its best 40 spots, round-robin across topics so a codebase full of .unwrap() does not turn the whole interview into error handling.
This is regex and brace counting, not a parser. It finds interesting code. It does not understand it. Understanding is the model's job.
Mastra talks to Ollama through its OpenAI-compatible endpoint, so there is no provider SDK and no API key:
The interviewer is told to ask exactly one question, to name an identifier from the snippet so the candidate knows it read the code, and never to answer or hint.
The grader is a separate agent with a separate prompt. It did not write the question, so it has no stake in the answer being good. It returns JSON:
