Skip to content

Angel Architecture v2 (R940 Platform)

Status: Planning artifact (August 2026).

Assumes: R940_PLATFORM_ARCHITECTURE.md. Prior recon: ../../../angel/ANGEL_DEPLOYMENT_PLAN.md.

Angel serves external users on a Cloudflare public edge while the local batch lane runs on angel-local for operator eval, experimental corpus work, and MCP-driven batch pipelines.


Component inventory

Public edge (unchanged — Cloudflare)

Component Host Purpose
API Worker api.angel.report Auth, vault, digest orchestration, research fetch
Pages angel.report Static Next.js export
Neon Postgres Hyperdrive binding Accounts, research corpus metadata, digest rows
R2 Worker secrets Encrypted vault ciphertext
Cron Worker triggers Daily/weekly digest (corpus-rank-lane.ts embed/rank)

Production corpus embedding/ranking runs inside the Worker during cron. It is not batch-replicated to angel-local.

Local lane (angel-local, VLAN 21 target)

Component Purpose
Git repo + Node/pnpm @angel/ai benchmark, eval harness, experimental pipelines
Postgres + pgvector Angel-owned local corpus experiments (not shared with Meridian/Sovereign)
MCP host (optional) Tool-driven batch jobs (filesystem, research fetch helpers) — Angel-scoped tools only
bws runtime Secrets injection; no committed .env
Tailscale Admin SSH

Shared compute (not on angel-local)

Component Host Purpose
Ollama inference-01 (192.168.1.40:11434) Model alias angel-mistral-7b; embed model (e.g. nomic-embed-text)

The hybrid split

  External users ──► Cloudflare edge (Workers + Neon + R2 + Pages)
                           │  Production digest: corpus-rank-lane.ts
                           │  calls Ollama via OLLAMA_BASE_URL + CF Access
                    inference-01 (via cloudflared tunnel — see below)

  Ryan (operator) ──► angel-local
                           │  LAN: http://192.168.1.40:11434
                           │  Batch/eval only; no user PHI (SECURITY.md §4.3)
                    inference-01
Lane Data allowed Serves
Cloudflare edge Ciphertext vault blobs, public research corpus in Neon, de-identified Claude calls Paying/free external users
angel-local Public corpus experiments, synthetic eval fixtures, operator batch Ryan only
inference-01 Transient prompts/responses; no durable tenant cross-talk Both lanes (different network paths)

Explicit: Angel local lane does not replace Neon for production corpus storage. angel-local pgvector is for experiments and offline R&D, not multi-tenant production serving.


How the Worker reaches Ollama after unicorn retires

Cloudflare Workers cannot call 192.168.1.40 on the LAN.

Step Action
1 Run cloudflared on inference-01 (or dedicated tunnel VM — prefer inference-01 to avoid angel-local proxy)
2 Zero Trust Access application in front of tunnel hostname (e.g. ollama.inference.last1.internal or product-specific hostname)
3 Service token → Bitwarden keys CF_ACCESS_CLIENT_ID, CF_ACCESS_CLIENT_SECRET
4 Worker secret OLLAMA_BASE_URL = tunnel HTTPS origin
5 ./scripts/secrets-push-wrangler.sh from Angel repo

Worker code already sends CF-Access-Client-Id / Secret headers when configured (packages/ai/src/ollama.ts).

Documented for completeness only. Adds failure domain and couples Angel batch VM to production digest path. Use only if inference-01 cannot run cloudflared.

angel-local LAN path

Batch jobs on angel-local use http://192.168.1.40:11434 directly with no Access headers. Separate from Worker tunnel config.


BWS integration

Consumer Pattern Bitwarden project
angel-local /etc/bitwarden/access-tokenbws run./scripts/secrets-run.sh angel
Cloudflare Worker Deploy machine runs scripts/secrets-push-wrangler.sh angel keys pushed to wrangler secrets

Local-lane keys (angel project):

Key Used by
OLLAMA_BASE_URL Worker (tunnel URL) + angel-local override (LAN URL via non-secret env file)
OLLAMA_MODEL Both; align to angel-mistral-7b
OLLAMA_TIMEOUT_MS Both
CF_ACCESS_CLIENT_ID / CF_ACCESS_CLIENT_SECRET Worker only
ANTHROPIC_API_KEY Worker + optional live eval on angel-local

Gap: OLLAMA_EMBED_MODEL used in code but missing from config/secrets.manifest.yaml — add to BWS or document default nomic-embed-text.

Profile integration: /etc/profile.d/bws.sh on angel-local for interactive shells; systemd units use EnvironmentFile=/etc/bitwarden/access-token.env.


Model policy

Policy Source
No Chinese-origin LLMs Angel .cursorrules, AI-STRATEGY.md
Production alias angel-mistral-7b Modelfile on inference-01
Legacy default qwen2.5:7b still in packages/ai/src/config.ts and BWS defaults — follow-up PR required

Meridian and Sovereign use distinct aliases on the same inference host; VRAM planning must account for concurrent model loads.


MCP integration (Angel)

When used, MCP host runs on angel-local only:

Tool scope Example servers
Allowed Read-only research corpus dirs, scheduled batch scripts, internal git status
Prohibited Bitwarden secret values, Neon production write without explicit job, cross-product tools

MCP calls inference-01 for planning steps via /api/chat with angel-mistral-7b.

Not a veteran-facing surface; no Streamlit-style chat UI.


Data sovereignty (Angel)

Store Location Tenant
Production user accounts + corpus rows Neon (Cloudflare) Angel
Vault ciphertext R2 Angel
Experimental embeddings Postgres/pgvector on angel-local Angel only
Model weights inference-01 Shared compute, no data commingling

Open questions (Angel)

  1. Tunnel hostname for Worker → inference-01 (shared vs per-product Access apps).
  2. Whether angel-local pgvector is Phase 1 or post-LastVet-cutover scope.
  3. Neon vs local for any future Angel MCP batch that writes corpus — production writes stay on edge by default.
  4. Repo follow-up to replace qwen2.5:7b defaults and populate pending BWS keys (OLLAMA_BASE_URL, CF_ACCESS_*).

Cross-references