Files
neuron/docs/architecture/04-runtime-and-deployment.md
T
will.anderson 65dd2cf097
Neuron Soul CI / build (pull_request) Failing after 4m9s
Neuron Soul CI / deploy (pull_request) Has been skipped
docs: record the correspondence corrections — grounding, faculties, wonder, consolidation
The architecture docs describe four things the design spec has since ruled out,
and each one is a supervisor invented for something that should be a property of
the substrate: grounding modelled as a subsystem rather than as the edge weight
it already is; faculties modelled as parameters of a read when abduce is a write;
wonder materialized as a maintained manifest when it is the boundary of the
structure; and consolidation implemented eleven times behind tickers when a brain
has no cron job.

Left standing rather than deleted, per the repo's own supersession discipline —
the trail of how the understanding matured is the point. Each stale passage is
marked inline and points at a new 06 §12 that transcribes the corrections and
records the measured consolidation inventory.

Authority: foundation/el, branch design/correspondence-and-censorship,
lang/spec/correspondence-and-censorship.md.
2026-08-16 13:31:27 -05:00

12 KiB
Raw Blame History

Neuron — Runtime & Deployment

Process/port topology, the end-to-end MCP request path, local vs GKE blue/green production, and a high-level view of secrets/config. Grounded in entrypoint.sh, scripts/blue-green-deploy.sh, the k8s manifests under infrastructure/platform/k8s/neuron-mcp/, and .gitea/workflows/.

Process & port topology

