Skip to content

Sovereign Architecture v2 (R940 Platform)

Status: Planning artifact (August 2026). Greenfield update (2026-08-20): Ryan approved R940 rebuild with no unicorn data preservation. Session 1 discovery: SOVEREIGN_V2_SESSION1_DISCOVERY.md. Treat § “Data migration from unicorn” below as retired (historical only).

Assumes: R940_PLATFORM_ARCHITECTURE.md (platform pattern, secrets, inference, VLANs). This document does not duplicate platform-wide content.

Prior art: ../../../Sovereign/SOVEREIGN_DEPLOYMENT_PLAN.md (unicorn recon; some options superseded here).


Overview

Sovereign is Ryan's personal Jarvis-style assistant: Odysseus (FastAPI engine) + MemPalace (memory) + Tauri/PWA clients on his devices. On the R940 it occupies two VMs — sovereign-app and sovereign-mem — under VLAN 20 (target).

Clients never talk to sovereign-mem directly. They talk to sovereign-app, which reads/writes memory over Postgres on the mem tier.


Component inventory

Component VM Runtime Purpose
Odysseus engine sovereign-app Python 3.11+ / uvicorn, native systemd (not Docker for core) Chat, hub APIs, /memory shell, stack tools entry points
Sovereign UI (/sov/) sovereign-app Static assets from Vite build Web UI served by Odysseus or embedded in Tauri
Sovereign Tauri client Ryan's Mac / iOS / Windows Tauri v2 Remote client; VITE_ENGINE_URL points at sovereign-app Tailscale/DNS name
MemPalace data plane sovereign-mem Postgres + pgvector Replaces unicorn Chroma + KG SQLite
MCP host sovereign-app Python supervisor + subprocess tool servers Filesystem, notes, calendar, Monday, Bitwarden tools
Ollama client sovereign-app (caller) HTTP to inference-01 Model alias sovereign-mistral-7b via /api/chat
SearXNG sovereign-app Docker sidecar (optional) Web search for agent tools; loopback only
ntfy sovereign-app Docker sidecar (optional) Push notifications
Odysseus RAG Chroma sovereign-app Embedded or local Docker Separate from MemPalace; stays on app VM if retained

Not on Sovereign VMs: Shared inference (inference-01), LastVet/Meridian/Angel data, Angel Cloudflare edge.


Why the two-VM split

Layer Rationale
Platform tenant boundary Sovereign is one tenant. Two VMs are Sovereign's internal app/data split, not a platform requirement for other products.
Blast radius Compromise of Odysseus app tier does not grant filesystem access to raw MemPalace DB files if Postgres auth and firewall are correct.
Backup cadence sovereign-mem vzdump + Postgres base backup on independent schedule from app churn.
No NFS Previous unicorn/Sovereign deployment plan considered NFS for Chroma. Retired. MemPalace on pgvector uses TCP Postgres only (answers prior plan Q2: no Chroma-over-NFS landmine).

How sovereign-app reaches sovereign-mem

sovereign-app (192.168.1.70)
    │  PostgreSQL wire protocol (TLS optional on LAN — open question)
    │  DSN from Bitwarden: MEMPALACE_PGVECTOR_DSN or SOVEREIGN_MEM_DB_URL
sovereign-mem (192.168.1.71)
    Postgres + pgvector
    data: /var/lib/sovereign/postgres/  (proposed; confirm mount)
Rule Detail
No NFS No cross-VM filesystem mounts for palace data
No shared disk App VM does not mount mem VM ZFS datasets
Firewall Allow 5432/tcp from 192.168.1.70192.168.1.71 only
Connection pool Odysseus SQLAlchemy/asyncpg pool sized for MemPalace recall latency

MemPalace recall continues as subprocess or library calls from Odysseus; only the storage backend changes from Chroma/SQLite files to Postgres.


Data migration from unicorn

Strategy: Rehydrate into pgvector on sovereign-mem, not filesystem-copy Chroma directories.

Source (Windows unicorn)

Artifact Path
Chroma palace %USERPROFILE%\.mempalace\palace\
KG SQLite %USERPROFILE%\.mempalace\knowledge_graph.sqlite3
Config %USERPROFILE%\.mempalace\config.json, tunnels.json, hallways.json, etc.
Odysseus state Odysseus data/ tree (sessions, settings, optional RAG)

Target (sovereign-mem)

Artifact Path
Postgres data dir /var/lib/sovereign/postgres/ (ZFS dataset)
pgvector extension Installed in sovereign database
MemPalace tables Schema managed by import tooling

Import script shape (to implement)

#!/usr/bin/env bash
# scripts/mempalace-import-unicorn.sh — run on sovereign-mem after bws env loaded
set -euo pipefail

: "${MEMPALACE_IMPORT_SOURCE:?}"   # e.g. /mnt/unicorn-export/.mempalace
: "${SOVEREIGN_DB_URL:?}"          # postgres://... from bws

