ELIPS is a small core with sharp seams. Domain code talks to abstractions — IndexPort, GpuPort, TextEmbedderPort, WAL — never to concrete engines. This is the lever that lets HNSW, exact search, GPU indexes, and future quantized variants compose behind one runtime.
System shape
Hexagonal ports
Every replaceable subsystem hides behind a pure-virtual port. Concrete engines plug in; nothing outside src/gpu_engine/ ever includes a backend header. The composition root is IndexFactory::make_index().
class Vault {
std::unique_ptr<IndexPort> index_; // abstract
WAL* wal_; // non-owning
};
auto index = make_index(config, dimension); // returns unique_ptr<IndexPort>Query path
Strategies emitted by the planner: ann_index, exact_candidates, full_scan, text_probe, hybrid_fusion. The strategy is the single source of truth for "what actually ran" — exposed through explain_seek and through EQL.
Persistence path
See Storage & recovery for the on-disk layout, the WAL operation set, and recovery rules.
Concurrency
ELIPS is single-writer, multi-reader. The writer takes an exclusive flock on the database's LOCK file; readers take a shared lock. Locks are RAII-bound to LockManager: dropping the handle releases the lock, even on exception unwinding. There is no background thread, no daemon, no cross-process coordination beyond the lock.
Surfaces
Two Python layers live on top of the same core:
- Low-level bindings mirror the C++ surface:
open,Database,Vault,Config,Filter,QueryPlan. - Modern wrapper adds typed text-first ergonomics:
connect,Engine,Arena,RecordInput,Row,Hit.
The wrapper prefers native core text APIs when the database has a resolved embedder. If only a Python callable is provided, it falls back to Python-side embedding plus seek_hybrid. If neither exists, text-first calls raise ConfigError — ELIPS never silently degrades to lexical-only behaviour.