Files
nexa/docs/11-open-questions.md
T
Claude dfd9aa7d2a 3-2-1 backup tiering with off-site cold (Jottacloud candidate)
- s3.nuclide.systems is on-site only — recasting it as the WARM tier,
  not the disaster-recovery copy. Off-site cold becomes a separate
  decision tracked as Q20.
- docs/12 #37 expanded with full provider comparison: Jottacloud
  Unlimited (~€9.50/mo, EU/Norway, soft-cap ~5 TB) is the user's
  stated candidate and a reasonable fit for the current 2 TB scale
  with ~10 years of headroom. Alternatives priced: Hetzner Storage
  Box, Backblaze B2, rsync.net, Storj. Always restic/rclone-crypt
  before upload.
- Off-site priority list pinned: Immich originals + documents +
  Nextcloud user data + Vaultwarden DB go off-site; movies / music /
  ROMs / derived caches don't.
- docs/10 backup section rewritten as the 3-2-1 pipeline (source →
  UNAS native snapshot → warm → encrypted cold). Nexa-specific
  snapshot rows updated for the new collection names.
- docs/11 Q20 added with the decision criteria.
- CLAUDE.md: backup model pinned so future agents don't propose
  alternative paths.
2026-05-05 04:50:43 +00:00

9.7 KiB
Raw Blame History

11 — Open Questions (user-info-required)

Items that block progress and need a human decision before a workflow can be implemented or a service deployed. Tick them off as you decide.

Resolved

  • Q1 — Graph DB choice → Ontotext GraphDB (SPARQL). Rationale: explore Nexa's memory through SPARQL is a stated goal. 08-graphrag-architecture is rewritten accordingly.

  • Q2 — Vector store → reuse qdrant_scientific with a nexa_* collection prefix. No dedicated container.

  • Q3 — Embeddings model → not OpenAI. Self-host on the docker host via TEI (HF text-embeddings-inference) — Rust single-binary, OpenAI-compatible, ~500 MB image, no LLM runtime overhead. Speed analysis in §"Speed budget" below.

  • Q5 — Display name → Karakeep. The Zoraxy host alias hoarder.nuclide.systems is legacy — keep it for compatibility, but all docs, prompts and new workflow nodes use "Karakeep".

  • Q13 — Octoprint container is intentionally temporary. Suppress from Phase-5 monitoring: container-up/down alerts must skip names matching octoprint* (or any container tagged proxmox-he 3d-printing).

  • Q14 — Homepage Zoraxy widget → no such widget. Config error in homepage/services.yaml; cosmetic, not Nexa-related.

  • Q15 — Embeddings staging plan → A now, C prepared.

    • Phase 3.1 (now): TEI + BAAI/bge-m3, single collection nexa_knowledge_text (1024-dim). DE/EN multilingual, fits the corpus.
    • Phase 3.2 (later): swap TEI → infinity, add jinaai/jina-clip-v2 (768-dim), second collection nexa_knowledge_visual. Backfill from the queue (see Q16).
    • All schema fields needed for 3.2 (modality, media_uri, graph_iri, nexa:pendingVisualIndex) are introduced now so 3.2 is purely additive — no rename, no migration. See qdrant_schema.json and qdrant_schema_visual.json.
  • Q16 — Image-attachment queue ergonomics → leave bytes at source, reference by media_uri. Zero copy. Memos attachments stay in Memos's data dir, Nextcloud images stay in Nextcloud, Obsidian images stay in the Notizen folder; the Phase-3.2 backfill workflow fetches them on demand via the URI scheme.

  • Q17 — Immich out-of-band. Nexa does not call the Immich smart-search API. Photo-library queries stay inside Immich.

  • Q18 — SAIA proxies an embedding model, but 10 msg/min rate limit makes it unusable for ingest. A 2 k-note Obsidian backfill would take ~3.3 h; real-time #nexa:ask would queue for tens of seconds during a writing burst. Decision: deploy TEI as planned. SAIA embeddings remain available as a manual fallback (e.g. for one-off #nexa:learn calls where rate is irrelevant).

  • Q4 — Obsidian sync via Nextcloud WebDAV. Confirmed the vault is nc.nuclide.systems/Notizen/ (multi-device sync via Nextcloud client). Nexa accesses it through WebDAV (/remote.php/dav/files/<user>/Notizen/) reusing the existing NC_APP_PASSWORD — no filesystem mount, no LXC-to-LXC privilege escalation. Phase 3.1 polls every 15 min; an upgrade to Nextcloud's notify_push for sub-second updates is captured as optimization #15. Ignore list (don't index):

    • .copilot/, .copilot-index/ — Obsidian Copilot's own embeddings cache.
    • .smart-env/ — Smart Connections / Smart Composer plugin data (~13 MB).
    • .caldav-sync/ — calendar sync, not notes.
    • assets/ — 186 MB of binaries; routed through the Phase-3.2 visual queue (nexa:pendingVisualIndex), not the text path.
    • Templates/ — empty templates, low semantic value.
    • BMO/, Excalidraw/ — plugin folders. Anything else under Notizen/**/*.md is fair game.
  • Q6 + Q7 — Lists & calendars discovered by name, not ID. Self-healing. Confirmed names from screenshots:

    • Tasks: Persönlich (14), DLR (13), Einkaufsliste (13), Wunschliste (9).
    • Calendars: Persönlich, DLR, Einkaufsliste, Wunschliste (Nextcloud Tasks is calendar-backed, so the names are shared; Tasks lives on the calendar of the same name).
    • Mapping in classification: DLR = Work-Kontext, Persönlich = Personal-Kontext, Einkaufsliste = Shopping, Wunschliste = Wishes.

    Self-healing requirement (the user explicitly noted lists may change/grow): Nexa must not cache IDs forever. The #nexa:config workflow runs (a) on demand, (b) once daily as a scheduled refresh, and (c) automatically as a retry whenever a list/calendar lookup returns 404 or "not found". The runtime-config record in Qdrant's _config namespace stores {name → id, discovered_at} and gets invalidated on cache-miss. New lists added in Nextcloud surface in the next scheduled refresh and Nexa starts honouring #einkaufsliste / #dlr etc. without code changes.

  • Q8 — Mail via Nextcloud, single account fkrebs@nucli.de. No extra IMAP entry. n8n's IMAP node uses the same server credentials Nextcloud Mail already holds for that account; Nexa never sees a second password. Folders confirmed: Posteingang (default), Archiv, Junk (61 — auto-filtered, ignored by Nexa), Papierkorb, Waiting. The Waiting folder is a useful manual signal — items moved there by the user are skipped from digest (treat as "in flight").

  • Q9 — Pocket-ID SSO is configured everywhere. No separate auth for Nexa: Memos / n8n / future Nexa dashboard authenticate humans via Pocket-ID at the Zoraxy layer. Machine-to-machine calls (n8n → Memos webhook, n8n → Nextcloud, n8n → Qdrant, n8n → LiteLLM) keep using API keys / app passwords — SSO is for human UIs only. Don't add basic-auth or per-app login screens.

    This resolves Q10 too (the proposed "Pocket-ID SSO in front of n8n / Memos" is already done; Nexa just inherits it).

  • Q10 — folded into Q9.

