Files
bikoret/deploy/ARCHITECTURE.md
T
Scott KarpandClaude Fable 5.1 53778f372e Gitea MCP connector: MCP OAuth mode on bikoret.ch
The claude.ai connector ran the OAuth flow against a server in
static-token mode, which has no OAuth endpoints: the login ended on a
404. The proper form is gitea-mcp's -oauth mode, where each user
authorizes with their own Gitea account; it needs both origins public
over HTTPS and Gitea's ROOT_URL to be that origin.

- gitea-ingress.yaml: git.bikoret.ch → temple-council/gitea, TLS
- gitea-public-patch.yaml: ROOT_URL/DOMAIN/SSH_DOMAIN = git.bikoret.ch
  (were a name that never resolved and a released NLB IP)
- gitea-mcp-deployment.yaml: -oauth -oauth-public-url
  https://mcp.bikoret.ch -H https://git.bikoret.ch, no static token,
  probes on /healthz
- gitea-mcp-ingress.yaml: host mcp.bikoret.ch (mcp.shorashim.ch retired)
- gitea-public-apply.sh / gitea-public-verify.sh: the operator's
  DNS-gated apply and read-only verification (also in ~/.local/bin)
- KOHEN.md, deploy/ARCHITECTURE.md: the new doors and the Gitea OAuth2
  app ("Claude", PKCE, claude.ai + Claude Code redirect URIs)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-19 21:55:05 +00:00

4.5 KiB

Deployment Architecture

Generic architecture shape for a bikoret deployment. Specifics of a particular deployment (hostnames, IPs, account names, credentials) live in the operator's private notes, not in this repo.

Components

One Kubernetes namespace runs the following:

Component Runtime Purpose
vav-pipeline Elixir/OTP release Bereishit cycle, ShemaContext, Cloud, Manna, HTTP API (pe'ah, courtyard, chatzer, kodesh)
shoresh-engine Haskell binary, spawned by vav-pipeline as an Erlang Port (staged into the pod by the shoresh-engine-install init container — NOT a sidecar container; a Port is a child process of the BEAM and cannot cross a container boundary) Root activation, te'amim parsing, gematria
talmudic-engine SWI-Prolog (sidecar via Unix socket) 613 mitzvot, 13 middot, kushya generation, teiku
korban-processor Python 3.12 (sidecar) Offering protocol, eish zarah validation

All four run in the same pod. vav-pipeline is the main container; talmudic-engine and korban-processor are sidecars; shoresh-engine runs inside vav-pipeline as an Erlang Port child process, staged in by an init container.

External dependencies

Dependency Purpose Contract
Managed PostgreSQL 17+ L3 Oral Tradition (append-only) DATABASE_URL env var. Requires SSL. Role with SELECT, INSERT only — UPDATE, DELETE revoked (see migration).
(none — in the images) L1 Torah filesystem (~29 MB) Baked into every image at /mnt/torah, owned by root with no write bit. No volume. The pipeline hashes the tree at startup and every ten minutes; no cycle runs on a scroll that does not match the pinned hash.
Block-storage PersistentVolume Manna provision and its ledger (read-write, 1 GiB) Mount at /var/lib/bikoret/manna. Operator writes today.json daily; the vessel writes ledger.json.
Ingress controller + TLS cert Public HTTPS access Cert-manager with Let's Encrypt HTTP-01 is the reference setup.
Container registry Image distribution Any registry that supports Docker v2 protocol.

Kubernetes manifests

Kept in deploy/k8s/:

  • namespace.yaml — the namespace
  • configmap.yaml — non-secret configuration
  • secrets.yaml — template only; operator fills in DATABASE_URL
  • l1-volume.yaml — PV and PVC for Torah filesystem (vestigial: L1 is in the images; do not apply)
  • manna-volume.yaml — PVC for provision file
  • deployment.yaml — the pod with 3 containers + 2 init containers (shoresh-engine-install, migrate). Four images are still built and pushed; shoresh-engine ships a binary, not a running container.
  • service.yaml — ClusterIP and external LoadBalancer
  • gitea-mcp-deployment.yaml — Gitea MCP server for the claude.ai / Claude Code connector, MCP OAuth mode (users act as themselves in Gitea)
  • gitea-mcp-ingress.yaml — TLS ingress mcp.bikoret.ch for the MCP server
  • gitea-mcp-secret.yaml — template for a Gitea PAT (static-token mode only; kept for rollback)
  • gitea-ingress.yaml — TLS ingress git.bikoret.ch for Gitea itself (namespace temple-council), required by OAuth mode
  • gitea-public-patch.yaml — patch that sets Gitea's ROOT_URL/DOMAIN/SSH_DOMAIN to git.bikoret.ch
  • gitea-public-apply.sh / gitea-public-verify.sh — the operator's apply and read-only check for the four above
  • cert-manager-issuer.yaml — Let's Encrypt ClusterIssuer

Containers

Four Dockerfiles in deploy/docker/:

  • Dockerfile.vav_pipeline — multi-stage Elixir 1.16.1 / OTP 26.2.1 release
  • Dockerfile.shoresh_engine — multi-stage Haskell GHC 9.6.4 / Cabal
  • Dockerfile.talmudic_engine — SWI-Prolog 9.2.2 with socket server
  • Dockerfile.korban_processor — Python 3.12.2 slim

Configuration surface

The system reads three things from its environment:

  1. L1 Torah — in the image at $L1_MOUNT_POINT, not writable by the service user. Read and hashed at startup and every ten minutes; every cycle is gated on the last reading.
  2. Manna provision — JSON file at $MANNA_PROVISION_FILE, written by the kohen/treasurer.
  3. L3 database — connection string in $DATABASE_URL.

Nothing else is configurable. The system obeys Torah (L1 + calendar) for governance and the provision file for resources.

Seven-day inauguration

Before serving users, run the shiv'at y'mei milu'im sequence documented in KOHEN.md. Each day validates a specific layer. Partial inauguration is no inauguration.