phase: 02-operations-maintenance
plan: 01
type: execute
wave: 1
depends_on: []
files_modified: [api.py]
autonomous: true
requirements: [OPS-02]
must_haves:
truths:
- "GET /health returns JSON with db, ollama, and claude status fields"
- "When DB is down, health reports db as unhealthy but does not crash"
- "When Ollama is down, health reports ollama as unhealthy but does not crash"
- "When Claude API key is invalid, health reports claude as unhealthy but does not crash"
artifacts:
- path: "api.py"
provides: "Extended /health endpoint with dependency checks"
contains: "ollama"
key_links:
- from: "api.py /health"
to: "psycopg2.connect"
via: "SELECT 1 probe"
pattern: "SELECT 1"
- from: "api.py /health"
to: "OLLAMA_URL"
via: "httpx GET to Ollama API"
pattern: "httpx.*ollama"
- from: "api.py /health"
to: "anthropic.Anthropic"
via: "models.list or lightweight API call"
pattern: "anthropic"
Extend the existing GET /health endpoint to probe all three dependencies (PostgreSQL, Ollama, Claude API) and return per-component status.
Purpose: OPS-02 requires the health endpoint to show status of all dependencies so the crew can diagnose which component is down.
Output: Updated api.py with rich health check returning {"status": "ok|degraded", "db": "ok|error", "ollama": "ok|error", "claude": "ok|error"}.
@$HOME/.claude/get-shit-done/workflows/execute-plan.md
@$HOME/.claude/get-shit-done/templates/summary.md
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/STATE.md
@app.get("/health")
def health():
return {"status": "ok"}
DB_URL = os.environ["DATABASE_URL"]
OLLAMA_URL = os.environ.get("OLLAMA_URL", "http://localhost:11434")
ANTHROPIC_KEY = os.environ["ANTHROPIC_API_KEY"]
conn = psycopg2.connect(DB_URL)
resp = httpx.post(f"{OLLAMA_URL}/api/embeddings", json={...}, timeout=60)
Replace the existing /health endpoint in api.py (lines 80-82) with a comprehensive health check function.
Add imports at the top of api.py (alongside existing imports):
- import httpx
- import psycopg2
- import anthropic
Add module-level env var reads (same pattern as query.py):
DB_URL = os.environ["DATABASE_URL"]
OLLAMA_URL = os.environ.get("OLLAMA_URL", "http://localhost:11434")
ANTHROPIC_KEY = os.environ.get("ANTHROPIC_API_KEY", "")
Replace the /health handler with:
-
DB check: Try
psycopg2.connect(DB_URL)thencur.execute("SELECT 1"), close connection. On success:"ok". On any exception:"error"+ str(exception) indetailfield. -
Ollama check: Try
httpx.get(f"{OLLAMA_URL}/api/tags", timeout=5). On 200:"ok". On any exception or non-200:"error"+ detail. -
Claude check: Try
anthropic.Anthropic(api_key=ANTHROPIC_KEY).models.list(limit=1). On success:"ok". On any exception:"error"+ detail. If ANTHROPIC_KEY is empty string, skip and return"not_configured".
Return JSON:
{
"status": "ok" or "degraded",
"components": {
"db": {"status": "ok|error", "detail": "...only if error..."},
"ollama": {"status": "ok|error", "detail": "...only if error..."},
"claude": {"status": "ok|error|not_configured", "detail": "...only if error..."}
}
}
Top-level status is "ok" only if ALL components are "ok" or "not_configured". Otherwise "degraded".
Each probe MUST be wrapped in its own try/except so one failure does not prevent checking the others. Use short timeouts (5s for Ollama, 5s for DB connect) to avoid slow health checks.
- grep "SELECT 1" api.py returns a match (DB probe present)
- grep "api/tags" api.py returns a match (Ollama probe present)
- grep "anthropic" api.py returns a match (Claude probe present)
- grep "degraded" api.py returns a match (degraded status logic present)
- grep "components" api.py returns a match (structured response)
- python -c "import ast; ast.parse(open('api.py').read())" succeeds (valid Python)
- python -c "import ast; ast.parse(open('api.py').read())" succeeds
- /health response contains components.db, components.ollama, components.claude fields
- Each component check is wrapped in its own try/except
GET /health returns structured JSON showing per-component status of DB, Ollama, and Claude API. No single component failure causes a 500 error.