Files
docs/services/nexa/index.html

2418 lines
49 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!doctype html>
<html lang="en" class="no-js">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="description" content="Single source of truth for the homelab">
<link rel="canonical" href="http://192.168.1.8:13080/services/nexa/">
<link rel="icon" href="../../assets/images/favicon.png">
<meta name="generator" content="mkdocs-1.6.1, mkdocs-material-9.7.6">
<title>Nexa — Neural Nexus for Information & Automation - nuclide.systems docs</title>
<link rel="stylesheet" href="../../assets/stylesheets/main.484c7ddc.min.css">
<link rel="stylesheet" href="../../assets/stylesheets/palette.ab4e12ef.min.css">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,300i,400,400i,700,700i%7CRoboto+Mono:400,400i,700,700i&display=fallback">
<style>:root{--md-text-font:"Roboto";--md-code-font:"Roboto Mono"}</style>
<script>__md_scope=new URL("../..",location),__md_hash=e=>[...e].reduce(((e,_)=>(e<<5)-e+_.charCodeAt(0)),0),__md_get=(e,_=localStorage,t=__md_scope)=>JSON.parse(_.getItem(t.pathname+"."+e)),__md_set=(e,_,t=localStorage,a=__md_scope)=>{try{t.setItem(a.pathname+"."+e,JSON.stringify(_))}catch(e){}}</script>
</head>
<body dir="ltr" data-md-color-scheme="slate" data-md-color-primary="black" data-md-color-accent="blue">
<input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="__drawer" autocomplete="off">
<input class="md-toggle" data-md-toggle="search" type="checkbox" id="__search" autocomplete="off">
<label class="md-overlay" for="__drawer"></label>
<div data-md-component="skip">
<a href="#nexa-neural-nexus-for-information-automation" class="md-skip">
Skip to content
</a>
</div>
<div data-md-component="announce">
</div>
<header class="md-header" data-md-component="header">
<nav class="md-header__inner md-grid" aria-label="Header">
<a href="../.." title="nuclide.systems docs" class="md-header__button md-logo" aria-label="nuclide.systems docs" data-md-component="logo">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 8a3 3 0 0 0 3-3 3 3 0 0 0-3-3 3 3 0 0 0-3 3 3 3 0 0 0 3 3m0 3.54C9.64 9.35 6.5 8 3 8v11c3.5 0 6.64 1.35 9 3.54 2.36-2.19 5.5-3.54 9-3.54V8c-3.5 0-6.64 1.35-9 3.54"/></svg>
</a>
<label class="md-header__button md-icon" for="__drawer">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M3 6h18v2H3zm0 5h18v2H3zm0 5h18v2H3z"/></svg>
</label>
<div class="md-header__title" data-md-component="header-title">
<div class="md-header__ellipsis">
<div class="md-header__topic">
<span class="md-ellipsis">
nuclide.systems docs
</span>
</div>
<div class="md-header__topic" data-md-component="header-topic">
<span class="md-ellipsis">
Nexa — Neural Nexus for Information &amp; Automation
</span>
</div>
</div>
</div>
<form class="md-header__option" data-md-component="palette">
<input class="md-option" data-md-color-media="(prefers-color-scheme: dark)" data-md-color-scheme="slate" data-md-color-primary="black" data-md-color-accent="blue" aria-hidden="true" type="radio" name="__palette" id="__palette_0">
<input class="md-option" data-md-color-media="(prefers-color-scheme: light)" data-md-color-scheme="default" data-md-color-primary="black" data-md-color-accent="blue" aria-hidden="true" type="radio" name="__palette" id="__palette_1">
</form>
<script>var palette=__md_get("__palette");if(palette&&palette.color){if("(prefers-color-scheme)"===palette.color.media){var media=matchMedia("(prefers-color-scheme: light)"),input=document.querySelector(media.matches?"[data-md-color-media='(prefers-color-scheme: light)']":"[data-md-color-media='(prefers-color-scheme: dark)']");palette.color.media=input.getAttribute("data-md-color-media"),palette.color.scheme=input.getAttribute("data-md-color-scheme"),palette.color.primary=input.getAttribute("data-md-color-primary"),palette.color.accent=input.getAttribute("data-md-color-accent")}for(var[key,value]of Object.entries(palette.color))document.body.setAttribute("data-md-color-"+key,value)}</script>
<label class="md-header__button md-icon" for="__search">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.52 6.52 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5"/></svg>
</label>
<div class="md-search" data-md-component="search" role="dialog">
<label class="md-search__overlay" for="__search"></label>
<div class="md-search__inner" role="search">
<form class="md-search__form" name="search">
<input type="text" class="md-search__input" name="query" aria-label="Search" placeholder="Search" autocapitalize="off" autocorrect="off" autocomplete="off" spellcheck="false" data-md-component="search-query" required>
<label class="md-search__icon md-icon" for="__search">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.52 6.52 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11z"/></svg>
</label>
<nav class="md-search__options" aria-label="Search">
<button type="reset" class="md-search__icon md-icon" title="Clear" aria-label="Clear" tabindex="-1">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/></svg>
</button>
</nav>
<div class="md-search__suggest" data-md-component="search-suggest"></div>
</form>
<div class="md-search__output">
<div class="md-search__scrollwrap" tabindex="0" data-md-scrollfix>
<div class="md-search-result" data-md-component="search-result">
<div class="md-search-result__meta">
Initializing search
</div>
<ol class="md-search-result__list" role="presentation"></ol>
</div>
</div>
</div>
</div>
</div>
</nav>
</header>
<div class="md-container" data-md-component="container">
<nav class="md-tabs" aria-label="Tabs" data-md-component="tabs">
<div class="md-grid">
<ul class="md-tabs__list">
<li class="md-tabs__item">
<a href="../.." class="md-tabs__link">
Home
</a>
</li>
<li class="md-tabs__item">
<a href="../../CHANGELOG/" class="md-tabs__link">
Changelog
</a>
</li>
<li class="md-tabs__item">
<a href="../../RESUME/" class="md-tabs__link">
Resume
</a>
</li>
<li class="md-tabs__item">
<a href="../../ct-inventory/" class="md-tabs__link">
CT inventory
</a>
</li>
<li class="md-tabs__item">
<a href="../../infra/proxmox-state/" class="md-tabs__link">
Infra
</a>
</li>
<li class="md-tabs__item">
<a href="../homelab-architecture/" class="md-tabs__link">
Services
</a>
</li>
<li class="md-tabs__item">
<a href="../../security/data-leak-audit-comparison/" class="md-tabs__link">
Security & audits
</a>
</li>
<li class="md-tabs__item">
<a href="../../ideas/stack-ideas/" class="md-tabs__link">
Ideas
</a>
</li>
<li class="md-tabs__item">
<a href="../../history/traefik-migration/" class="md-tabs__link">
History
</a>
</li>
</ul>
</div>
</nav>
<main class="md-main" data-md-component="main">
<div class="md-main__inner md-grid">
<div class="md-sidebar md-sidebar--primary" data-md-component="sidebar" data-md-type="navigation" >
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--primary md-nav--lifted" aria-label="Navigation" data-md-level="0">
<label class="md-nav__title" for="__drawer">
<a href="../.." title="nuclide.systems docs" class="md-nav__button md-logo" aria-label="nuclide.systems docs" data-md-component="logo">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 8a3 3 0 0 0 3-3 3 3 0 0 0-3-3 3 3 0 0 0-3 3 3 3 0 0 0 3 3m0 3.54C9.64 9.35 6.5 8 3 8v11c3.5 0 6.64 1.35 9 3.54 2.36-2.19 5.5-3.54 9-3.54V8c-3.5 0-6.64 1.35-9 3.54"/></svg>
</a>
nuclide.systems docs
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../.." class="md-nav__link">
<span class="md-ellipsis">
Home
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../CHANGELOG/" class="md-nav__link">
<span class="md-ellipsis">
Changelog
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../RESUME/" class="md-nav__link">
<span class="md-ellipsis">
Resume
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../ct-inventory/" class="md-nav__link">
<span class="md-ellipsis">
CT inventory
</span>
</a>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle md-toggle--indeterminate" type="checkbox" id="__nav_5" >
<label class="md-nav__link" for="__nav_5" id="__nav_5_label" tabindex="0">
<span class="md-ellipsis">
Infra
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_5_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_5">
<span class="md-nav__icon md-icon"></span>
Infra
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../infra/proxmox-state/" class="md-nav__link">
<span class="md-ellipsis">
Proxmox state
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../infra/portmap/" class="md-nav__link">
<span class="md-ellipsis">
Port map
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../infra/storage/" class="md-nav__link">
<span class="md-ellipsis">
Storage
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../infra/volumes/" class="md-nav__link">
<span class="md-ellipsis">
Volumes
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../infra/docker-networks/" class="md-nav__link">
<span class="md-ellipsis">
Docker networks
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../infra/connection-hosts/" class="md-nav__link">
<span class="md-ellipsis">
Connection hosts
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../infra/proxmox-memory-audit/" class="md-nav__link">
<span class="md-ellipsis">
Memory audit
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle md-toggle--indeterminate" type="checkbox" id="__nav_6" >
<label class="md-nav__link" for="__nav_6" id="__nav_6_label" tabindex="0">
<span class="md-ellipsis">
Services
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_6_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_6">
<span class="md-nav__icon md-icon"></span>
Services
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../homelab-architecture/" class="md-nav__link">
<span class="md-ellipsis">
Homelab architecture
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../dev-environment/" class="md-nav__link">
<span class="md-ellipsis">
Dev environment (Coder + Gitea)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../mcp-gateway/" class="md-nav__link">
<span class="md-ellipsis">
MCP gateway
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../mcp-servers/" class="md-nav__link">
<span class="md-ellipsis">
MCP servers
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../pocket-id/" class="md-nav__link">
<span class="md-ellipsis">
Pocket-ID (OIDC)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../backrest/" class="md-nav__link">
<span class="md-ellipsis">
Backrest (backups)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../databases/" class="md-nav__link">
<span class="md-ellipsis">
Databases
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../secrets-manager/" class="md-nav__link">
<span class="md-ellipsis">
Secrets manager
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../comfyui/" class="md-nav__link">
<span class="md-ellipsis">
ComfyUI
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../zoraxy/" class="md-nav__link">
<span class="md-ellipsis">
Zoraxy
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../adguard-dns/" class="md-nav__link">
<span class="md-ellipsis">
AdGuard DNS
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../cloud-gpu/" class="md-nav__link">
<span class="md-ellipsis">
Cloud GPU
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../arcane/" class="md-nav__link">
<span class="md-ellipsis">
Arcane
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../doc-ingestion/" class="md-nav__link">
<span class="md-ellipsis">
Doc ingestion pipeline
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../llm-benchmark/" class="md-nav__link">
<span class="md-ellipsis">
LLM benchmark
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle md-toggle--indeterminate" type="checkbox" id="__nav_7" >
<label class="md-nav__link" for="__nav_7" id="__nav_7_label" tabindex="0">
<span class="md-ellipsis">
Security & audits
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_7_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_7">
<span class="md-nav__icon md-icon"></span>
Security & audits
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../security/data-leak-audit-comparison/" class="md-nav__link">
<span class="md-ellipsis">
Comparison
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../security/data-leak-audit-2026-05-20-tr004-cloud-sandbox/" class="md-nav__link">
<span class="md-ellipsis">
2026-05-20 · cloud-sandbox breach
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../security/data-leak-audit-2026-05-21-tr004-artifacts/" class="md-nav__link">
<span class="md-ellipsis">
2026-05-21 · artifacts (clean)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../security/audit-claude-code-meta/" class="md-nav__link">
<span class="md-ellipsis">
Self-audit (Claude Code)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../security/transcripts/audit-chat-2026-05-21/" class="md-nav__link">
<span class="md-ellipsis">
Transcript (audit session)
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle md-toggle--indeterminate" type="checkbox" id="__nav_8" >
<label class="md-nav__link" for="__nav_8" id="__nav_8_label" tabindex="0">
<span class="md-ellipsis">
Ideas
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_8_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_8">
<span class="md-nav__icon md-icon"></span>
Ideas
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../ideas/stack-ideas/" class="md-nav__link">
<span class="md-ellipsis">
Stack ideas
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle md-toggle--indeterminate" type="checkbox" id="__nav_9" >
<label class="md-nav__link" for="__nav_9" id="__nav_9_label" tabindex="0">
<span class="md-ellipsis">
History
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_9_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_9">
<span class="md-nav__icon md-icon"></span>
History
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../history/traefik-migration/" class="md-nav__link">
<span class="md-ellipsis">
Traefik (abandoned 2026-05-16)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../history/traefik-migration-docker-labels/" class="md-nav__link">
<span class="md-ellipsis">
Traefik labels (abandoned)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../history/mcp-gateway-requirements/" class="md-nav__link">
<span class="md-ellipsis">
MCP gateway requirements (superseded)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../history/scrubbing-list-2026-05-17/" class="md-nav__link">
<span class="md-ellipsis">
Scrubbing list (2026-05-17)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../history/case-study/" class="md-nav__link">
<span class="md-ellipsis">
Case study
</span>
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div class="md-sidebar md-sidebar--secondary" data-md-component="sidebar" data-md-type="toc" >
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--secondary" aria-label="Table of contents">
<label class="md-nav__title" for="__toc">
<span class="md-nav__icon md-icon"></span>
Table of contents
</label>
<ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
<li class="md-nav__item">
<a href="#synopsis" class="md-nav__link">
<span class="md-ellipsis">
Synopsis
</span>
</a>
<nav class="md-nav" aria-label="Synopsis">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#what-nexa-is-not" class="md-nav__link">
<span class="md-ellipsis">
What Nexa is not
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#core-goals" class="md-nav__link">
<span class="md-ellipsis">
Core goals
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#how-nexa-maps-to-nuclidesystems" class="md-nav__link">
<span class="md-ellipsis">
How Nexa maps to nuclide.systems
</span>
</a>
<nav class="md-nav" aria-label="How Nexa maps to nuclide.systems">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#what-is-genuinely-missing" class="md-nav__link">
<span class="md-ellipsis">
What is genuinely missing
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#phased-roadmap-mapped-to-infrastructure" class="md-nav__link">
<span class="md-ellipsis">
Phased roadmap (mapped to infrastructure)
</span>
</a>
<nav class="md-nav" aria-label="Phased roadmap (mapped to infrastructure)">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#phase-1-the-spine-no-new-containers" class="md-nav__link">
<span class="md-ellipsis">
Phase 1 — The Spine (no new containers)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#phase-2-senses-searxng-optional" class="md-nav__link">
<span class="md-ellipsis">
Phase 2 — Senses (SearXNG optional)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#phase-3-memory-two-new-containers-rest-is-curl-commands" class="md-nav__link">
<span class="md-ellipsis">
Phase 3 — Memory (two new containers; rest is curl commands)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#phase-4-motor-no-new-infrastructure" class="md-nav__link">
<span class="md-ellipsis">
Phase 4 — Motor (no new infrastructure)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#phase-5-daily-integration-ha-voice-only-new-piece" class="md-nav__link">
<span class="md-ellipsis">
Phase 5 — Daily Integration (HA Voice only new piece)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#phase-6-homelab-steward-uses-existing-arcane-proxmox-apis" class="md-nav__link">
<span class="md-ellipsis">
Phase 6 — Homelab Steward (uses existing Arcane + Proxmox APIs)
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#tool-realization-whats-not-deployed-yet-and-the-options" class="md-nav__link">
<span class="md-ellipsis">
Tool realization: what's not deployed yet and the options
</span>
</a>
<nav class="md-nav" aria-label="Tool realization: what&#39;s not deployed yet and the options">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#embeddings-phase-31" class="md-nav__link">
<span class="md-ellipsis">
Embeddings (Phase 3.1)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#web-search-phase-24" class="md-nav__link">
<span class="md-ellipsis">
Web search (Phase 2.4)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#graphdb-phase-34" class="md-nav__link">
<span class="md-ellipsis">
GraphDB (Phase 3.4)
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#open-items" class="md-nav__link">
<span class="md-ellipsis">
Open items
</span>
</a>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div class="md-content" data-md-component="content">
<article class="md-content__inner md-typeset">
<h1 id="nexa-neural-nexus-for-information-automation">Nexa — Neural Nexus for Information &amp; Automation<a class="headerlink" href="#nexa-neural-nexus-for-information-automation" title="Permanent link">&para;</a></h1>
<p><strong>Repo</strong>: <code>https://git.nuclide.systems/fkrebs/nexa</code><br />
<strong>Stack location</strong>: CT104 <code>/opt/stacks/nexa/</code><br />
<strong>Status</strong>: Designed, partially implemented — Phase 1 workflows exist; not yet deployed end-to-end.</p>
<hr />
<h2 id="synopsis">Synopsis<a class="headerlink" href="#synopsis" title="Permanent link">&para;</a></h2>
<p>Nexa is a personal AI middleware layer that sits between input sources and organisation tools. It is not a new app — it is a set of wired-together workflows running on top of services already deployed in nuclide.systems.</p>
<p><strong>Mental model:</strong>
- <strong>Memos</strong> = mouth and ear (voice interface, reply surface)
- <strong>n8n</strong> = reflexes (workflow logic, classification, routing)
- <strong>LiteLLM / SAIA</strong> = brain (language model gateway)
- <strong>Qdrant</strong> = long-term memory (semantic recall)
- <strong>Nextcloud</strong> = hands (tasks, calendar, files, mail)</p>
<p>The user types (or speaks) into Memos. A Memos webhook fires an n8n workflow. n8n classifies the input (Work vs. Personal, command vs. capture), calls LiteLLM for any reasoning, stores embeddings in Qdrant, and writes back a comment on the original memo. Side effects — task creation, calendar blocks, archive entries — go to Nextcloud.</p>
<h3 id="what-nexa-is-not">What Nexa is not<a class="headerlink" href="#what-nexa-is-not" title="Permanent link">&para;</a></h3>
<ul>
<li>A replacement for specialist UIs (Arcane, Dozzle, Grafana).</li>
<li>An active document editor.</li>
<li>A work-IT bridge (work mail/servers remain out of scope).</li>
</ul>
<h3 id="core-goals">Core goals<a class="headerlink" href="#core-goals" title="Permanent link">&para;</a></h3>
<ol>
<li><strong>Cognitive offload</strong> — sort, filter, propose; don't just store.</li>
<li><strong>Context separation</strong> — clean Work vs. Personal split enforced by LLM classification.</li>
<li><strong>Single interaction point</strong> — Memos is the only interface the user must open.</li>
<li><strong>Knowledge synergy</strong> — link ephemeral memos to deep Obsidian notes via semantic search.</li>
</ol>
<hr />
<h2 id="how-nexa-maps-to-nuclidesystems">How Nexa maps to nuclide.systems<a class="headerlink" href="#how-nexa-maps-to-nuclidesystems" title="Permanent link">&para;</a></h2>
<p>Every component Nexa depends on is already deployed. Nothing new needs to be provisioned for Phase 12.</p>
<table>
<thead>
<tr>
<th>Nexa concept</th>
<th>nuclide.systems service</th>
<th>Host</th>
<th>URL/port</th>
</tr>
</thead>
<tbody>
<tr>
<td>Interface / voice</td>
<td><strong>Memos</strong></td>
<td>CT104</td>
<td><code>https://memos.nuclide.systems</code></td>
</tr>
<tr>
<td>Workflow engine</td>
<td><strong>n8n</strong></td>
<td>CT104</td>
<td><code>http://192.168.1.40:15678</code></td>
</tr>
<tr>
<td>LLM gateway (SAIA)</td>
<td><strong>LiteLLM</strong></td>
<td>CT104</td>
<td><code>https://ai.nuclide.systems</code> (internal :4000)</td>
</tr>
<tr>
<td>Vector memory</td>
<td><strong>Qdrant</strong> (<code>qdrant_scientific</code>)</td>
<td>CT104</td>
<td>internal :6333</td>
</tr>
<tr>
<td>File / task / calendar</td>
<td><strong>Nextcloud</strong></td>
<td>CT105</td>
<td><code>https://nc.nuclide.systems</code></td>
</tr>
<tr>
<td>Link curation</td>
<td><strong>Karakeep</strong></td>
<td>CT104</td>
<td><code>https://hoarder.nuclide.systems</code></td>
</tr>
<tr>
<td>Push alerts</td>
<td><strong>ntfy</strong></td>
<td>CT104</td>
<td><code>https://ntfy.nuclide.systems</code></td>
</tr>
<tr>
<td>Note vault</td>
<td><strong>Obsidian</strong> (via Nextcloud WebDAV)</td>
<td>CT105</td>
<td><code>nc.nuclide.systems/Notizen/</code></td>
</tr>
<tr>
<td>Auth / SSO</td>
<td><strong>Pocket-ID</strong></td>
<td>CT110</td>
<td><code>https://id.nuclide.systems</code></td>
</tr>
<tr>
<td>Reverse proxy</td>
<td><strong>Zoraxy</strong></td>
<td>CT108</td>
<td>all <code>*.nuclide.systems</code></td>
</tr>
<tr>
<td>Push notifications (alerts)</td>
<td><strong>Gotify</strong></td>
<td>CT104</td>
<td>internal :10003</td>
</tr>
<tr>
<td>Social feed</td>
<td><strong>Bluesky</strong></td>
<td>external</td>
<td>API only</td>
</tr>
<tr>
<td>Mail</td>
<td><strong>Nextcloud Mail</strong> (<code>fkrebs@nucli.de</code>)</td>
<td>CT105</td>
<td>IMAP via NC</td>
</tr>
<tr>
<td>Web fetch (Phase 2.4)</td>
<td><strong>crawl4ai MCP</strong></td>
<td>CT104</td>
<td>via MCP gateway</td>
</tr>
<tr>
<td>Search (Phase 2.4)</td>
<td><strong>SearXNG</strong> (if deployed)</td>
<td>CT104</td>
<td>internal</td>
</tr>
</tbody>
</table>
<h3 id="what-is-genuinely-missing">What is genuinely missing<a class="headerlink" href="#what-is-genuinely-missing" title="Permanent link">&para;</a></h3>
<table>
<thead>
<tr>
<th>Missing component</th>
<th>Phase needed</th>
<th>Notes</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>TEI</strong> (text-embeddings-inference)</td>
<td>Phase 3.1</td>
<td>Self-hosted embeddings for Qdrant ingest. <code>bge-m3</code> model, CPU-only, ~1.1 GB RAM. Deploy as <code>nexa-embed</code> container on CT104.</td>
</tr>
<tr>
<td><strong>Ontotext GraphDB</strong></td>
<td>Phase 3.4</td>
<td>SPARQL structural memory. Deferred until Phase 3.13.3 ship. Needs ~4 GB heap on CT104.</td>
</tr>
<tr>
<td><strong><code>nexa_knowledge_text</code> Qdrant collection</strong></td>
<td>Phase 3.1</td>
<td>One <code>curl -X PUT</code> against the existing <code>qdrant_scientific</code> instance.</td>
</tr>
<tr>
<td><strong>n8n workflow import</strong></td>
<td>Phase 1</td>
<td>JSON exports are in <code>nexa-core/n8n-workflows/</code>. Import via n8n API or UI.</td>
</tr>
<tr>
<td><strong>Memos → n8n webhook</strong></td>
<td>Phase 1</td>
<td>One URL field in Memos admin: <code>https://n8n.nuclide.systems/webhook/memos</code>.</td>
</tr>
<tr>
<td><strong>LiteLLM virtual key for Nexa</strong></td>
<td>Phase 1</td>
<td>Create <code>nexa</code> user in LiteLLM admin, issue key scoped to one chat model.</td>
</tr>
<tr>
<td><strong>SearXNG</strong> (optional)</td>
<td>Phase 2.4</td>
<td>Web-search for <code>#nexa:ask --web</code>. Not deployed yet.</td>
</tr>
<tr>
<td><strong>infinity</strong> (Phase 3.2 upgrade)</td>
<td>Phase 3.2</td>
<td>Replaces TEI to add CLIP-family visual embeddings (<code>jina-clip-v2</code>).</td>
</tr>
<tr>
<td><strong><code>nexa_knowledge_visual</code> collection</strong></td>
<td>Phase 3.2</td>
<td>Second Qdrant collection for image embeddings. Schema already defined in repo.</td>
</tr>
</tbody>
</table>
<hr />
<h2 id="phased-roadmap-mapped-to-infrastructure">Phased roadmap (mapped to infrastructure)<a class="headerlink" href="#phased-roadmap-mapped-to-infrastructure" title="Permanent link">&para;</a></h2>
<h3 id="phase-1-the-spine-no-new-containers">Phase 1 — The Spine <em>(no new containers)</em><a class="headerlink" href="#phase-1-the-spine-no-new-containers" title="Permanent link">&para;</a></h3>
<p>Wire existing services together. All components are already running.</p>
<ol>
<li>Import <code>nexa-core/n8n-workflows/phase-1/</code> into n8n at <code>http://192.168.1.40:15678</code>.</li>
<li>Set Memos webhook URL → <code>https://n8n.nuclide.systems/webhook/memos</code>.</li>
<li>Create LiteLLM virtual key for <code>nexa</code> user (chat model only — no embeddings yet).</li>
<li>Fill <code>nexa-core/.env</code> with <code>MEMOS_API_KEY</code>, <code>SAIA_API_KEY</code>, <code>NC_APP_PASSWORD</code>, <code>QDRANT_API_KEY</code>.</li>
<li>Import <code>phase-2/2_1_email_butler.json</code> and attach Nextcloud Mail credentials in n8n.</li>
<li>Fire <code>#nexa:config</code> in Memos → confirms Nextcloud lists, calendar IDs, mail folder structure.</li>
</ol>
<p><strong>Milestone</strong>: Memos comment-back works. Work vs. Personal classification active. Email butler running.</p>
<h3 id="phase-2-senses-searxng-optional">Phase 2 — Senses <em>(SearXNG optional)</em><a class="headerlink" href="#phase-2-senses-searxng-optional" title="Permanent link">&para;</a></h3>
<ul>
<li><strong>2.1 Email butler</strong> — already has an n8n workflow JSON. Needs credentials in n8n.</li>
<li><strong>2.2 RSS digest</strong> — new n8n workflow polling feeds → daily summary memo.</li>
<li><strong>2.3 Bluesky antenna</strong> — liked posts → <code>nexa_knowledge_text</code> entries once Qdrant collection exists.</li>
<li><strong>2.4 Web fetch</strong><code>#nexa:ask --web</code>: SearXNG + <code>crawl4ai</code> MCP (already deployed via MCP gateway) + markitdown.</li>
<li>SearXNG not yet deployed on CT104. Deploy if 2.4 is needed.</li>
</ul>
<p><strong>Milestone</strong>: Nexa reads the web, Bluesky, and daily RSS. Morning digest appears in Memos.</p>
<h3 id="phase-3-memory-two-new-containers-rest-is-curl-commands">Phase 3 — Memory <em>(two new containers; rest is curl commands)</em><a class="headerlink" href="#phase-3-memory-two-new-containers-rest-is-curl-commands" title="Permanent link">&para;</a></h3>
<ul>
<li><strong>3.1 TEI + Qdrant collection</strong> — deploy <code>nexa-embed</code> container (CT104), create <code>nexa_knowledge_text</code>, wire TEI into LiteLLM as <code>nexa-embed</code> model, add Qdrant ingest step to n8n workflows.</li>
<li>Storage: <code>/mnt/pve/unas/services/nexa/tei-cache</code> (NFS already mounted on CT104).</li>
<li><strong>3.2 Visual collection</strong> — swap TEI → <code>infinity</code>, add <code>jina-clip-v2</code>, create <code>nexa_knowledge_visual</code>. Backfill image queue from GraphDB.</li>
<li><strong>3.3 S3 archive</strong> — Qdrant snapshots to <code>s3.nuclide.systems</code> (Garage). Blocked on Q12/Q20 decision.</li>
<li><strong>3.4 Ontotext GraphDB</strong> — SPARQL pillar. One new container on CT104, <code>GDB_JAVA_OPTS: -Xmx4g</code>. SPARQL Workbench optionally via Zoraxy → <code>graph.nuclide.systems</code>.</li>
</ul>
<p><strong>Milestone</strong>: <code>#nexa:ask</code> returns answers grounded in Obsidian notes, archived memos, mail threads.</p>
<h3 id="phase-4-motor-no-new-infrastructure">Phase 4 — Motor <em>(no new infrastructure)</em><a class="headerlink" href="#phase-4-motor-no-new-infrastructure" title="Permanent link">&para;</a></h3>
<ul>
<li>Bidirectional NC Tasks sync (Memos checkboxes ↔ Nextcloud Tasks lists).</li>
<li>Time-boxing agent: calendar-aware gap-finder in NC Calendar → proposes focus slots.</li>
<li>Karakeep curation: scheduled review workflow flags stale saved links.</li>
</ul>
<p><strong>Milestone</strong>: Memos <code>- [ ]</code> items automatically appear in the right NC Tasks list.</p>
<h3 id="phase-5-daily-integration-ha-voice-only-new-piece">Phase 5 — Daily Integration <em>(HA Voice only new piece)</em><a class="headerlink" href="#phase-5-daily-integration-ha-voice-only-new-piece" title="Permanent link">&para;</a></h3>
<ul>
<li><strong>5.1 HA Voice</strong> — Wyoming protocol bridge from HAOS (VM 100) to Nexa n8n endpoint. Needs Wyoming server container (small) or HA add-on.</li>
<li><strong>5.2 System monitoring</strong> — Proxmox + Backrest alerts → ntfy → Memos system feed. Homelab watchdog already posts to Gotify; route a copy to Memos via n8n.</li>
<li><strong>5.3 Morning digest</strong> — daily 07:00 n8n cron: mail summary + tasks + drift report + one open question from <code>docs/11</code>.</li>
</ul>
<p><strong>Milestone</strong>: Nexa speaks. Morning context summary lands in Memos without user action.</p>
<h3 id="phase-6-homelab-steward-uses-existing-arcane-proxmox-apis">Phase 6 — Homelab Steward <em>(uses existing Arcane + Proxmox APIs)</em><a class="headerlink" href="#phase-6-homelab-steward-uses-existing-arcane-proxmox-apis" title="Permanent link">&para;</a></h3>
<ul>
<li><strong>6.1 Inventory sync</strong> — n8n polls Arcane API + Proxmox API + <code>docker ps</code> on a schedule → snapshot stored in GraphDB.</li>
<li><strong>6.2 Drift detection</strong> — diff snapshot against documented desired state in <code>docs/</code> → Memos <code>[STEWARD]</code> comment.</li>
<li><strong>6.3 Steward commands</strong><code>#nexa:retire &lt;svc&gt;</code>, <code>#nexa:document &lt;svc&gt;</code>, <code>#nexa:wishlist-status</code>.</li>
<li><strong>6.4 Docs self-update</strong> — Nexa proposes <code>docs/11</code> diffs as PRs when the user answers open questions via Memos.</li>
</ul>
<p><strong>Milestone</strong>: Nexa replaces the manual "what's stale?" audit. The homelab docs update themselves.</p>
<hr />
<h2 id="tool-realization-whats-not-deployed-yet-and-the-options">Tool realization: what's not deployed yet and the options<a class="headerlink" href="#tool-realization-whats-not-deployed-yet-and-the-options" title="Permanent link">&para;</a></h2>
<p>The docs are designed around a specific tool set, but several pieces have alternatives worth considering given the current nuclide.systems stack:</p>
<h3 id="embeddings-phase-31">Embeddings (Phase 3.1)<a class="headerlink" href="#embeddings-phase-31" title="Permanent link">&para;</a></h3>
<p>The plan calls for <strong>TEI + <code>bge-m3</code></strong>. Alternatives:</p>
<table>
<thead>
<tr>
<th>Option</th>
<th>Pros</th>
<th>Cons</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>TEI + bge-m3</strong> <em>(plan)</em></td>
<td>Lightest (~500 MB image, ~1.1 GB RAM), OpenAI-compatible, single model, no LLM runtime</td>
<td>CPU-only (fine for the workload)</td>
</tr>
<tr>
<td><strong>Ollama</strong> (already on CT104?)</td>
<td>Already deployed if running</td>
<td>Heavier image, slower cold start, designed for chat not embedding throughput</td>
</tr>
<tr>
<td><strong>LiteLLM pass-through to Claude</strong></td>
<td>No new container</td>
<td>10 req/min rate limit — unusable for Qdrant ingest (2k Obsidian notes = 3 h)</td>
</tr>
<tr>
<td><strong>infinity</strong> (skip straight to Phase 3.2)</td>
<td>Supports both text and visual models simultaneously</td>
<td>Slightly more complex setup; Phase 3.2 is not urgent</td>
</tr>
</tbody>
</table>
<p><strong>Lean: deploy TEI now, swap to infinity when Phase 3.2 visual collection is needed.</strong></p>
<h3 id="web-search-phase-24">Web search (Phase 2.4)<a class="headerlink" href="#web-search-phase-24" title="Permanent link">&para;</a></h3>
<p>The plan calls for <strong>SearXNG</strong> (not yet deployed):</p>
<table>
<thead>
<tr>
<th>Option</th>
<th>Pros</th>
<th>Cons</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>SearXNG</strong> <em>(plan)</em></td>
<td>Self-hosted, no API key, privacy-preserving</td>
<td>New container to maintain</td>
</tr>
<tr>
<td><strong>Exa MCP</strong> (already in MCP gateway)</td>
<td>Already wired, no new container</td>
<td>Paid/rate-limited external service</td>
</tr>
<tr>
<td><strong>crawl4ai alone</strong></td>
<td>Already deployed (Phase 2.4 fetch step)</td>
<td>No search, only direct-URL fetch</td>
</tr>
<tr>
<td><strong>Brave Search API</strong></td>
<td>Simple, fast</td>
<td>API key + cost</td>
</tr>
</tbody>
</table>
<p><strong>Lean: use Exa MCP for Phase 2.4 (already available in the gateway), deploy SearXNG only if privacy or rate limits become a concern.</strong></p>
<h3 id="graphdb-phase-34">GraphDB (Phase 3.4)<a class="headerlink" href="#graphdb-phase-34" title="Permanent link">&para;</a></h3>
<p>The plan calls for <strong>Ontotext GraphDB</strong>:</p>
<table>
<thead>
<tr>
<th>Option</th>
<th>Pros</th>
<th>Cons</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Ontotext GraphDB</strong> <em>(plan)</em></td>
<td>Full SPARQL 1.1, production-grade, free Community Edition</td>
<td>~4 GB heap; heavyweight for a homelab</td>
</tr>
<tr>
<td><strong>Apache Jena Fuseki</strong></td>
<td>Lighter, Apache licensed, same SPARQL interface</td>
<td>Less tooling, fewer connectors</td>
</tr>
<tr>
<td><strong>Oxigraph</strong></td>
<td>Tiny Rust binary (~50 MB), OpenAPI + SPARQL</td>
<td>Newer, smaller community</td>
</tr>
<tr>
<td><strong>Skip GraphDB entirely</strong></td>
<td>Qdrant alone covers 80% of the Phase 3 value</td>
<td>Phase 6 steward commands lose structural query capability</td>
</tr>
</tbody>
</table>
<p><strong>Lean: defer until Phase 3.13.3 are running. Then re-evaluate Oxigraph vs. GraphDB based on RAM budget at that time.</strong></p>
<hr />
<h2 id="open-items">Open items<a class="headerlink" href="#open-items" title="Permanent link">&para;</a></h2>
<ul>
<li>[ ] Import Phase 1 n8n workflows (manual step — credentials required in n8n UI).</li>
<li>[ ] Wire Memos webhook → n8n.</li>
<li>[ ] Create LiteLLM <code>nexa</code> virtual key.</li>
<li>[ ] Deploy TEI container on CT104 (Phase 3.1 prerequisite).</li>
<li>[ ] Create <code>nexa_knowledge_text</code> Qdrant collection.</li>
<li>[ ] Decide SearXNG vs. Exa MCP for Phase 2.4.</li>
</ul>
<p>See <code>docs/11-open-questions.md</code> in the Nexa repo for all design decisions and their resolution status.</p>
</article>
</div>
<script>var target=document.getElementById(location.hash.slice(1));target&&target.name&&(target.checked=target.name.startsWith("__tabbed_"))</script>
</div>
<button type="button" class="md-top md-icon" data-md-component="top" hidden>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M13 20h-2V8l-5.5 5.5-1.42-1.42L12 4.16l7.92 7.92-1.42 1.42L13 8z"/></svg>
Back to top
</button>
</main>
<footer class="md-footer">
<div class="md-footer-meta md-typeset">
<div class="md-footer-meta__inner md-grid">
<div class="md-copyright">
Made with
<a href="https://squidfunk.github.io/mkdocs-material/" target="_blank" rel="noopener">
Material for MkDocs
</a>
</div>
</div>
</div>
</footer>
</div>
<div class="md-dialog" data-md-component="dialog">
<div class="md-dialog__inner md-typeset"></div>
</div>
<script id="__config" type="application/json">{"annotate": null, "base": "../..", "features": ["navigation.tabs", "navigation.sections", "navigation.expand", "navigation.top", "search.highlight", "search.suggest", "content.code.copy"], "search": "../../assets/javascripts/workers/search.2c215733.min.js", "tags": null, "translations": {"clipboard.copied": "Copied to clipboard", "clipboard.copy": "Copy to clipboard", "search.result.more.one": "1 more on this page", "search.result.more.other": "# more on this page", "search.result.none": "No matching documents", "search.result.one": "1 matching document", "search.result.other": "# matching documents", "search.result.placeholder": "Type to start searching", "search.result.term.missing": "Missing", "select.version": "Select version"}, "version": null}</script>
<script src="../../assets/javascripts/bundle.79ae519e.min.js"></script>
</body>
</html>