Skip to content

๐Ÿ—๏ธ Architecture Overview

Spector is a modular, JVM-native AI memory backbone organized as a Maven multi-module project. This page covers the module structure, dependency graph, data flow, threading model, and memory architecture that make sub-millisecond, agent-native search possible.


๐Ÿ“ฆ Module Diagram

graph LR
    subgraph "๐Ÿ”ฌ Core Layer"
        core["spector-core<br/><i>SIMD kernels</i>"]
        commons["spector-commons<br/><i>Config, chunkers, tokenizer</i>"]
    end

    subgraph "๐Ÿ’พ Storage Layer"
        storage["spector-storage<br/><i>Panama MemorySegment stores</i>"]
    end

    subgraph "๐Ÿ“Š Index Layer"
        index["spector-index<br/><i>HNSW + IVF-PQ + BM25</i>"]
    end

    subgraph "๐Ÿ” Query Layer"
        query["spector-query<br/><i>Hybrid orchestrator + RRF</i>"]
    end

    subgraph "๐Ÿง  Intelligence"
        embedapi["spector-embed-api<br/><i>EmbeddingProvider SPI</i>"]
        embedollama["spector-embed-ollama<br/><i>Ollama provider</i>"]
        gpu["spector-gpu<br/><i>Panama FFM + CUDA</i>"]
    end

    subgraph "๐Ÿ“ฅ Pipelines"
        ingestion["spector-ingestion<br/><i>Ingest orchestration</i>"]
        rag["spector-rag<br/><i>RAG pipeline</i>"]
    end

    subgraph "โšก Runtime & Interfaces"
        runtime["spector-runtime<br/><i>Unified context (engine + memory)</i>"]
        engine["spector-engine<br/><i>Search facade + lifecycle</i>"]
        node["spector-node<br/><i>Armeria: REST + gRPC + SSE + cluster</i>"]
        mcp["spector-mcp<br/><i>MCP Server โ€” Agent-native</i>"]
        cli["spector-cli<br/><i>spectorctl CLI</i>"]
        client["spector-client<br/><i>Java client SDK</i>"]
        spring["spector-spring<br/><i>Spring AI VectorStore</i>"]
    end

    subgraph "๐Ÿง  Cognitive Memory"
        memory["spector-memory<br/><i>Biologically-inspired agent memory</i>"]
    end

    subgraph "๐Ÿ“ˆ Distribution"
        bench["spector-bench<br/><i>JMH benchmarks</i>"]
        dist["spector-dist<br/><i>Single fat JAR</i>"]
    end

Note

Index sub-modules: hnsw/ (graph-based ANN), ivf/ (inverted file + posting lists), pq/ (product quantizer, K-Means++, ADC), bm25/ (keyword scoring + analyzers)


๐Ÿ”— Dependency Graph

graph TD
    node["๐ŸŒ node"] --> runtime["โšก runtime"]
    node --> mcp["๐Ÿค– mcp"]
    node --> metrics["๐Ÿ“ˆ metrics"]
    mcp --> runtime
    mcp --> ingestion["๐Ÿ“ฅ ingestion"]
    cli["๐Ÿ–ฅ๏ธ cli"] --> runtime
    cli --> client["๐Ÿ“ฆ client"]

    runtime --> engine["โšก engine"]
    runtime --> memory["๐Ÿง  memory"]
    runtime --> ingestion

    engine --> query["๐Ÿ” query"]
    engine --> rag["๐Ÿค– rag"]
    engine --> ingestion
    engine --> index["๐Ÿ“Š index"]
    engine --> storage["๐Ÿ’พ storage"]
    engine --> embedapi["๐Ÿงฌ embed-api"]
    engine -.-> gpu["๐ŸŽฎ gpu"]

    memory --> index
    memory --> storage
    memory --> ingestion
    memory --> embedapi
    memory --> core["๐Ÿ”ฌ core"]

    metrics --> engine
    metrics --> memory

    ingestion --> config["โš™๏ธ config"]
    ingestion --> embedapi

    rag --> query
    rag --> index
    rag --> storage
    rag --> embedapi
    rag --> commons["๐Ÿ“„ commons"]

    query --> index
    query --> commons
    index --> storage
    index --> config
    storage --> config
    storage --> core
    config --> core

    embedapi --> commons
    gpu --> core
    gpu --> storage

    dist["๐Ÿ“ฆ dist"] --> mcp
    dist --> cli
    dist --> runtime

    spring["๐ŸŒฑ spring"] --> engine
    spring --> memory
    spring --> metrics
    bench["๐Ÿงช bench"] --> engine
    bench --> memory

Legend: Solid arrows = compile dependency. Dotted arrow (gpu) = optional dependency.

Dependency rules:

