Frequently Asked Questions
Product: v0.19.0 · Contract: OpenAPI snapshot · Spec ops: Ingestion cancel & fairness
Frequently Asked Questions
Section titled “Frequently Asked Questions”Common Questions About EdgeQuake
General
Section titled “General”What is EdgeQuake?
Section titled “What is EdgeQuake?”EdgeQuake is a production-grade Graph-RAG framework written in Rust. It combines:
- Knowledge Graphs for entity and relationship extraction
- Vector Search for semantic retrieval
- LLM Integration for natural language answers
Think of it as a smarter search engine that understands concepts, not just keywords.
How is EdgeQuake different from vector-only RAG?
Section titled “How is EdgeQuake different from vector-only RAG?”| Aspect | Vector-Only RAG | EdgeQuake (Graph-RAG) |
|---|---|---|
| Retrieval | Semantic similarity | Semantic + structural |
| Multi-hop | ❌ Single retrieval | ✅ Follows relationships |
| Context | Flat chunks | Connected entities |
| “What connects X to Y?” | Cannot answer | Native query type |
What’s the relationship to LightRAG?
Section titled “What’s the relationship to LightRAG?”EdgeQuake is a Rust implementation inspired by LightRAG, a Python Graph-RAG research project.
Key differences:
- Language: Rust vs Python (10–50× faster)
- Production Ready: Multi-tenant, auth, observability, deployment
- Storage: PostgreSQL + pgvector + Apache AGE
- API: REST with async ingestion, streaming, and WebSocket progress
Deployment
Section titled “Deployment”What are the minimum requirements?
Section titled “What are the minimum requirements?”Development:
- 4 GB RAM
- 2 CPU cores
- Rust 1.95+
- PostgreSQL 16, 17, or 18 with pgvector and Apache AGE (Docker image:
ghcr.io/raphaelmansuy/edgequake-postgres:0.19.0)
Production (minimum to boot):
- 8+ GB RAM is enough to start the stack — not enough for Proven 50k / Supported 100k filtered ANN
- Floors: Product limits — Pick your size — ≥16 GB for ≤50k (Proven); ≥32 GB preferred for 100k Wave-2 (Supported);
shared_buffers≥2 GB - 4+ CPU cores
- PostgreSQL 16+ with pgvector + AGE
- LLM provider (OpenAI, Ollama, or other supported provider)
- Vision-capable model for PDF ingestion (see Vision & PDF Processing)
Ports (defaults): API 8080, WebUI 3000.
Can I run EdgeQuake without PostgreSQL?
Section titled “Can I run EdgeQuake without PostgreSQL?”No — DATABASE_URL is required for all server modes. In-memory storage was removed in v0.4.0. Running without a database causes the server to exit with error code 1.
For development and testing, use the Docker-based PostgreSQL setup:
# Start full stack (PostgreSQL + backend + frontend)make dev
# Start PostgreSQL only, then run testsmake db-startcargo testFor production-style deployments, use prebuilt GHCR images:
EDGEQUAKE_VERSION=0.19.0 docker compose -f docker-compose.quickstart.yml up -dImages: ghcr.io/raphaelmansuy/edgequake:0.19.0, ghcr.io/raphaelmansuy/edgequake-postgres:0.19.0-pg18 (also -pg16, -pg17).
Can I run EdgeQuake without an LLM?
Section titled “Can I run EdgeQuake without an LLM?”Yes, for testing with the mock provider:
cargo testFor production, you need a real LLM. Options:
- OpenAI (
OPENAI_API_KEY) - Ollama (local, free)
- LM Studio (local, free)
- Mistral, Anthropic, Gemini, Vertex AI (see
.env.example)
How much does it cost to run EdgeQuake?
Section titled “How much does it cost to run EdgeQuake?”EdgeQuake itself is free and open source. Costs come from:
| Component | Cost |
|---|---|
| EdgeQuake | Free |
| PostgreSQL | Free (self-hosted) or ~$15/mo (managed) |
| OpenAI | ~$0.002 per document (~500 words) |
| Ollama | Free (local GPU) |
How can I reduce LLM costs?
Section titled “How can I reduce LLM costs?”-
Use cheaper models:
Terminal window EDGEQUAKE_DEFAULT_LLM_MODEL=gpt-5-mini -
Use local LLM (Ollama):
Terminal window EDGEQUAKE_DEFAULT_LLM_PROVIDER=ollamaEDGEQUAKE_DEFAULT_LLM_MODEL=gemma4:latest -
Reduce chunk size (fewer LLM calls) in pipeline configuration.
Is there a free tier for OpenAI?
Section titled “Is there a free tier for OpenAI?”OpenAI offers free credits for new accounts. After that, gpt-5-mini and text-embedding-3-small are cost-effective defaults (see .env.example).
Performance
Section titled “Performance”How fast is EdgeQuake?
Section titled “How fast is EdgeQuake?”| Operation | Typical Time |
|---|---|
| Document admit (HTTP) | < 1 s (returns 202 + track_id) |
| Entity extraction | 2–5 s per chunk (with LLM, async) |
| Vector search | < 100 ms |
| Graph traversal | < 50 ms |
| Full query | 2–10 s (depends on LLM) |
Uploads are async: the API accepts the document immediately; poll GET /api/v1/tasks/{track_id} or subscribe via WebSocket/SSE for progress.
How does it scale?
Section titled “How does it scale?”SSOT: Product limits — start with TL;DR and Pick your size.
| Status | What you can promise | Recipe |
|---|---|---|
| Proven | ≤50k chunk vectors @1536 under prod stress; Louvain gated at 50k nodes | Defaults + shared_buffers ≥2 GB; host ≥16 GB |
| Supported (default) | 100k filtered ANN @1536 (Q1-d) | Wave-2: halfvec + EDGEQUAKE_HNSW_PARTIAL_BY_WORKSPACE=1 + residency (host ≥32 GB preferred) |
| Supported opt-in | 150k on dedicated DiskANN | query_search_list_size≥400 + query_rescore≈list/2 (pg18-vectorscale) — not a silent default |
| Not promoted | Wave-2 above 100k (250k+) | Mid-scale wall — do not sell |
| Aspirational | 100k+ documents / 1M+ entities per workspace | Not a latency-gated claim |
Hard caps: 50 MiB/upload, HNSW dim ≤2000/4000. Concurrent tip @100k Wave-2: EDGEQUAKE_HNSW_EF_SEARCH=240. Mix/hybrid seeds ≪ ANN ladder.
There is no enforced per-workspace storage-GB quota. Workspace max_documents (when set) is fail-closed at upload / new PDF mint (SPEC-066). Size disk/RAM from product-limits. Ceiling ladder: make ceiling-proof (SPEC-066).
For multi-replica worker deployments, see Ingestion, replicas & leases.
How can I speed up queries?
Section titled “How can I speed up queries?”Data plane (often the real cliff before LLM):
- Wave-2 for ~100k filtered ANN —
EDGEQUAKE_VECTOR_STORAGE=halfvec+EDGEQUAKE_HNSW_PARTIAL_BY_WORKSPACE=1(greenfield only); see Product limits - Residency — keep
shared_buffers≥2 GB (4 GB class for large lab); cold ~1.5 s @100k default path is expected without this - Warm a filtered query after deploy so partial HNSW exists (or
./scripts/wave2_warmup.sh/POST /api/v1/admin/ann/warmup) 3b. Filtered recall underfill — EdgeQuake setshnsw.iterative_scan=relaxed_order+max_scan_tupleson filtered queries only; tuneEDGEQUAKE_HNSW_MAX_SCAN_TUPLES/EDGEQUAKE_HNSW_SCAN_MEM_MULTIPLIERif needed (SPEC-075). Promote with filtered recall@20 (make filtered-recall-gate), never unfiltered-only.
Query / LLM:
- Use
naivemode for simple queries (vector-only, no graph) - Reduce
max_chunksfrom 20 to 5–10 - Use faster LLM (
gpt-5-minivs larger models) - Use GPU for Ollama embedding
How do I enable the supported 100k shape?
Section titled “How do I enable the supported 100k shape?”Use the Turnkey greenfield recipe in Product limits:
eval "$(make -s wave2-greenfield-env)"# or: WAVE2_GREENFIELD=1 make backend-bg./scripts/wave2_warmup.sh <workspace_uuid>That sets halfvec + workspace partial HNSW + optional EDGEQUAKE_HNSW_EF_SEARCH=240 (concurrent tip — not a silent default). Do not silent-flip existing vector DBs. Dedicated *_ws_* + HNSW is dimension isolation only — not the 100k concurrent path.
How do I enable opt-in DiskANN @150k / @250k?
Section titled “How do I enable opt-in DiskANN @150k / @250k?”See Product limits — Opt-in DiskANN recipe: pg18-vectorscale image, dedicated table + USING diskann. @150k: query_search_list_size ≥ 400 + query_rescore ≈ list/2. @250k (SPEC-082 floor): list ≥ 800, rescore ≈ 400, prefer a higher-quality DiskANN build (num_neighbors=64, search_list_size=200). Wave-2 remains the default; DiskANN is opt-in only (make diskann-recall-pareto / make push-scale-ladder / make diskann-rescore-smoke).
How do I gate filtered recall@20?
Section titled “How do I gate filtered recall@20?”Use make filtered-recall-gate (SPEC-075). It archives workspace-filtered recall@20 for Wave-2 (+ iterative_scan-only compare). Soft-fails product floors; does not raise the 100k Wave-2 floor. See Product limits — Filtered recall + iterative_scan.
How do I improve ranking precision without raising floors?
Section titled “How do I improve ranking precision without raising floors?”See Product limits — Precision tips (SPEC-076):
- Opt-in ANN→exact reorder —
EDGEQUAKE_ANN_EXACT_REORDER=1+ optionalEDGEQUAKE_ANN_REORDER_CANDIDATE_K=50(default OFF; not a silent flip). - Sparse FTS+ANN RRF tip for codes/names —
EDGEQUAKE_SPARSE_FUSION=rrf(default remains sparse-first weighted).
Gate: make precision-layers-gate. Mix/RRF does not raise the Wave-2 / DiskANN ANN floors.
What about binary quantization for larger corpora?
Section titled “What about binary quantization for larger corpora?”Study-only (SPEC-077): make binary-quantize-bakeoff compares Wave-2 halfvec HNSW to pgvector binary_quantize + Hamming ANN + exact rerank under a workspace filter. Default remains Wave-2; do not silent-flip (EDGEQUAKE_BINARY_QUANTIZE stays off). See Product limits — Binary quantize study.
What about Filtered-DiskANN labels for shared tables?
Section titled “What about Filtered-DiskANN labels for shared tables?”Study-only (SPEC-078): make filtered-diskann-labels-bakeoff compares Wave-2 to post-filter DiskANN and to pgvectorscale Filtered-DiskANN (labels smallint[] + labels && …) under a workspace filter. Default remains Wave-2; dedicated DiskANN @150k unchanged; do not silent-flip (EDGEQUAKE_FILTERED_DISKANN_LABELS stays off; no product labels migration). See Product limits — Filtered-DiskANN labels study.
Mid-scale archive: make midscale-quantize-labels (SPEC-079) — tips stay Not promoted unless a full concurrent gate says otherwise.
Why are tiny workspaces forced onto HNSW?
Section titled “Why are tiny workspaces forced onto HNSW?”They should not be. SPEC-080 skips Wave-2 enable_seqscan=off bias when workspace rows ≤ EDGEQUAKE_ANN_EXACT_MAX_ROWS (default 2000). Gate: make tiny-slice-exact-gate.
Is there a serving view for “chunks that have vectors”?
Section titled “Is there a serving view for “chunks that have vectors”?”Admin/debug only (SPEC-081): eq_serving_chunk_presence / eq_serving_vector_presence. This is not the RAG ANN path and does not unify dual-SSOT stores. Gate: make serving-view-check.
How do we push performance tests / floors further?
Section titled “How do we push performance tests / floors further?”make push-scale-ladder (SPEC-082) archives A6 Filtered-DiskANN @150k/250k, Wave-2 filtered spot @150k, and DiskANN primary full-gate @250k. Floors rise only when the full-gate is green; Wave-2 default stays 100k unless a separate full-gate says otherwise. Silent flip remains forbidden. See Product limits.
Multi-Tenancy
Section titled “Multi-Tenancy”Is EdgeQuake multi-tenant?
Section titled “Is EdgeQuake multi-tenant?”Yes. Each workspace is isolated:
- Separate document collections
- Separate knowledge graphs
- Per-workspace LLM configuration
- No data leakage between workspaces
Use X-Tenant-ID and X-Workspace-ID headers (or JWT claims) on protected routes when auth is enabled.
Can different tenants use different LLMs?
Section titled “Can different tenants use different LLMs?”Yes. LLM provider and model are configured per workspace via the API or environment defaults.
Security
Section titled “Security”Is my data encrypted?
Section titled “Is my data encrypted?”| Level | Status |
|---|---|
| At rest | Depends on PostgreSQL config |
| In transit | Yes (HTTPS recommended) |
| API keys | Never logged |
Does EdgeQuake send data to external services?
Section titled “Does EdgeQuake send data to external services?”Only to LLM providers you configure:
- OpenAI / cloud providers: Document chunks sent for extraction and vision
- Ollama: Local, no external calls
- No telemetry sent by EdgeQuake itself
How do I secure the API?
Section titled “How do I secure the API?”Authentication is ON by default (SPEC-027). Protected routes require a JWT (Authorization: Bearer …) or API key (X-API-Key).
| Mode | When to use | Configuration |
|---|---|---|
| Production | Deployed stacks | Auth enabled (default); set JWT_SECRET, bootstrap admin, disable demo login |
| Local dev | make dev |
EDGEQUAKE_DEV_MODE=true (Makefile sets this when DEV_AUTH_ENABLED=false) |
Bootstrap first admin (before first login):
export EDGEQUAKE_BOOTSTRAP_ADMIN_USERNAME=adminexport EDGEQUAKE_BOOTSTRAP_ADMIN_PASSWORD='ChangeMe123!'export EDGEQUAKE_BOOTSTRAP_ADMIN_EMAIL=admin@example.comOr create a user with the master API key: EDGEQUAKE_MASTER_API_KEY.
Full hardening checklist: Runtime auth hardening.
Additional layers for production:
- Reverse proxy (nginx/Caddy) with TLS
- Network isolation (private subnet)
- External SSO via oauth2-proxy (recommended over in-process OIDC for enterprise)
Explicit opt-out (not recommended outside local dev): EDGEQUAKE_AUTH_ENABLED=false or EDGEQUAKE_AUTH_DISABLED=true.
Ingestion: cancel, fairness, replicas & convert → ingest
Section titled “Ingestion: cancel, fairness, replicas & convert → ingest”Operational details live in Ingestion cancel & fairness. Summary:
How do I cancel an in-flight upload or ingestion?
Section titled “How do I cancel an in-flight upload or ingestion?”Canonical endpoint:
POST /api/v1/tasks/{track_id}/cancelAlso supported: DELETE /api/v2/workspaces/{id}/jobs/{job_id}, PDF cancel, pipeline-wide cancel, and WebSocket { "type": "cancel", "track_id": "…" }.
Cancel is cooperative — expect a short delay until the current LLM/vision round-trip aborts. UI should show Stopping… until status is terminal (display_status=cancelled).
What is tenant fairness / why is my second upload waiting?
Section titled “What is tenant fairness / why is my second upload waiting?”Workers limit concurrency per tenant and per fairness lane:
- Ingest (
MAX_TASKS_PER_TENANT): Pdf/Insert/… — local Ollama/LM Studio clamps to 2 (workers capped at 4) unlessEDGEQUAKE_ALLOW_LOCAL_HIGH_CONCURRENCY=1 - Lifecycle (
MAX_LIFECYCLE_TASKS_PER_TENANT, local default 4): Deletion/Wipe — separate from ingest so deletes do not serialize new uploads
Parked tasks wait on that lane’s semaphore — they are not requeued in a reclaim storm. Check GET /api/v1/pipeline/queue-metrics → tenant_park_waiters, tenant_park_waiters_ingest, tenant_park_waiters_lifecycle, max_tasks_per_tenant, max_lifecycle_tasks_per_tenant.
If a new PDF stays Queued while deletes run, that was the old shared-lane bug; with dual lanes the PDF should take the ingest slot while lifecycle deletes continue.
What are claim / lease semantics on restart?
Section titled “What are claim / lease semantics on restart?”Postgres task rows are the delivery SSOT. Workers claim via FOR UPDATE SKIP LOCKED, hold a lease (EDGEQUAKE_TASK_LEASE_TTL_SECS, default 120 s), and refresh every 60 s.
| Status at boot | Default (unset / ON) | EDGEQUAKE_STARTUP_AUTO_RESUME=0 |
|---|---|---|
| Pending | Claimable | Claimable |
| Processing (stale) | → Pending (reclaimable) | → Failed (failure_code=server_restart_interrupted; use Reprocess) |
| Cancelled | Never claimed | Never claimed |
Can I run multiple API/worker replicas?
Section titled “Can I run multiple API/worker replicas?”Set EDGEQUAKE_REPLICAS to your process count. When EDGEQUAKE_REPLICAS>1, EDGEQUAKE_TASK_DELIVERY=local fails at boot — use bridged or notify_only. Correctness remains claim_next + lease; delivery modes are wake signals only.
Monitor: GET /api/v1/pipeline/queue-metrics (store_contention, cancel_intent_count).
Why does PDF processing have two phases (convert → ingest)?
Section titled “Why does PDF processing have two phases (convert → ingest)?”PDF admission enqueues convert only (TaskType::PdfProcessing). After durable markdown is stored and the PDF row is Completed, a separate Insert task runs KG ingestion under its own lease, timeout, and fairness permit.
Cancelling convert or an in-flight ingest cancels both linked tasks for the same pdf_id. After convert completes, cancelling ingest leaves the PDF Completed (markdown barrier kept).
Features
Section titled “Features”What document formats are supported?
Section titled “What document formats are supported?”| Format | Support |
|---|---|
| Plain text | ✅ Full |
| Markdown | ✅ Full |
| ✅ Full (vision LLM required) | |
| HTML | 🔄 Planned |
| DOCX | 🔄 Planned |
What LLM providers are supported?
Section titled “What LLM providers are supported?”| Provider | Support | Notes |
|---|---|---|
| OpenAI | ✅ Full | GPT-5.x series (catalog) |
| Anthropic | ✅ Full | Claude models (ANTHROPIC_API_KEY) |
| Mistral | ✅ Full | Mistral models (MISTRAL_API_KEY) |
| Google Gemini | ✅ Full | Developer API (GEMINI_API_KEY) |
| Vertex AI | ✅ Full | Enterprise GCP identity (ADC/SA) |
| Ollama | ✅ Full | Local models (default: gemma4:latest) |
| LM Studio | ✅ Full | OpenAI-compatible |
| Azure OpenAI | ✅ Full | Via AZURE_OPENAI_* env vars |
| OpenRouter | ✅ Full | Model aggregator |
What query modes are available?
Section titled “What query modes are available?”| Mode | Use Case |
|---|---|
naive |
Simple vector search |
local |
Entity-focused queries |
global |
High-level summaries |
hybrid |
Best of all modes (DEFAULT) |
mix |
Custom weighted blend |
bypass |
Direct LLM, no retrieval (debug) |
Troubleshooting
Section titled “Troubleshooting”Why are my queries returning empty?
Section titled “Why are my queries returning empty?”-
Check documents exist:
Terminal window curl http://localhost:8080/api/v1/documents -
Check entities extracted (graph namespace):
Terminal window curl http://localhost:8080/api/v1/graph/entities -
Try
naivemode (vector-only):{ "query": "test", "mode": "naive" }
When auth is enabled, add -H "Authorization: Bearer $TOKEN" or -H "X-API-Key: $KEY".
See Troubleshooting Guide for more.
Why is document processing stuck?
Section titled “Why is document processing stuck?”- Check LLM is running (Ollama:
ollama list) - Check API key is valid (OpenAI)
- Poll task status:
GET /api/v1/tasks/{track_id} - Check queue metrics:
GET /api/v1/pipeline/queue-metrics - Check logs:
tail -f /tmp/edgequake-backend.log
How do I check if EdgeQuake is healthy?
Section titled “How do I check if EdgeQuake is healthy?”# Basic health (no auth)curl http://localhost:8080/health
# Full readiness (checks database + store contention)curl http://localhost:8080/readyComparison
Section titled “Comparison”EdgeQuake vs LightRAG (Python)?
Section titled “EdgeQuake vs LightRAG (Python)?”| Aspect | LightRAG | EdgeQuake |
|---|---|---|
| Language | Python | Rust |
| Speed | Baseline | 10–50× faster |
| Memory | Higher | Lower (no GC) |
| Multi-tenant | No | Yes |
| Production | Research | Production |
| Algorithm | Same | Same |
EdgeQuake vs Microsoft GraphRAG?
Section titled “EdgeQuake vs Microsoft GraphRAG?”| Aspect | GraphRAG | EdgeQuake |
|---|---|---|
| Approach | Hierarchical communities | Flat entity graph |
| Cost | Very high ($$$) | Low–medium |
| Index time | Hours–days | Minutes |
| Queries | Global summaries | Hybrid modes |
| Use case | Large corpora | General purpose |
EdgeQuake vs Pinecone/Weaviate?
Section titled “EdgeQuake vs Pinecone/Weaviate?”| Aspect | Vector DBs | EdgeQuake |
|---|---|---|
| Type | Storage only | Full RAG stack |
| Retrieval | Vector similarity | Vector + Graph |
| Extraction | Not included | Built-in |
| Multi-hop | No | Yes |
Contributing
Section titled “Contributing”How can I contribute?
Section titled “How can I contribute?”- Fork the repository
- Create a feature branch
- Make changes following AGENTS.md
- Run
cargo clippy && cargo test - Submit a pull request
What’s the development workflow?
Section titled “What’s the development workflow?”git clone https://github.com/your-fork/edgequakemake devcargo testcargo clippycargo fmtVision & PDF Processing
Section titled “Vision & PDF Processing”Why is my PDF failing with “Vision extraction timed out” or “Circuit breaker tripped”?
Section titled “Why is my PDF failing with “Vision extraction timed out” or “Circuit breaker tripped”?”This almost always means the vision model does not match the vision provider.
For example, EDGEQUAKE_VISION_MODEL=gpt-4.1-nano paired with EDGEQUAKE_LLM_PROVIDER=ollama
will fail because Ollama cannot serve OpenAI models.
Diagnose — check the effective config endpoint:
curl -s http://localhost:8080/api/v1/config/effective | jq '.areas[] | select(.name == "Vision")'If has_mismatch is true, the response explains exactly which env var is wrong
and how to fix it.
Fix — pick one:
| Option | Action |
|---|---|
| A | Unset the mismatched env var so the default takes over: unset EDGEQUAKE_VISION_MODEL |
| B | Change the provider to match the model: EDGEQUAKE_VISION_PROVIDER=openai |
| C | Change the model to match the provider: EDGEQUAKE_VISION_MODEL=gemma4:latest |
Then restart the backend.
How does EdgeQuake decide which vision provider and model to use?
Section titled “How does EdgeQuake decide which vision provider and model to use?”The resolution chain (highest priority first):
- Per-request form field (
vision_provider/vision_modelin upload) EDGEQUAKE_VISION_PROVIDER/EDGEQUAKE_VISION_MODELenv varsEDGEQUAKE_VISION_LLM_PROVIDER/EDGEQUAKE_VISION_LLM_MODELenv varsEDGEQUAKE_DEFAULT_LLM_PROVIDER/EDGEQUAKE_DEFAULT_LLM_MODELenv varsEDGEQUAKE_LLM_PROVIDER/EDGEQUAKE_LLM_MODELenv vars- Vision fallback (when no env vars match):
ollama/gemma4:latest
At each step, incompatible combinations are skipped with a warning log.
Can I use a different model for vision than for text extraction?
Section titled “Can I use a different model for vision than for text extraction?”Yes. Set the vision-specific env vars:
EDGEQUAKE_DEFAULT_LLM_PROVIDER=ollamaEDGEQUAKE_DEFAULT_LLM_MODEL=gemma4:latest
EDGEQUAKE_VISION_PROVIDER=openaiEDGEQUAKE_VISION_MODEL=gpt-4.1-nanoOPENAI_API_KEY=sk-...Where can I see the active configuration in the UI?
Section titled “Where can I see the active configuration in the UI?”Open Settings → Configuration Explainability. The same data is available via GET /api/v1/config/effective.