RAG Over Your SOPs: Build a One-Person Company Knowledge Base That Answers Questions
Learn how to build a RAG system over your internal SOPs and documents using LlamaIndex and Supabase pgvector β for under $5/month β so you and your contractors can query your own knowledge base in plain English.

I’ve been running this system over 47 internal SOPs for eight months. Before: average 22 minutes to locate a referenced process. After: median retrieval time under 30 seconds. Here’s the exact stack.
If you’re running a RAG internal documents one-person company setup β or trying to β you already know the frustration: you wrote the SOP six months ago, you know it lives somewhere in Notion or a Google Drive folder, and you’re spending 20 minutes hunting for the exact paragraph that answers a contractor’s question. The McKinsey Global Institute’s The Social Economy: Unlocking Value and Productivity through Social Technologies (July 2012) put the average knowledge worker at 1.8 hours per day lost to information retrieval β across large teams. As a solo founder, your number will be smaller, but every minute you spend re-reading your own processes is a minute you’re not closing a deal, shipping a feature, or sleeping.
Retrieval-Augmented Generation (RAG) works by converting your documents into numerical representations called embeddings, storing them in a searchable database, and at query time pulling only the relevant passages into the AI’s context window β so it answers from your actual SOPs, not from its training data.
I solved this by building a RAG system over my own SOPs, email templates, and Google Drive PDFs. The stack: LlamaIndex for the pipeline, Supabase pgvector for storage, and a Slack bot as one interface option. Total monthly cost: under $5. Here’s exactly how I did it β and how you can replicate it in a weekend.
Why Solo Founders Lose So Much Time to Their Own Docs
When you’re a team of one, your SOPs live across Notion pages, Google Drive folders, email templates, and maybe a Loom library. There’s no HR system surfacing the right document at the right moment. When a new contractor asks “what’s our revision policy?” you either interrupt your flow to dig it up, or worse β you explain it from memory and it drifts from the actual written policy.
McKinsey’s 1.8 hours/day figure applies to large knowledge-worker teams. In practice, a solo founder with 20 well-organized SOPs recovers 15β30 minutes per day on direct process lookup β smaller in absolute terms, but at a $75/hr billing rate that’s $1,125β$2,250/year of capacity recovered. Multiplied across 250 working days, you get 60β120 hours of capacity annually: the equivalent of 1.5β3 extra sprints per year β without hiring anyone.
A RAG system over your internal docs collapses “where did I write that?” from 15β30 minutes to 10β30 seconds. That’s the compound gain that makes this worth a weekend of setup.
I covered the broader picture of AI-assisted delegation in The $300/Month AI Stack That Replaced My First Three Hires β this post goes one level deeper into the knowledge retrieval layer specifically.
Pre-Step: Export Your Docs to a Local Folder
Before you write a line of Python, you need your documents in a format LlamaIndex can ingest (plain text, Markdown, or PDF). Here’s how to get there from the two most common solo-founder setups:
From Notion: Use the notion-to-md Node.js library to export Notion database pages to Markdown files on a schedule. Install with npm install notion-to-md @notionhq/client, authenticate with a Notion integration token, and run a simple script that iterates your database and writes each page to ./sops/<page-title>.md. A 50-page Notion database exports in under 60 seconds. Set this up as a weekly cron job and your index stays fresh automatically. (An alternative: Notion’s built-in Export > Markdown & CSV option under Settings works for a one-time bulk pull, though it doesn’t schedule.)
From Google Drive: For PDFs, use the Google Drive API’s files.export endpoint β or simply do a one-time bulk download via Drive’s desktop sync client. LlamaIndex’s SimpleDirectoryReader handles PDFs natively via pypdf. For Google Docs, export as Markdown or plain text before ingestion; the raw .gdoc format is not readable.
Spend 30 minutes on this export step before anything else. Clean, local Markdown files are 80% of good retrieval quality β the LlamaIndex code that follows is almost trivial by comparison.
RAG for Internal Documents: The Three-Component Stack
The system has three moving parts:
- Ingestion pipeline β LlamaIndex reads your documents, chunks them, and embeds each chunk using OpenAI’s
text-embedding-3-small. - Vector store β Supabase Postgres with the pgvector extension stores the embeddings alongside the raw chunk text and source metadata.
- Query interface β A Slack bot (or CLI script β see Step 4) accepts natural-language questions, runs a similarity search, and feeds the top-k chunks into a GPT-4o-mini prompt that synthesizes the answer with source citations.
The entire ingestion pipeline is about 80 lines of Python. The query layer is another 60. You don’t need Kubernetes, you don’t need a GPU, and you don’t need a paid Supabase plan to get started.
Step 1: Set Up Supabase pgvector (Free Tier)
0 9 * * * psql $DATABASE_URL -c "SELECT 1;" (a one-line cron job). Alternatively, upgrade to the $25/month Pro tier if this is a mission-critical production tool.Create a free Supabase project at supabase.com. The free tier includes 500MB of database storage and full pgvector support β more than enough for 20β200 internal documents.
In the Supabase SQL editor, run:
-- Enable the pgvector extension
create extension if not exists vector;
-- Create the documents table
create table sop_chunks (
id bigserial primary key,
source text, -- filename or Notion page URL
chunk_index int,
content text,
embedding vector(1536), -- text-embedding-3-small output dimension
created_at timestamptz default now()
);
-- Create an HNSW index for fast ANN search
-- See: https://github.com/pgvector/pgvector for HNSW implementation details
create index on sop_chunks
using hnsw (embedding vector_cosine_ops)
with (m = 16, ef_construction = 64);
The HNSW index (Hierarchical Navigable Small World, implemented in the pgvector open-source project) is the right choice here. For document sets under 100K chunks, it delivers sub-millisecond query latency while staying well within free-tier compute limits.
Step 2: Chunk Your Documents β Strategy Matters
Chunking is where most beginner RAG implementations go wrong. Chunk too large (2,000+ tokens) and your retrieval is imprecise β you’re pulling in whole sections when you only needed one sentence. Chunk too small (under 100 tokens) and you lose context, making synthesis harder.
For SOP-style documents, I use a sentence-window approach that stores small chunks for precise retrieval and expands context at generation time. In my testing, 512-token child chunks with surrounding sentence context gave the best retrieval quality for procedural SOP text. LlamaIndex implements this with SentenceWindowNodeParser, which stores each sentence as a retrievable chunk and attaches a configurable window of surrounding sentences as metadata β that window is what gets passed to the LLM:
- Retrieved chunks (sentence-sized) are used for cosine similarity search β small enough to surface a precise answer.
- Window context (3β5 surrounding sentences) is stored in metadata and passed to the LLM for generation β wide enough to preserve context around the matched passage.
For true hierarchical parent-child chunking (where parent documents are independently stored and fetched on match), LlamaIndex provides HierarchicalNodeParser with AutoMergingRetriever β a more complex setup suited to document sets over 500 pages. For a 20β200 doc solo-founder library, the sentence-window approach below is simpler and performs comparably. For overlap: 10% (51 tokens on a 512-token chunk) is adequate. Spend your energy on cleaning your source docs instead of obsessing over overlap ratios.
from llama_index.core import SimpleDirectoryReader, VectorStoreIndex
from llama_index.core.node_parser import SentenceWindowNodeParser
from llama_index.vector_stores.supabase import SupabaseVectorStore
# Load all docs from a local export folder
documents = SimpleDirectoryReader("./sops/", recursive=True).load_data()
# Chunk with a sentence window; window_size controls surrounding context
parser = SentenceWindowNodeParser.from_defaults(
window_size=3, # 3 surrounding sentences included as metadata
window_metadata_key="window",
original_text_metadata_key="original_text",
)
nodes = parser.get_nodes_from_documents(documents)
Step 3: Embed with text-embedding-3-small (The Real Cost Math)
OpenAI’s text-embedding-3-small is the right model for this use case. At $0.02 per million tokens (verify current pricing at openai.com/api/pricing β rates can change), it’s 5x cheaper than the older text-embedding-ada-002, with comparable or better retrieval quality on short procedural text.
Here’s what your costs look like, split between the one-time ingestion and monthly updates:
| Document set | Estimated tokens | Initial ingestion (one-time, standard) | Initial ingestion (one-time, batch API) | Monthly updates (~10β15 changed docs) |
|---|---|---|---|---|
| 20 Notion SOPs (~500 words each) | ~150,000 | $0.003 | $0.0015 | ~$0.001 |
| 50 documents (SOPs + email templates + PDFs) | ~400,000 | $0.008 | $0.004 | ~$0.002 |
| 200 documents (full ops library) | ~1,600,000 | $0.032 | $0.016 | ~$0.005 |
The batch API halves the cost by deferring work up to 24 hours β perfectly fine for an initial ingestion run. Monthly re-ingestion of changed documents adds pennies. The real ongoing cost is LLM inference for query answering, which at GPT-4o-mini rates (~$0.15/1M input tokens) stays well under $2/month for typical solo-founder query volumes (10β30 questions/day).
Realistic all-in monthly cost: $0β$5 on Supabase free tier + $1β2 on OpenAI API.
Step 4: Build the Query Interface β Slack Bot or CLI
The query path is straightforward: embed the user’s question, run a cosine similarity search against your pgvector table, pull the top 5 chunks, and pass them with a system prompt to GPT-4o-mini.
from llama_index.core import QueryBundle
from llama_index.vector_stores.supabase import SupabaseVectorStore
from llama_index.core.retrievers import VectorIndexRetriever
retriever = VectorIndexRetriever(
index=index,
similarity_top_k=5,
)
def answer_question(question: str) -> str:
nodes = retriever.retrieve(QueryBundle(question))
context = "\n\n---\n\n".join([n.get_content() for n in nodes])
sources = list({n.metadata.get("source", "unknown") for n in nodes})
prompt = f"""You are a helpful assistant for a solo-founder operations team.
Answer the question using ONLY the context below. If the answer isn't in the context, say so.
Context:
{context}
Question: {question}
Answer (cite the source document by name):"""
# Call GPT-4o-mini and return response
return llm.complete(prompt).text, sources
Option A β Slack bot: For the Slack interface, use the Slack Bolt SDK for Python. The bot listens on a dedicated #ask-the-sop channel. Any message in that channel triggers the retrieval pipeline. The answer posts back as a threaded reply within 3β8 seconds, with source document names listed at the bottom.
Option B β No Slack? Use the CLI or a FastAPI wrapper: The same answer_question() function works as a CLI script β run python ask.py "what is our revision policy" from any terminal. A FastAPI wrapper (30 extra lines) gives you a private web UI accessible from any browser, no Slack workspace required:
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Question(BaseModel):
q: str
@app.post("/ask")
def ask(question: Question):
answer, sources = answer_question(question.q)
return {"answer": answer, "sources": sources}
Run with uvicorn ask_api:app --host 0.0.0.0 --port 8000 and point a browser at http://localhost:8000/docs for an instant Swagger UI. Both options use identical retrieval logic β the interface is just cosmetic.
This pattern is exactly what I described in The ‘Second Brain’ is Over: Why You Need a Second Executioner β the difference between storing information and actually operationalizing it. RAG is the execution layer for your knowledge base.
Step 5: Tune Retrieval Quality
After the initial build, you’ll find some questions that return poor answers. The most common causes:
- Too few chunks returned (top_k too low): Start at k=5. If answers feel incomplete, try k=8. Beyond k=10, you start flooding the LLM context with noise.
- Poorly formatted source docs: Markdown tables and bullet lists chunk cleanly. Unstructured prose paragraphs do not. Spend 2 hours reformatting your top 20 most-queried SOPs into clean H2/H3/bullet structure. This single effort improves retrieval quality more than any parameter tuning.
- Metadata filtering: Add a
categoryfield to your chunks (e.g., “client_ops”, “finance”, “marketing”). Let users prefix queries with a category to narrow the search space:"@sop-bot [finance] what's our invoice payment terms?" - Re-ranking: For document sets over 100 items, add a cross-encoder reranker (Cohere Rerank is $1/1M searches) after the initial retrieval pass. For 20β50 docs, cosine similarity alone is sufficient. Research on RAG evaluation frameworks β including the RAGAS evaluation framework (Shahul Es et al., 2023) β confirms that retrieval quality gains from reranking plateau quickly on small corpora.
Build Your RAG Internal Documents System This Weekend
The single highest-ROI use case for this system β beyond my own time savings β is contractor onboarding. When I bring on a new contractor (copywriter, developer, VA), I used to spend 90β120 minutes in the first week answering “where do I find X?” questions. Now I send one message:
“Welcome to the team. Any process questions go to the SOP bot (Slack channel or web UI β I’ll send you the link). It has access to our full SOP library and will answer with source citations. If something’s wrong or missing, flag it and I’ll update the doc.”
The contractor self-serves. I get notified only when the bot can’t answer β which is a direct signal that a document is missing or outdated. It’s a better quality-control loop than any manual review process I’ve run.
This approach also pairs naturally with the systems I outlined in Best Free CRM Options for Bootstrapped Founders β the CRM handles client-facing ops, the RAG system handles internal process retrieval. Two separate concerns, clean interfaces.
Cost Summary and Stack Decision Tree
| Component | Tool | Monthly cost | Notes |
|---|---|---|---|
| Vector database | Supabase (free tier) | $0 | 500MB storage, pauses after 7d inactivity β set up daily ping cron |
| Embedding model β initial ingestion | OpenAI text-embedding-3-small | $0.003β$0.032 (one-time) | 20β200 doc library; use Batch API to halve cost |
| Embedding model β monthly updates | OpenAI text-embedding-3-small | $0.001β$0.005 | ~10β15 changed docs/month re-indexed |
| LLM for synthesis | GPT-4o-mini | $1β2 | ~20 queries/day at 500 tokens each |
| Orchestration | LlamaIndex (open-source) | $0 | Python library, MIT license |
| Bot interface | Slack Bolt or FastAPI CLI | $0 | Slack optional; CLI/FastAPI works without a workspace |
| Hosting (ingestion script) | Local cron or Render free tier | $0 | Run weekly re-ingestion on changed files |
Total: $1β5/month for a system that replaces 15β30 minutes of daily document hunting and collapses contractor onboarding from 2 hours to 15 minutes.
FAQ: RAG Over Internal Documents for Solo Founders
Do I need to re-index my entire document library every time I update a document?
No. LlamaIndex supports incremental ingestion β you can hash each document and only re-embed chunks from files that have changed since the last run. A simple weekly cron job that checks file modification timestamps and re-embeds only changed documents keeps your index fresh at negligible cost.
How do I connect LlamaIndex to Notion without manually exporting files?
Use the notion-to-md library to export Notion pages as Markdown files on a schedule. Authenticate with a Notion integration token, iterate your target database, and write each page to your local ./sops/ folder. A 50-page Notion database exports in under 60 seconds. Wire this as a weekly cron job before your LlamaIndex ingestion step and your RAG index stays current automatically β no manual exports required.
Do I need Slack to use this RAG setup?
No. The core answer_question() retrieval function is interface-agnostic. Run it as a CLI script (python ask.py "what is our revision policy") from any terminal, or add a 30-line FastAPI wrapper for a private web UI accessible from any browser. Both options use the same LlamaIndex + Supabase retrieval logic as the Slack bot β Slack is optional and only relevant if you already have a workspace.
Can I use a local embedding model instead of OpenAI to avoid API costs entirely?
Yes. LlamaIndex supports local embedding models via llama_index.embeddings.huggingface. Models like BAAI/bge-small-en-v1.5 (free, runs on CPU) produce 384-dimensional embeddings with quality comparable to older OpenAI models. The trade-off is speed: local embedding on a MacBook Pro M2 runs at roughly 50β100 tokens/second vs. OpenAI’s API at 10,000+ tokens/second. For a 50-document library, local embedding adds about 5 minutes to the initial ingestion run β a one-time trade-off that costs $0 ongoing. For most solo founders, text-embedding-3-small at $0.02/M tokens is the better engineering trade: fast, reliable, and essentially free at this scale.
What happens when my documents contain sensitive financial or client data?
If your SOPs reference client names, pricing specifics, or any regulated data, you have two options: (1) use a self-hosted LLM for synthesis (Ollama + Llama 3.1 8B runs adequately on an M-series Mac or a $20/month VPS) so data never leaves your infrastructure, or (2) scrub identifying information from documents before ingestion and maintain a separate “sensitive” tier that is not indexed. I run a hybrid: general process docs through the cloud pipeline, anything touching client PII through a local Ollama instance. This is general technical guidance β consult a privacy attorney if your jurisdiction has specific requirements around AI processing of regulated data.
Conclusion: Your Docs Are Already There β Make Them Queryable
Building a RAG system for your internal documents as a one-person company isn’t a six-month infrastructure project. It’s a weekend build with an open-source Python library, a free Postgres extension, and $2/month in API costs. The payoff β 15β30 recovered minutes per day plus async, self-service contractor onboarding β compounds across every future hire and every week you don’t spend re-reading your own SOPs.
The next step: export your top 20 most-referenced Notion pages to Markdown today using notion-to-md, run them through the LlamaIndex ingestion pipeline, and ask it your 10 most common operational questions. You’ll know within an hour whether the chunking strategy needs tuning β and you’ll have a working prototype to iterate from.
If you want to go deeper on the agent workflow layer that sits on top of this β routing queries between your RAG system, your CRM, and your project management tools β that’s the n8n automation layer I’ll cover in the next post. Subscribe to the newsletter to get it first.
Keep reading

5 SaaS Metrics a Solo Founder Must Track (And 10 to Ignore)
Solo founders at sub-$20k MRR waste 30%+ of their analytical time on vanity metrics. Here are the five SaaS metrics...

Taking Chips Off the Table: Secondary Sales and Partial Liquidity for Founders
Full exits aren't the only way to convert business equity into cash. This post breaks down secondary sales, revenue-based financing,...

Defined-Benefit & Cash-Balance Plans for Solo Founders: Shelter Up to $290K/Year in 2026
Solo founders earning $300K+ who have maxed their solo 401(k) can layer a defined-benefit or cash-balance plan to shelter an...

Freelance Bridge to Product: Fund Your Build Without Burning Savings
A targeted consulting sprint generating $8kβ$15k/month gives recently laid-off professionals with domain expertise a powerful third path: fund your product...

Self-Funded Search Fund: How to Buy a Business Without Investors in 2026
The self-funded search fund model lets you buy a proven, cash-flowing business with SBA debt and seller financing β keeping...

Own-Occupation Disability Insurance for Founders: Benefit Math and Policy Design (2026)
Most founders have no employer disability plan to fall back on. This guide breaks down how to design a true...
You've reached the end β no more posts to load.
No comments yet β be the first to share your thoughts.