Path Description
runtime โ†’ engine + memory + ingestion Composition root โ€” wires all subsystems
cli โ†’ runtime + client CLI with local batch (runtime) and remote (client) modes
node โ†’ runtime Unified Armeria node: REST + gRPC + cluster coordination
mcp โ†’ runtime + ingestion MCP agent entry point (in-process, zero network)
engine โ†’ ingestion EngineIngestionTarget implements IngestionTarget
memory โ†’ ingestion CognitiveIngestionTarget implements IngestionTarget
engine โ†’ rag RAG context assembly pipeline
engine -.-> gpu Optional GPU acceleration
memory โ†’ index, storage, core, embed-api Cognitive memory (independent of engine)
dist โ†’ mcp + cli + runtime Fat JAR distribution

Important

No circular dependencies. spector-memory and spector-engine are peers โ€” both depend on spector-ingestion for the IngestionTarget interface, but neither depends on the other. SpectorRuntime is the single composition root that wires them together.


๐Ÿ“ฅ Data Flow: Ingest Path

sequenceDiagram
    participant Client as ๐Ÿ‘ค Client (CLI/MCP/REST)
    participant Runtime as โšก SpectorRuntime
    participant Handler as ๐Ÿ“ฅ IngestionHandler
    participant Pipeline as ๐Ÿ”„ IngestionPipeline
    participant Embed as ๐Ÿง  ParallelEmbeddingPipeline
    participant Target as ๐Ÿ’พ IngestionTarget
    participant Store as ๐Ÿ’พ Storage (mmap)

    Client->>Runtime: runtime.ingestion().ingest(dir, pattern)
    Runtime->>Handler: Pre-configured pipeline + target
    Handler->>Handler: FileDiscoveryService.discover()
    loop Each file
        Handler->>Pipeline: pipeline.ingest(id, content)
        Pipeline->>Pipeline: TextChunker.chunk(content)
        Pipeline->>Embed: embed(chunkTexts) via virtual threads
        Embed-->>Pipeline: List<vector>
        loop Each chunk
            Pipeline->>Target: target.ingest(id, text, vector)
            Target->>Store: VectorStore + VectorIndex + KeywordIndex
        end
    end
    Store-->>Client: โœ… Indexed
  1. Client calls runtime.ingestion().ingest() โ€” all entry points use this
  2. IngestionHandler delegates to a pre-configured IngestionPipeline
  3. IngestionPipeline handles chunking (from config) and parallel embedding
  4. IngestionTarget receives pre-embedded chunks โ€” EngineIngestionTarget for SEARCH, CognitiveIngestionTarget for MEMORY
  5. Each target handles its own downstream storage (VectorStore/HNSW or Quantize/TierRoute/WAL)

Tip

FileDiscoveryService can be used independently for file discovery without any engine or runtime dependency.


๐Ÿ” Data Flow: Search Path

sequenceDiagram
    participant Client as ๐Ÿ‘ค Client
    participant Engine as โšก SpectorEngine
    participant QB as ๐Ÿงญ Query Builder
    participant BM25 as ๐Ÿ“ BM25 Search
    participant HNSW as ๐Ÿง  HNSW Search
    participant RRF as ๐Ÿงฌ RRF Fusion
    participant LLM as ๐Ÿค– LLM Reranker

    Client->>Engine: Search (text + vector + topK)
    Engine->>QB: Auto-detect mode
    Note over QB: text only โ†’ KEYWORD<br/>vector only โ†’ VECTOR<br/>both โ†’ HYBRID
    par Parallel search on virtual threads
        QB->>BM25: Keyword search
        QB->>HNSW: Vector search
    end
    BM25->>RRF: Ranked results
    HNSW->>RRF: Ranked results
    RRF->>LLM: Fused top candidates
    LLM-->>Client: โœจ Final ranked results
  1. Query Builder determines search mode from provided fields
  2. BM25 and HNSW searches run in parallel on virtual threads
  3. RRF Fusion merges both ranked lists using 1/(k + rank) scoring
  4. Optional LLM Reranker rescores top candidates via Ollama

๐Ÿค– Data Flow: MCP Agent Path

sequenceDiagram
    participant Agent as ๐Ÿค– AI Agent (Claude/Cursor)
    participant MCP as ๐Ÿ“ก MCP Transport (stdio)
    participant Handler as ๐Ÿ”ง McpToolHandler
    participant Runtime as โšก SpectorRuntime
    participant Engine as ๐Ÿ”ง SpectorEngine
    participant SIMD as ๐Ÿ”ฌ SIMD Kernels

    Agent->>MCP: tools/call {"name": "semantic_search", "arguments": {"query": "..."}}
    MCP->>Handler: SemanticSearchTool.execute(runtime, args)
    Handler->>Runtime: runtime.search().query(text, topK)
    Runtime->>Engine: engine.search(query, topK)
    Engine->>SIMD: HNSW traversal (off-heap MemorySegment)
    SIMD-->>Engine: ScoredResult[] (~100ยตs)
    Engine-->>Runtime: SearchResponse
    Runtime-->>Handler: SpectorResult[]
    Handler-->>MCP: CallToolResult
    MCP-->>Agent: JSON-RPC response with search results

