Skip to content
Adrian
← Back to projects

Reflection

Reflection desktop knowledge system cover art

Reflection is a local-first desktop application that turns a folder of Markdown notes into structured, searchable context for AI systems. It began as a way to make years of Obsidian notes useful without manually reorganizing them every time I wanted to study, revisit an idea, or continue an unfinished line of thought.

The current prototype combines a document-ingestion pipeline, semantic retrieval, persistent chat history, and a desktop interface. The larger engineering goal is to move beyond a basic “chat with your documents” tool and explore how software can preserve relationships, context, and changes in a person’s knowledge over time.

Why I built it

While working on an enterprise AI platform, I saw how retrieval pipelines and language models could make large collections of technical information usable. Reflection applies those ideas to a more personal problem: digital notes are easy to accumulate, but difficult to reuse once their location, surrounding context, or original purpose has been forgotten.

I wanted a system that could ingest notes as they already exist, preserve enough of their Markdown structure to remain understandable, and retrieve the most relevant sections when a user asks a question. Rather than treating note-taking as passive storage, Reflection treats a knowledge vault as an evolving dataset that can support study planning, technical research, project development, and long-term recall.

Reflection chat being used

How it works

Reflection uses a modular Python ingestion pipeline to process individual Markdown files or entire directories:

  1. Parse: Mistune converts each document into an abstract syntax tree. A custom parser extracts headings, paragraphs, lists, code blocks, links, and other useful structural elements.
  2. Chunk: A structure-aware chunker groups elements within a token budget without cutting through Markdown elements. Each chunk retains its document path, heading hierarchy, tags, links, element types, and a deterministic identifier.
  3. Embed and index: Chunks are embedded in batches and stored in a persistent ChromaDB collection using cosine similarity. The storage layer supports semantic queries and metadata filtering.
  4. Retrieve: A service layer exposes typed ingestion and query operations, returning source text, document metadata, and similarity scores to the rest of the application.
  5. Interact: A React and TypeScript interface runs inside a PyWebView desktop host. Python methods are exposed to the frontend for native file selection, ingestion, retrieval, and model interaction.
  6. Persist: Chat messages are represented as typed domain objects and stored in SQLite with validation, indexing, and write-ahead logging.

The model interface and vector pipeline are intentionally separated from the UI. This keeps Reflection usable as a desktop application while allowing the retrieval, memory, and inference components to evolve independently.

Engineering focus

Reflection is less about attaching a chatbot to a folder and more about designing the data and service boundaries required for durable machine-assisted memory. The project has required work across:

  • structure-aware document parsing and chunking
  • embedding batch management and vector indexing
  • deterministic metadata and document traceability
  • desktop-to-Python API design
  • typed service responses across Python and TypeScript
  • local persistence and cross-platform configuration
  • modular model and orchestration interfaces

One of the central design problems is deciding what context should survive ingestion. Flattening every note into plain text makes retrieval easy, but removes the headings, links, and relationships that give the note meaning. Reflection therefore stores both semantic content and structural metadata so future retrieval strategies can use more than vector similarity alone.

Current state

The prototype can ingest Markdown files through the desktop interface, parse and chunk their contents, generate embeddings, persist them in ChromaDB, and return semantically related passages with source metadata. It also includes an early chat pipeline with persistent SQLite logging and a replaceable model interface.

Development is now focused on strengthening the boundary between short-term conversation state, searchable document memory, and more durable relationships between ideas. Planned work includes richer retrieval strategies, knowledge-graph-style relationships, local model support, retrieval evaluation, and memory consolidation workflows that reduce redundant or conflicting information over time.

What I learned

Reflection began with a vision that was much larger than the first implementation. Early versions mixed future ideas with immediate requirements, which made the architecture harder to stabilize. Refactoring the project into parsing, chunking, storage, service, orchestration, and interface layers taught me to treat ambitious AI products as systems-engineering problems rather than model-selection problems.

The biggest lesson has been that useful AI memory depends less on simply storing more text and more on preserving provenance, structure, scope, and relationships. A model can only reason over the context the surrounding system is capable of representing and retrieving.