Files
nexa/docs/03-architecture.md
T
Claude 17c7f5033f Stage embeddings: ship Path A (text) now, prepare Path C (text+visual) additively
Decision (Q15 resolved): start with text-only via TEI + bge-m3 in Phase 3.1,
prepare data shapes so Phase 3.2 (visual collection via infinity + jina-clip-v2)
is a pure additive operation — no rename, no schema migration, no n8n rewiring.

Concretely:
- Qdrant collection renamed nexa_knowledge → nexa_knowledge_text (1024-dim
  for bge-m3) with modality-aware payload (modality, source_type, media_uri,
  graph_iri, content_hash, context). Visual placeholder schema committed
  alongside (qdrant_schema_visual.json, 768-dim, jina-clip-v2).
- Image attachments captured in 3.1 are recorded in GraphDB as nexa:Note with
  nexa:modality "image" + nexa:pendingVisualIndex true; the 3.2 backfill
  workflow picks them up and embeds. No data lost between phases — the queue
  is the GraphDB itself.
- RDF schema (docs/08) gains nexa:modality, nexa:mediaUri,
  nexa:vectorCollection, nexa:pendingVisualIndex from day one.
- docs/02 roadmap split: 3.1 = text RAG (Path A), 3.2 = visual collection
  (Path C), 3.4 = Ontotext GraphDB.
- docs/09 grows a "Phase add-on: visual collection (Phase 3.2)" section with
  the TEI→infinity swap, second collection create, LiteLLM second model
  registration, and the SPARQL-driven backfill query.
- New open questions: Q16 (queue ergonomics + does SAIA already proxy an
  embed model?), Q17 (reuse Immich's CLIP for photo-library queries?).
- docs/03 + CLAUDE.md updated so future runs use the new collection names
  and don't re-decide the staging.
2026-05-04 21:33:59 +00:00

4.0 KiB

03 — Architecture Overview

A one-page mental model. For details follow the cross-links.

Topology

                         ┌────────────────┐
   voice / typing ──────▶│     Memos      │◀──── Nexa replies as comments
                         │  (interface)   │
                         └───────┬────────┘
                                 │ webhook (- [ ] / #nexa:*)
                                 ▼
                         ┌────────────────┐
   IMAP / RSS / NC  ────▶│      n8n       │◀──── workflows live in
   Karakeep / Bluesky    │  (logic)       │      ./nexa-core/n8n-workflows
                         └───┬────────┬───┘
                  classify ▲ │        │ ▲ retrieve
                           │ ▼        ▼ │
                       ┌──────────┐  ┌──────────┐
                       │  SAIA    │  │  Qdrant  │
                       │ LiteLLM  │  │  vector  │
                       └──────────┘  └────┬─────┘
                                          │
                                          ▼
                                     ┌──────────┐
                                     │ GraphDB  │  Ontotext, SPARQL
                                     │  (RDF)   │  Phase 3.4
                                     └──────────┘
                                 │
                                 ▼ writes
                  ┌──────────────────────────────┐
                  │  Nextcloud (Tasks, Calendar, │
                  │  Mail, Files / Obsidian)     │
                  └──────────────────────────────┘

Components

Component Role Where it runs (today)
Memos Interface, voice input, webhook source docker host LXC 104 → memos.nuclide.systems
n8n Workflow / logic engine docker host LXC 104 → n8n.nuclide.systems
SAIA / LiteLLM Model gateway, embeddings, classification docker host LXC 104 → ai.nuclide.systems (LiteLLM internal :4000)
Qdrant Vector memory (semantic recall) docker host LXC 104 — reuse qdrant_scientific. Collections: nexa_knowledge_text (Phase 3.1, 1024-dim) and nexa_knowledge_visual (Phase 3.2, 768-dim)
Ontotext GraphDB Structural memory via SPARQL (Phase 3.4) not yet deployed; see 09-deployment
TEI (HF text-embeddings-inference) Self-hosted text embeddings, BAAI/bge-m3, Phase 3.1 docker host LXC 104, CPU only — swapped for infinity in Phase 3.2 to add jina-clip-v2
Nextcloud Tasks, calendar, mail, files dedicated LXC 105 → nc.nuclide.systems
ntfy Push channel for system alerts docker host → ntfy.nuclide.systems
Backrest Backup orchestration LXC 103
Zoraxy Reverse proxy + TLS LXC 108 (192.168.1.4:8000)
AdGuard DNS Internal name resolution LXC 102
Home Assistant Voice + house automation VM 100 (HAOS)

Two-pillar memory

  • Qdrant answers "what is similar / relevant?" (cosine search over embeddings).
  • Ontotext GraphDB answers "who, what depends on what, how is it structured?" (SPARQL over RDF).

Both pillars are queried in parallel for #nexa:ask and merged before SAIA generates the final answer. See 08 — GraphRAG architecture.

Dual-context routing

Every input is classified work or personal before any side effect (task creation, calendar write). See 04 — Integration matrix and 06 — Classification logic.