The MCP path routes through SpectorRuntime โ€” the single composition root that holds both the search engine and optional cognitive memory. The MCP server wraps runtime handler calls with JSON-RPC transport. There is zero network overhead because everything runs in the same JVM process.

Tip

For full MCP architecture details, tool schemas, and design patterns, see the dedicated MCP Integration page.


๐Ÿงต Threading Model: Virtual Threads

Spector is designed from the ground up for Java virtual threads:

Tip

No synchronized blocks anywhere in the codebase. All coordination uses ReentrantLock to avoid virtual thread pinning.

Operation Threading Strategy
REST request handling One virtual thread per request
Hybrid search Parallel BM25 + HNSW via StructuredTaskScope
Bulk ingest Virtual thread per document
Embedding generation Batched across virtual threads
HNSW construction (>10K) Virtual threads per core for parallel insertion
Distributed fan-out Virtual thread per shard query

๐Ÿ“ˆ Scaling Results

At 50K docs with hybrid search (384-dim, production-realistic):

Virtual Threads Throughput Scaling
1 3,739 ops/s 1.0ร—
4 10,317 ops/s 2.8ร—
8 11,812 ops/s 3.2ร—
16 14,022 ops/s 3.7ร—

Note

Scaling depends on vector dimensions and workload type. 384-dim shows ~3.7ร— at 16 threads due to higher per-query memory bandwidth. Individual HNSW queries are inherently sequential (graph traversal data dependencies) โ€” scaling comes from concurrent queries sharing CPU cores.


๐Ÿ’พ Memory Model: Panama Off-Heap

All vector data lives off-heap using the Panama Foreign Function & Memory API:

graph TB
    subgraph "โ˜• JVM Heap (minimal)"
        HG["HNSW Graph<br/>(adjacency lists)"]
        BM["BM25 Index<br/>(inverted index)"]
        ES["Engine State<br/>(config, lifecycle)"]
    end

    subgraph "๐ŸงŠ Off-Heap (Panama MemorySegment)"
        VS["Vector Store<br/>Contiguous float32, SIMD-aligned<br/>Zero-copy reads, no GC pressure"]
        QS["Quantized Store<br/>INT8 or PQ codes"]
        GM["GPU Device Memory<br/>CUDA via FFM"]
    end

    HG -.-> VS
    BM -.-> VS
    ES -.-> QS
    ES -.-> GM

Benefits:

  • โœ… Zero GC pressure โ€” Vectors never touch the garbage collector

  • โœ… Instant startup โ€” Memory-mapped files load via mmap syscall, no deserialization

  • โœ… SIMD-friendly layout โ€” Contiguous float32 arrays ready for Vector API operations

  • โœ… Explicit lifecycle โ€” Arena-scoped memory with deterministic cleanup

  • โœ… Memory efficiency โ€” Store billions of vectors limited only by disk/address space

๐Ÿ“Š Storage Types

Store Location Use Case
InMemoryVectorStore Off-heap (Arena) Development, small datasets
MmapVectorStore Memory-mapped file Production, persistence
QuantizedVectorStore Off-heap (INT8) Memory-constrained deployments
IvfPqStore Off-heap (PQ codes) Billion-scale (32ร— compression)

๐ŸŒ API Layer

graph TD
    subgraph "SpectorNode - Armeria Server, single port"
        CORS["CorsService decorator"]
        Auth["API Key decorator"]
        COMPRESS["EncodingService - gzip/brotli"]
        subgraph "ApiModule Registration"
            SE["๐Ÿ” SearchEndpoint"]
            IE["๐Ÿ“ฅ IngestEndpoint"]
            RE["๐Ÿค– RagEndpoint"]
            DE["๐Ÿ—‘๏ธ DocumentEndpoint"]
            STE["๐Ÿ“Š StatusEndpoint"]
            ESE["๐Ÿ“ก EventStreamEndpoint"]
        end
        gRPC["gRPC Service<br/>inter-node fan-out"]
        HEALTH["๐Ÿ’š /health"]
        PROM["๐Ÿ“Š /metrics"]
    end

    subgraph "Service Facades"
        SS["SearchService"]
        IS["IngestService"]
        RS["RagService"]
    end

    SE --> SS
    IE --> IS
    RE --> RS
    SS & IS --> EB["SpectorEventBus<br/>17 event types"]
    SS --> ENGINE["โšก SpectorEngine"]

Every request runs on its own virtual thread. The Armeria server handles HTTP REST, gRPC, and SSE events on a single port. API endpoints are registered via the ApiModule factory pattern, enabling straightforward API versioning (/api/v1, /api/v2).

Streaming via SSE

The /api/v1/search/stream endpoint uses Server-Sent Events to emit results progressively. The /api/v1/events endpoint provides a live event stream where clients can subscribe to search, ingest, cluster, MCP, and engine events with optional category filtering.


๐Ÿ”— See Also