DEV Community

Kunal Kushwaha
Kunal Kushwaha

Posted on

My friend's notes were scattered across a dozen files, so I built him a private search-and-answer tool

Hacktoberfest Weekend Challenge: Build for a Friend Submission 🤝

This is a submission for the Hacktoberfest Weekend Challenge: Build for a Friend

What I Built

NotesBuddy is a study assistant I built for my friend Alekh. His problem was simple: his notes were scattered across many different files, and finding one small concept took forever.

NotesBuddy fixes that. You drop your notes into a folder, ask a question in plain language, and get a short answer along with the exact passage of your notes it came from. If the notes don't contain the answer, it says so instead of guessing. A study tool that confidently makes things up is worse than no tool at all, so that behavior was non-negotiable.

Demo

Live demo: https://notebuddy-lnka.onrender.com/

This hosted version is a retrieval-only demo on sample notes, because the free hosting tier can't run an LLM. It shows the real search and the cited passages. The full version, with Gemma generating the answers, runs locally. (The free tier sleeps when idle, so the first load can take up to a minute.)

Run the full version yourself:

git clone https://github.com/KunalKushwaha1806/NoteBuddy
cd NoteBuddy
ollama pull gemma3:4b
python notesbuddy.py serve   # then open http://localhost:8000
Enter fullscreen mode Exit fullscreen mode

Put your own .txt / .md notes in ./notes first.

Code

https://github.com/KunalKushwaha1806/NoteBuddy

How I Built It

The whole project is a single Python file with no dependencies beyond the standard library.

  • Retrieval: notes are split into overlapping ~120-word chunks and ranked with BM25, which I implemented from scratch. Each chunk keeps its file name and position, so every answer can point back to its source (like operating-systems.md#1).
  • Generation: the top four chunks go to Gemma 3 (4B), an open-weight model running locally through Ollama. The prompt tells it to answer only from the provided notes, cite sources as [file#n], and say plainly when the notes don't cover the question.
  • Graceful fallback: if Ollama isn't running, NotesBuddy still returns the matching passages instead of failing.
  • Interface: a CLI for me, and a tiny local web page so Alekh never has to touch a terminal.

The heart of it is one function:

def ask_llm(question, hits):
    ctx = "\n\n".join(f"[{l}] {t}" for l, t in hits)
    sys_p = ("You are a study buddy. Answer ONLY from the notes below. Cite sources like [file#n]. "
             "If the notes don't contain the answer, say so plainly. Keep it short and clear.")
    body = {"model": MODEL, "stream": False, "messages": [
        {"role": "system", "content": sys_p},
        {"role": "user", "content": f"NOTES:\n{ctx}\n\nQUESTION: {question}"}]}
    req = urllib.request.Request(f"{OLLAMA}/api/chat", json.dumps(body).encode(),
                                 {"Content-Type": "application/json"})
    with urllib.request.urlopen(req, timeout=120) as r:
        return json.load(r)["message"]["content"]
Enter fullscreen mode Exit fullscreen mode

What Alekh Said

I gave Alekh NotesBuddy and asked him to try it on his own notes. His reaction:

"Honestly, NotesBuddy is exactly what I needed. I've got so many notes scattered across different files that finding one small concept takes forever. Now I can just ask a question and get the answer along with the exact part of my notes it came from.

And the fact that it tells me when something isn't in my notes instead of making up an answer is actually really useful. It feels like having a study assistant that works directly with my own material."

The two things he singled out, seeing the exact source passage and getting an honest "that's not in your notes," are the two design decisions I cared about most.

Why Does Open Innovation Matter?

  • His notes stay on his machine. Study notes are personal. With a local open-weight model there is no upload, no account, and no question about who else might see or train on his material.
  • It costs nothing to run. No API key, no per-token bill. Any laptop with around 8 GB of RAM can run it.
  • I could change how it behaves. The model is one environment variable (NOTESBUDDY_MODEL), so swapping Gemma for another Ollama model needs no code change. And because I control the prompt and the retrieval, I could build the "admit when you don't know" behavior directly into the pipeline.
  • Where a closed model would be better: a large hosted model would write smoother answers, and it would handle questions phrased very differently from the notes better than my keyword-based BM25 retrieval does. I traded some polish for privacy and zero cost, and for a personal study tool I'd make that trade again.

What's next: swapping BM25 for local embeddings to handle paraphrased questions, and a quiz mode that turns notes into practice questions.

Prize Categories

Best Use of Gemma: Gemma 3 runs locally via Ollama as the generation model that answers every question.

Top comments (0)