Omnidirectional Research Agent with Corpus Logic and Epistemological Engine
ORACLE is a distributed research system with a Docker-based core stack, an optional GPU inference layer, a FastAPI command-center backend, and a Vite frontend.
tei-emb, gliner, coref (pronoun resolution), relex (inline relation extraction), vllm (deprecated):8010, Vite frontend on :5173| Phase | Status | Notes |
|---|---|---|
| Phase 0 — KG Schema | ✅ Complete | Typed multi-label entities, pattern-based relationship inference, profile system |
| Phase 1 — Entity Resolution | ⚠️ Partial | Exact/fuzzy/alias resolution works; context-aware disambiguation not yet implemented |
| Phase 2 — Tool Wiring | ✅ Complete | 12 tools (8 base + 4 domain) wired to FalkorDB, Qdrant, TEI, LiteLLM |
| Phase 3 — Investigation Pipeline | ✅ Complete | Dynamic loop with 8 LangGraph nodes, MERGE-based graph write-back, report engine |
| Phase 4 — Agentic AI | ⚠️ Partial | 6 specialists with ModelRouter; structured output parsing and debate engine pending |
| Phase 5 — Scale & Production | ⚠️ Partial | Monitoring stack ready; sequential GPU benchmark added; FalkorDB write bottleneck under investigation |
Benchmark status: 30/30 quality checks pass ✅ | 6/6 stress tests pass ✅ | Throughput benchmarks run ✅ | GPU sequential benchmark: parse/chunk/embed functional, extraction recovered, graph writes bottlenecked |
Production readiness: See PRODUCTION_READINESS.md for a detailed assessment. Bottom line: the code is solid but needs ~1 week of integration hardening before 300GB PDF ingestion.
These are the commands verified against the current repo.
# 1. Clone and configure
git clone <repo-url> oracle
cd oracle
cp .env.example .env
# Edit .env and set at least:
# POSTGRES_PASSWORD
# NATS_AUTH_TOKEN
# LITELLM_MASTER_KEY
# one provider key such as OPENROUTER_API_KEY
# 2. Start the core Docker stack
docker compose up -d
# 3. Initialize NATS JetStream streams
docker compose --profile manual-start up nats-init
# 4. Optional: start monitoring
docker compose -f monitoring/docker-compose.monitoring.yml up -d
# 5. Optional: start GPU services
docker compose --profile gpu up -d tei-emb gliner coref relex
# Verify GPU services:
curl -fsS http://127.0.0.1:8001/health # GLiNER entity extraction (joint-encoder, 304M params)
curl -fsS http://127.0.0.1:8003/health # F-COREF pronoun resolution
curl -fsS http://127.0.0.1:8004/health # GLiNER-Relex inline relation extraction (317 rel/sec)
# 6. Start the Command Center backend
set -a
source .env
export ORACLE_LEDGER_DSN="postgresql://oracle:${POSTGRES_PASSWORD}@localhost:15432/oracle"
export FALKORDB_HOST=localhost
export FALKORDB_PORT=17379
.venv/bin/python command-center/api/main.py
# 7. In another terminal, start the frontend
cd command-center/frontend
npm run dev -- --host 0.0.0.0
http://localhost:5173http://localhost:8010/healthhttp://localhost:13500http://localhost:4000/health/livelinesshttp://localhost:8222http://localhost:16333/dashboardhttp://localhost:13000http://localhost:19090http://localhost:7997http://localhost:8001http://localhost:8003http://localhost:8004http://localhost:8002This smoke pass exercises file discovery, parsing, chunking, embeddings, Qdrant writes, and entity extraction:
mkdir -p tmp/oracle-smoke-corpus
cat <<'EOF' > tmp/oracle-smoke-corpus/sample_text.txt
ORACLE smoke test input.
This file verifies local file discovery and text parsing.
EOF
cat <<'EOF' > tmp/oracle-smoke-corpus/machine_learning.md
# Machine Learning Smoke Document
Embeddings map text into vectors.
Entity extraction should identify organizations, locations, and dates when present.
EOF
.venv/bin/python tests/test_complete_e2e.py \
--corpus tmp/oracle-smoke-corpus \
--output tmp/oracle-smoke-output
Expected result: Overall: PASS
The primary kept end-to-end throughput validation is:
ORACLE_E2E_SKIP_LITELLM=1 .venv/bin/python tests/test_e2e_without_litellm.py
This writes a report to reports/e2e-without-litellm-report.md and a machine-readable result to tests/e2e_results_no_litellm.json.
# Quality checks (7 categories, 30 individual checks)
python -m oracle.benchmarks.quality_checks
# Stress tests (6 scenarios: large corpus, connection pool, deep traversal, etc.)
python -m oracle.benchmarks.stress_test --quick
# Throughput benchmarks (parse, chunk, embed, extract, graph write, full pipeline)
python -m oracle.benchmarks.throughput_benchmarks --iterations 5
# Cross-module import verification
python -c "from oracle.investigation_graph import build_investigation_graph; print('OK')"
python -c "from oracle.tools.executors import wire_all_executors; print('OK')"
python -c "from oracle.tools.new_tools import wire_domain_executors; print('OK')"
python -c "from oracle.knowledge_graph.investigation_writer import write_investigation_graph; print('OK')"
Runs each pipeline stage in isolation to measure per-stage GPU throughput without resource contention. Designed for 12 GB VRAM cards where TEI (~2.5 GB), GLiNER (~0.6 GB), and Relex (~3 GB) together exceed VRAM.
# Requires: Docker stack running, corpus selected
# Select corpus first (one-time):
python benchmarks/select_corpus.py --n 250
# Run benchmark:
python benchmarks/benchmark_sequential_gpu.py [--docs N]
# Results written to reports/benchmarks/
Phases:
Historical targets (from prior joint-encoder benchmark):
ORACLE has 12 typed tools with Pydantic-validated I/O and pluggable backends:
Base tools (8): graph_search, vector_search, entity_lookup, claim_trace, source_fetch, contradiction_check, model_call, report_note
Domain tools (4): temporal_query, relationship_path, passenger_list, financial_flow
All tools have real backend executors (FalkorDB, Qdrant, TEI, LiteLLM) wired via wire_all_executors() and wire_domain_executors(). See oracle/tools/executors.py and oracle/tools/new_tools.py.
Entities are stored with multi-label nodes (:Entity:Person, :Entity:Organization, :Entity:Location, etc.) enabling type-specific queries. Relationships are typed (KNOWS, PASSENGER_ON, LOCATED_IN, OWNS, etc.) using pattern-based inference — no LLM costs during ingestion.
Key modules:
oracle/ingestion/entity_classifier.py): Maps GLiNER labels to concrete graph node types with sub-classification (org_type, loc_type, event_type)oracle/ingestion/relationship_inference.py): 27 pattern rules across all entity pair combinationsoracle/knowledge_graph/__init__.py): MERGE-based idempotent writes with dynamic CypherThe Command Center renders the full knowledge graph (12K+ nodes, growing) using a pre-computed server-side layout:
# Pre-compute graph layout, PageRank, and Louvain communities
.venv/bin/python scripts/precompute_graph_layout.py [--force] [--iterations 50]
This runs spring_layout on all nodes, computes PageRank and community assignments, and writes coordinates (viz_x, viz_y, viz_pagerank, viz_community) back to FalkorDB. The frontend reads these pre-computed positions and renders via WebGL — no client-side physics, instant load.
Graph page features:
Relevant endpoints:
GET /api/graph/export?limit=N — Type-proportional graph data with edgesGET /api/graph/summary — Node/edge counts and top entitiesGET /api/graph/health — Database connectivity statusThe investigation system uses a LangGraph state machine with 8 nodes and conditional routing:
planner → tool_dispatcher → evidence_collector → hypothesis_generator
↓
orchestrator
↙ ↓ ↘
[challenger] [loop] [reporter → completer]
AsyncPostgresSaverKey modules:
oracle/investigation_graph.py): 1,019 lines, 8 nodes with conditional edgesoracle/knowledge_graph/investigation_writer.py): MERGE-based artifact persistenceoracle/reporting/report_engine.py): Confidence blending with provenance chains, exports to Markdown/HTML/PDF/DOCXNamed profiles configure entity types, chunk sizes, and relationship rules per dataset:
from oracle.profiles import get_profile_for_corpus
profile = get_profile_for_corpus("epstein_files") # or "bible_kjv", "default"
Profiles defined in oracle/profiles.py.
Relation extraction now runs inline during the extraction phase via ExtractResultHandler — not as a separate post-hoc enrichment task. After GLiNER extracts entities from each chunk, GLiNER-Relex is called immediately to extract typed relationships between those entities. Pattern-based relationships (from relationship_inference.py's 27 rules) and Relex relationships are merged in dispatcher._merge_relationships() before writing to FalkorDB. This means typed edges (WORKS_FOR, FOUNDED, LOCATED_IN, PART_OF, COMPETITOR, etc.) flow end-to-end in a single ingestion pass — no separate enrichment worker needed.
Unlike the old vLLM pipeline (~0.04 pairs/sec autoregressive), Relex performs joint NER+relation extraction in a single encoder forward pass at 317 relations/sec — an ~8,000x speedup.
Key implementation:
ExtractResultHandler: Calls Relex API (:8004) inline after entity extraction, sending entity pairs with context textdispatcher._merge_relationships(): Merges Relex typed relationships with pattern-inferred relationships, resolving conflicts by confidencesource:gliner_relex or source:pattern property for provenance trackingNo capability flag needed — relation extraction is part of the standard extraction capability. Ensure relex is running and ORACLE_RELEX_URL is set (defaults to http://localhost:8004).
The old post-hoc enrichment pipeline (NATS oracle.tasks.enrichment.graph stream, graph_enrichment worker capability, separate GraphResultHandler enrichment pass) is deprecated. It is gated behind ORACLE_ENABLE_DEPRECATED_ENRICHMENT=1. Do not use in new deployments — all relationship extraction now happens inline.
Add coref to the GPU stack for pronoun resolution before entity extraction (344 chunks/sec, 93ms latency):
docker compose --profile gpu up -d coref
Set ORACLE_ENABLE_COREF=true to enable in the ingestion pipeline.
Relex integration tests require the Relex service running:
# Relex integration tests — health, load, accuracy, throughput, no-hallucination
python tests/test_relex_enrichment.py
# Legacy vLLM tests (only if vLLM is running and ORACLE_ENABLE_DEPRECATED_ENRICHMENT=1)
python tests/test_vllm_enrichment.py --smoke
Controller
Postgres NATS LiteLLM FalkorDB Qdrant Worker
Optional GPU
tei-emb gliner coref relex (inline RE)
Command Center
FastAPI backend (:8010)
Vite frontend (:5173)
The current dockerized worker container reports healthy on :18080, but it also logs recurring NATS fetch_error messages after startup. A local ingestion smoke pass still succeeds, but the README does not currently treat the worker log noise as a clean operational state. See TROUBLESHOOTING.md.
| Document | Purpose |
|---|---|
| INSTALL.md | Full bring-up runbook |
| WORKER_GUIDE.md | Worker-specific setup |
| ENV_REFERENCE.md | Environment variables |
| ARCHITECTURE.md | System layout, data flow, and graph viz pipeline |
| DEVELOPMENT.md | Local development workflow |
| PRODUCTION_READINESS.md | Honest audit of what's ready and what's not |
| TROUBLESHOOTING.md | Known failures and fixes |
| monitoring/README.md | Monitoring stack |
| command-center/frontend/README.md | Frontend runbook |
| docs/COMMAND_CENTER_PRODUCT_SPEC.md | Command Center vision and design |
| docs/ENGINEERING_DEFINITION_OF_DONE.md | Completion criteria |
| docs/ENRICHMENT_PIPELINE.md | Graph enrichment pipeline (encoder-based, GLiNER-Relex) |
| PIPELINE_TECHNICAL_REPORT.md | Complete pipeline technical reference (for AI/developer onboarding) |
Last updated: 2026-06-03
1 commits
Python
83.9%
TypeScript
8.8%
CSS
5.5%
Shell
1.1%
Omnidirectional Research Agent with Corpus Logic and Epistemological Engine
ORACLE is a distributed research system with a Docker-based core stack, an optional GPU inference layer, a FastAPI command-center backend, and a Vite frontend.
tei-emb, gliner, coref (pronoun resolution), relex (inline relation extraction), vllm (deprecated):8010, Vite frontend on :5173| Phase | Status | Notes |
|---|---|---|
| Phase 0 — KG Schema | ✅ Complete | Typed multi-label entities, pattern-based relationship inference, profile system |
| Phase 1 — Entity Resolution | ⚠️ Partial | Exact/fuzzy/alias resolution works; context-aware disambiguation not yet implemented |
| Phase 2 — Tool Wiring | ✅ Complete | 12 tools (8 base + 4 domain) wired to FalkorDB, Qdrant, TEI, LiteLLM |
| Phase 3 — Investigation Pipeline | ✅ Complete | Dynamic loop with 8 LangGraph nodes, MERGE-based graph write-back, report engine |
| Phase 4 — Agentic AI | ⚠️ Partial | 6 specialists with ModelRouter; structured output parsing and debate engine pending |
| Phase 5 — Scale & Production | ⚠️ Partial | Monitoring stack ready; sequential GPU benchmark added; FalkorDB write bottleneck under investigation |
Benchmark status: 30/30 quality checks pass ✅ | 6/6 stress tests pass ✅ | Throughput benchmarks run ✅ | GPU sequential benchmark: parse/chunk/embed functional, extraction recovered, graph writes bottlenecked |
Production readiness: See PRODUCTION_READINESS.md for a detailed assessment. Bottom line: the code is solid but needs ~1 week of integration hardening before 300GB PDF ingestion.
These are the commands verified against the current repo.
# 1. Clone and configure
git clone <repo-url> oracle
cd oracle
cp .env.example .env
# Edit .env and set at least:
# POSTGRES_PASSWORD
# NATS_AUTH_TOKEN
# LITELLM_MASTER_KEY
# one provider key such as OPENROUTER_API_KEY
# 2. Start the core Docker stack
docker compose up -d
# 3. Initialize NATS JetStream streams
docker compose --profile manual-start up nats-init
# 4. Optional: start monitoring
docker compose -f monitoring/docker-compose.monitoring.yml up -d
# 5. Optional: start GPU services
docker compose --profile gpu up -d tei-emb gliner coref relex
# Verify GPU services:
curl -fsS http://127.0.0.1:8001/health # GLiNER entity extraction (joint-encoder, 304M params)
curl -fsS http://127.0.0.1:8003/health # F-COREF pronoun resolution
curl -fsS http://127.0.0.1:8004/health # GLiNER-Relex inline relation extraction (317 rel/sec)
# 6. Start the Command Center backend
set -a
source .env
export ORACLE_LEDGER_DSN="postgresql://oracle:${POSTGRES_PASSWORD}@localhost:15432/oracle"
export FALKORDB_HOST=localhost
export FALKORDB_PORT=17379
.venv/bin/python command-center/api/main.py
# 7. In another terminal, start the frontend
cd command-center/frontend
npm run dev -- --host 0.0.0.0
http://localhost:5173http://localhost:8010/healthhttp://localhost:13500http://localhost:4000/health/livelinesshttp://localhost:8222http://localhost:16333/dashboardhttp://localhost:13000http://localhost:19090http://localhost:7997http://localhost:8001http://localhost:8003http://localhost:8004http://localhost:8002This smoke pass exercises file discovery, parsing, chunking, embeddings, Qdrant writes, and entity extraction:
mkdir -p tmp/oracle-smoke-corpus
cat <<'EOF' > tmp/oracle-smoke-corpus/sample_text.txt
ORACLE smoke test input.
This file verifies local file discovery and text parsing.
EOF
cat <<'EOF' > tmp/oracle-smoke-corpus/machine_learning.md
# Machine Learning Smoke Document
Embeddings map text into vectors.
Entity extraction should identify organizations, locations, and dates when present.
EOF
.venv/bin/python tests/test_complete_e2e.py \
--corpus tmp/oracle-smoke-corpus \
--output tmp/oracle-smoke-output
Expected result: Overall: PASS
The primary kept end-to-end throughput validation is:
ORACLE_E2E_SKIP_LITELLM=1 .venv/bin/python tests/test_e2e_without_litellm.py
This writes a report to reports/e2e-without-litellm-report.md and a machine-readable result to tests/e2e_results_no_litellm.json.
# Quality checks (7 categories, 30 individual checks)
python -m oracle.benchmarks.quality_checks
# Stress tests (6 scenarios: large corpus, connection pool, deep traversal, etc.)
python -m oracle.benchmarks.stress_test --quick
# Throughput benchmarks (parse, chunk, embed, extract, graph write, full pipeline)
python -m oracle.benchmarks.throughput_benchmarks --iterations 5
# Cross-module import verification
python -c "from oracle.investigation_graph import build_investigation_graph; print('OK')"
python -c "from oracle.tools.executors import wire_all_executors; print('OK')"
python -c "from oracle.tools.new_tools import wire_domain_executors; print('OK')"
python -c "from oracle.knowledge_graph.investigation_writer import write_investigation_graph; print('OK')"
Runs each pipeline stage in isolation to measure per-stage GPU throughput without resource contention. Designed for 12 GB VRAM cards where TEI (~2.5 GB), GLiNER (~0.6 GB), and Relex (~3 GB) together exceed VRAM.
# Requires: Docker stack running, corpus selected
# Select corpus first (one-time):
python benchmarks/select_corpus.py --n 250
# Run benchmark:
python benchmarks/benchmark_sequential_gpu.py [--docs N]
# Results written to reports/benchmarks/
Phases:
Historical targets (from prior joint-encoder benchmark):
ORACLE has 12 typed tools with Pydantic-validated I/O and pluggable backends:
Base tools (8): graph_search, vector_search, entity_lookup, claim_trace, source_fetch, contradiction_check, model_call, report_note
Domain tools (4): temporal_query, relationship_path, passenger_list, financial_flow
All tools have real backend executors (FalkorDB, Qdrant, TEI, LiteLLM) wired via wire_all_executors() and wire_domain_executors(). See oracle/tools/executors.py and oracle/tools/new_tools.py.
Entities are stored with multi-label nodes (:Entity:Person, :Entity:Organization, :Entity:Location, etc.) enabling type-specific queries. Relationships are typed (KNOWS, PASSENGER_ON, LOCATED_IN, OWNS, etc.) using pattern-based inference — no LLM costs during ingestion.
Key modules:
oracle/ingestion/entity_classifier.py): Maps GLiNER labels to concrete graph node types with sub-classification (org_type, loc_type, event_type)oracle/ingestion/relationship_inference.py): 27 pattern rules across all entity pair combinationsoracle/knowledge_graph/__init__.py): MERGE-based idempotent writes with dynamic CypherThe Command Center renders the full knowledge graph (12K+ nodes, growing) using a pre-computed server-side layout:
# Pre-compute graph layout, PageRank, and Louvain communities
.venv/bin/python scripts/precompute_graph_layout.py [--force] [--iterations 50]
This runs spring_layout on all nodes, computes PageRank and community assignments, and writes coordinates (viz_x, viz_y, viz_pagerank, viz_community) back to FalkorDB. The frontend reads these pre-computed positions and renders via WebGL — no client-side physics, instant load.
Graph page features:
Relevant endpoints:
GET /api/graph/export?limit=N — Type-proportional graph data with edgesGET /api/graph/summary — Node/edge counts and top entitiesGET /api/graph/health — Database connectivity statusThe investigation system uses a LangGraph state machine with 8 nodes and conditional routing:
planner → tool_dispatcher → evidence_collector → hypothesis_generator
↓
orchestrator
↙ ↓ ↘
[challenger] [loop] [reporter → completer]
AsyncPostgresSaverKey modules:
oracle/investigation_graph.py): 1,019 lines, 8 nodes with conditional edgesoracle/knowledge_graph/investigation_writer.py): MERGE-based artifact persistenceoracle/reporting/report_engine.py): Confidence blending with provenance chains, exports to Markdown/HTML/PDF/DOCXNamed profiles configure entity types, chunk sizes, and relationship rules per dataset:
from oracle.profiles import get_profile_for_corpus
profile = get_profile_for_corpus("epstein_files") # or "bible_kjv", "default"
Profiles defined in oracle/profiles.py.
Relation extraction now runs inline during the extraction phase via ExtractResultHandler — not as a separate post-hoc enrichment task. After GLiNER extracts entities from each chunk, GLiNER-Relex is called immediately to extract typed relationships between those entities. Pattern-based relationships (from relationship_inference.py's 27 rules) and Relex relationships are merged in dispatcher._merge_relationships() before writing to FalkorDB. This means typed edges (WORKS_FOR, FOUNDED, LOCATED_IN, PART_OF, COMPETITOR, etc.) flow end-to-end in a single ingestion pass — no separate enrichment worker needed.
Unlike the old vLLM pipeline (~0.04 pairs/sec autoregressive), Relex performs joint NER+relation extraction in a single encoder forward pass at 317 relations/sec — an ~8,000x speedup.
Key implementation:
ExtractResultHandler: Calls Relex API (:8004) inline after entity extraction, sending entity pairs with context textdispatcher._merge_relationships(): Merges Relex typed relationships with pattern-inferred relationships, resolving conflicts by confidencesource:gliner_relex or source:pattern property for provenance trackingNo capability flag needed — relation extraction is part of the standard extraction capability. Ensure relex is running and ORACLE_RELEX_URL is set (defaults to http://localhost:8004).
The old post-hoc enrichment pipeline (NATS oracle.tasks.enrichment.graph stream, graph_enrichment worker capability, separate GraphResultHandler enrichment pass) is deprecated. It is gated behind ORACLE_ENABLE_DEPRECATED_ENRICHMENT=1. Do not use in new deployments — all relationship extraction now happens inline.
Add coref to the GPU stack for pronoun resolution before entity extraction (344 chunks/sec, 93ms latency):
docker compose --profile gpu up -d coref
Set ORACLE_ENABLE_COREF=true to enable in the ingestion pipeline.
Relex integration tests require the Relex service running:
# Relex integration tests — health, load, accuracy, throughput, no-hallucination
python tests/test_relex_enrichment.py
# Legacy vLLM tests (only if vLLM is running and ORACLE_ENABLE_DEPRECATED_ENRICHMENT=1)
python tests/test_vllm_enrichment.py --smoke
Controller
Postgres NATS LiteLLM FalkorDB Qdrant Worker
Optional GPU
tei-emb gliner coref relex (inline RE)
Command Center
FastAPI backend (:8010)
Vite frontend (:5173)
The current dockerized worker container reports healthy on :18080, but it also logs recurring NATS fetch_error messages after startup. A local ingestion smoke pass still succeeds, but the README does not currently treat the worker log noise as a clean operational state. See TROUBLESHOOTING.md.
| Document | Purpose |
|---|---|
| INSTALL.md | Full bring-up runbook |
| WORKER_GUIDE.md | Worker-specific setup |
| ENV_REFERENCE.md | Environment variables |
| ARCHITECTURE.md | System layout, data flow, and graph viz pipeline |
| DEVELOPMENT.md | Local development workflow |
| PRODUCTION_READINESS.md | Honest audit of what's ready and what's not |
| TROUBLESHOOTING.md | Known failures and fixes |
| monitoring/README.md | Monitoring stack |
| command-center/frontend/README.md | Frontend runbook |
| docs/COMMAND_CENTER_PRODUCT_SPEC.md | Command Center vision and design |
| docs/ENGINEERING_DEFINITION_OF_DONE.md | Completion criteria |
| docs/ENRICHMENT_PIPELINE.md | Graph enrichment pipeline (encoder-based, GLiNER-Relex) |
| PIPELINE_TECHNICAL_REPORT.md | Complete pipeline technical reference (for AI/developer onboarding) |
Last updated: 2026-06-03
1 commits
Python
83.9%
TypeScript
8.8%
CSS
5.5%
Shell
1.1%