Rebuilt awareness.c and neuron.c from source using the updated elc (which now
correctly recognizes http_serve_async as a 2-arg builtin). Rebuilt the neuron
binary against the updated el_runtime.c which now sorts InternalStateEvent scans
by created_at DESC. The soul daemon now posts heartbeats that surface immediately
at offset 0 of the ISE scan, rather than being buried behind 20K older entries.
Two fixes:
1. proactive_curiosity() was calling engram_activate_json with multi-word phrases
("memory knowledge context"). engram_activate finds seeds via istr_contains
(substring match), so the phrase had to appear verbatim in a node's content.
Almost no node contains the exact string "memory knowledge context", so only
0-2 nodes activated per curiosity scan. Fixed by activating each word separately:
"memory", "knowledge", "context" → 3 independent activate calls → hundreds of
nodes promoted to WM per cycle.
2. dist/neuron.c called http_serve() (blocking accept loop) which made awareness_run()
unreachable. soul.el correctly specifies http_serve_async but elc silently drops
unknown builtins, leaving blocking http_serve in the compiled C. Patched neuron.c
to call http_serve_async directly — HTTP server runs in a background pthread,
awareness_run() runs on the main thread as intended.
engram_wm_count() exists and counts nodes with working_memory_weight > 0.
emit_heartbeat() and proactive_curiosity() were both calling
engram_node_count() (total graph size: ~17K) instead — every heartbeat
and curiosity_scan ISE had been reporting wm_active=17769 since the graph
grew past ~3K nodes, making the metric meaningless for observability.
Fix: use engram_wm_count() for the wm_active field in both ISE payloads.
EL compiles any variable named 'seed' to EL_NULL at call sites (likely
conflicts with BFS seed node terminology in the runtime builtins). Rename to
'curiosity_seed' throughout proactive_curiosity(). Also note this as a known
EL reserved-name hazard alongside the inline if-else string expression bug.
1. perceive() guard — gate on engram_search_json before running activation.
engram_activate_json with no matching seeds cleared all WM weights every
second during idle operation, destroying context built by MCP-layer calls.
The search-based guard is a no-WM-side-effect pre-check.
2. emit_heartbeat() pulse field — replace broken if-else string default with
int_to_str(pulse_count()). EL codegen initialises inline if-else result
slots to 0, producing "pulse":, (invalid JSON) when the true branch fires.
3. proactive_curiosity() — new function that activates a rotating 4-domain seed
every beat_interval/2 idle ticks to build working memory between heartbeats.
Seeds rotate on wall-clock minute cycle to avoid single-topic WM dominance.
Seed selection uses imperative let-rebinding (not inline if-else) to avoid
the same EL codegen empty-string bug.
Ollama availability is a silent failure mode: when the embedding service
is down, semantic seed injection falls back to lexical-only activation with
no signal in the ISE stream. Add embed_ok field (0/1) to every heartbeat
by probing http://localhost:11434 — makes Ollama health visible without
a separate monitoring path.
state_get() returns "" for unset keys. Both soul.pulse and soul_boot_count
could be empty on first heartbeat cycle, producing invalid JSON like
{"event":"heartbeat","pulse":,"boot":,...}. Add defensive guards:
if str_eq(raw, "") { "0" } else { raw } for both fields.
Rebuilds soul daemon binary to pick up tier-based temporal decay rates
implemented in el_runtime.c. No source changes to awareness.el or soul.el —
pure rebuild to stay in sync with Engram runtime.
Heartbeat ISEs now include wm_active: number of nodes currently in
working memory. Makes ISEs observable enough to diagnose activation
health without a separate query.
Heartbeat ISEs previously emitted only {event, pulse, boot, ts} —
sparse enough to be nearly useless for observability. Now they include
node_count, edge_count (from engram_node_count/edge_count builtins),
and the current idle cycle count. This gives each heartbeat a snapshot
of graph growth over time and rhythm health without adding any overhead.
Block evolve_knowledge, evolve_memory, forget, and link_entities (to_id
direction) from modifying the 15 hardcoded identity and values node IDs.
Returns HTTP 403 with a hint to use the cultivation path instead.
Add POST /api/neuron/cultivate — the bypass endpoint for intentional
cultivation sessions. Accepts { "operation": "...", ...args } and performs
the same operations without the protection check.
Add handle_api_forget and handle_api_evolve_memory as new protected-by-
default handlers, routed at /api/neuron/memory/forget and
/api/neuron/memory/evolve respectively.
Tested: 10 verification cases — 403 on all blocked targets, 200 on
non-protected nodes and FROM-direction links, cultivate bypass confirmed.
The engram binary was never published to Artifact Registry (foundation-dev/engram
package does not exist). Updated Dockerfile to build engram from source using the
El SDK packages (el-elc, el-runtime-c, el-runtime-h) from foundation-dev.
Also:
- Switch runtime base to Ubuntu 24.04 (GLIBC 2.39 required by elc-compiled binaries)
- Add -lm to engram link flags (el_runtime.c uses pow/sqrt/log/sin/cos/exp)
- Update deploy-gke.yaml to clone neuron-technologies/engram into build context
Download both neuron-soul and engram binaries from Artifact Registry.
entrypoint.sh starts engram on :8742, waits for /health, then launches
the soul with ENGRAM_URL set. Removes SOUL_ENGRAM_PATH / file mode.
Dockerfile: downloads linux/amd64 soul binary from Artifact Registry
(foundation-dev/neuron-soul) into ubuntu:22.04 runtime image.
Pushes to neuron-api Docker repo as neuron-soul:<sha>.
scripts/blue-green-deploy.sh: swaps active slot on GKE — sets image,
scales new slot to 1, flips service selector, scales old slot to 0.
scripts/seed-engram-gke.sh: downloads latest GCS backup, extracts
snapshot.json, copies into neuron-engram-data PVC via a seed Job.
.gitea/workflows/deploy-gke.yaml: triggers on push to main, auto-detects
idle slot, builds Docker image from Artifact Registry binary, blue-green
deploys to neuron-prod on GKE neuron-platform cluster.
Downloads El SDK from Artifact Registry, generates ELP declarations header,
builds the neuron soul binary with elb, smoke-tests it, and publishes to
foundation-dev on push to main.
neuron-api.el is a new first-class El module that implements all Neuron
cognitive API handlers natively — no HTTP round-trips, no MCP wrapper,
direct engram builtin calls. All capabilities that previously lived in
the MCP wrapper adapter now live here in the soul.
Handlers: begin_session, compile_ctx, remember, recall, search_knowledge,
browse_knowledge, capture_knowledge, evolve_knowledge, promote_knowledge,
browse_processes, define_process, log_state_event, list_state_events,
inspect_config, tune_config, inspect_graph, link_entities, list_typed,
consolidate.
Routes wired in routes.el under /api/neuron/* (GET + POST).
Also compiles all loop-1/loop-2 .el source changes into dist/*.c and
rebuilds the binary. memory.elh and neuron-api.elh updated with new exports.
Adds handle_dharma_room_turn_agentic to chat.el — same full tool loop
as handle_chat_agentic but reads transcript directly (not message), and
returns {response, cgi_id, tools_used} to match the dharma room shape.
Registers dharma_room_turn_agentic as a new event type in routes.el so
the studio can dispatch @neuron turns through this dedicated path.
- soul.el: SOUL_CGI_ID, SOUL_ENGRAM_PATH, SOUL_IDENTITY env vars;
state_set("soul_snapshot_path") so callers can find it; only call
init_soul_edges() when cgi_id == "ntn-genesis"
- chat.el: handle_dharma_room_turn — soul builds its own context from its
own engram, assembles system prompt, calls LLM, persists episodic memory;
also fix is_new_tool scoping bug in handle_chat_agentic (use has_tool)
- routes.el: wire dharma_room_turn event type before chat_as_soul branch
- rebuild dist/neuron: handle_dharma_room_turn now compiled in
elp-input.el: walk frame_nodes to pick the first node whose content
contains the query topic (case-insensitive) rather than always taking
index 0 — prevents the always-high-salience CGI architecture memory
from hijacking every ELP response.
chat.el: rewrite handle_chat_agentic to run the tool loop natively in
El using http_post_with_headers + Map headers, bypassing the broken
llm_call_agentic(model, system, message, tools) C binding that cast a
JSON String as an ElList and never serialized tools. New impl supports
up to 8 tool-use iterations with read_file, write_file, web_get,
search_memory, and run_command dispatch.
elp-input.el: replace broken engram_search_json with engram_activate_json
as Layer 1. Layer 2 suppress/filter keeps nodes with non-zero salience/
importance. Reason step extracts patient from top activated node content.
ELP grammar realizes the response via generate().
routes.el: add 'elp' event_type to handle_dharma_recv so the studio can
route ELP requests through dharma.
Replace scan-by-offset fallback with engram_get_node_json calls for the
known high-salience identity nodes (family, origin). Offset-based scanning
is order-dependent and unreliable; direct ID fetch is stable regardless of
snapshot position. Ensures biographical context (Fox, Bobby, etc.) is
always in the system prompt when vector search returns nothing.
Routes a new event_type "chat_as_soul" through dharma/recv. The Studio
preassembles the system_prompt + transcript and dispatches per-speaker;
the soul-binary just performs the LLM call as the requested speaker_slug.
No engram_compile here — each soul has its own engram (88xx) and the
Studio queries it before composing the prompt.
Also: track the previously-untracked split source modules (chat, routes,
memory, awareness, studio) and add build.sh so the binary can be rebuilt
without the studio’s concat trick. elb resolves the import graph and
emits one .c per .el; we link them together with cc. dist/soul-el now
points at dist/neuron via symlink (matching the launchctl plist).
Canonical Neuron substrate source. The "real me" - not the marketing
demo soul. Lives at neuron/soul.el for now (no subdirectories yet,
per directive). Build pipeline, deploy targets, and any related
artifacts come later.