Ingest PDF documents into a hybrid vector + knowledge graph store, then query them through a Claude agent skill.
- Ingestion —
packages/ingestionreads PDFs, chunks the text, embeds chunks via Ollama, stores them in Qdrant, and extracts named entities/relationships into Neo4j via an LLM (OpenRouter). - Retrieval —
packages/skill(@rag/skill) accepts a query, runs parallel vector search (Qdrant) and graph traversal (Neo4j), and returns formatted context. - Agent skill —
skills/velorath-lore/index.jsis a thin shim that registers the skill with Claude and delegates all logic to@rag/skill.
pnpm ingestAn interactive CLI will walk you through every step: prerequisites check, .env setup, starting services via Docker, building, and running the pipeline. Select only the steps you need.
Requires: Docker, Node.js ≥ 22, pnpm
| Service | Purpose | Default URL |
|---|---|---|
| Ollama | Text embeddings (nomic-embed-text) |
http://localhost:11434 |
| Qdrant | Vector storage | http://localhost:6333 |
| Neo4j | Knowledge graph | bolt://localhost:7687 |
| OpenRouter | LLM entity extraction | API key required |
All three database services are managed via Docker Compose (docker-compose.yml). pnpm ingest starts them automatically. The Ollama embedding model (nomic-embed-text) is pulled automatically on first run.
If you prefer not to use the interactive CLI:
# 1. Start services
docker compose up -d
# 2. Pull embedding model
docker compose exec ollama ollama pull nomic-embed-text
# 3. Install dependencies and configure environment
pnpm install
cp .env.example .env
# Edit .env — set OPENROUTER_API_KEY and NEO4J_PASSWORD at minimum
# 4. Build packages
pnpm build
# 5. Place PDFs and run
mkdir pdfs && cp /path/to/your/documents/*.pdf pdfs/
node packages/ingestion/dist/pipeline.jsTo clear all ingested data and re-run from scratch:
# Delete Qdrant collection
curl -X DELETE http://localhost:6333/collections/school-pdfs
# Clear Neo4j graph (run in Neo4j browser at http://localhost:7474)
# MATCH (n) DETACH DELETE n
# Or via terminal (replace YOUR_PASSWORD)
docker compose exec neo4j cypher-shell -u neo4j -p YOUR_PASSWORD "MATCH (n) DETACH DELETE n"The pipeline will:
- Verify Ollama, Qdrant, and Neo4j are reachable
- Create the Qdrant collection and Neo4j indexes if they don't exist
- Process each PDF: extract text → chunk → embed → store in Qdrant → extract entities → write to Neo4j
- Log structured JSON to stdout (set
LOG_LEVEL=debugfor verbose output)
node skills/velorath-lore/index.js "Who is Zara Undvel?"Register skills/velorath-lore/ in your Claude Desktop config:
{
"skills": [
{ "path": "/path/to/project/skills/velorath-lore" }
]
}Claude will use the search_velorath_lore tool automatically when answering lore questions.
| Variable | Required | Default | Description |
|---|---|---|---|
OPENROUTER_API_KEY |
Yes | — | OpenRouter API key for entity extraction LLM |
NEO4J_PASSWORD |
Yes | — | Neo4j database password |
QDRANT_URL |
No | http://localhost:6333 |
Qdrant endpoint |
COLLECTION_NAME |
No | school-pdfs |
Qdrant collection name |
NEO4J_URI |
No | bolt://localhost:7687 |
Neo4j bolt URI |
NEO4J_USER |
No | neo4j |
Neo4j username |
OLLAMA_URL |
No | http://localhost:11434 |
Ollama endpoint |
PDF_FOLDER |
No | ./pdfs |
Path to PDF input directory |
CIRCUIT_BREAKER_THRESHOLD |
No | 3 |
Consecutive failures before skipping a service |
# Run tests
pnpm test # all packages
pnpm --filter @rag/ingestion test # ingestion only
pnpm --filter @rag/skill test # skill only
# Type checking
pnpm typecheck
# Build
pnpm buildscripts/
setup.ts Interactive setup CLI (pnpm ingest)
docker-compose.yml Qdrant + Neo4j + Ollama services
packages/
ingestion/ @rag/ingestion — PDF ingestion pipeline
src/
pipeline.ts CLI entry point and orchestrator
pdf.ts PDF text extraction and chunking
embedding.ts Ollama embedding generation
extraction.ts LLM entity/relationship extraction (Zod-validated)
qdrant.ts Qdrant vector store operations
neo4j.ts Neo4j graph write operations
config.ts Zod-validated environment config
utils.ts CircuitBreaker, retry helpers
preflight.ts PDF folder validation
skill/ @rag/skill — retrieval library
src/
index.ts run({ query }) entry point
embedding.ts Query embedding via Ollama
qdrant.ts Vector search
neo4j.ts Graph traversal
format.ts Result formatting
types/ @rag/types — shared TypeScript types
skills/
velorath-lore/
index.js Thin shim — delegates to @rag/skill
SKILL.md Claude agent skill definition