Put your wardrobe in rows. Snap. Organize. Wear.
Features • Quick Start • Deployment • Architecture • Contributing
Self-hosted wardrobe management with AI-powered outfit recommendations. Take photos of your clothes, let AI tag them, and get daily outfit suggestions based on weather and occasion.
- Photo-based wardrobe - Upload photos, AI extracts clothing details automatically
- Smart recommendations - Outfits matched to weather, occasion, and your preferences
- Scheduled notifications - Daily outfit suggestions via ntfy/Mattermost/email
- Family support - Manage wardrobes for household members
- Wear tracking - History, ratings, and outfit feedback
- Analytics - See what you wear, what you don't, color distribution
- Fully self-hosted - Your data stays on your hardware
- Works with any AI - OpenAI, Ollama, LocalAI, or any OpenAI-compatible API
| Grid View | Item Details & AI Analysis |
|---|---|
![]() |
![]() |
| Wash Tracking | Suggestions |
|---|---|
![]() |
![]() |
| History Calendar | Analytics |
|---|---|
![]() |
![]() |
| Pairing View | Pairing Modal |
|---|---|
![]() |
![]() |
- Docker and Docker Compose installed
- At least 4GB of RAM available
- An AI service (Ollama recommended for free local AI, or OpenAI API key)
Option A: Using Ollama (Recommended - Free, runs locally)
# Install Ollama from https://ollama.ai
# Then pull required models:
ollama pull gemma3 # Multimodel LLM (for image analysis and outfit recommendations)
# Verify it's running:
curl http://localhost:11434/api/tagsOption B: Using OpenAI (Paid API)
Get your API key from https://platform.openai.com/api-keys
# Clone the repository
git clone https://github.com/yourusername/wardrowbe.git
cd wardrowbe
# Copy environment template
cp .env.example .env
# IMPORTANT: Edit .env and configure AI settings
# For Ollama (default in .env.example):
# AI_BASE_URL=http://host.docker.internal:11434/v1
# AI_VISION_MODEL=gemma3:latest
# AI_TEXT_MODEL=gemma3:latest
#
# For OpenAI, uncomment and set:
# AI_BASE_URL=https://api.openai.com/v1
# AI_API_KEY=sk-your-api-key-here
# AI_VISION_MODEL=gpt-4o
# AI_TEXT_MODEL=gpt-4o
# Optional: Generate secure secrets for production
# SECRET_KEY=$(openssl rand -hex 32)
# NEXTAUTH_SECRET=$(openssl rand -hex 32)docker-compose.yml pulls pre-built multi-arch images (linux/amd64 and linux/arm64, so Raspberry Pi and other ARM hosts work) from GitHub Container Registry. No local build tooling is required on the host.
# Pull the latest published images, then start all containers
docker compose pull
docker compose up -d
# Wait for services to be healthy (30 seconds)
docker compose ps
# Run database migrations (REQUIRED)
docker compose exec backend alembic upgrade head
# Verify everything is working
curl http://localhost:8000/api/v1/health
# Should return: {"status":"healthy"}To build the images from source instead of pulling them, use the development stack below (docker-compose.dev.yml), which builds locally and enables hot reload.
- Frontend: http://localhost:3000
- API Docs: http://localhost:8000/docs
- Login: Click "Login" - uses dev credentials by default (no password needed)
For hot reloading during development (auto-rebuilds on code changes):
# Start in dev mode
docker compose -f docker-compose.yml -f docker-compose.dev.yml up -d
# Run migrations (first time only)
docker compose exec backend alembic upgrade head
# View logs
docker compose logs -f frontend backendWardrowbe works with any OpenAI-compatible API. You need two types of models:
- Vision model: Analyzes clothing images to extract colors, patterns, styles
- Text model: Generates outfit recommendations and descriptions
Internal AI is optional. Set AI_INTERNAL_ENABLED=false to run the backend with
no internal AI provider at all — it boots and serves without AI_BASE_URL,
AI_API_KEY, or model names configured, and defers tagging/suggestions/pairings
to an external agent. You can also disable a single capability with
AI_VISION_ENABLED=false (auto-tagging) or AI_TEXT_ENABLED=false
(suggestions/pairings); unset switches inherit the master. The effective state is
reported at GET /api/v1/capabilities. Defaults keep internal AI on, so
existing deployments are unaffected.
Free, runs locally, no API key needed, works offline
-
Install Ollama
-
Pull models:
ollama pull gemma3:latest # multimodel LLM (3.4GB) - analyze images and generates recommendations # Alternative text models you can use: # ollama pull llama3:latest # Good all-around model # ollama pull qwen2.5:latest # Fast and efficient # ollama pull mistral:latest # Great for creative text
-
Configure in
.env:AI_BASE_URL=http://host.docker.internal:11434/v1 AI_API_KEY=not-needed AI_VISION_MODEL=gemma3:latest AI_TEXT_MODEL=gemma3:latest
Note: Use host.docker.internal instead of localhost so Docker containers can reach your host's Ollama.
Paid API, requires internet connection
- Get API key from https://platform.openai.com/api-keys
- Configure in
.env:AI_BASE_URL=https://api.openai.com/v1 AI_API_KEY=sk-your-api-key-here AI_VISION_MODEL=gpt-4o AI_TEXT_MODEL=gpt-4o
Self-hosted OpenAI alternative
AI_BASE_URL=http://localai:8080/v1
AI_API_KEY=not-needed
AI_VISION_MODEL=gpt-4-vision-preview
AI_TEXT_MODEL=gpt-3.5-turboSome models can handle both vision and text (like qwen2-vl, llama3.2-vision):
AI_VISION_MODEL=llama3.2-vision:11b
AI_TEXT_MODEL=llama3.2-vision:11b # Same model for both tasks┌─────────────────────────────────────────────────────────────┐
│ Frontend │
│ (Next.js + React Query) │
└─────────────────────────┬───────────────────────────────────┘
│
┌─────────────────────────▼───────────────────────────────────┐
│ Backend │
│ (FastAPI + SQLAlchemy) │
└──────────┬──────────────┬──────────────────┬────────────────┘
│ │ │
┌──────▼──────┐ ┌─────▼─────┐ ┌──────▼──────┐
│ PostgreSQL │ │ Redis │ │ AI Service │
│ (Database) │ │ (Job Queue)│ │ (OpenAI/etc)│
└─────────────┘ └─────┬─────┘ └─────────────┘
│
┌──────────▼──────────┐
│ Background Worker │
│ (arq - AI Jobs) │
└─────────────────────┘
| Layer | Technology |
|---|---|
| Frontend | Next.js 14, TypeScript, TanStack Query, Tailwind CSS, shadcn/ui |
| Backend | FastAPI, SQLAlchemy (async), Pydantic, Python 3.11+ |
| Database | PostgreSQL 15 |
| Cache/Queue | Redis 7 |
| Background Jobs | arq |
| Authentication | NextAuth.js (supports OIDC, dev credentials) |
| AI | Any OpenAI-compatible API |
See docker-compose.prod.yml for production configuration. Like the default stack, it pulls pre-built images from GHCR rather than building on the host.
docker compose -f docker-compose.prod.yml pull
docker compose -f docker-compose.prod.yml up -d
docker compose exec backend alembic upgrade headImages are tagged backend-latest / frontend-latest, and each release also
publishes backend-<version> / frontend-<version> (e.g. backend-1.3.0). To
pin a deployment to a specific release, replace the -latest tags in the
compose file with the version, e.g. ghcr.io/anyesh/wardrowbe:backend-1.3.0.
See the k8s/ directory for Kubernetes manifests including:
- PostgreSQL and Redis with persistent storage
- Backend API and worker deployments
- Next.js frontend
- Ingress with TLS
- Network policies
| Variable | Description | Required |
|---|---|---|
DATABASE_URL |
PostgreSQL connection string | Yes |
SECRET_KEY |
Backend secret for JWT | Yes |
NEXTAUTH_SECRET |
NextAuth session encryption | Yes |
AI_BASE_URL |
AI service URL | Yes |
AI_API_KEY |
AI API key (if required) | Depends |
OIDC_ISSUER_URL |
OIDC provider URL (enables SSO login) | No |
OIDC_CLIENT_ID |
OIDC client ID | If OIDC |
OIDC_CLIENT_SECRET |
OIDC client secret | If OIDC |
OIDC_SKIP_SSL_VERIFY |
Skip TLS verification for OIDC provider (self-signed certs) | No |
LOCAL_DNS |
Custom DNS server for container name resolution (e.g. local OIDC host) | No |
SMTP_HOST |
SMTP server for email notifications | No |
SMTP_PORT |
SMTP port (default: 587) | No |
SMTP_USER |
SMTP username | No |
SMTP_PASSWORD |
SMTP password | No |
BG_REMOVAL_PROVIDER |
Background removal backend: rembg or http (default: rembg) |
No |
BG_REMOVAL_MODEL |
rembg model name (default: u2net) |
No |
BG_REMOVAL_URL |
URL for HTTP bg removal provider | If http |
BG_REMOVAL_API_KEY |
API key for HTTP bg removal provider | No |
NEXT_PUBLIC_ENABLE_IP_LOCATION_FALLBACK |
Enable IP-based approximate location when browser geolocation is denied/unavailable. Off by default (sends the user's IP to a third party). Set to true to enable |
No |
NEXT_PUBLIC_NETWORK_LOCATION_URL |
Override the IP geolocation provider (default: https://ipapi.co/json/). Only used when the fallback above is enabled |
No |
See .env.example for all options.
The Settings page can fill in your coordinates from the browser's Geolocation API. If that is denied or unavailable, an optional fallback can approximate your location from your IP address via a third-party service (ipapi.co by default). This fallback is disabled by default because it sends the user's IP to an external provider; enable it with NEXT_PUBLIC_ENABLE_IP_LOCATION_FALLBACK=true and optionally point NEXT_PUBLIC_NETWORK_LOCATION_URL at a provider you trust. These are build-time frontend variables, so set them before building the frontend image. Geocoding a location name you type yourself still uses OpenStreetMap Nominatim regardless of this setting.
Remove image backgrounds from wardrobe items. Two backends supported:
rembg (local, default):
pip install rembg[cpu] # add to your image, or install manuallyNo config needed — works out of the box. Change model with BG_REMOVAL_MODEL (default: u2net, options: isnet-general-use, silueta, u2netp).
HTTP provider (e.g. withoutbg):
BG_REMOVAL_PROVIDER=http
BG_REMOVAL_URL=http://withoutbg:5000
BG_REMOVAL_API_KEY= # optionalIf neither is configured, the remove-background button returns a 501 with setup instructions.
- Development Mode (default): Simple email/name login, no setup required
- OIDC Mode: Any OIDC provider (PocketID, Authentik, Keycloak, Auth0, etc.)
To enable OIDC, set OIDC_ISSUER_URL, OIDC_CLIENT_ID, and OIDC_CLIENT_SECRET in your .env. If your OIDC provider uses a self-signed certificate, set OIDC_SKIP_SSL_VERIFY=true. If your OIDC provider runs on a hostname that Docker containers can't resolve (e.g. a local DNS name), set LOCAL_DNS to your DNS server IP, or set OIDC_HOST and OIDC_HOST_IP to inject the hostname directly into the container's /etc/hosts.
When registering the app in your OIDC provider, use this as the callback/redirect URI:
{NEXTAUTH_URL}/api/auth/callback/oidc
For example, if NEXTAUTH_URL=http://localhost:8080, the callback URL is:
http://localhost:8080/api/auth/callback/oidc
- ntfy.sh: Free push notifications
- Email: SMTP-based (set
SMTP_HOST,SMTP_USER,SMTP_PASSWORDin.env)
Uses Open-Meteo - free, no API key needed.
# Run tests (requires running containers)
docker compose exec backend python -m pytest tests/ -v --tb=short
# Run a specific test file
docker compose exec backend python -m pytest tests/test_notification_workers.py -v
# Lint
pip install ruff
ruff check --fix backend/app/ && ruff format backend/app/cd frontend
npm install
# Run dev server
npm run dev
# Run tests
npm test
# Build
npm run buildAvailable when running:
- Swagger UI: http://localhost:8000/docs
- ReDoc: http://localhost:8000/redoc
# Check for type errors
cd frontend
npm install
npx tsc --noEmit
# If you see errors, please report them as a bug# 1. Check all services are healthy
docker compose ps
# 2. Check backend is responding
curl http://localhost:8000/api/v1/health
# 3. Verify migrations ran successfully
docker compose exec backend alembic current
# 4. Check logs for errors
docker compose logs backend frontend --tail=50
# 5. If migrations failed, run them manually
docker compose exec backend alembic upgrade head# For Ollama users:
# 1. Verify Ollama is running and accessible
curl http://localhost:11434/api/tags
# Should show your installed models
# 2. Check you have the vision model
ollama list | grep gemma
# 3. Verify .env has correct configuration
cat .env | grep AI_
# 4. Check worker logs for AI errors
docker compose logs worker --tail=50
# For OpenAI users:
# 1. Verify API key is valid
curl https://api.openai.com/v1/models \
-H "Authorization: Bearer $AI_API_KEY"
# 2. Check you have credits remaining in your account# 1. Ensure you're using the dev compose file
docker compose -f docker-compose.yml -f docker-compose.dev.yml down
docker compose -f docker-compose.yml -f docker-compose.dev.yml build frontend
docker compose -f docker-compose.yml -f docker-compose.dev.yml up -d
# 2. Check frontend logs
docker compose logs frontend -f
# Alternative: Run frontend locally for development
cd frontend
npm install
npm run dev
# Then access at http://localhost:3000# Check what's using the ports
sudo lsof -i :3000 # Frontend
sudo lsof -i :8000 # Backend
sudo lsof -i :5432 # PostgreSQL
sudo lsof -i :6379 # Redis
# Stop conflicting services or change ports in .env# Check current migration version
docker compose exec backend alembic current
# View migration history
docker compose exec backend alembic history
# If migrations are corrupted, reset (WARNING: Deletes all data!)
docker compose down -v
docker compose up -d
sleep 10
docker compose exec backend alembic upgrade head# Check container logs
docker compose logs <service-name> --tail=100
# Common issues:
# - Database not ready: Wait 30 seconds and retry
# - Out of memory: Increase Docker memory limit
# - Permission errors: Check file permissions on volumes# Check resource usage
docker stats
# If backend is slow:
# 1. Check PostgreSQL performance
docker compose exec postgres psql -U wardrobe -c "SELECT * FROM pg_stat_activity;"
# 2. Check Redis connection
docker compose exec redis redis-cli ping
# If AI analysis is slow:
# - For Ollama: Use smaller quantized models
# - For OpenAI: Check your rate limitsIf you're still stuck:
- Check existing GitHub Issues
- Search Discussions
- Create a new issue with:
- Output of
docker compose ps - Relevant logs from
docker compose logs - Your .env configuration (redact secrets!)
- Steps to reproduce the problem
- Output of
Contributions are welcome! Please see CONTRIBUTING.md for guidelines.
If you find wardrowbe useful, consider supporting its development:
This project is licensed under the MIT License - see the LICENSE file for details.
- Docker & Docker Compose
- ~4GB RAM (with local Ollama models)
- Storage for clothing photos
Works great on a Raspberry Pi 5!







