Second Brain is a hackathon MVP for a personal knowledge-base assistant. It helps users save knowledge from notes, PDFs, and links, then recall it later through search, generated summaries, a knowledge graph, and an agent chat experience.
The app uses a FastAPI backend, a React/Vite frontend, Firebase Auth, optional Firestore persistence, Anthropic Claude for enrichment and chat, and OpenAI embeddings when configured.
- Ingest notes, PDFs, and web links.
- Convert saved material into structured memories with summaries, key ideas, claims, questions, concepts, and tags.
- Build retrieval chunks and a knowledge graph that connects related ideas.
- Chat with an agent that uses saved knowledge, citations, graph context, tool traces, and streaming responses.
- Edit saved memory content and regenerate related artifacts.
- Archive chat sessions back into the knowledge base.
- Store original uploaded files with GitHub by default or Google Drive as an alternate provider.
- Run locally with in-memory demo data or persist data in Firebase Firestore.
- Python, FastAPI, Uvicorn
- TypeScript, React, Vite
- Firebase Auth, Firebase Admin SDK, Firestore
- Anthropic Claude API
- OpenAI Embeddings API
- GitHub Contents API
- Google Drive API
- Tailwind CSS, Radix UI, Vaul, Lucide React
- D3 Force, React Markdown, Remark GFM
- PyPDF, Pillow, HTTPX
- Pytest
From the project root:
uv sync
cd frontend
npm installCopy the example backend environment file:
cp .env.example .envThe backend can run without AI keys for local development. Without ANTHROPIC_API_KEY, it uses local fallback enrichment. Without OPENAI_API_KEY, it uses deterministic local embeddings.
Common backend variables:
ANTHROPIC_API_KEY="your_claude_key"
OPENAI_API_KEY="your_openai_key"
SECONDBRAIN_STORAGE_BACKEND=memory
SECONDBRAIN_SEED_MOCK_DATA=1Create frontend/.env for the Vite app:
VITE_API_BASE_URL="http://localhost:8000"
VITE_FIREBASE_API_KEY="your-firebase-web-api-key"
VITE_FIREBASE_AUTH_DOMAIN="your-project.firebaseapp.com"
VITE_FIREBASE_PROJECT_ID="your-firebase-project-id"
VITE_FIREBASE_APP_ID="your-firebase-web-app-id"Firebase Auth is used by the frontend for Google sign-in. The backend accepts Firebase ID tokens when present and falls back to the mock account for local demo mode.
Start the backend from the project root:
uv run python -m backend.apiEquivalent Uvicorn command:
uv run uvicorn backend.api:app --reloadDo not run uv run api.py from inside backend/; the backend imports expect the project root to be on Python's module path.
In another terminal, start the frontend:
cd frontend
npm run devThe frontend runs on the Vite URL printed in the terminal and talks to VITE_API_BASE_URL, defaulting to http://127.0.0.1:8000.
The backend defaults to seeded in-memory storage:
SECONDBRAIN_STORAGE_BACKEND=memory
SECONDBRAIN_SEED_MOCK_DATA=1Use Firestore for persistent accounts, sources, chunks, posts, and graph data:
SECONDBRAIN_STORAGE_BACKEND=firestore
FIREBASE_PROJECT_ID="your-firebase-project-id"
FIREBASE_SERVICE_ACCOUNT_FILE="/absolute/path/to/service-account.json"
# or:
FIREBASE_SERVICE_ACCOUNT_JSON='{"type":"service_account",...}'For local Firestore emulator development:
SECONDBRAIN_STORAGE_BACKEND=firestore
FIREBASE_PROJECT_ID="secondbrain-local"
FIRESTORE_EMULATOR_HOST="127.0.0.1:8080"Firestore collections used by the backend are accounts, sources, chunks, posts, and graphs. Records are scoped by account_id.
PDF uploads and scraped-link Markdown snapshots are stored outside the database, then linked from source metadata.
The default provider is GitHub:
ORIGINAL_FILE_STORAGE=github
GITHUB_TOKEN="your-github-token"
GITHUB_STORAGE_REPO="owner/repo"
GITHUB_STORAGE_BRANCH="main"
GITHUB_STORAGE_PATH_PREFIX="uploads"To use Google Drive instead:
ORIGINAL_FILE_STORAGE=drive
GOOGLE_DRIVE_FOLDER_ID="your-drive-folder-id"
GOOGLE_DRIVE_SERVICE_ACCOUNT_FILE="/absolute/path/to/drive-service-account.json"
# or:
GOOGLE_DRIVE_SERVICE_ACCOUNT_JSON='{"type":"service_account",...}'For Drive storage, share the target folder with the service account email before ingesting PDFs or links.
GET /accountGET /sourcesGET /sources/{source_id}POST /sources- accepts JSON or multipart form data
- fields:
type=note|pdf|link,title,text,source_url,file
PATCH /sources/{source_id}- JSON body:
{ "content": "updated memory content" }
- JSON body:
GET /postsGET /graphPOST /chat- JSON body:
{ "message": "...", "history": [] }
- JSON body:
POST /chat/stream- streams server-sent events for text, tool calls, trace steps, and final citations
uv run python -m backend.ingest note --account-id "cli-user" --title "Transformers" --text "Self-attention connects tokens."
uv run python -m backend.ingest pdf --account-id "cli-user" --title "Paper" --file ./paper.pdf
uv run python -m backend.ingest link --account-id "cli-user" --title "Article" --source-url "https://example.com"Backend tests:
uv run pytestFrontend typecheck and build:
cd frontend
npm run buildMore technical notes are in documents/: