CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Project: DeepbitDesktop v0 β€” ozmai RAG Support Desk

Local RAG system for IT support teams. Documents and logfiles are ingested, chunked, and embedded into pgvector. Queries go through Ollama embeddings β†’ cosine search β†’ Claude/OpenRouter for answer generation. Everything runs in Docker; no data leaves the machine except Claude API calls.

Key Commands

# Start full stack
docker compose up --build

# Logs
docker compose logs -f app

# Ingest a file via CLI (outside container)
python ingest.py --file /path/to/file.log --channel dns

# Query via CLI
python query.py "Was ist mit dem Mailserver passiert?"

# Export current knowledge snapshot
docker exec <db-container> pg_dump -U rag -d supportdesk --data-only --no-privileges --no-owner > seed/02-seed.sql

# Reset knowledge (channel-scoped)
curl -X POST "http://localhost:8080/admin/reset?channel_id=dns"

# Health check
curl http://localhost:8080/health

# Interactive DB access
docker compose exec db psql -U rag -d supportdesk

Architecture

Data Flow

Text/file β†’ ingest.py β†’ chunk_lines() (20 lines/chunk)
         β†’ embeddings.py get_embedding() β†’ Ollama nomic-embed-text (768-dim)
         β†’ chunks table (pgvector)

Query β†’ embeddings.py β†’ similarity_search() (cosine, TOP 5)
      β†’ query.py ask() β†’ Claude or OpenRouter
      β†’ chat_history table

Module Responsibilities

  • api.py β€” FastAPI app, all HTTP endpoints, Pydantic models, DB connections via raw psycopg2
  • ingest.py β€” Chunking (20 lines) and embedding pipeline; usable as CLI or imported by api.py
  • query.py β€” RAG query (ask()), log analysis (analyze_log()), OpenRouter fallback
  • embeddings.py β€” Ollama HTTP client with retry logic; shared by ingest and query

Query Modes

  • vektor: strict β€” answer only from retrieved chunks, refuses if not found
  • llm: supplementary β€” Claude can add its own knowledge, marked with 🧠 [Allgemeines Wissen]:

Provider Selection

  • anthropic: Direct Anthropic API (claude-sonnet-4-6)
  • openrouter: OpenAI-compatible gateway; model set via OPENROUTER_MODEL env var

Channel Scoping

Queries search the target channel first. If the channel has zero chunks, it falls back to general. The general channel always exists and cannot be deleted.

Log Analysis (/analyze-log)

Raw logs are never stored. Claude anonymizes IPs β†’ [IP-xxx], hostnames β†’ [HOST-xxx], users β†’ [USER-xxx]. Only the anonymized analysis can be optionally saved via /save-analysis.

Database Schema

Three tables: channels (id TEXT PK, name, category), chunks (id, source, content, embedding vector(768), channel_id FK, created_at), chat_history (channel_id FK, question, answer, sources JSONB, created_at).

IVFFlat index on chunks.embedding with lists=1 β€” increase to sqrt(row_count) once you exceed ~10k rows.

Environment Variables (.env)

DATABASE_URL=postgresql://rag:rag@db:5432/supportdesk
OLLAMA_URL=http://ollama:11434
ANTHROPIC_API_KEY=sk-ant-...
POSTGRES_USER=rag
POSTGRES_PASSWORD=rag
POSTGRES_DB=supportdesk
# Optional:
OPENROUTER_API_KEY=sk-or-v1-...
OPENROUTER_MODEL=anthropic/claude-3.5-haiku

Deployment

Seed (seed/02-seed.sql) auto-imports on empty volume via docker-entrypoint-initdb.d. To force re-import: docker compose down -v && docker compose up.

To deploy to a new machine: bash setup_deploy_crewscript.sh β€” exports DB, copies source, generates docker-compose and .env template.

Chunk Quality Notes

20-line chunks work well for logs. For documentation, use FAQ format (question on first line, answer follows) so the retrieval query matches the question text directly. One chunk = one topic.