A running neuron is two processes in one container: the soul and the engram, started by entrypoint.sh.

 container (one pod)
 ┌──────────────────────────────────────────────────────────┐
 │  entrypoint.sh                                             │
 │    1. start engram  (background)   ── listens :8742       │
 │    2. wait /health up to 60s                              │
 │    3. exec soul (PID 1 foreground)  ── listens :7770      │
 │                                                           │
 │   soul  :7770  ──HTTP──►  engram  :8742                    │
 │   (ENGRAM_URL=http://localhost:8742, HTTP mode)           │
 │                                                           │
 │   /data  (PVC mount) ◄── engram snapshot.json             │
 └──────────────────────────────────────────────────────────┘
  • entrypoint.sh starts engram with ENGRAM_BIND=:8742 and ENGRAM_DATA_DIR=/data, polls http://localhost:8742/health (up to 60s; Autopilot cold starts are slow), then execs the soul. SOUL_ENGRAM_PATH is deliberately unset so ENGRAM_URL triggers HTTP mode (soul talks to engram over localhost HTTP, not an in-process embed).
  • EL HTTP runtime is tuned down for co-located calls: EL_HTTP_TIMEOUT_MS=10000, EL_HTTP_CONNECT_TIMEOUT_MS=3000 (entrypoint.sh).

Full port map

Port Process Role Source
7779 mcp-proxy MCP client entry; byte-forward + retry mcp-proxy/src/main.el
17779 mcp-wrapper MCP JSON-RPC ⇄ soul REST; tool catalog mcp-wrapper/src/main.el
7770 soul HTTP cognitive API + handle_request NEURON_PORT, deployment-blue.yaml
8742 engram graph store HTTP entrypoint.sh, server.el:711
7771 neuron-connectd MCP connector bridges routes.el connectd_*

Local vs prod, an important distinction. The proxy → wrapper chain is the local developer adapter: a stdio MCP client (Claude Code) needs to reach an HTTP soul, so the proxy/wrapper translate and add resilience. In production, the neuron-mcp Kubernetes Service is a ClusterIP that targets the soul's :7770 directly (service.yaml) — external access is "to be wired via Cloudflare Tunnel later" (annotation, same file). So in prod the MCP/HTTP boundary is the soul's own HTTP surface; the proxy/wrapper are not (yet) in the cluster path. (inference from the ClusterIP-only Service + the local-only proxy/wrapper binaries.)

The MCP request path (end to end)

A single tools/call from an MCP client, local topology:

 client                proxy :7779         wrapper :17779        soul :7770            engram :8742
   │  JSON-RPC             │                    │                    │                     │
   │ tools/call ─────────► │  forward+retry     │                    │                     │
   │                       │ ─────────────────► │  map tool→REST     │                     │
   │                       │                    │ ─── HTTP POST ────► │  handle_request     │
   │                       │                    │   /api/neuron/...   │   → handle_api_*    │
   │                       │                    │                    │  engram_* builtin   │
   │                       │                    │                    │ ── (HTTP mode) ───► │  activate/search/
   │                       │                    │                    │                     │  save
   │                       │                    │                    │ ◄─── nodes/edges ── │
   │                       │                    │ ◄── JSON result ── │                     │
   │                       │                    │  fire_activation    │                     │
   │                       │                    │  /recall warm-up ─► soul (side effect)    │
   │ ◄──── result ──────── │ ◄───────────────── │                    │                     │

Responsibilities per hop, and the volatility each isolates (VBD reading):

  1. proxy — transport resilience. Isolates client connection volatility (drops, retries, health) from everything above. No MCP semantics.
  2. wrapper — protocol translation. Isolates the MCP protocol from the soul: owns initialize/tools/list/tools/call, the ~90-tool catalog, and dispatch_tool_call. Also fires the fire_activation /recall side effect so tool use warms working memory.
  3. soul — cognition. handle_request dispatch → handle_api_* → engram builtins. In HTTP mode it reaches engram over localhost; otherwise embedded.
  4. engram — the graph. Spreading activation, Hebbian edges, snapshot persistence.

For the user-facing chat pipeline (not tool calls), /api/chat enters layered_cycle (soul.el) — L1 safety → L2 stewardship → L3 imprint — described in 02-components.md §3c.

Production: GKE blue/green

Neuron prod runs on GKE cluster neuron-platform (Autopilot, us-central1), namespace neuron-prod. Two Deployments, neuron-mcp-blue and neuron-mcp-green, share one Service selector that names the active slot.

  • Deployments (deployment-blue.yaml / deployment-green.yaml): one container soul, image pinned by digest (not :latest) so Argo CD can't drift the active slot to an untested build (see the pin comment in deployment-blue.yaml). strategy: Recreate — the PVC is RWO so only one pod can hold it at a time. Probes hit /health on :7770.
  • Service (service.yaml): ClusterIP neuron-mcp, port 7770 → 7770, selector: {app: neuron-mcp, slot: blue}. The blue/green script patches slot.
  • Storage (pvc.yaml): neuron-engram-data, standard-rwo (pd-balanced), 10Gi, RWO. Engram data is the single snapshot.json (~8MB active).
  • The swap (scripts/blue-green-deploy.sh): (1) set image on the target slot; (2) scale target to 1, wait for rollout; (3) patch the Service selector to the new slot (traffic flip); (4) scale the old slot to 0. Imperative kubectl for the live swap, then git-update the Argo manifests so a sync doesn't revert replica counts.
  • Backup (backup-cronjob.yaml): every 15 min, tar /data → GCS, keep 96.

    Ticker, but not consolidation (2026-08-16). Flagged only because 06 §12.4 sequences "no tickers, no cron" and an auditor sweeping for them will land here. This is ops/backup, not cognition — it does not consolidate and must not be folded into the dreamer. Local counterparts measured 2026-08-16: ai.neuron.engram-backup (StartInterval = 3600), ai.neuron.snapshot-backup (StartInterval = 900), ai.neuron.act-runner-watchdog (StartInterval = 120). Also measured: crontab -l contains zero neuron entries — every neuron schedule on this machine is launchd StartInterval / StartCalendarInterval, not cron.

Resource sizing (learned the hard way)

deployment-blue.yaml documents the memory history in comments: idle soul RSS ~860Mi; the beginSession call (loads memories + backlog + preferences) spikes past 1Gi and OOM-killed the pod mid-request (client socket closed). Current setting: requests = limits = 2Gi, cpu 250m/1000m. This is why the cognitive API projects/compacts payloads so aggressively (doc 02 §2, doc 01 axis 1) — the memory ceiling is real and close.

CI/CD

Two Gitea Actions workflows (.gitea/workflows/), serialized on a single GCE runner (concurrency: neuron-runner).

  • ci.yaml (push/PR to main):
    • build: free disk → checkout → install gcc/libcurl/gcloud → download el-runtime-c/el-runtime-h from Artifact Registry foundation-prod (elc/elb intentionally not downloaded) → compile the committed dist/soul.c directly: cc -O2 -DHAVE_CURL dist/soul.c el_runtime.c -lssl -lcrypto -lcurl -lpthread -lm -o dist/neuronstrip -s → smoke test dist/neuron --help → publish neuron-soul@<sha8> to AR (push only).
    • deploy (push-to-main only): auth GCP → get-credentials neuron-platformdetermine idle slot (the deployment at 0 replicas) → prepare artifacts (soul binary + elc + runtime for the Docker build) → clone the engram repo into ./engram/ (Dockerfile builds engram from source) → docker build+push neuron-soul:<sha>scripts/blue-green-deploy.sh --image --slot → git-push updated infra manifests → kubectl rollout status → verify neuron-mcp endpoints.
  • deploy-gke.yaml (workflow_dispatch only, slot default green) — manual rollback / forced-slot deploy without a rebuild; same auth → slot → docker → blue-green → manifest-sync → verify steps.

The Docker image (Dockerfile) is a two-stage build: stage 1 compiles engram/src/server.elengram.cengram binary via elc + cc; stage 2 is an Ubuntu 24.04 runtime (GLIBC 2.39 satisfies both binaries) with soul + engram + entrypoint.sh.

Config & secrets (high level)

Runtime configuration is injected as environment, sourced from a Kubernetes Secret neuron-soul-secrets via ExternalSecret (ESO → GCP Secret Manager, Workload Identity — no key files). From deployment-blue.yaml:

Env Meaning
NEURON_PORT soul HTTP port (7770)
NEURON_LLM_0_URL / _KEY / _FORMAT primary LLM endpoint (Anthropic format)
SOUL_CGI_ID / SOUL_IDENTITY CGI id + identity seed (→ seed_persona_from_env, soul.el:250)
NEURON_TOKEN auth token (present in env; note the HTTP dispatch does not currently check it — doc 01 Divergence 3)
NEURON_API_URL self-callback URL (http://neuron-mcp.neuron-prod.svc.cluster.local:7770)
ENGRAM_URL / ENGRAM_DATA_DIR http://localhost:8742 / /data

There is also an in-graph config surface: ConfigEntry nodes read/written by inspect_config / tune_config (neuron-api.el:616-653) — runtime-tunable persona/behavior keys stored in the engram rather than the environment.

Operational note to flag. The deployment-blue.yaml image pin comment (dated Jul 2026) records that :latest resolved to an untested build lacking a mem_save/genesis-SIGSEGV fix, which is why the active slot is pinned to a digest. Any promotion must (a) rebuild a good soul and (b) update the digest in git so Argo CD and blue-green-deploy.sh agree. (state as-of the manifests read; verify current slot before deploying.)

Performance & retrieval cost (MEASURED, 2026-08-14; ANN index PLANNED)

Measured envelope of a live mind, and where the time goes:

  • Working footprint: a live mind is ~1 GB resident.
  • Retrieval is the bottleneck. Retrieval today does brute-force cosine over all nodes~330 ms at ~13k nodes — and that scan dominates request latency (the geometric-retrieval path of 03 §Retrieval / 06 §2.5 improved quality, not the scan cost).
  • Planned fix — an HNSW approximate-nearest-neighbour index (backlog d3d0d644): turns the linear scan into ≈O(D·log N), so a 100× larger graph costs ≈1.5× rather than ≈100×. PLANNED, not built — brute-force is the live behavior; do not present the ANN speedup as shipped.