Hardware / capacity

  • Q11 — Capacity confirmed from Proxmox node + LXC summaries.
    • Host (NUC 14 Pro): 22 threads (Intel Core Ultra 7 155H, 1 socket), 62.12 GiB RAM, 1.64 TiB disk (0.35% used). Steady state: 32.4 GiB used (≈24 GiB of which is ZFS ARC), load avg 1.99 / 1.39 / 1.15, IO delay 0.04%.
    • LXC 104 (docker, unprivileged): 16 CPU, 31.25 GiB RAM cap (7.86 GiB used = 25%), 8 GiB swap (idle), 200 GiB boot disk at 47.7% used (~95 GiB). Tag proxmox-helper-scripts. Intel iGPU passthrough configured but currently failing — see 12/#26.
    • RAM headroom is comfortable: Phase-3 budget (~7 GiB additional — Qdrant ~1.5 + TEI/bge-m3 ~1.1 + GraphDB 4-GB heap + later +infinity/jina-clip-v2 ~1) fits inside the existing LXC cap with ~16 GiB still free. Levers if needed: (1) raise the LXC cap (host has plenty), (2) cap zfs_arc_max lower (ARC currently 24 GiB). Either is one line of config.
    • Disk is fine — the LXC also NFS-mounts the UNAS at /mnt/pve/unas (19.4 TiB total, 16.3 TiB free). Large/persistent volumes (Qdrant data, GraphDB repo, snapshots, image bytes if we ever stage them) bind-mount there; the 200 GiB local boot disk only carries images and small ephemeral state. See 12/#27.
    • Verdict: no blockers for Phase-3.1. Revisit once 3.4 GraphDB lands.
  • Q12 — S3 archive bucket. s3.nuclide.systems is up. Bucket name + access key for Qdrant snapshots and GraphDB exports?

Verification needed before Phase-3.1 deploy

  • Q19 — Confirm the SMB share name + mount syntax by reading an existing stack in Arcane (recommended: karakeep or immich). The SMB share name on UNAS that maps to the NFS root /var/nfs/shared/storage is currently a placeholder <unas-share> in docs/09. Required action: open the running Karakeep stack in Arcane, copy its volumes: block verbatim, swap karakeepnexa in the path, drop into the Nexa stack. This locks Nexa to the same convention every other container in the homelab uses — same driver, same credentials secret, same uid/gid — and avoids reinventing storage just for Nexa.

  • Q20 — Off-site cold-tier backup provider. s3.nuclide.systems is on-site only, so today the homelab has no real disaster-recovery copy (fire / theft / ransomware kills it). Comparison + recommendation in docs/12 #37. User's stated candidate is Jottacloud Unlimited (~€9.50/mo, EU/Norway, soft-cap ~5 TB — comfortable for the next 10 years given current 2 TB and slow growth). Alternatives: Hetzner Storage Box BX21 (€13/mo, predictable quota), Backblaze B2 ($12/mo, US, S3-compatible). Always encrypt before upload with restic or rclone crypt regardless of provider. Decision needed: pick one, create the account, share account email here (no password). Once chosen, optimization #37 can be implemented end-to-end.


Speed budget (Q3 follow-up)

Workload measured against the LXC 104 cap (16 CPU, 31.25 GiB RAM — host has 22 threads / 62 GiB if we ever raise the cap):

Task Volume Latency target Achievable on CPU with bge-m3 Achievable with nomic-embed-text
Real-time memo embed 1 doc <500 ms incl. n8n round-trip ~50100 ms ~20 ms
Daily ingest ~70 docs <60 s ~510 s ~2 s
Obsidian backfill (one-shot) ~2 000 docs <15 min ~24 min <1 min
RAG query embed (#nexa:ask) 1 doc <300 ms ~50 ms ~20 ms

Conclusion: CPU-only TEI is sufficient — no GPU needed for current scope. Bottleneck is SAIA chat (already remote), not embeddings. SAIA's own embedding endpoint is rate-limited to 10 req/min which would block real-time embed; self-hosted TEI side-steps that completely.