Skip to content

Frequently Asked Questions

Product: v0.19.0 · Contract: OpenAPI snapshot · Spec ops: Ingestion cancel & fairness

Common Questions About 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

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

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_buffers2 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.

NoDATABASE_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:

Terminal window
# Start full stack (PostgreSQL + backend + frontend)
make dev
# Start PostgreSQL only, then run tests
make db-start
cargo test

For production-style deployments, use prebuilt GHCR images:

Terminal window
EDGEQUAKE_VERSION=0.19.0 docker compose -f docker-compose.quickstart.yml up -d

Images: ghcr.io/raphaelmansuy/edgequake:0.19.0, ghcr.io/raphaelmansuy/edgequake-postgres:0.19.0-pg18 (also -pg16, -pg17).

Yes, for testing with the mock provider:

Terminal window
cargo test

For 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)

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)
  1. Use cheaper models:

    Terminal window
    EDGEQUAKE_DEFAULT_LLM_MODEL=gpt-5-mini
  2. Use local LLM (Ollama):

    Terminal window
    EDGEQUAKE_DEFAULT_LLM_PROVIDER=ollama
    EDGEQUAKE_DEFAULT_LLM_MODEL=gemma4:latest
  3. Reduce chunk size (fewer LLM calls) in pipeline configuration.

OpenAI offers free credits for new accounts. After that, gpt-5-mini and text-embedding-3-small are cost-effective defaults (see .env.example).


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.

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.

Data plane (often the real cliff before LLM):

  1. Wave-2 for ~100k filtered ANNEDGEQUAKE_VECTOR_STORAGE=halfvec + EDGEQUAKE_HNSW_PARTIAL_BY_WORKSPACE=1 (greenfield only); see Product limits
  2. Residency — keep shared_buffers ≥2 GB (4 GB class for large lab); cold ~1.5 s @100k default path is expected without this
  3. 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 sets hnsw.iterative_scan=relaxed_order + max_scan_tuples on filtered queries only; tune EDGEQUAKE_HNSW_MAX_SCAN_TUPLES / EDGEQUAKE_HNSW_SCAN_MEM_MULTIPLIER if needed (SPEC-075). Promote with filtered recall@20 (make filtered-recall-gate), never unfiltered-only.

Query / LLM:

  1. Use naive mode for simple queries (vector-only, no graph)
  2. Reduce max_chunks from 20 to 5–10
  3. Use faster LLM (gpt-5-mini vs larger models)
  4. Use GPU for Ollama embedding

Use the Turnkey greenfield recipe in Product limits:

Terminal window
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).

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):

  1. Opt-in ANN→exact reorderEDGEQUAKE_ANN_EXACT_REORDER=1 + optional EDGEQUAKE_ANN_REORDER_CANDIDATE_K=50 (default OFF; not a silent flip).
  2. 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.

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.


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.

Yes. LLM provider and model are configured per workspace via the API or environment defaults.


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

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):

Terminal window
export EDGEQUAKE_BOOTSTRAP_ADMIN_USERNAME=admin
export EDGEQUAKE_BOOTSTRAP_ADMIN_PASSWORD='ChangeMe123!'
export EDGEQUAKE_BOOTSTRAP_ADMIN_EMAIL=admin@example.com

Or create a user with the master API key: EDGEQUAKE_MASTER_API_KEY.

Full hardening checklist: Runtime auth hardening.

Additional layers for production:

  1. Reverse proxy (nginx/Caddy) with TLS
  2. Network isolation (private subnet)
  3. 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}/cancel

Also 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) unless EDGEQUAKE_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-metricstenant_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

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).


Format Support
Plain text ✅ Full
Markdown ✅ Full
PDF ✅ Full (vision LLM required)
HTML 🔄 Planned
DOCX 🔄 Planned
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
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)

  1. Check documents exist:

    Terminal window
    curl http://localhost:8080/api/v1/documents
  2. Check entities extracted (graph namespace):

    Terminal window
    curl http://localhost:8080/api/v1/graph/entities
  3. Try naive mode (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.

  1. Check LLM is running (Ollama: ollama list)
  2. Check API key is valid (OpenAI)
  3. Poll task status: GET /api/v1/tasks/{track_id}
  4. Check queue metrics: GET /api/v1/pipeline/queue-metrics
  5. Check logs: tail -f /tmp/edgequake-backend.log
Terminal window
# Basic health (no auth)
curl http://localhost:8080/health
# Full readiness (checks database + store contention)
curl http://localhost:8080/ready

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
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
Aspect Vector DBs EdgeQuake
Type Storage only Full RAG stack
Retrieval Vector similarity Vector + Graph
Extraction Not included Built-in
Multi-hop No Yes

  1. Fork the repository
  2. Create a feature branch
  3. Make changes following AGENTS.md
  4. Run cargo clippy && cargo test
  5. Submit a pull request
Terminal window
git clone https://github.com/your-fork/edgequake
make dev
cargo test
cargo clippy
cargo fmt

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:

Terminal window
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):

  1. Per-request form field (vision_provider / vision_model in upload)
  2. EDGEQUAKE_VISION_PROVIDER / EDGEQUAKE_VISION_MODEL env vars
  3. EDGEQUAKE_VISION_LLM_PROVIDER / EDGEQUAKE_VISION_LLM_MODEL env vars
  4. EDGEQUAKE_DEFAULT_LLM_PROVIDER / EDGEQUAKE_DEFAULT_LLM_MODEL env vars
  5. EDGEQUAKE_LLM_PROVIDER / EDGEQUAKE_LLM_MODEL env vars
  6. 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:

Terminal window
EDGEQUAKE_DEFAULT_LLM_PROVIDER=ollama
EDGEQUAKE_DEFAULT_LLM_MODEL=gemma4:latest
EDGEQUAKE_VISION_PROVIDER=openai
EDGEQUAKE_VISION_MODEL=gpt-4.1-nano
OPENAI_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.