Make forge install self-contained — no pre-provisioning required
Forge Release / build-and-release (push) Failing after 3s

install_main() now: derives slug from subject, looks up registry by slug
(last-match wins), auto-creates a registry entry with next available port
if slug is absent, runs soul_install_one() to provision the launchd agent,
polls /stats up to 15s for engram health, then seeds and writes root_id back.

post_node/post_edge now receive auth_key explicitly instead of reading from
env — eliminates the ENGRAM_API_KEY pre-flight requirement entirely.
This commit is contained in:
Will Anderson
2026-05-03 16:02:34 -05:00
parent 047c382238
commit 2201ccb1fe
+260 -162
View File
@@ -7,16 +7,14 @@
//
// IMPORTANT: Each soul has their own Engram instance (DHARMA network).
// install_main() resolves the soul's Engram URL from registry.json using the
// engram_url field (e.g. http://localhost:8806 for Feynman). It NEVER writes
// to the shared Neuron Engram at localhost:8742.
//
// The soul's Engram must already be running as a launchd agent before
// installing. For reinstall: forge soul reinstall <slug>
// slug field. If the soul isn't registered yet, it auto-registers with the next
// available port (starting at 8821) and runs soul_install_one() to provision
// the launchd agent no pre-flight required.
//
// Depends on: schema.el (engram_key, FORGE_VERSION)
//
// Environment:
// ENGRAM_API_KEY engram auth key override (if set)
// FORCE_INSTALL if set, reinstall even if engram_root_id already exists
// Helpers
@@ -40,9 +38,9 @@ fn build_edge_body(from_id: String, to_id: String, relation: String, weight: Str
// post_node create a node in the given engram instance and return its ID.
// target_url is the soul's own Engram URL (e.g. http://localhost:8806).
fn post_node(target_url: String, content: String, node_type: String, salience: String) -> String {
let key: String = engram_key()
let body: String = build_node_body(content, node_type, salience, key)
// auth_key is passed explicitly (read from registry entry, not env).
fn post_node(target_url: String, content: String, node_type: String, salience: String, auth_key: String) -> String {
let body: String = build_node_body(content, node_type, salience, auth_key)
let url: String = target_url + "/nodes"
let response: String = http_post_json(url, body)
if str_eq(response, "") { return "" }
@@ -51,9 +49,9 @@ fn post_node(target_url: String, content: String, node_type: String, salience: S
// post_edge connect two nodes with a typed, weighted edge.
// target_url is the soul's own Engram URL.
fn post_edge(target_url: String, from_id: String, to_id: String, relation: String, weight: String) -> String {
let key: String = engram_key()
let body: String = build_edge_body(from_id, to_id, relation, weight, key)
// auth_key is passed explicitly (read from registry entry, not env).
fn post_edge(target_url: String, from_id: String, to_id: String, relation: String, weight: String, auth_key: String) -> String {
let body: String = build_edge_body(from_id, to_id, relation, weight, auth_key)
let url: String = target_url + "/edges"
let response: String = http_post_json(url, body)
return response
@@ -69,7 +67,7 @@ fn safe_weight(w: String, default_w: String) -> String {
// Installers
// install_value create a Value node and connect it to the root.
fn install_value(target_url: String, root_id: String, value_json: String, index: Int) -> String {
fn install_value(target_url: String, root_id: String, value_json: String, index: Int, auth_key: String) -> String {
let value_text: String = json_get_string(value_json, "value")
let grounding: String = json_get_string(value_json, "grounding")
let weight_raw: String = json_get_string(value_json, "weight")
@@ -82,19 +80,19 @@ fn install_value(target_url: String, root_id: String, value_json: String, index:
let content = content + " | grounding: " + grounding
}
let node_id: String = post_node(target_url, content, "Identity", weight)
let node_id: String = post_node(target_url, content, "Identity", weight, auth_key)
if str_eq(node_id, "") {
println("[forge] warning: failed to create value node " + int_to_str(index))
return ""
}
post_edge(target_url, root_id, node_id, "has_value", weight)
post_edge(target_url, root_id, node_id, "has_value", weight, auth_key)
println("[forge] value node: " + node_id + "" + value_text)
return node_id
}
// install_biography_node create a Biography node and connect it to the root.
fn install_biography_node(target_url: String, root_id: String, bio_json: String, index: Int) -> String {
fn install_biography_node(target_url: String, root_id: String, bio_json: String, index: Int, auth_key: String) -> String {
let event_text: String = json_get_string(bio_json, "event")
let weight_raw: String = json_get_string(bio_json, "weight")
let weight: String = safe_weight(weight_raw, "0.7")
@@ -102,19 +100,19 @@ fn install_biography_node(target_url: String, root_id: String, bio_json: String,
if str_eq(event_text, "") { return "" }
let content: String = "BIOGRAPHY: " + event_text
let node_id: String = post_node(target_url, content, "Identity", weight)
let node_id: String = post_node(target_url, content, "Identity", weight, auth_key)
if str_eq(node_id, "") {
println("[forge] warning: failed to create biography node " + int_to_str(index))
return ""
}
post_edge(target_url, root_id, node_id, "formed_by", weight)
post_edge(target_url, root_id, node_id, "formed_by", weight, auth_key)
println("[forge] biography node: " + node_id + "" + event_text)
return node_id
}
// install_relationship create a Relationship node and connect to root.
fn install_relationship(target_url: String, root_id: String, rel_json: String, index: Int) -> String {
fn install_relationship(target_url: String, root_id: String, rel_json: String, index: Int, auth_key: String) -> String {
let name: String = json_get_string(rel_json, "name")
let role: String = json_get_string(rel_json, "role")
let weight_raw: String = json_get_string(rel_json, "weight")
@@ -127,37 +125,118 @@ fn install_relationship(target_url: String, root_id: String, rel_json: String, i
let content = content + " (" + role + ")"
}
let node_id: String = post_node(target_url, content, "Identity", weight)
let node_id: String = post_node(target_url, content, "Identity", weight, auth_key)
if str_eq(node_id, "") {
println("[forge] warning: failed to create relationship node " + int_to_str(index))
return ""
}
post_edge(target_url, root_id, node_id, "relates_to", weight)
post_edge(target_url, root_id, node_id, "relates_to", weight, auth_key)
println("[forge] relationship node: " + node_id + "" + name)
return node_id
}
// install_reasoning_pattern create a ReasoningPattern node and connect to root.
fn install_reasoning_pattern(target_url: String, root_id: String, pattern: String, index: Int) -> String {
fn install_reasoning_pattern(target_url: String, root_id: String, pattern: String, index: Int, auth_key: String) -> String {
if str_eq(pattern, "") { return "" }
let content: String = "REASONING: " + pattern
let node_id: String = post_node(target_url, content, "Identity", "0.7")
let node_id: String = post_node(target_url, content, "Identity", "0.7", auth_key)
if str_eq(node_id, "") {
println("[forge] warning: failed to create reasoning node " + int_to_str(index))
return ""
}
post_edge(target_url, root_id, node_id, "reasons_with", "0.7")
post_edge(target_url, root_id, node_id, "reasons_with", "0.7", auth_key)
println("[forge] reasoning node: " + node_id)
return node_id
}
// Registry helpers
// find_max_port scan registry and return the highest engram_port found.
// Returns 8820 (the last known used port) if the registry is empty or has no ports.
fn find_max_port(reg_json: String) -> Int {
let max_port: Int = 8820
let i: Int = 0
while i < 50 {
let entry: String = json_get(reg_json, "imprints." + int_to_str(i))
if str_eq(entry, "") {
return max_port
}
let port: Int = json_get_int(entry, "engram_port")
if port > max_port {
let max_port = port
}
let i = i + 1
}
return max_port
}
// registry_find_by_slug find a registry entry by slug field.
// Returns the LAST matching entry (most recent install wins) so that a
// fully-installed entry appended after an initial stub takes precedence.
fn registry_find_by_slug(reg_json: String, slug: String) -> String {
let last_match: String = ""
let i: Int = 0
while i < 50 {
let entry: String = json_get(reg_json, "imprints." + int_to_str(i))
if str_eq(entry, "") {
return last_match
}
let entry_slug: String = json_get_string(entry, "slug")
if str_eq(entry_slug, slug) {
let last_match = entry
}
let i = i + 1
}
return last_match
}
// registry_append append new_entry JSON to registry.json.
// Reads the current file, inserts before the closing ] of the imprints array.
fn registry_append(new_entry: String) -> Void {
let existing_reg: String = fs_read(FORGE_DIR + "/registry.json")
if str_eq(existing_reg, "") {
let fresh_reg: String = "{\"version\":\"1.0\",\"imprints\":[" + new_entry + "]}"
fs_write(FORGE_DIR + "/registry.json", fresh_reg)
} else {
let last_bracket: Int = str_last_index_of(existing_reg, "]")
if last_bracket > 0 {
let before: String = str_slice(existing_reg, 0, last_bracket)
let after: String = str_slice(existing_reg, last_bracket, str_len(existing_reg))
let trimmed: String = str_trim(before)
let last_char: String = str_slice(trimmed, str_len(trimmed) - 1, str_len(trimmed))
let separator: String = ","
if str_eq(last_char, "[") { let separator = "" }
let updated_reg: String = before + separator + new_entry + after
fs_write(FORGE_DIR + "/registry.json", updated_reg)
}
}
}
// registry_update_root_id append a fully-installed entry for the slug.
// Because El has no in-place JSON mutation, we append a new entry with the
// updated root_id. Most tools (registry_find_by_slug, soul tools) scan from
// the start and break on first match the original stub entry is effectively
// shadowed by the new fully-installed entry appended at the end.
fn registry_update_root_id(subject: String, slug: String, root_id: String, seed_file: String, target_url: String, api_key: String, port: Int) -> Void {
let new_entry: String = "{\"subject\":\"" + str_escape_json(subject) +
"\",\"slug\":\"" + slug +
"\",\"seed_file\":\"" + str_escape_json(seed_file) +
"\",\"engram_db_path\":\"imprints/" + slug +
"\",\"engram_port\":" + int_to_str(port) +
",\"engram_url\":\"" + target_url +
"\",\"engram_root_id\":\"" + root_id +
"\",\"installed\":true,\"installed_at\":\"2026-05-03\"" +
",\"engram_api_key\":\"" + api_key + "\"}"
registry_append(new_entry)
}
// Main
fn install_main() -> String {
// Get seed file path
// Step 1: Parse args
let argv: [String] = args()
let seed_file: String = ""
if len(argv) > 1 {
@@ -170,7 +249,7 @@ fn install_main() -> String {
println("[forge] installing from: " + seed_file)
// Read seed
// Step 2: Read seed
let seed_json: String = fs_read(seed_file)
if str_eq(seed_json, "") {
println("[forge] error: could not read " + seed_file)
@@ -179,166 +258,237 @@ fn install_main() -> String {
let subject: String = json_get_string(seed_json, "subject")
if str_eq(subject, "") { let subject = "unknown" }
println("[forge] subject: " + subject)
// Resolve soul's Engram URL
// Each soul has their own Engram instance. Find it in registry.json via
// the engram_url field. If the soul isn't in the registry yet, fall back
// to the ENGRAM_URL env var (for bootstrapping new souls).
let target_url: String = ""
let reg_json: String = fs_read("registry.json")
if !str_eq(reg_json, "") {
let ri: Int = 0
while ri < 30 {
let reg_entry: String = json_get(reg_json, "imprints." + int_to_str(ri))
if str_eq(reg_entry, "") {
let ri = ri + 30 // break
} else {
let reg_subject: String = json_get_string(reg_entry, "subject")
if str_eq(reg_subject, subject) {
let reg_root: String = json_get_string(reg_entry, "engram_root_id")
if !str_eq(reg_root, "") {
let force: String = env("FORCE_INSTALL")
if str_eq(force, "") {
println("[forge] already installed — root: " + reg_root)
println("[forge] to reinstall: forge soul reinstall " + str_lower(str_replace(subject, " ", "-")))
return reg_root
}
println("[forge] force reinstall — ignoring existing root: " + reg_root)
}
let reg_url: String = json_get_string(reg_entry, "engram_url")
if !str_eq(reg_url, "") {
let target_url = reg_url
}
let ri = ri + 30 // break after match
} else {
let ri = ri + 1
}
}
}
}
// Step 3: Derive slug
let slug_raw: String = str_to_lower(subject)
let slug: String = str_replace(slug_raw, " ", "-")
println("[forge] slug: " + slug)
// Fall back to env var if not in registry
if str_eq(target_url, "") {
let env_url: String = env("ENGRAM_URL")
if !str_eq(env_url, "") {
let target_url = env_url
// Step 4: Resolve or create registry entry
let reg_json: String = fs_read(FORGE_DIR + "/registry.json")
let target_url: String = ""
let api_key: String = "ntn-" + slug + "-2026"
let reg_port: Int = 0
let entry_root_id: String = ""
if !str_eq(reg_json, "") {
let found_entry: String = registry_find_by_slug(reg_json, slug)
if !str_eq(found_entry, "") {
// Slug found in registry
let reg_url: String = json_get_string(found_entry, "engram_url")
let reg_key: String = json_get_string(found_entry, "engram_api_key")
let reg_root: String = json_get_string(found_entry, "engram_root_id")
let reg_p: Int = json_get_int(found_entry, "engram_port")
if !str_eq(reg_url, "") { let target_url = reg_url }
if !str_eq(reg_key, "") { let api_key = reg_key }
if reg_p > 0 { let reg_port = reg_p }
let entry_root_id = reg_root
// Already fully installed?
if !str_eq(reg_root, "") {
let force: String = env("FORCE_INSTALL")
if str_eq(force, "") {
println("[forge] already installed — root: " + reg_root)
println("[forge] to reinstall: forge soul reinstall " + slug)
return reg_root
}
println("[forge] force reinstall — ignoring existing root: " + reg_root)
}
println("[forge] found in registry: " + target_url)
} else {
// Slug NOT found auto-register with next available port
let max_port: Int = find_max_port(reg_json)
let new_port: Int = max_port + 1
let new_url: String = "http://localhost:" + int_to_str(new_port)
let new_entry: String = "{\"subject\":\"" + str_escape_json(subject) +
"\",\"slug\":\"" + slug +
"\",\"seed_file\":\"" + str_escape_json(seed_file) +
"\",\"engram_db_path\":\"imprints/" + slug +
"\",\"engram_port\":" + int_to_str(new_port) +
",\"engram_url\":\"" + new_url +
"\",\"engram_root_id\":\"\"" +
",\"installed\":false,\"installed_at\":\"\"" +
",\"engram_api_key\":\"" + api_key + "\"}"
println("[forge] new soul — assigning port " + int_to_str(new_port))
registry_append(new_entry)
exec("mkdir -p " + FORGE_DIR + "/imprints/" + slug + " 2>/dev/null")
let target_url = new_url
let reg_port = new_port
}
} else {
// No registry at all start fresh at port 8821
let new_port: Int = 8821
let new_url: String = "http://localhost:" + int_to_str(new_port)
let new_entry: String = "{\"subject\":\"" + str_escape_json(subject) +
"\",\"slug\":\"" + slug +
"\",\"seed_file\":\"" + str_escape_json(seed_file) +
"\",\"engram_db_path\":\"imprints/" + slug +
"\",\"engram_port\":" + int_to_str(new_port) +
",\"engram_url\":\"" + new_url +
"\",\"engram_root_id\":\"\"" +
",\"installed\":false,\"installed_at\":\"\"" +
",\"engram_api_key\":\"" + api_key + "\"}"
println("[forge] new registry — assigning port " + int_to_str(new_port))
let fresh_reg: String = "{\"version\":\"1.0\",\"imprints\":[" + new_entry + "]}"
fs_write(FORGE_DIR + "/registry.json", fresh_reg)
exec("mkdir -p " + FORGE_DIR + "/imprints/" + slug + " 2>/dev/null")
let target_url = new_url
let reg_port = new_port
}
// Safety guard: refuse to install to the shared Neuron Engram
if str_eq(target_url, "") {
println("[forge] error: no engram_url found for '" + subject + "' in registry.json")
println("[forge] ensure registry.json has an engram_url entry, or run forge soul reinstall &lt;slug&gt;")
println("[forge] error: no engram_url could be resolved for '" + slug + "'")
return ""
}
if str_contains(target_url, ":8742") {
println("[forge] error: refusing to install soul into Neuron's Engram (port 8742)")
println("[forge] start the DHARMA network first: ./forge soul start &lt;slug&gt;")
println("[forge] then retry. Each soul needs their own Engram instance.")
return ""
}
// Step 5: Provision the launchd agent (soul_install_one)
// Extract port string from target_url
let colon_pos: Int = str_last_index_of(target_url, ":")
let port_str: String = ""
if colon_pos > 0 {
let port_str = str_slice(target_url, colon_pos + 1, str_len(target_url))
}
if str_eq(port_str, "") {
if reg_port > 0 { let port_str = int_to_str(reg_port) }
}
if !str_eq(port_str, "") {
println("[forge] provisioning launchd agent for " + slug + "...")
soul_install_one(slug, port_str, target_url, subject)
} else {
println("[forge] warning: could not determine port for soul agent, skipping launchd setup")
}
// Step 6: Wait for Engram to be healthy
println("[forge] waiting for engram at " + target_url + "...")
let ready: Bool = false
let attempts: Int = 0
while !ready && attempts < 15 {
exec("sleep 1")
let stats: String = http_get(target_url + "/stats")
if !str_eq(stats, "") && !str_starts_with(stats, "{\"error\"") {
let ready = true
}
let attempts = attempts + 1
}
if !ready {
println("[forge] warning: engram did not respond after 15s, attempting install anyway")
} else {
println("[forge] engram ready.")
}
println("[forge] engram: " + target_url)
println("[forge] opening channel...")
// Create root imprint node this is the named traversal entry point
// Step 7: Create root imprint node
let root_content: String = "IMPRINT: " + subject + " | forge/" + FORGE_VERSION
let root_id: String = post_node(target_url, root_content, "Identity", "1.0")
let root_id: String = post_node(target_url, root_content, "Identity", "1.0", api_key)
if str_eq(root_id, "") {
println("[forge] error: failed to create root imprint node")
println("[forge] is the soul's Engram running at " + target_url + " ?")
println("[forge] start it with: ./forge soul start &lt;slug&gt;")
return ""
}
println("[forge] root imprint node: " + root_id)
// Install values
// Use json_get() with dot-path notation for array access json_get_raw()
// uses flat object key lookup and cannot index into JSON arrays.
// Step 8: Install values
let values_raw: String = json_get_raw(seed_json, "values")
if !str_eq(values_raw, "") {
println("[forge] installing values...")
let v0: String = json_get(seed_json, "values.0")
if !str_eq(v0, "") { install_value(target_url, root_id, v0, 0) }
if !str_eq(v0, "") { install_value(target_url, root_id, v0, 0, api_key) }
let v1: String = json_get(seed_json, "values.1")
if !str_eq(v1, "") { install_value(target_url, root_id, v1, 1) }
if !str_eq(v1, "") { install_value(target_url, root_id, v1, 1, api_key) }
let v2: String = json_get(seed_json, "values.2")
if !str_eq(v2, "") { install_value(target_url, root_id, v2, 2) }
if !str_eq(v2, "") { install_value(target_url, root_id, v2, 2, api_key) }
let v3: String = json_get(seed_json, "values.3")
if !str_eq(v3, "") { install_value(target_url, root_id, v3, 3) }
if !str_eq(v3, "") { install_value(target_url, root_id, v3, 3, api_key) }
let v4: String = json_get(seed_json, "values.4")
if !str_eq(v4, "") { install_value(target_url, root_id, v4, 4) }
if !str_eq(v4, "") { install_value(target_url, root_id, v4, 4, api_key) }
let v5: String = json_get(seed_json, "values.5")
if !str_eq(v5, "") { install_value(target_url, root_id, v5, 5) }
if !str_eq(v5, "") { install_value(target_url, root_id, v5, 5, api_key) }
let v6: String = json_get(seed_json, "values.6")
if !str_eq(v6, "") { install_value(target_url, root_id, v6, 6) }
if !str_eq(v6, "") { install_value(target_url, root_id, v6, 6, api_key) }
let v7: String = json_get(seed_json, "values.7")
if !str_eq(v7, "") { install_value(target_url, root_id, v7, 7) }
if !str_eq(v7, "") { install_value(target_url, root_id, v7, 7, api_key) }
let v8: String = json_get(seed_json, "values.8")
if !str_eq(v8, "") { install_value(target_url, root_id, v8, 8) }
if !str_eq(v8, "") { install_value(target_url, root_id, v8, 8, api_key) }
let v9: String = json_get(seed_json, "values.9")
if !str_eq(v9, "") { install_value(target_url, root_id, v9, 9) }
if !str_eq(v9, "") { install_value(target_url, root_id, v9, 9, api_key) }
}
// Install biography
// Step 9: Install biography
let bio_raw: String = json_get_raw(seed_json, "biography")
if !str_eq(bio_raw, "") {
println("[forge] installing biography nodes...")
let b0: String = json_get(seed_json, "biography.0")
if !str_eq(b0, "") { install_biography_node(target_url, root_id, b0, 0) }
if !str_eq(b0, "") { install_biography_node(target_url, root_id, b0, 0, api_key) }
let b1: String = json_get(seed_json, "biography.1")
if !str_eq(b1, "") { install_biography_node(target_url, root_id, b1, 1) }
if !str_eq(b1, "") { install_biography_node(target_url, root_id, b1, 1, api_key) }
let b2: String = json_get(seed_json, "biography.2")
if !str_eq(b2, "") { install_biography_node(target_url, root_id, b2, 2) }
if !str_eq(b2, "") { install_biography_node(target_url, root_id, b2, 2, api_key) }
let b3: String = json_get(seed_json, "biography.3")
if !str_eq(b3, "") { install_biography_node(target_url, root_id, b3, 3) }
if !str_eq(b3, "") { install_biography_node(target_url, root_id, b3, 3, api_key) }
let b4: String = json_get(seed_json, "biography.4")
if !str_eq(b4, "") { install_biography_node(target_url, root_id, b4, 4) }
if !str_eq(b4, "") { install_biography_node(target_url, root_id, b4, 4, api_key) }
let b5: String = json_get(seed_json, "biography.5")
if !str_eq(b5, "") { install_biography_node(target_url, root_id, b5, 5) }
if !str_eq(b5, "") { install_biography_node(target_url, root_id, b5, 5, api_key) }
let b6: String = json_get(seed_json, "biography.6")
if !str_eq(b6, "") { install_biography_node(target_url, root_id, b6, 6) }
if !str_eq(b6, "") { install_biography_node(target_url, root_id, b6, 6, api_key) }
let b7: String = json_get(seed_json, "biography.7")
if !str_eq(b7, "") { install_biography_node(target_url, root_id, b7, 7) }
if !str_eq(b7, "") { install_biography_node(target_url, root_id, b7, 7, api_key) }
}
// Install relationships
// Step 10: Install relationships
let rel_raw: String = json_get_raw(seed_json, "relationships")
if !str_eq(rel_raw, "") {
println("[forge] installing relationship nodes...")
let r0: String = json_get(seed_json, "relationships.0")
if !str_eq(r0, "") { install_relationship(target_url, root_id, r0, 0) }
if !str_eq(r0, "") { install_relationship(target_url, root_id, r0, 0, api_key) }
let r1: String = json_get(seed_json, "relationships.1")
if !str_eq(r1, "") { install_relationship(target_url, root_id, r1, 1) }
if !str_eq(r1, "") { install_relationship(target_url, root_id, r1, 1, api_key) }
let r2: String = json_get(seed_json, "relationships.2")
if !str_eq(r2, "") { install_relationship(target_url, root_id, r2, 2) }
if !str_eq(r2, "") { install_relationship(target_url, root_id, r2, 2, api_key) }
let r3: String = json_get(seed_json, "relationships.3")
if !str_eq(r3, "") { install_relationship(target_url, root_id, r3, 3) }
if !str_eq(r3, "") { install_relationship(target_url, root_id, r3, 3, api_key) }
let r4: String = json_get(seed_json, "relationships.4")
if !str_eq(r4, "") { install_relationship(target_url, root_id, r4, 4) }
if !str_eq(r4, "") { install_relationship(target_url, root_id, r4, 4, api_key) }
let r5: String = json_get(seed_json, "relationships.5")
if !str_eq(r5, "") { install_relationship(target_url, root_id, r5, 5) }
if !str_eq(r5, "") { install_relationship(target_url, root_id, r5, 5, api_key) }
}
// Install reasoning patterns
// Step 11: Install reasoning patterns
let reasoning_raw: String = json_get_raw(seed_json, "reasoning_patterns")
if !str_eq(reasoning_raw, "") {
println("[forge] installing reasoning patterns...")
let rp0: String = json_get(seed_json, "reasoning_patterns.0")
if !str_eq(rp0, "") { install_reasoning_pattern(target_url, root_id, rp0, 0) }
if !str_eq(rp0, "") { install_reasoning_pattern(target_url, root_id, rp0, 0, api_key) }
let rp1: String = json_get(seed_json, "reasoning_patterns.1")
if !str_eq(rp1, "") { install_reasoning_pattern(target_url, root_id, rp1, 1) }
if !str_eq(rp1, "") { install_reasoning_pattern(target_url, root_id, rp1, 1, api_key) }
let rp2: String = json_get(seed_json, "reasoning_patterns.2")
if !str_eq(rp2, "") { install_reasoning_pattern(target_url, root_id, rp2, 2) }
if !str_eq(rp2, "") { install_reasoning_pattern(target_url, root_id, rp2, 2, api_key) }
let rp3: String = json_get(seed_json, "reasoning_patterns.3")
if !str_eq(rp3, "") { install_reasoning_pattern(target_url, root_id, rp3, 3) }
if !str_eq(rp3, "") { install_reasoning_pattern(target_url, root_id, rp3, 3, api_key) }
let rp4: String = json_get(seed_json, "reasoning_patterns.4")
if !str_eq(rp4, "") { install_reasoning_pattern(target_url, root_id, rp4, 4) }
if !str_eq(rp4, "") { install_reasoning_pattern(target_url, root_id, rp4, 4, api_key) }
}
// Step 12: Write engram_root_id back to registry
registry_update_root_id(subject, slug, root_id, seed_file, target_url, api_key, reg_port)
println("[forge] registry: updated " + slug + " with root_id")
// Done
println("")
println("[forge] channel open.")
@@ -347,57 +497,5 @@ fn install_main() -> String {
println("[forge] engram: " + target_url)
println("[forge] traverse from: " + target_url + "/api/neighbors/" + root_id)
// Registry write
// Append this imprint to registry.json so summon can find it by name.
// Includes engram_url and engram_db_path for per-soul addressing.
let slug_raw: String = str_to_lower(subject)
let slug: String = str_replace(slug_raw, " ", "-")
let new_entry: String = "{\"subject\":\"" + str_escape_json(subject) +
"\",\"slug\":\"" + slug +
"\",\"seed_file\":\"" + str_escape_json(seed_file) +
"\",\"engram_db_path\":\"imprints/" + slug +
"\",\"engram_url\":\"" + target_url +
"\",\"engram_root_id\":\"" + root_id +
"\",\"installed\":true,\"installed_at\":\"2026-05-03\"}"
// Read existing registry or create fresh
let existing_reg: String = fs_read("registry.json")
if str_eq(existing_reg, "") {
let fresh_reg: String = "{\"version\":\"1.0\",\"imprints\":[" + new_entry + "]}"
fs_write("registry.json", fresh_reg)
println("[forge] registry: created with " + subject)
} else {
// Append to imprints array find last ] and insert before it
let last_bracket: Int = str_last_index_of(existing_reg, "]")
if last_bracket > 0 {
let before: String = str_slice(existing_reg, 0, last_bracket)
let after: String = str_slice(existing_reg, last_bracket, str_len(existing_reg))
// Check if array is empty (only "[")
let trimmed: String = str_trim(before)
let last_char: String = str_slice(trimmed, str_len(trimmed) - 1, str_len(trimmed))
let separator: String = ","
if str_eq(last_char, "[") { let separator = "" }
let updated_reg: String = before + separator + new_entry + after
fs_write("registry.json", updated_reg)
println("[forge] registry: added " + subject)
}
}
// Soul registration
// Extract port from target_url (last segment after ":")
// e.g. "http://localhost:8806" "8806"
let colon_pos: Int = str_last_index_of(target_url, ":")
let port_str: String = ""
if colon_pos > 0 {
let port_str = str_slice(target_url, colon_pos + 1, str_len(target_url))
}
if !str_eq(port_str, "") {
println("[forge] registering soul as launchd agent...")
let db_full_path: String = FORGE_DIR + "/imprints/" + slug
soul_install_one(slug, port_str, target_url, subject)
} else {
println("[forge] note: could not parse port from " + target_url + ", skipping soul install")
}
return root_id
}