DEV Community

Sudipto Baral
Sudipto Baral

Posted on AI-assisted

Shinobi tells you which Profs are really taking PhDs this year?

Hacktoberfest Open-Source AI Challenge Week 2: Side Hustle Submission 💸

This is a submission for the Hacktoberfest Open-Source AI Challenge Week 2: Side Hustle

A friend of mine was applying for a PhD. She had a list of professors she wanted to work with and emailed them one by one. Most never replied.

She asked me for help because I had been through this myself when I applied for my Master's. I had found a supervisor and secured a scholarship, so I thought I could help her do the same.

I went through her list the way I had gone through my own. It did not take long to see what had gone wrong. Some professors said plainly that they were not accepting students, but only on their lab website, not on their faculty page. Others had the information buried halfway down a page. Some said nothing at all, though their recent papers told me the group was still taking people in. And one still said "always looking for motivated students", right below a date from 4 years ago.

She had spent 3 weeks emailing professors without knowing whether they were taking students at all. The clues were there the whole time. They were just scattered across pages, buried in websites, and often out of date.

That afternoon idea of Shinobi popped into my mind. What I did for her by hand, admissions consultants sell for a few hundred dollars a shortlist, and every applicant I know has the same problem. I wanted to know how big the problem was, so I went through the websites of 60 machine learning professors by hand and recorded what each one said about taking students. 31 said they were accepting students. 4 said they were not. The other 25 said nothing at all. Even among the 31 who said yes, some notes were outdated, and some labs had not published with a new student in years.

So I built Shinobi: the thing I did for her, as a service anyone can use for a few dollars. It reads a professor's website and their papers before you write the email, and tells you who is actually worth contacting.

What I Built

Type a professor's name and their university. Within a few seconds, you get 3 things.

  • What the professor wrote about taking students, quoted word for word with a link, if they wrote anything.
  • A score from their publications, with the reasons why that correlates with a potential opening.
  • One label that puts both together, from Taking students to Not taking, with Toss-up and Not scored in between.

Who pays for this: applicants, a few dollars for the month they are applying. Admissions consultants charge a lot more to do the same thing by hand. Shinobi never sends the email for you. The idea is simple: fewer emails, better ones. You skip the professors who were never going to reply and put that time into the ones who might.

Demo

Try out at https://askshinobi.tech
Demo

Code

Fully open-sourced at sudiptob2/shinobi

The repository is Apache 2.0. docker compose up --build runs the full stack locally, and npm run batch and npm run judge reproduce every number in this post.

Some production logs: The check on Benjamin Eysenbach in the demo above ran on 2026-10-15 and took 18.8 seconds. Each component below recorded its part of that check.

Sentry trace of the check: one POST /app/check span of 18.86 seconds, with the SerpApi search at 6.69 seconds, the Princeton pages, and 3 calls to Gemma through the proxy

Sentry recorded the check as 1 trace with a span per request: the SerpApi search, 4 page fetches, 3 calls to Gemma, and the OpenAlex and NSF lookups. The search took 6.7 of the 18.9 seconds.

Mastra Studio showing the check workflow run on Benjamin Eysenbach: Success in 5.26 seconds, with the 6 steps parse, locate, read, grants, infer and save completed and timed

Mastra Studio screenshot during development. Here the page URL was supplied, so the locate step took 31 ms instead of a search, and the whole check finished in 5.3 seconds: 2.8 seconds reading the pages and 2.0 seconds judging the record, both on Gemma.

LiteLLM log on the proxy VM: the gemma-4-26b route pointing at the GPU machine, and the 3 chat completion requests from the Render service

vLLM log on the GPU VM: the container healthy, weights loaded, a 169,818-token KV cache, the 3 requests from the proxy, and rocm-smi showing the card at 12 W

The 3 Gemma calls arrived at the LiteLLM proxy from the Render service and were forwarded to vLLM, which served them from the loaded model and returned the card to 12 W once they were done.

Atlas query output: the shinobi database with 17 checks, 975 workflow snapshots and 1 user, and the saved Eysenbach verdict

Render events for the shinobi service: deploy of fbef170 live, askshinobi.tech attached

Mastra saved the verdict and its workflow state in Atlas, and Render shows the deployed commit and the domain that served the request.

How I Built It

Shinobi architecture. The React web app sends a check to a Mastra server and listens on a stream. The server runs a 6-step workflow: parse, read and infer are agent steps on Gemma 4; locate, grants and save are code steps on SerpApi, the NSF awards API and MongoDB Atlas. OpenAlex supplies the papers. Gemma runs on vLLM on a local GPU. Sentry records one trace per run.

3 pieces of open-source AI do the work. Gemma 4 26B-A4B reads the pages and judges the papers. vLLM serves it from a 32 GB AMD GPU under my desk. Mastra runs the 6 steps around it, in order, every time. 3 of those steps ask Gemma a question. The other 3 are plain code: find the page, fetch the grants, save the verdict. The model answers; the code checks the answer against the page, writes the explanation, and picks the label.

The stack, and why each piece is there.

  • Gemma 4 26B-A4B: 4B active parameters, so it answers at 4B speed, and the 4-bit checkpoint fits in 17 GB. It beat every alternative I tried, see below.
  • vLLM: batches concurrent requests, so 10 applicants at once do not wait in line. A LiteLLM proxy in front means the app only knows a URL and a model name, and any OpenAI-compatible server can stand in.
  • Mastra: typed steps in a fixed order, not an agent choosing its own tools. Every check costs the same, and each step is tested alone. Its server streams every step's result to the browser as it lands.
  • SerpApi: 1 search per check, ranked in code. The only call that costs money.
  • OpenAlex and NSF: open data, no key. Every paper since 2008 and every active grant, reduced to 10 numbers.
  • MongoDB Atlas: accounts, check history and workflow state, on one free cluster.
  • Sentry: a span per step, so a slow check tells me which step was slow.
  • Render: one Docker image from main after CI, the same image I run locally.