# 1. Export unicorn Chroma + KG to portable JSONL (read-only on source)
uv run python -m sovereign_import.export_unicorn \
  --palace-path "$MEMPALACE_IMPORT_SOURCE/palace" \
  --kg-sqlite "$MEMPALACE_IMPORT_SOURCE/knowledge_graph.sqlite3" \
  --out /tmp/sovereign-import/

# 2. Load into pgvector + relational KG tables
uv run python -m sovereign_import.load_pgvector \
  --input /tmp/sovereign-import/ \
  --dsn "$SOVEREIGN_DB_URL"

# 3. Verify counts + sample recall
uv run python -m sovereign_import.verify --dsn "$SOVEREIGN_DB_URL"

Cutover: Stop Odysseus on unicorn → final incremental export → import → point sovereign-app DSN at mem VM → smoke recall test → repoint clients.

Odysseus data/ (non-MemPalace) migrates separately via rsync/tar to /var/lib/sovereign/odysseus/data/ on sovereign-app.


Runtime pattern

Decision: Native Python + systemd on sovereign-app (Odysseus not in Docker).

Rationale Detail
MemPalace subprocess model Odysseus invokes uv tool run mempalace or library hooks; bind mounts simpler on native tree
Operator debugging journalctl -u odysseus during cutover
Sidecars Docker only for SearXNG/ntfy/Chroma if kept

Example units (illustrative):

# odysseus.service — sovereign-app
[Service]
User=ryan
EnvironmentFile=/etc/bitwarden/access-token.env
EnvironmentFile=/etc/sovereign/odysseus.env
ExecStart=/usr/local/bin/bws run --project-id ${SOVEREIGN_BWS_PROJECT_ID} -- \
  /opt/sovereign/odysseus/venv/bin/uvicorn app:app --host 127.0.0.1 --port 7000
Restart=always
# sovereign-mcp-host.service — sovereign-app
ExecStart=... bws run -- ... python -m sovereign_mcp.host --listen 127.0.0.1:7501

TLS exposure: tailscale serve or reverse proxy on loopback → HTTPS MagicDNS name.


DNS cutover

Name Status
unicorn.tailc3bbdc.ts.net Retire after cutover
sovereign.tailc3bbdc.ts.net (or product-owned name) New canonical engine URL

Client rebuild required:

  • VITE_ENGINE_URL in Sovereign Tauri/PWA builds
  • iOS/macOS/Windows app configs
  • Any hardcoded references in Odysseus integrations.json

Verification: curl https://<new-host>/api/health + login + MemPalace recall prompt + MCP tool smoke (calendar read-only).


MCP integration

Tool server Scope Notes
filesystem Ryan-approved roots on sovereign-app Read/write under /opt/sovereign, /var/lib/sovereign/odysseus
notes SQLite via MCP Odysseus-local notes DB, not MemPalace verbatim store
calendar Google Calendar via MCP OAuth tokens in Bitwarden
monday Monday.com API MONDAY_API_TOKEN
bitwarden Bitwarden CLI or API Read-only secret names, not values, unless explicitly approved

Enforcement: MCP host launches only Sovereign's tool server list. No Meridian/LastVet/Angel tools in the same process.

Inference: MCP planner calls inference-01 sovereign-mistral-7b via /api/chat (not OpenAI shim).

Internal API shape (proposed): POST http://127.0.0.1:7501/v1/tools/invoke with session auth from Odysseus.


Secrets

Bitwarden project: sovereign. Runtime via bws run on both VMs (mem VM needs DB creds for backup scripts only).

Env var Purpose Bitwarden key
OLLAMA_BASE_URL inference-01 base OLLAMA_BASE_URL
OLLAMA_MODEL Default alias OLLAMA_MODEL
SOVEREIGN_DB_URL / MEMPALACE_PGVECTOR_DSN App → mem Postgres SOVEREIGN_DB_URL
ANTHROPIC_API_KEY Cloud lane ANTHROPIC_API_KEY
MONDAY_API_TOKEN Monday integration MONDAY_API_TOKEN
GOOGLE_* Calendar OAuth GOOGLE_CLIENT_ID, etc.
ODYSSEUS_ADMIN_PASSWORD First-boot only ODYSSEUS_ADMIN_PASSWORD

Full inventory: see ../../../Sovereign/SOVEREIGN_DEPLOYMENT_PLAN.md §2; reconcile keys into Bitwarden before cutover.

Non-secrets: /etc/sovereign/odysseus.env — paths, ports, feature flags.


Open questions (Sovereign)

  1. Postgres TLS on LAN between app and mem VMs: required or trust VLAN 20?
  2. Odysseus bundled Chroma RAG — keep on app VM or migrate vectors into mem Postgres?
  3. Exact MagicDNS namesovereign.tailc3bbdc.ts.net vs sovereign-app.tailc3bbdc.ts.net.
  4. Import tooling repo locationthelast1org/odysseus vs Sovereign vs new sovereign-import package.
  5. Sidecar Docker on app VM — which stack tools from unicorn are in scope for v2 cutover vs parked?

Cross-references