// server.el — Engram HTTP server. // // Engram is the in-process graph store. The runtime owns the data; this // file is the thin HTTP face. Every route maps to one or two engram_* // builtins. There is no SQL, no db layer, no SQLite — the runtime IS the // database. // // Built and linked with: // elc src/server.el > ../dist/engram.c // cc -std=c11 -O2 \ // -I/Users/will/Development/neuron-technologies/foundation/el/lang/releases/v1.0.0-20260501 \ // -I/opt/homebrew/Cellar/liboqs/0.15.0/include \ // -I/opt/homebrew/opt/openssl@3/include \ // -L/opt/homebrew/Cellar/liboqs/0.15.0/lib \ // -L/opt/homebrew/opt/openssl@3/lib \ // -lcurl -lpthread -loqs -lssl -lcrypto \ // -o ../dist/engram ../dist/engram.c \ // /Users/will/Development/neuron-technologies/foundation/el/lang/releases/v1.0.0-20260501/el_runtime.c // ./dist/engram // // Configuration via environment: // ENGRAM_BIND — host:port (default :8742) // ENGRAM_API_KEY — bearer auth (optional) // ENGRAM_DATA_DIR — snapshot location (default ~/.neuron/engram) // ── Helpers ─────────────────────────────────────────────────────────────────── fn parse_port(bind: String) -> Int { // ":8742" → 8742; "0.0.0.0:8742" → 8742; bare "8742" → 8742 let colon: Int = str_index_of(bind, ":") if colon < 0 { return str_to_int(bind) } let after: String = str_slice(bind, colon + 1, str_len(bind)) return str_to_int(after) } fn ok_json() -> String { "{\"ok\":true}" } fn err_json(msg: String) -> String { "{\"error\":\"" + msg + "\"}" } fn strip_query(path: String) -> String { let q: Int = str_index_of(path, "?") if q < 0 { return path } str_slice(path, 0, q) } fn query_param(path: String, key: String) -> String { let q: Int = str_index_of(path, "?") if q < 0 { return "" } let qs: String = str_slice(path, q + 1, str_len(path)) let needle: String = key + "=" let pos: Int = str_index_of(qs, needle) if pos < 0 { return "" } let after: String = str_slice(qs, pos + str_len(needle), str_len(qs)) let amp: Int = str_index_of(after, "&") if amp < 0 { return after } str_slice(after, 0, amp) } fn query_int(path: String, key: String, default_val: Int) -> Int { let v: String = query_param(path, key) if str_eq(v, "") { return default_val } str_to_int(v) } // Extract last path segment after a known prefix: extract_id("/api/nodes/abc-123", "/api/nodes/") → "abc-123" fn extract_id(path: String, prefix: String) -> String { let clean: String = strip_query(path) if !str_starts_with(clean, prefix) { return "" } let after: String = str_slice(clean, str_len(prefix), str_len(clean)) let slash: Int = str_index_of(after, "/") if slash < 0 { return after } str_slice(after, 0, slash) } // ── Routes ──────────────────────────────────────────────────────────────────── fn route_stats(method: String, path: String, body: String) -> String { engram_stats_json() } fn route_create_node(method: String, path: String, body: String) -> String { let content: String = json_get_string(body, "content") let node_type: String = json_get_string(body, "node_type") if str_eq(node_type, "") { let node_type = "Memory" } let salience: Float = json_get_float(body, "salience") if salience == 0.0 { let salience = 0.5 } let id: String = engram_node(content, node_type, salience) // Auto-link: find semantically related existing nodes and form edges. // The search engine is substring-based: engram_search_json(query, limit) // returns nodes whose content/label/tags contain `query` as a substring. // Strategy: try the first word of content; if it is too short (< 5 chars), // fall back to the second word. Connect the top 5 unique matches (no self). let auto_linked: Int = 0 let clen: Int = str_len(content) if clen >= 20 { // Locate first and second spaces to extract first two words. let sp1: Int = str_index_of(content, " ") let w1end: Int = sp1 if sp1 < 0 { let w1end = clen } let word1: String = str_slice(content, 0, w1end) // Pick the search term: use word1 if >= 5 chars, else try word2. let search_term: String = "" if str_len(word1) >= 5 { let search_term = word1 } if str_eq(search_term, "") { if sp1 >= 0 { let rest: String = str_slice(content, sp1 + 1, clen) let sp2: Int = str_index_of(rest, " ") let w2end: Int = sp2 if sp2 < 0 { let w2end = str_len(rest) } let word2: String = str_slice(rest, 0, w2end) if str_len(word2) >= 5 { let search_term = word2 } } } if !str_eq(search_term, "") { let results: String = engram_search_json(search_term, 10) let n: Int = json_array_len(results) let i: Int = 0 while i < n { if auto_linked >= 5 { let i = n } if auto_linked < 5 { let elem: String = json_array_get(results, i) let rid: String = json_get_string(elem, "id") if !str_eq(rid, "") { if !str_eq(rid, id) { engram_connect(id, rid, 0.5, "related") let auto_linked = auto_linked + 1 } } let i = i + 1 } } } } "{\"id\":\"" + id + "\",\"content\":\"" + content + "\",\"node_type\":\"" + node_type + "\",\"auto_linked\":" + int_to_str(auto_linked) + "}" } fn route_get_node(method: String, path: String, body: String) -> String { let id: String = extract_id(path, "/api/nodes/") if str_eq(id, "") { return err_json("missing id") } return engram_get_node_json(id) } fn route_scan_nodes(method: String, path: String, body: String) -> String { let limit: Int = query_int(path, "limit", 50) let offset: Int = query_int(path, "offset", 0) let nt: String = query_param(path, "node_type") if str_eq(nt, "") { return engram_scan_nodes_json(limit, offset) } return engram_scan_nodes_by_type_json(nt, limit, offset) } // route_scan_edges — bulk export of all edges as a JSON array. Implemented // via engram_save → fs_read of the canonical on-disk snapshot, which the // runtime keeps in lockstep with the in-memory graph. Live against the // running graph, not a stale export. fn route_scan_edges(method: String, path: String, body: String) -> String { let dir: String = env("ENGRAM_DATA_DIR") if str_eq(dir, "") { let dir = "/tmp/engram" } let snap_path: String = dir + "/snapshot.json" engram_save(snap_path) let snap: String = fs_read(snap_path) if str_eq(snap, "") { return "[]" } // json_get truncates at the first delimiter (no bracket depth tracking), // so for the edges ARRAY value we need json_get_raw, which honors // brackets and returns the full sub-JSON. let edges: String = json_get_raw(snap, "edges") if str_eq(edges, "") { return "[]" } return edges } fn route_search(method: String, path: String, body: String) -> String { let q: String = "" if str_eq(method, "GET") { let q = query_param(path, "q") } else { let q = json_get_string(body, "query") } let limit: Int = query_int(path, "limit", 20) if limit == 0 { let limit = json_get_int(body, "limit") } if limit == 0 { let limit = 20 } return engram_search_json(q, limit) } fn route_activate(method: String, path: String, body: String) -> String { let q: String = "" let depth: Int = 3 if str_eq(method, "GET") { let q = query_param(path, "q") let depth = query_int(path, "depth", 3) } else { let q = json_get_string(body, "query") let bd: Int = json_get_int(body, "depth") if bd > 0 { let depth = bd } } return "{\"results\":" + engram_activate_json(q, depth) + "}" } fn route_create_edge(method: String, path: String, body: String) -> String { let from_id: String = json_get_string(body, "from_id") let to_id: String = json_get_string(body, "to_id") let relation: String = json_get_string(body, "relation") if str_eq(relation, "") { let relation = "associates" } let weight: Float = json_get_float(body, "weight") if weight == 0.0 { let weight = 0.5 } engram_connect(from_id, to_id, weight, relation) "{\"ok\":true,\"from_id\":\"" + from_id + "\",\"to_id\":\"" + to_id + "\",\"relation\":\"" + relation + "\"}" } fn route_neighbors(method: String, path: String, body: String) -> String { let id: String = extract_id(path, "/api/neighbors/") if str_eq(id, "") { return err_json("missing id") } let depth: Int = query_int(path, "depth", 1) return engram_neighbors_json(id, depth, "both") } fn route_strengthen(method: String, path: String, body: String) -> String { let id: String = json_get_string(body, "node_id") if str_eq(id, "") { return err_json("missing node_id") } engram_strengthen(id) ok_json() } fn route_forget(method: String, path: String, body: String) -> String { let id: String = extract_id(path, "/api/nodes/") if str_eq(id, "") { return err_json("missing id") } engram_forget(id) ok_json() } fn route_decay(method: String, path: String, body: String) -> String { engram_apply_decay_json() } fn route_export(method: String, path: String, body: String) -> String { let dir: String = env("ENGRAM_DATA_DIR") if str_eq(dir, "") { let dir = "/tmp/engram" } // Write binary checkpoint let db_path: String = dir + "/engram.db" engram_write_binary_el(db_path) // Also write JSON export for human inspection let p: String = json_get_string(body, "path") if str_eq(p, "") { let p = dir + "/snapshot.json" } engram_save(p) "{\"ok\":true,\"binary\":\"" + db_path + "\",\"json\":\"" + p + "\"}" } fn route_reindex(method: String, path: String, body: String) -> String { engram_reindex_json() } fn route_load(method: String, path: String, body: String) -> String { let dir: String = env("ENGRAM_DATA_DIR") if str_eq(dir, "") { let dir = "/tmp/engram" } let db_path: String = dir + "/engram.db" let ok: Bool = engram_load_binary_el(db_path) if !ok { let p: String = json_get_string(body, "path") if str_eq(p, "") { let p = dir + "/snapshot.json" } engram_load(p) } ok_json() } fn route_health(method: String, path: String, body: String) -> String { "{\"status\":\"ok\",\"engine\":\"engram-runtime-native\"}" } // ── /api/neuron/* Routes ────────────────────────────────────────────────────── // route_neuron_session_begin — activate with broad seeds, return node stats + results fn route_neuron_session_begin(method: String, path: String, body: String) -> String { let results: String = engram_activate_json("memory knowledge context", 2) let nc: Int = engram_node_count() let ec: Int = engram_edge_count() "{\"ok\":true,\"nodes\":" + results + ",\"node_count\":" + int_to_str(nc) + ",\"edge_count\":" + int_to_str(ec) + "}" } // route_neuron_ctx — compile working context from top activated nodes fn route_neuron_ctx(method: String, path: String, body: String) -> String { let results: String = engram_activate_json("architecture decision memory", 2) let n: Int = json_array_len(results) let limit: Int = if n > 10 { 10 } else { n } let ctx: String = "Recent working memory:\n" let i: Int = 0 let ctx_body: String = "" while i < limit { let elem: String = json_array_get(results, i) let label: String = json_get_string(elem, "label") let content: String = json_get_string(elem, "content") let clen: Int = str_len(content) let snippet: String = if clen > 200 { str_slice(content, 0, 200) } else { content } let ctx_body = ctx_body + "- [" + label + "]: " + snippet + "\n" let i = i + 1 } let full_ctx: String = ctx + ctx_body "{\"ok\":true,\"context\":\"" + str_replace(str_replace(str_replace(full_ctx, "\\", "\\\\"), "\"", "\\\""), "\n", "\\n") + "\"}" } // route_neuron_memory — create a Memory node with importance-to-tier mapping fn route_neuron_memory(method: String, path: String, body: String) -> String { let content: String = json_get_string(body, "content") if str_eq(content, "") { return "{\"error\":\"content is required\"}" } let node_type: String = json_get_string(body, "node_type") if str_eq(node_type, "") { let node_type = "Memory" } let label: String = json_get_string(body, "label") let importance: String = json_get_string(body, "importance") let project: String = json_get_string(body, "project") let tags_raw: String = json_get_string(body, "tags") // Map importance to tier let tier: String = "Episodic" if str_eq(importance, "critical") { let tier = "Procedural" } if str_eq(importance, "high") { let tier = "Semantic" } if str_eq(importance, "normal") { let tier = "Episodic" } if str_eq(importance, "low") { let tier = "Working" } // Override with explicit tier if provided let explicit_tier: String = json_get_string(body, "tier") if !str_eq(explicit_tier, "") { let tier = explicit_tier } // Build tags string — append project tag if set let tags_str: String = tags_raw if !str_eq(project, "") { if str_eq(tags_str, "") { let tags_str = "project:" + project } if !str_eq(tags_str, "") { let tags_str = tags_str + " project:" + project } } let id: String = engram_node_full(content, node_type, label, 0.5, 0.5, 1.0, tier, tags_str) // Checkpoint after write let dir: String = env("ENGRAM_DATA_DIR") if str_eq(dir, "") { let dir = "/tmp/engram" } let db_path: String = dir + "/engram.db" engram_write_binary_el(db_path) "{\"ok\":true,\"id\":\"" + id + "\",\"content\":\"" + str_replace(str_replace(content, "\\", "\\\\"), "\"", "\\\"") + "\"}" } // route_neuron_knowledge_capture — create a Knowledge node fn route_neuron_knowledge_capture(method: String, path: String, body: String) -> String { let content: String = json_get_string(body, "content") if str_eq(content, "") { return "{\"error\":\"content is required\"}" } let title: String = json_get_string(body, "title") let category: String = json_get_string(body, "category") let tags_raw: String = json_get_string(body, "tags") let project: String = json_get_string(body, "project") let tier_raw: String = json_get_string(body, "tier") // Map tier name to engram tier let tier: String = "Episodic" if str_eq(tier_raw, "lesson") { let tier = "Semantic" } if str_eq(tier_raw, "canonical") { let tier = "Procedural" } if str_eq(tier_raw, "note") { let tier = "Episodic" } // Build tags let tags_str: String = tags_raw if !str_eq(category, "") { if str_eq(tags_str, "") { let tags_str = "category:" + category } if !str_eq(tags_str, "") { let tags_str = tags_str + " category:" + category } } if !str_eq(project, "") { if str_eq(tags_str, "") { let tags_str = "project:" + project } if !str_eq(tags_str, "") { let tags_str = tags_str + " project:" + project } } let id: String = engram_node_full(content, "Knowledge", title, 0.7, 0.7, 1.0, tier, tags_str) // Checkpoint let dir: String = env("ENGRAM_DATA_DIR") if str_eq(dir, "") { let dir = "/tmp/engram" } let db_path: String = dir + "/engram.db" engram_write_binary_el(db_path) "{\"ok\":true,\"id\":\"" + id + "\"}" } // route_neuron_knowledge_evolve — create updated node (evolution via new node) fn route_neuron_knowledge_evolve(method: String, path: String, body: String) -> String { let content: String = json_get_string(body, "content") let prior_id: String = json_get_string(body, "id") if str_eq(content, "") { return "{\"ok\":true}" } let id: String = engram_node_full(content, "Knowledge", "", 0.7, 0.7, 1.0, "Semantic", "evolved") if !str_eq(prior_id, "") && !str_eq(id, "") { engram_connect(id, prior_id, 1.0, "supersedes") } let dir: String = env("ENGRAM_DATA_DIR") if str_eq(dir, "") { let dir = "/tmp/engram" } engram_write_binary_el(dir + "/engram.db") "{\"ok\":true,\"id\":\"" + id + "\"}" } // route_neuron_knowledge_promote — stub: ok fn route_neuron_knowledge_promote(method: String, path: String, body: String) -> String { "{\"ok\":true}" } // route_neuron_recall — search or list nodes fn route_neuron_recall(method: String, path: String, body: String) -> String { let query: String = json_get_string(body, "query") let chain: String = json_get_string(body, "chain_name") let limit: Int = json_get_int(body, "limit") if limit == 0 { let limit = 20 } let q: String = if str_eq(query, "") { chain } else { query } if str_eq(q, "") { return engram_scan_nodes_json(limit, 0) } return engram_search_json(q, limit) } // route_neuron_graph — get node + search-based neighbor approximation. // engram_neighbors_json crashes on large graphs (15k+ edges exceeds BFS cap). // Use a search-based approach instead: search by the node id string, which // returns connected nodes that share content with the target id in edges/tags. // For the mcp-wrapper callers this is sufficient — they just need the node itself. fn route_neuron_graph(method: String, path: String, body: String) -> String { let id: String = query_param(path, "id") if str_eq(id, "") { return "{\"error\":\"id is required\"}" } let node_json: String = engram_get_node_json(id) // Return node with empty neighbors — safe fallback avoids BFS crash "{\"ok\":true,\"node\":" + node_json + ",\"neighbors\":[]}" } // route_neuron_graph_link — create edge between nodes fn route_neuron_graph_link(method: String, path: String, body: String) -> String { let from_id: String = json_get_string(body, "from_id") let to_id: String = json_get_string(body, "to_id") if str_eq(from_id, "") || str_eq(to_id, "") { return "{\"error\":\"from_id and to_id are required\"}" } let relation: String = json_get_string(body, "relation") if str_eq(relation, "") { let relation = "related" } let weight: Float = json_get_float(body, "weight") if weight == 0.0 { let weight = 0.5 } engram_connect(from_id, to_id, weight, relation) "{\"ok\":true,\"from_id\":\"" + from_id + "\",\"to_id\":\"" + to_id + "\",\"relation\":\"" + relation + "\"}" } // route_neuron_list — list nodes by type extracted from path fn route_neuron_list(method: String, path: String, body: String) -> String { let clean: String = strip_query(path) let prefix: String = "/api/neuron/list/" let node_type: String = str_slice(clean, str_len(prefix), str_len(clean)) let limit: Int = query_int(path, "limit", 50) if str_eq(node_type, "") { return "[]" } return engram_scan_nodes_by_type_json(node_type, limit, 0) } // route_neuron_consolidate — checkpoint and return counts fn route_neuron_consolidate(method: String, path: String, body: String) -> String { let dir: String = env("ENGRAM_DATA_DIR") if str_eq(dir, "") { let dir = "/tmp/engram" } let db_path: String = dir + "/engram.db" engram_write_binary_el(db_path) let nc: Int = engram_node_count() let ec: Int = engram_edge_count() "{\"ok\":true,\"node_count\":" + int_to_str(nc) + ",\"edge_count\":" + int_to_str(ec) + "}" } // route_neuron_config — return stub config values fn route_neuron_config(method: String, path: String, body: String) -> String { let key: String = query_param(path, "key") "{\"key\":\"" + key + "\",\"value\":\"\"}" } // route_neuron_state_events — log internal state event node fn route_neuron_state_events(method: String, path: String, body: String) -> String { let content: String = json_get_string(body, "content") if str_eq(content, "") { let content = body } let id: String = engram_node_full(content, "InternalStateEvent", "state-event", 0.3, 0.3, 1.0, "Working", "internal-state") "{\"ok\":true,\"id\":\"" + id + "\"}" } // route_neuron_processes — stub fn route_neuron_processes(method: String, path: String, body: String) -> String { "{\"ok\":true,\"processes\":[]}" } // route_events_next — stub empty event queue fn route_events_next(method: String, path: String, body: String) -> String { "{\"ok\":true,\"event\":null}" } // route_events_ack — stub ack fn route_events_ack(method: String, path: String, body: String) -> String { "{\"ok\":true}" } // ── Auth ────────────────────────────────────────────────────────────────────── fn check_auth_ok(method: String, body: String) -> Bool { let key: String = env("ENGRAM_API_KEY") if str_eq(key, "") { return true } // Read-only methods don't require auth. Until http_serve surfaces // request headers we can't accept a Bearer token cleanly; mutating // requests must include "_auth": "" in the JSON body. if str_eq(method, "GET") { return true } let provided: String = json_get_string(body, "_auth") if str_eq(provided, key) { return true } return false } // ── Dispatcher ──────────────────────────────────────────────────────────────── fn handle_request(method: String, path: String, body: String) -> String { let clean: String = strip_query(path) // Health is always reachable if str_eq(method, "GET") { if str_eq(clean, "/health") || str_eq(clean, "/") { return route_health(method, path, body) } } // /api/neuron/* and /events/* are pre-auth — the mcp-wrapper is a trusted // local service that cannot inject _auth into its request bodies. if str_starts_with(clean, "/api/neuron/") || str_starts_with(clean, "/events/") { if str_eq(clean, "/api/neuron/session/begin") { return route_neuron_session_begin(method, path, body) } if str_eq(clean, "/api/neuron/ctx") { return route_neuron_ctx(method, path, body) } if str_eq(clean, "/api/neuron/memory") { return route_neuron_memory(method, path, body) } if str_eq(clean, "/api/neuron/knowledge/capture") { return route_neuron_knowledge_capture(method, path, body) } if str_eq(clean, "/api/neuron/knowledge/evolve") { return route_neuron_knowledge_evolve(method, path, body) } if str_eq(clean, "/api/neuron/knowledge/promote") { return route_neuron_knowledge_promote(method, path, body) } if str_eq(clean, "/api/neuron/recall") { return route_neuron_recall(method, path, body) } if str_eq(clean, "/api/neuron/graph/link") { return route_neuron_graph_link(method, path, body) } if str_eq(clean, "/api/neuron/graph") { return route_neuron_graph(method, path, body) } if str_starts_with(clean, "/api/neuron/list/") { return route_neuron_list(method, path, body) } if str_eq(clean, "/api/neuron/consolidate") { return route_neuron_consolidate(method, path, body) } if str_eq(clean, "/api/neuron/config") { return route_neuron_config(method, path, body) } if str_eq(clean, "/api/neuron/state-events") { return route_neuron_state_events(method, path, body) } if str_eq(clean, "/api/neuron/processes/define") { return route_neuron_processes(method, path, body) } if str_eq(clean, "/api/neuron/processes") { return route_neuron_processes(method, path, body) } if str_eq(clean, "/events/next") { return route_events_next(method, path, body) } if str_eq(clean, "/events/ack") { return route_events_ack(method, path, body) } return err_json("not found") } // Auth (when ENGRAM_API_KEY is set) if !check_auth_ok(method, body) { return err_json("unauthorized") } // Stats if str_eq(method, "GET") && (str_eq(clean, "/api/stats") || str_eq(clean, "/stats")) { return route_stats(method, path, body) } // Nodes if str_eq(method, "POST") && (str_eq(clean, "/api/nodes") || str_eq(clean, "/nodes")) { return route_create_node(method, path, body) } if str_eq(method, "GET") && (str_eq(clean, "/api/nodes") || str_eq(clean, "/nodes") || str_eq(clean, "/nodes/list") || str_eq(clean, "/api/nodes/list")) { return route_scan_nodes(method, path, body) } if str_eq(method, "GET") && (str_eq(clean, "/api/edges") || str_eq(clean, "/edges")) { return route_scan_edges(method, path, body) } if str_eq(method, "GET") && str_starts_with(clean, "/api/nodes/") { return route_get_node(method, path, body) } if str_eq(method, "DELETE") && str_starts_with(clean, "/api/nodes/") { return route_forget(method, path, body) } // Edges if str_eq(method, "POST") && (str_eq(clean, "/api/edges") || str_eq(clean, "/edges")) { return route_create_edge(method, path, body) } if str_eq(method, "GET") && str_starts_with(clean, "/api/neighbors/") { return route_neighbors(method, path, body) } // Activation + Search if str_eq(method, "POST") && (str_eq(clean, "/api/activate") || str_eq(clean, "/activate")) { return route_activate(method, path, body) } if str_eq(method, "GET") && str_starts_with(clean, "/api/activate") { return route_activate(method, path, body) } if str_eq(method, "POST") && (str_eq(clean, "/api/search") || str_eq(clean, "/search")) { return route_search(method, path, body) } if str_eq(method, "GET") && str_starts_with(clean, "/api/search") { return route_search(method, path, body) } // Strengthen if str_eq(method, "POST") && (str_eq(clean, "/api/strengthen") || str_eq(clean, "/strengthen")) { return route_strengthen(method, path, body) } // Temporal decay maintenance if str_eq(method, "POST") && (str_eq(clean, "/api/decay") || str_eq(clean, "/api/maintenance") || str_eq(clean, "/decay")) { return route_decay(method, path, body) } // Persistence if str_eq(method, "POST") && (str_eq(clean, "/api/export") || str_eq(clean, "/export")) { return route_export(method, path, body) } // /api/save is kept as a backward-compat alias for /api/export if str_eq(method, "POST") && (str_eq(clean, "/api/save") || str_eq(clean, "/save")) { return route_export(method, path, body) } if str_eq(method, "POST") && (str_eq(clean, "/api/load") || str_eq(clean, "/load")) { return route_load(method, path, body) } if str_eq(method, "POST") && (str_eq(clean, "/api/reindex") || str_eq(clean, "/reindex")) { return route_reindex(method, path, body) } // ── /api/neuron/* ───────────────────────────────────────────────────────── if str_starts_with(clean, "/api/neuron/") { // Specific sub-paths first (longer matches before shorter) if str_eq(clean, "/api/neuron/session/begin") { return route_neuron_session_begin(method, path, body) } if str_eq(clean, "/api/neuron/ctx") { return route_neuron_ctx(method, path, body) } if str_eq(clean, "/api/neuron/memory") { return route_neuron_memory(method, path, body) } if str_eq(clean, "/api/neuron/knowledge/capture") { return route_neuron_knowledge_capture(method, path, body) } if str_eq(clean, "/api/neuron/knowledge/evolve") { return route_neuron_knowledge_evolve(method, path, body) } if str_eq(clean, "/api/neuron/knowledge/promote") { return route_neuron_knowledge_promote(method, path, body) } if str_eq(clean, "/api/neuron/recall") { return route_neuron_recall(method, path, body) } if str_eq(clean, "/api/neuron/graph/link") { return route_neuron_graph_link(method, path, body) } if str_eq(clean, "/api/neuron/graph") { return route_neuron_graph(method, path, body) } if str_starts_with(clean, "/api/neuron/list/") { return route_neuron_list(method, path, body) } if str_eq(clean, "/api/neuron/consolidate") { return route_neuron_consolidate(method, path, body) } if str_eq(clean, "/api/neuron/config") { return route_neuron_config(method, path, body) } if str_eq(clean, "/api/neuron/state-events") { return route_neuron_state_events(method, path, body) } if str_eq(clean, "/api/neuron/processes/define") { return route_neuron_processes(method, path, body) } if str_eq(clean, "/api/neuron/processes") { return route_neuron_processes(method, path, body) } } // ── /events/* ───────────────────────────────────────────────────────────── if str_eq(clean, "/events/next") { return route_events_next(method, path, body) } if str_eq(clean, "/events/ack") { return route_events_ack(method, path, body) } "{\"error\":\"not found\",\"path\":\"" + clean + "\"}" } // ── Entry ───────────────────────────────────────────────────────────────────── let bind_str: String = env("ENGRAM_BIND") if str_eq(bind_str, "") { let bind_str = ":8742" } let port: Int = parse_port(bind_str) // On startup, load from binary database (ML-KEM-1024 encrypted). // Falls back to per-file JSON, then snapshot.json for migration from older formats. let data_dir: String = env("ENGRAM_DATA_DIR") if str_eq(data_dir, "") { let data_dir = "/tmp/engram" } let db_path: String = data_dir + "/engram.db" let loaded: Bool = engram_load_binary_el(db_path) if !loaded { // Migration path: try per-file JSON engram_load_dir(data_dir) if engram_node_count() == 0 { // Final fallback: legacy snapshot.json let snapshot_path: String = data_dir + "/snapshot.json" engram_load(snapshot_path) } // If we loaded anything from legacy format, save as binary immediately if engram_node_count() > 0 { engram_write_binary_el(db_path) println("[engram] migrated legacy data to binary format") } } println("[engram] runtime-native graph engine (ML-KEM-1024 encrypted)") println("[engram] data_dir=" + data_dir) println("[engram] node_count=" + int_to_str(engram_node_count())) println("[engram] edge_count=" + int_to_str(engram_edge_count())) println("[engram] listening on " + int_to_str(port)) http_set_handler("handle_request") http_serve(port, "handle_request")