This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Always use uv to run Python — never invoke pip or python directly.
# Install dependencies (from project root)
uv sync
# Run the application
./run.sh
# or manually:
cd backend && uv run uvicorn app:app --reload --port 8000The app runs at http://localhost:8000. API docs at http://localhost:8000/docs.
Requires a .env file in the project root:
ANTHROPIC_API_KEY=your_key_here
This is a RAG chatbot with a FastAPI backend and vanilla JS frontend. All backend code runs from the backend/ directory — imports are relative to it (e.g., from config import config).
frontend/script.js— POSTs{ query, session_id }to/api/querybackend/app.py— creates a session if needed, callsRAGSystem.query()backend/rag_system.py— fetches conversation history, callsAIGenerator.generate_response()with thesearch_course_contenttool attachedbackend/ai_generator.py— calls Claude; ifstop_reason == "tool_use", executes the tool and makes a second Claude call with the resultsbackend/search_tools.py—CourseSearchToolperforms the vector search and formats chunks for Claudebackend/vector_store.py— queries ChromaDB usingSentenceTransformerembeddings; resolves partial course names via semantic search on thecourse_catalogcollection before filteringcourse_content
Two persistent collections (stored at ./chroma_db):
course_catalog— one document per course (title, instructor, lesson metadata as JSON); used for fuzzy course-name resolutioncourse_content— chunked text with metadata{ course_title, lesson_number, chunk_index }; used for semantic search
Course title is used as the ChromaDB document ID in course_catalog, so it must be unique.
document_processor.py parses .txt/.pdf/.docx files from docs/ at startup into Course + List[CourseChunk] objects (800-char chunks, 100-char overlap). Already-loaded courses are skipped by title to avoid duplicates.
| Setting | Default |
|---|---|
ANTHROPIC_MODEL |
claude-sonnet-4-20250514 |
EMBEDDING_MODEL |
all-MiniLM-L6-v2 |
CHUNK_SIZE |
800 |
CHUNK_OVERLAP |
100 |
MAX_RESULTS |
5 |
MAX_HISTORY |
2 (conversation exchanges) |
- Subclass
Toolinbackend/search_tools.py, implementget_tool_definition()andexecute() - Register with
tool_manager.register_tool(your_tool)inRAGSystem.__init__()
Claude will automatically receive the tool definition and can invoke it during query handling.