# Install dependencies (creates .venv automatically)
uv syncTwo env files, loaded in order:
# Production secrets (DATABASE_URL) — persistent, survives repo resets
/etc/watcher/.env
# Dev/agent secrets (GH_TOKEN, TEST_DATABASE_URL) — repo root, git-ignored
.env
# Load both for shell commands
export $(cat /etc/watcher/.env .env 2>/dev/null | xargs)The systemd service loads both automatically (see deploy/watcher.service).
The watcher service runs via systemd. Always use systemctl — never start uvicorn manually on port 8000.
# Restart after code changes (migrations are NOT auto-run)
sudo systemctl restart watcher
# Check status
sudo systemctl status watcher
# Follow logs
sudo journalctl -u watcher -f
# Reload systemd after editing deploy/watcher.service
sudo systemctl daemon-reload && sudo systemctl restart watcher# Dev server — use a non-conflicting port so the systemd service stays up
export $(cat /etc/watcher/.env .env 2>/dev/null | xargs)
uv run uvicorn src.api.main:app --host 0.0.0.0 --port 8001 --reload
# CAUTION: Only stop the service if you need port 8000 specifically.
# The live site will be DOWN until you restart. Prefer port 8001.
# sudo systemctl stop watcher
# uv run uvicorn src.api.main:app --host 0.0.0.0 --port 8000 --reload
# sudo systemctl start watcher # MUST restart when doneAfter committing to main, restart the service to pick up changes:
sudo systemctl restart watcher
# Verify
curl -s http://localhost:8000/health | python3 -m json.toolRun a worktree build on a different port to avoid conflicting with the service:
cd .worktrees/<branch>
export $(cat /etc/watcher/.env .env 2>/dev/null | xargs)
uv run uvicorn src.api.main:app --host 0.0.0.0 --port 8001 --reload# Run all tests (excludes integration)
uv run pytest
# Run with coverage
uv run pytest --cov
# Run a specific file
uv run pytest tests/path/to/test_file.py --no-cov
# Run integration tests (hits live external services)
uv run pytest -m integration# Check
uv run ruff check .
# Fix auto-fixable issues
uv run ruff check --fix .# PostgreSQL setup (first time)
sudo apt-get install -y postgresql postgresql-client
sudo systemctl start postgresql
sudo -u postgres psql -c "CREATE USER watcher WITH PASSWORD 'watcher';"
sudo -u postgres psql -c "CREATE DATABASE watcher OWNER watcher;"
sudo -u postgres psql -c "CREATE DATABASE watcher_test OWNER watcher;"
# Apply migrations (requires DATABASE_URL in env)
export $(cat /etc/watcher/.env .env 2>/dev/null | xargs)
uv run alembic upgrade head
# Generate a new migration after model changes
uv run alembic revision --autogenerate -m "description of change"
# Check current migration state
uv run alembic current# Apply procrastinate schema (first time, after DB setup)
export $(cat /etc/watcher/.env .env 2>/dev/null | xargs)
uv run procrastinate --app=src.workers.app schema --apply
# Run worker standalone (alternative to embedded mode in FastAPI)
uv run procrastinate --app=src.workers.app worker
# The worker also runs embedded in FastAPI via lifespan — no separate process needed for dev# Build Tailwind CSS
bash scripts/build-css.sh
# Watch mode (auto-rebuild on changes)
bash scripts/build-css.sh --watch# Init after cloning
git submodule update --init --recursive
# Force-refresh vendor skills
git submodule update --remote --merge vendor/gregoryfoster-skills vendor/obra-superpowers