MARGINALIA.PRG
WHAT IT IS.
Marginalia is a retrieval-augmented Q&A service over a private microeconomics course corpus I used for study. The repository was originally named brian_gpt and is now public as marginalia. A Tornado server routes chat, question-answering, database and search requests to separate handlers, with a React client for conversation and source navigation. Postgres with pgvector holds the embedded document chunks; LangChain coordinates retrieval and answer generation. The history includes transcript processing, embeddings, chat revisions, Docker packaging and a search interface. A sibling q_and_a directory contains a containerized variant of the service; the archive establishes its structure, while current deployment status is outside this devlog's scope. Course material and persona prompts remain private. This 2023 project is distinct from the later industrial-organization paper-study workflow.
THE ARC.
The opening day is one of the most compressed in the journal: Parsed first time builds the transcript-processing path, followed by Output.json retouch, Computed embeddings, and Basic Q&A with pgvector — four substantive commits from source material to a working retrieval loop. The repo then sits quiet for three weeks.
Return: Working, Review continued, then two Rearrange commits 30 seconds apart moving files before the refactor. Hardening week: refactoring, Refactoring chat, UI is usable, QA handler OK. Docker push follows: Q&A working fine, Docker build, Improved logging (qa_handler rewritten). Final stretch: updated question prompts (chunking and prompts getting their first real audit), added lint, custom query (custom_query.jsx 219 lines in), Fixed in docker images, and the closing commit Search (search_handler.py +76 in, notebooks/explore.ipynb -354 lines of dead exploration retired). The q_and_a fork reuses the server-side handler skeleton with a built dist/ bundle — same lineage, containerised.
The architecture: server.py is the Tornado router; qa_handler.py is where the LangChain chain lives (MapReduce retriever over pgvector; the lecture-PhD persona prompt is intentionally not shown); db_handler.py owns the pgvector connection via psycopg/psycopg_pool. On the client, chat.jsx is the conversation, question.jsx the suggested questions, custom_query.jsx the user-typed retrieval, navigator.jsx the file-source list. notebooks/explore.ipynb is where chunking and prompt-template choices were actually made — the production scripts are the trimmed residue.
Stack chips: Tornado · LangChain (community + core) · pgvector · psycopg/psycopg_pool · OpenAI · tiktoken · unstructured · pydub · PyPDF2 · ebooklib · BeautifulSoup4 · spacy · Redis · React · SCSS · ESLint · concurrently · Docker.
WHAT I LEARNED.
Chunking policy and the teaching voice were the main levers. The first day proved that a modest retrieval pipeline could become useful quickly; the later revisions show how much work remained in context selection and answer behavior.
The notebook was the workshop:
notebooks/explore.ipynbis where chunking, prompt-template and reducer choices were tested; the production scripts are the trimmed residue.The search handler made retrieval inspectable in the UI. That turned prompt changes from blind tuning into something I could diagnose against the retrieved material.