Hackathon edition. Read this before writing a single line of code. If something in here is wrong or out of date, fix it — don't just work around it.
- Prerequisites
- Clone & Python Environment
- Environment Variables — Where to Get Every Credential
- Local Services (Postgres + Redis)
- Run the Backend
- Docker Compose (Alternative to Steps 4–5)
- Phase 1 Health Check
- Troubleshooting
Install these before anything else. If you already have them, skip.
| Tool | Version | Install |
|---|---|---|
| Python | 3.12.x | python.org/downloads or brew install python@3.12 |
| PostgreSQL | 16.x | brew install postgresql@16 or postgresql.org |
| Redis | 7.x | brew install redis or redis.io |
| Git | any recent | pre-installed on Mac; brew install git otherwise |
| Docker + Docker Compose | latest | docker.com/get-started — only needed if using the compose path |
Verify everything is on PATH:
python3.12 --version # Python 3.12.x
psql --version # psql (PostgreSQL) 16.x
redis-cli --version # Redis cli 7.x# from ProjectOS root
cd backend
# create the virtual environment
python3.12 -m venv .venv
# activate it (do this every time you open a new terminal)
source .venv/bin/activate # macOS / Linux
# .venv\Scripts\activate # Windows
# install dependencies
pip install -r requirements.txtYour shell prompt should now show (.venv). Every command in this guide assumes the venv is active.
Copy the example file first:
cp backend/.env.example backend/.envThen fill in each blank below. The .env file is git-ignored — never commit it.
DATABASE_URL=postgresql+asyncpg://postgres:postgres@localhost:5432/projectos
REDIS_URL=redis://localhost:6379/0These point at the local Postgres and Redis you'll start in Step 4. No changes needed for local dev.
If you change the Postgres password when creating the DB, update postgres:postgres accordingly.
Used by: Squad A (ai_service.py). Every squad's feature work ultimately flows through this.
Required for: Phase 2 onwards (stub works without it in Phase 1).
How to get it:
- Go to console.anthropic.com
- Sign in with the team account (ask Karan for credentials if you don't have access)
- Navigate to API Keys → Create Key
- Copy the key — it starts with
sk-ant-
ANTHROPIC_API_KEY=sk-ant-...
CLAUDE_SONNET_MODEL=claude-sonnet-4-6
CLAUDE_HAIKU_MODEL=claude-haiku-4-5-20251001The model names are already correct in the example — do not change them unless Karan explicitly says so.
Used by: Squad A / Prit Chavda (rag_service.py) for embedding code chunks (voyage-code-2).
Required for: Phase 2 (knowledge hub ingestion).
How to get it:
- Go to dash.voyageai.com
- Sign in / create account with the team email
- Navigate to API Keys → New Key
- Copy the key — it starts with
pa-
VOYAGE_API_KEY=pa-...Used by: Squad A / Prit Chavda (rag_service.py) for embedding prose chunks — docs, tickets, meeting transcripts — using text-embedding-004.
Required for: Phase 2 (knowledge hub ingestion — prose content).
Free tier: 1500 embedding requests/day via Google AI Studio — no billing required, no credit card.
How to get it:
- Go to aistudio.google.com/app/apikey
- Sign in with a Google account
- Click Create API key → Create API key in new project
- Copy the key — it starts with
AIza
GEMINI_API_KEY=AIza...Why two embedding providers? Voyage AI's
voyage-code-2is purpose-built for code — it outperforms general embedders on function/class-level retrieval. Gemini'stext-embedding-004handles prose (docs, tickets, meetings) for free. Using one model for both degrades code search quality (§11.2).
Used by: Squad A (login flow, auth.py) and Squad B (repo connector, GitHubConnector).
Required for: Phase 1 — the OAuth redirect is the very first thing the demo shows.
How to get it:
- Go to github.com/settings/developers
- Click New OAuth App
- Fill in:
- Application name:
ProjectOS (Local Dev)— one app per dev is fine - Homepage URL:
http://localhost:8000 - Authorization callback URL:
http://localhost:8000/api/v1/auth/github/callback
- Application name:
- Click Register application
- On the next screen: copy Client ID immediately
- Click Generate a new client secret → copy it immediately (shown only once)
GITHUB_CLIENT_ID=Ov23li...
GITHUB_CLIENT_SECRET=...
GITHUB_OAUTH_REDIRECT_URI=http://localhost:8000/api/v1/auth/github/callbackOne OAuth app per developer. Each person's callback URL points to their own
localhost:8000. For the shared demo host, Chaitanya (Squad F) will create a separate app with the production URL.
Used by: Squad D (risks.py) to fire alerts when a risk hits severity = HIGH.
Required for: Phase 2 (risk digest feature). Leave blank in Phase 1 — the code guards against an empty URL.
How to get it:
- Go to api.slack.com/apps → Create New App → From scratch
- Name it
ProjectOS Alerts, pick the team Slack workspace - Under Add features and functionality → Incoming Webhooks → toggle On
- Click Add New Webhook to Workspace → pick the
#projectos-alertschannel (create it first) - Copy the webhook URL — it looks like
https://hooks.slack.com/services/T.../B.../...
SLACK_WEBHOOK_URL=https://hooks.slack.com/services/...Used by: Auth system (security.py). These are generated once per environment, never shared publicly.
Required for: Phase 1 — auth won't start without valid values.
Run these two commands and paste the output:
# JWT_SECRET_KEY — 64 random hex chars
python3 -c "import secrets; print(secrets.token_hex(32))"
# TOKEN_ENCRYPTION_KEY — must be exactly 32 bytes for Fernet/AES-256
python3 -c "import secrets; print(secrets.token_urlsafe(32)[:32])"JWT_SECRET_KEY=<output of first command>
JWT_ALGORITHM=HS256
ACCESS_TOKEN_EXPIRE_MINUTES=15
REFRESH_TOKEN_EXPIRE_DAYS=7
TOKEN_ENCRYPTION_KEY=<output of second command — exactly 32 chars>Every developer generates their own values. Do not share these across machines — they only need to match if you're sharing a running database with someone else.
No credentials needed. ChromaDB runs embedded inside the FastAPI process and persists to disk.
CHROMA_PERSIST_PATH=./data/chromadbThe directory is created automatically on first run. Leave this as-is.
CORS_ORIGINS=["http://localhost:5173"]
INGESTION_WORKER_CONCURRENCY=5
LOG_FORMAT=text
LOG_PROMPTS=FalseCORS_ORIGINS— matches Vite's default dev port. Squad E: don't change this unless you change Vite's port.LOG_PROMPTS=True— set this locally if you want to see the full Claude prompts in logs while building. Never set it on the demo host.
Here is the full .env with all keys in one place:
# --- Infrastructure ---
DATABASE_URL=postgresql+asyncpg://postgres:postgres@localhost:5432/projectos
REDIS_URL=redis://localhost:6379/0
# --- AI APIs ---
ANTHROPIC_API_KEY=sk-ant-... # console.anthropic.com
VOYAGE_API_KEY=pa-... # dash.voyageai.com (code embeddings)
GEMINI_API_KEY=AIza... # aistudio.google.com/app/apikey (prose embeddings — FREE)
CLAUDE_SONNET_MODEL=claude-sonnet-4-6
CLAUDE_HAIKU_MODEL=claude-haiku-4-5-20251001
# --- Vector Store ---
CHROMA_PERSIST_PATH=./data/chromadb
# --- Auth ---
JWT_SECRET_KEY= # generate: python3 -c "import secrets; print(secrets.token_hex(32))"
JWT_ALGORITHM=HS256
ACCESS_TOKEN_EXPIRE_MINUTES=15
REFRESH_TOKEN_EXPIRE_DAYS=7
TOKEN_ENCRYPTION_KEY= # generate: python3 -c "import secrets; print(secrets.token_urlsafe(32)[:32])"
# --- GitHub OAuth ---
GITHUB_CLIENT_ID= # github.com/settings/developers
GITHUB_CLIENT_SECRET=
GITHUB_OAUTH_REDIRECT_URI=http://localhost:8000/api/v1/auth/github/callback
# --- Slack (Phase 2) ---
SLACK_WEBHOOK_URL= # api.slack.com/apps — leave blank for Phase 1
# --- App ---
CORS_ORIGINS=["http://localhost:5173"]
INGESTION_WORKER_CONCURRENCY=5
LOG_FORMAT=text
LOG_PROMPTS=False# Start the Postgres service (macOS with Homebrew)
brew services start postgresql@16
# Create the database
createdb projectos
# Verify
psql projectos -c "SELECT version();"If createdb fails with a role error, create the role first:
psql postgres -c "CREATE USER postgres WITH SUPERUSER PASSWORD 'postgres';"
createdb -U postgres projectos# Start Redis
brew services start redis
# Verify
redis-cli ping # should return PONGcd backend
source .venv/bin/activate
# Run database migrations (creates all tables)
alembic upgrade head
# Start the dev server with live reload
uvicorn app.main:app --reload --host 0.0.0.0 --port 8000Health check — open in browser or run:
curl http://localhost:8000/health
# {"status":"ok"}API docs (auto-generated):
- Swagger UI: http://localhost:8000/docs
- ReDoc: http://localhost:8000/redoc
If you prefer not to install Postgres/Redis locally, use Compose — it manages both services for you.
# From ProjectOS root
docker compose up -d postgres redis
# Then run the backend locally (steps above) pointing at the compose containers
# DATABASE_URL and REDIS_URL in .env already point at localhost — it works as-isOr run the full stack including the backend container:
docker compose up -dChaitanya (Squad F): you own the
docker-compose.yml. When it's committed, update this section.
Before calling Phase 1 done, verify each of these yourself:
| Check | Command / Action | Expected |
|---|---|---|
| Backend starts | uvicorn app.main:app --reload |
No import errors, server listening on 8000 |
| Health endpoint | curl http://localhost:8000/health |
{"status":"ok"} |
| DB connected | alembic upgrade head |
Runs with no errors |
| Redis connected | redis-cli ping |
PONG |
| GitHub OAuth redirect | Visit http://localhost:8000/api/v1/auth/github/login |
Redirects to GitHub login |
| AI stub contract | python3 -c "from app.services.ai_service import AIService; print('ok')" |
Prints ok |
| RAG stub contract | python3 -c "from app.services.rag_service import RAGService; print('ok')" |
Prints ok |
If any of these fail, fix it before pushing to main — every other squad is blocked until the stubs are in and the server runs clean.
ModuleNotFoundError on startup
The venv is either not activated or pip install didn't run. Run:
source backend/.venv/bin/activate
pip install -r backend/requirements.txtconnection refused on port 5432
Postgres isn't running. Run brew services start postgresql@16 (or docker compose up -d postgres).
connection refused on port 6379
Redis isn't running. Run brew services start redis (or docker compose up -d redis).
pydantic_settings.env_settings.EnvSettingsError on startup
A required env var is missing or empty. Check your .env file — every field in section 3 without a default must have a value. The error message names the missing variable.
GitHub OAuth redirects to an error page
- Double-check the callback URL in your GitHub OAuth app matches exactly:
http://localhost:8000/api/v1/auth/github/callback - Make sure
GITHUB_CLIENT_IDandGITHUB_CLIENT_SECRETare both set in.env
alembic upgrade head fails with "table already exists"
The database has a partial migration. Reset it:
dropdb projectos && createdb projectos
alembic upgrade headQuestions? Blockers? Ping Karan Bosamiya (Squad A lead) on the team channel. For CI / deploy issues, ping Shubham Nayak (Squad F lead).