The hook carried ~50 lines of gitleaks logic and a comment explaining it was self-contained because "this repo has no Makefile". It has one now, so the reason is gone and the arrangement is backwards: a hook is a trigger, and logic belongs where it can be read, run by hand, and changed under review. .githooks/pre-push is now a byte-identical shim onto `make pre-push` in every repo in the workspace. The scan itself moves to ci/secrets.sh unchanged, and `make secrets` runs it on its own. The call surface is identical everywhere; what it runs is not, and should not be — each repo gates what it actually has. That is the point of standardising the name rather than the contents: nobody has to read a repo to find out how to check it. secrets runs first, deliberately. It is the only failure here that cannot be undone by fixing it afterwards — a failed lint costs another commit, a pushed credential is cached and indexed whether or not it is later deleted. Some of these gates fail today, on lint debt that predates them, and they are left wired anyway. The board was measured once and written down in T-56 instead of being worked around here. Narrowing each gate to whatever already passes would produce a gate that reports success for doing nothing, which is the failure this workspace keeps rediscovering. Co-Authored-By: Claude <noreply@anthropic.com>
Library Desk - API Coordination Service
FastAPI service that coordinates all Library operations
Overview
Library Desk is the central coordination layer for The Library system, providing a unified API for:
- HybridRAG Queries - Combines Neo4j (structure) + Qdrant (semantics) + SearXNG (web)
- Document Ingestion - Parse, chunk, embed, and index documents
- Entity Extraction - NLP to identify classes, functions, concepts
- Relationship Mapping - Link entities in Neo4j knowledge graph
- Mind Map Generation - Query Neo4j graph → Render D3.js visualizations
- Wiki.js Proxy - CRUD operations for dossiers
- Deduplication - Vector similarity + graph analysis
Architecture
Library Desk API (FastAPI)
├── Neo4j (knowledge graph)
├── Qdrant (vector search)
├── Wiki.js (wiki operations)
├── SearXNG (web search)
├── Ollama (embeddings)
└── Redis (caching)
Requirements
- Python: 3.12+
- Dependencies: See
requirements.txt
Configuration
Environment variables (set in Portainer stack):
# Required
LIBRARY_API_KEY=<generate-with-openssl-rand-hex-32>
NEO4J_PASSWORD=<neo4j-password>
WIKIJS_API_KEY=<from-wiki-admin-panel>
# Optional (defaults provided)
NEO4J_URI=bolt://neo4j:7687
NEO4J_USER=neo4j
QDRANT_HOST=qdrant
QDRANT_PORT=6333
WIKIJS_URL=http://wiki:3000
SEARXNG_URL=http://searxng:8080
OLLAMA_URL=http://ollama:11434
OLLAMA_MODEL=mistral-nemo-large:latest
OLLAMA_EMBEDDING_MODEL=nomic-embed-text
REDIS_HOST=redis-shared
REDIS_PORT=6379
REDIS_DB=2
API Endpoints
System
GET /- Root endpointGET /health- Health check (public)GET /stats- System statistics (authenticated)
Query (All require API key)
POST /query/hybrid- HybridRAG (graph + vector + web)POST /query/semantic- Vector search onlyPOST /query/graph- Graph traversal onlyGET /query/related/{id}- Find related content
Content Management (Future)
POST /ingest/document- Index new documentPOST /ingest/wiki-page- Sync Wiki.js pagePOST /wiki/dossier- Create dossier (proxies to Wiki.js)PUT /wiki/dossier/{id}- Update dossierDELETE /wiki/dossier/{id}- Delete dossier
Graph Operations (Future)
GET /graph/entities- List entitiesGET /graph/mindmap/{id}- Generate mind mapPOST /graph/query- Execute Cypher query
Deduplication (Future)
POST /deduplicate/find- Find duplicatesPOST /deduplicate/merge- Merge duplicates
Development
Local Setup
# Create virtual environment
python3 -m venv venv
source venv/bin/activate
# Install dependencies
pip install -r requirements.txt
# Run development server
uvicorn src.main:app --reload --host 0.0.0.0 --port 8089
Project Structure
Following FastAPI Best Practices:
library-desk/
├── src/
│ ├── __init__.py # Package initialization
│ ├── main.py # FastAPI application
│ ├── config.py # Pydantic settings
│ └── [future modules] # Domain-specific modules
├── requirements.txt # Python dependencies
└── README.md # This file
Future structure (as features are added):
library-desk/
├── src/
│ ├── query/ # Query domain
│ │ ├── router.py
│ │ ├── schemas.py
│ │ ├── service.py
│ │ └── dependencies.py
│ ├── graph/ # Graph domain
│ ├── wiki/ # Wiki domain
│ └── ingest/ # Ingestion domain
Best Practices Implemented
✅ Async routes for I/O operations
✅ Dependency injection for configuration and auth
✅ Pydantic models for request/response validation
✅ Modular settings using Pydantic Settings
✅ API key authentication with Bearer tokens
✅ OpenAPI documentation auto-generated
✅ Proper logging with structured format
✅ CORS middleware configured
✅ Health checks for monitoring
✅ Minor version locking (~=) in requirements
✅ CVE-checked dependencies (Dec 2025)
API Documentation
Once running, access:
- Interactive docs: http://localhost:8089/docs
- ReDoc: http://localhost:8089/redoc
- OpenAPI spec: http://localhost:8089/openapi.json
Authentication
All protected endpoints require a Bearer token:
curl -H "Authorization: Bearer ${LIBRARY_API_KEY}" \
http://localhost:8089/stats
Testing
# Run tests (when implemented)
pytest
# With coverage
pytest --cov=src --cov-report=term
Deployment
Deployed via Portainer stack: /stacks/library-desk.yml
The container:
- Runs on port 8089
- Auto-creates venv on startup
- Installs dependencies from requirements.txt
- Starts uvicorn with 2 workers
- Mounts source code for live editing
Monitoring
- Uptime Kuma: Monitor
/healthendpoint - Logs:
docker logs library-desk - Stats:
GET /stats(requires API key)
Scheduler Integration
See LIBRARIAN_INTEGRATION.md for details on how The Scheduler (Librarian) integrates with Library Desk for automated documentation indexing.
Key Workflow:
- Scheduler mirrors docs to Gitea (daily 03:00)
- Scheduler syncs to Library Desk (daily 03:30)
- Library Desk ingests, chunks, embeds, and indexes
- Content becomes searchable via HybridRAG
Future Enhancements
- Implement HybridRAG query logic
- Add Neo4j connection pooling
- Add Qdrant client initialization
- Implement Wiki.js API proxy
- Add entity extraction (spaCy/NLP)
- Implement mind map generation
- Add deduplication logic
- Implement Scheduler integration endpoints (see LIBRARIAN_INTEGRATION.md)
- Add comprehensive tests
- Add rate limiting
- Add request tracing
References
- FastAPI Best Practices
- FastAPI Documentation
- Pydantic Documentation
- Neo4j Python Driver
- Qdrant Python Client
License
Part of Portainer Core infrastructure.
Support
- Check logs:
docker logs library-desk - Health check:
curl http://localhost:8089/health - API docs: http://localhost:8089/docs