STATUS: STALE — many claims (PVE version, Pocket-ID port, Dockge as docker manager) no longer accurate. Source of truth is /CLAUDE.md and /docs/services/. This file kept for the original nexa-stack design notes only.
Instructions for Claude (and other agents)¶
This file tells future automated runs what they need to know about this repo.
Repo conventions¶
- Documentation: all docs live in
/docs/and are numbered. Entry point isdocs/index.md. When you add a doc, give it the next freeNN-prefix and add a row to the index TOC. - Runtime artifacts: live in
nexa-core/(workflows, prompts, configs, scripts). Don't put.mddocumentation in there — link from/docs/instead. - Source-of-truth: if a doc duplicates content from
nexa-core/config/*.md, delete the duplicate. Single source of truth.
Real infrastructure (verified from screenshots, May 2026)¶
- Proxmox host
nucat192.168.1.20:8006(PVE 9.1.9, kernel 6.17.13-4-pve, EFI). - Hardware: 22 threads (Intel Core Ultra 7 155H, 1 socket), 62 GiB RAM, 1.64 TiB disk.
- Steady state: ~32 GiB used (≈24 GiB of which is ZFS ARC, tunable via
zfs_arc_max), CPU load <2.0, IO delay <0.05%. - LXC 102 dns (AdGuard) — internal DNS, rewrites for
*.nuclide.systems. - LXC 103 backrest — backup orchestration.
- LXC 104 docker — main docker host at
192.168.1.40, hostnamedocker, OS Debian 13. Unprivileged, originally provisioned from the Dockge helper-script template, but Arcane is the active docker manager today (Dockge is stale, slated for retirement — see docs/12 #33). Dozzle is the live log viewer. Allocated: 16 CPU, 31.25 GiB RAM (25% used), 8 GiB swap, 200 GiB boot disk (47.7% used). Storage = Ubiquiti UNAS Pro at192.168.1.31(UniFi Drive 4.1.16 on UniFi OS 5.0.17, SFP+ 10 GbE, RAID 6, 19.96 TiB raw / 2.05 TiB used). NFS-exported at/var/nfs/shared/storage, mounted by Proxmox at/mnt/pve/unas, also exposed via SMB atsmb://192.168.1.31/<share>(Mac) /\\192.168.1.31\<share>(Win).
Standard pattern for docker volumes (verified via Karakeep, Q19): plain host bind-mount of /mnt/pve/unas/services/<svc>/<vol> from inside LXC 104. No driver_opts, no CIFS, no credentials in the compose. Karakeep, Immich and the rest do exactly this. Nexa follows suit. SMB-as-docker-volume is documented as an escape hatch only (docs/12 #27) for services that hit Nextcloud-style NFS issues — Nexa doesn't, so we don't use it.
Storage-layer snapshots are NOT configured on UNAS Pool 1 ("Click to Setup" in the UniFi Drive dashboard). All 2 TB of homelab data has no point-in-time protection at the storage layer — Backrest covers files, not "the whole pool last Tuesday". Highest-leverage fix in the homelab right now (docs/12 #38).
UNAS layout conventions (homelab-wide, all docker containers follow them):
- services/<svc>/ is the general docker config store — every container in LXC 104 binds its persistent data here. Existing tenants observed: immich, karakeep, nextcloud, ntfy, paperless-ai, pocketid, shelfmark, stremio, traccar, vaultwarden, gluetun. Stale (retire, do not consume): services/siyuan/ (migrated to Obsidian), services/open-webui/ (unused — LobeHub is the active LLM UI), and services/dockge/ if it exists (retired in favor of Arcane). Nexa MUST follow the same pattern: services/nexa/{qdrant,tei-cache,graphdb,...}. Don't invent a parallel layout.
- backup/<svc>/ — per-service backups (existing: home-assistant tars, immich pgdump, nextcloud borg). Nexa snapshots → backup/nexa/.
- media/, code/, _sortMe/, dump/, test_perm — user data, not Nexa's concern.
- Before deploying any Nexa container, READ AN EXISTING STACK in Arcane (e.g. karakeep or immich) to confirm the exact mount syntax in use — driver name, share path, credential injection pattern. Match it. The actual NFS export root is /var/nfs/shared/storage; the SMB share name is still TBD — see Q19 in docs/11.
Hard-blocklist for any Nexa indexer / agent (never read these paths or matching glob):
- _sortMe/wallet/** — contains PGP keys + bitcoin wallet files.
- Any path matching *.gpg, *.asc, *.key, *.pem, id_rsa*, *wallet*, *.kdbx, *credentials*, *secret*.
- The Nextcloud appdata dir (services/nextcloud/appdata_*) — Nextcloud-internal, not user content. Intel iGPU passthrough is configured but currently broken — see docs/12 #26.
- LXC 105 nextcloud — Nextcloud at nc.nuclide.systems.
- LXC 106 octoprint — currently Exited; flagged in docs/11.
- LXC 108 zoraxy — reverse proxy at 192.168.1.4:8000, TLS for *.nuclide.systems.
- VM 100 haos — Home Assistant.
- Already-running services on docker host (don't redeploy):
- Memos :5230, n8n :5678, LiteLLM :4000 (UI LobeHub :3210), Qdrant (qdrant_scientific), ntfy :7998, Karakeep (legacy alias hoarder.nuclide.systems), Vaultwarden :11001, Pocket-ID :1411, Immich, Audiobookshelf, Paperless-ngx, Traccar, Prowlarr, plus MCP containers (crawl4ai-mcp, markitdown-mcp, papersearch-mcp).
- Octoprint (LXC 106) is intentionally powered down most of the time. Phase-5 monitoring must skip names matching octoprint* rather than alert on its Exited state.
- Obsidian vault lives inside Nextcloud at nc.nuclide.systems/Notizen/ (multi-device sync via Nextcloud client). Nexa accesses it via WebDAV — read-only, no filesystem mount. Ignore list: .copilot/, .copilot-index/, .smart-env/, .caldav-sync/, assets/ (visual queue, Phase 3.2), Templates/, BMO/, Excalidraw/. Index target: Notizen/**/*.md.
- Nextcloud Tasks lists & calendars (German names, may grow over time):
- Persönlich → Personal context.
- DLR → Work context (DLR is the user's employer).
- Einkaufsliste → Shopping.
- Wunschliste → Wishes.
Lists are discovered by name at runtime (Qdrant _config namespace caches name → id). Never hardcode IDs. The discovery workflow runs daily and on cache-miss; new lists added in Nextcloud are honoured automatically next refresh.
- Mail = Nextcloud Mail, single account fkrebs@nucli.de. No separate IMAP entry. The Waiting folder is a manual user signal — items there are skipped from digests.
- Backup model is 3-2-1: UNAS native snapshots → s3.nuclide.systems (warm, on-site) → encrypted off-site cold tier (provider TBD, Jottacloud is the user's candidate — see Q20). Always restic/rclone-crypt before upload — third-party provider sees only ciphertext. Don't propose alternative backup paths without checking docs/12 #37 first.
- Auth = Pocket-ID SSO is global at the Zoraxy layer. Don't add app-level basic-auth to Nexa surfaces; UIs inherit SSO. Machine-to-machine still uses API keys / app passwords.
- Decided for Nexa (don't re-litigate without user input):
- Vector store: reuse qdrant_scientific with collections suffixed by modality (nexa_knowledge_text, nexa_knowledge_visual).
- Embeddings staged: Phase 3.1 TEI + BAAI/bge-m3 (text-only, 1024-dim). Phase 3.2 swap to infinity and add jinaai/jina-clip-v2 (768-dim, joint text+image space). All forward-compat fields (modality, media_uri, graph_iri, nexa:pendingVisualIndex) exist from 3.1 — adding the visual collection is additive.
- Graph store: Ontotext GraphDB (SPARQL/RDF), Phase 3.4. RDF schema in docs/08 already includes nexa:modality / nexa:mediaUri / nexa:vectorCollection / nexa:pendingVisualIndex.
- Chat model: SAIA via LiteLLM virtual key.
When working on Nexa¶
- Read
docs/index.mdfirst — it's the navigator. - Open questions first. Before writing code or workflow JSON, scan
docs/11-open-questions.md. If your task touches an unanswered Q, stop and ask rather than picking a default. Append new blockers to that doc as[ ] Q-NN. - Optimization findings. When you spot infrastructure improvements, add them to
docs/12-optimization-opportunities.mdas a numbered bullet — don't just mention them in commit messages. - Never inline secrets in workflow JSON or
.envcommitted to git. Use n8n credentials, LiteLLM virtual keys, or (longer term) Vaultwarden. - Keep deployment minimal. The default answer to "do we need a new container?" is no — the existing stack covers most needs.
Branch policy¶
- This branch is
claude/organize-docs-deployment-7N4v2. Push only here unless told otherwise. - New work for an unrelated feature → new branch under
claude/<topic>.
Quick links¶
- docs/index.md
- docs/09-deployment.md — most-touched file during bring-up
- docs/11-open-questions.md — read before assuming defaults