Skip to content
Skip to content

Nathan Espejo

Software engineer building applied AI tools. 3rd-year Software Engineering at Western.

Ask about me

all projects

Campus

A self-hosted study assistant for my courses: Brightspace sync, hybrid retrieval and an agent that logs every write.

Aug 2026 to nowsolo

tl;dr

  • Syncs my Brightspace courses into local SQLite and answers questions from the course files.
  • Hybrid retrieval over my course files: just over 200 of them as of early October 2026.
  • A 20-tool agent that can also edit my notes and due dates. Every write it makes is logged.
  • 308 tests run in CI on every push.
  • Works with any OpenAI-compatible endpoint, local or hosted.

Why I built it

My course material lives in Brightspace, spread across 6 courses. I wanted one place to look up deadlines, study from the slides, and check a draft against the assignment brief, running on hardware I control.

I also wanted it to update my notes and due dates. That is only useful if I can see exactly what it changed, so every AI write is logged with the before and after.

What I built

It's a solo project, so everything below is mine.

  • LMS sync with Playwright, MFA login included, into SQLite and a local file store.
  • sha256 change detection, so unchanged files are not downloaded again.
  • Hybrid retrieval: embedding search, cross-encoder reranking, and a lexical SQL prefilter.
  • A fix for exact phrases that scored below the semantic cutoff. They now go through the lexical path.
  • A 20-tool agent that answers questions, reads files, and edits notes or due dates, in a bounded tool loop.
  • An append-only audit log with the before and after state of every AI write.
  • A React, TypeScript and Vite PWA. <!-- one-source-ok -->
  • CI on GitHub Actions: pytest, frontend type-check and a production build on every push.

How it works

Brightspace syncs into SQLite and a local file store. Those files are split into an index of chunks. Retrieval reads the index and feeds an agent with twenty tools, which answers questions and writes every change to an audit log with the before and after state.
  1. Sync. Playwright signs in and pulls course content. Files with an unchanged sha256 are skipped.
  2. Index. Course files are split into chunks.
  3. Retrieve. A SQL prefilter catches exact phrases, embedding search finds related chunks, and a cross-encoder reranks them.
  4. Answer. The agent picks from its tools to search, read files, or change notes and due dates.
  5. Audit. Every write is logged with its before and after state.

Models and cost

  • The agent talks to any OpenAI-compatible endpoint. Same code for a local server or a hosted API, set in config.

Results

  • I use it across 6 courses for deadline lookups, studying from slides, and checking drafts against briefs.
  • As of early October 2026 it had synced just over 200 course files. I'm the only user, so that number is my course load, not adoption.
  • 308 tests pass in CI on every push.
  • Retrieval and answer quality: evaluation in progress.

Next

Finish the retrieval and answer evaluation, then post the numbers here.

  • Python
  • FastAPI
  • SQLite
  • embeddings
  • cross-encoder reranking
  • React

Next case study: NixOS homelab