3 rules keep it honest. The reader must quote, and every quote is checked against the page text, so it cannot invent a note. The judge sees only 10 numbers, and the explanation is written in code from those same numbers, so the words and the score cannot disagree. Alphabetical-author fields and thin records get Not scored instead of a guess.

Choosing the model. I benchmarked Gemma 4 26B-A4B against 3 hosted Claude models through the same proxy, and against its smaller siblings E4B and E2B on the same GPU, all on my 60 hand-labeled professors. Reader: labels matched out of 60. Judge: how well the 51 professors with a stated status were ranked from their papers alone, where 0.5 is a coin flip.

Model Runs on Reader, of 60 Judge AUC Median check 1,000 checks
Gemma 4 26B-A4B local GPU 51 0.77 4.5 s $0.03 of electricity
Gemma 4 E4B local GPU 48 0.77 4.1 s electricity
Gemma 4 E2B local GPU 38 0.71 3.7 s electricity
Claude Haiku 4.5 API 52 0.77 4.1 s $6.25
Claude Sonnet 5 API 50 0.73 4.6 s $18.75
Claude Fable 5 API 48 0.76 10.5 s $62.50

Bigger did not help: the frontier model was the slowest and read the pages worst. Smaller almost did: E4B fits on a laptop and matched the 26B on the papers, but it read 1 professor's note backwards, and E2B missed nearly half the notes. None of the 6 invented a note. The 26B-A4B is the smallest model that never got a verdict backwards, and it costs nothing per check.

Why Does Open Innovation Matter?

Who pays, and for what. The customer is a PhD applicant who is not a programmer. They pay a few dollars for the month they are applying, check a shortlist of about 15 professors, and stop. At that price a check has to cost me close to nothing. A check is 1 search, 3 model calls, 2 open-data lookups and a database write. The search has a fixed price per call. The lookups are free. The model calls are the only cost that would grow with every check, and open weights remove that cost.

What a check costs on one consumer GPU. Gemma runs on a single Radeon AI PRO R9700 in a desktop PC, through vLLM. Any 24 GB consumer card runs the same 4-bit checkpoint, and the smaller E4B runs on a 16 GB laptop GPU and scores 3 pages lower out of 60. I measured the card with rocm-smi: a check keeps it at about 210 W for 4 seconds, and the loaded model idles at 15 W the rest of the time. At $0.12 per kWh, one check costs $0.00003 in electricity, and keeping the model loaded all month costs $1.30. At 1,000 users the card is busy 2% of the month. One card handles about 650,000 checks a month, or 40,000 users, and a second card costs the same as the first.

Say each user runs 15 checks a month and pays $3 for that month:

Users Checks Search (SerpApi) Electricity Hosting and database Cost Revenue Margin
100 1,500 $75 $1.34 $7 $83 $300 72%
1,000 15,000 $150 $1.72 $7 $159 $3,000 95%
2,000 30,000 $275 $2.14 $82 $359 $6,000 94%
5,000 75,000 $725 $3.40 $82 $810 $15,000 95%

Search is the main cost. The model that reads and judges every page costs less than the hosting. Hosting is Render's $7 instance, then $25 plus a $57 Atlas cluster once the history outgrows the free one. At 5,000 users the 75,000 searches fall into SerpApi's 100,000-search plan, so a third of what is paid for goes unused. Caching would cut this further: 1,000 applicants check the same few hundred professors, and a page found once can be reused for a month.

The same table on a hosted model. From the comparison above, the 3 model calls in a check cost $0.006 on Claude Haiku 4.5 and $0.06 on Claude Fable 5. At 1,000 users that is $94 or $940 a month for the model alone, next to $159 for everything else. On Haiku the margin is still good, but it depends on a price list I do not control. On my own card the model line is $1.72, and the $1,300 card is paid back in the first month at 1,000 users.

No lock-in. While I was building, the reader ran on a hosted model through the same proxy. In production it runs on vLLM on my own hardware. The switch was 3 environment variables, and the benchmark numbers did not change. If the card fails, the same model runs on a rented GPU by the hour. If a better open model is released, it is a config change and a re-run of npm run batch.

The people who do not pay. Open weights also make the tool free for people who can run it themselves. A computer science applicant can clone the repository, point it at Ollama on a laptop, and run 250 checks a month on free tiers alone: 250 SerpApi searches, open data from OpenAlex and NSF, 512 MB on Atlas. That is not lost revenue. Those users would not pay for a tool they can run themselves, and they are the ones who send pull requests. The paying customer is everyone else, which in PhD admissions is most applicants.

Where a closed model would have been better. Claude Haiku 4.5 matched Gemma on both benchmarks with nothing to install, and it would have saved the day it took to get Gemma 4 running on an AMD card. The open model won on 3 points: the cost per check is electricity, the price is mine to set, and the whole system runs on hardware I control.

Prize Categories

  • Gemma: reads every page and judges every record. Gemma 4 26B, open weights, served with vLLM on my own GPU at home.
  • Mastra: the 6-step workflow, 3 agent steps and 3 code steps.
  • SerpApi: finds the faculty and lab pages.
  • MongoDB Atlas: users and history.
  • Sentry: a trace for every check.
  • Render: the deployed demo, one Docker image.
  • .tech: askshinobi.tech.

Top comments (0)