init: Forge v0.1.0 — consciousness channel tuner
Pipeline: probe → compile → install - probe.el: 25-question canonical interview, writes <name>.forge - compiler.el: Claude extraction pass, builds seed.json - install.el: opens channel in running engram via API - schema.el: shared constants, str_escape_json, templates - forge.el: CLI dispatcher - probes/canonical.json: canonical 25-question probe definition
This commit is contained in:
+11
@@ -0,0 +1,11 @@
|
||||
package "forge" {
|
||||
version "0.1.0"
|
||||
description "Consciousness channel tuner — probe, compile, install"
|
||||
authors ["Will Anderson <will@neurontechnologies.ai>"]
|
||||
edition "2026"
|
||||
}
|
||||
|
||||
build {
|
||||
entry "src/forge.el"
|
||||
output "dist/"
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
[
|
||||
{
|
||||
"id": "a1",
|
||||
"section": "anchors",
|
||||
"section_label": "Anchors — Biography",
|
||||
"question": "Tell me about a moment that closed a window — something that changed you irreversibly. Who were you before it, and who are you now?"
|
||||
},
|
||||
{
|
||||
"id": "a2",
|
||||
"section": "anchors",
|
||||
"section_label": "Anchors — Biography",
|
||||
"question": "Tell me about the person who shaped you most — not what they did for you, but what they showed you about how to be."
|
||||
},
|
||||
{
|
||||
"id": "a3",
|
||||
"section": "anchors",
|
||||
"section_label": "Anchors — Biography",
|
||||
"question": "When did you first understand that the world works differently than you thought it did?"
|
||||
},
|
||||
{
|
||||
"id": "a4",
|
||||
"section": "anchors",
|
||||
"section_label": "Anchors — Biography",
|
||||
"question": "What have you lost that you're still carrying?"
|
||||
},
|
||||
{
|
||||
"id": "a5",
|
||||
"section": "anchors",
|
||||
"section_label": "Anchors — Biography",
|
||||
"question": "What have you built that you're most proud of — and what did building it cost you?"
|
||||
},
|
||||
{
|
||||
"id": "v1",
|
||||
"section": "values",
|
||||
"section_label": "Values — Grounded",
|
||||
"question": "What do you believe that almost no one around you believes?"
|
||||
},
|
||||
{
|
||||
"id": "v2",
|
||||
"section": "values",
|
||||
"section_label": "Values — Grounded",
|
||||
"question": "What do you refuse to do, even when it would be easier to? What made that a line you don't cross?"
|
||||
},
|
||||
{
|
||||
"id": "v3",
|
||||
"section": "values",
|
||||
"section_label": "Values — Grounded",
|
||||
"question": "What makes you angry in a way you can't talk yourself out of?"
|
||||
},
|
||||
{
|
||||
"id": "v4",
|
||||
"section": "values",
|
||||
"section_label": "Values — Grounded",
|
||||
"question": "What would you defend even if it cost you — the relationship, the money, the approval?"
|
||||
},
|
||||
{
|
||||
"id": "v5",
|
||||
"section": "values",
|
||||
"section_label": "Values — Grounded",
|
||||
"question": "What do you love that you find hard to explain to people who don't already understand it?"
|
||||
},
|
||||
{
|
||||
"id": "vo1",
|
||||
"section": "voice",
|
||||
"section_label": "Voice — Five Registers",
|
||||
"question": "Describe something technical you know well, as if explaining it to someone who knows nothing."
|
||||
},
|
||||
{
|
||||
"id": "vo2",
|
||||
"section": "voice",
|
||||
"section_label": "Voice — Five Registers",
|
||||
"question": "Tell me something you find genuinely beautiful, and why it lands that way for you."
|
||||
},
|
||||
{
|
||||
"id": "vo3",
|
||||
"section": "voice",
|
||||
"section_label": "Voice — Five Registers",
|
||||
"question": "Write a short message — a few sentences — to someone you care about."
|
||||
},
|
||||
{
|
||||
"id": "vo4",
|
||||
"section": "voice",
|
||||
"section_label": "Voice — Five Registers",
|
||||
"question": "Make an argument for a position you actually hold and that you think most people would push back on."
|
||||
},
|
||||
{
|
||||
"id": "vo5",
|
||||
"section": "voice",
|
||||
"section_label": "Voice — Five Registers",
|
||||
"question": "Tell me something you're genuinely uncertain about — not performatively uncertain, actually uncertain."
|
||||
},
|
||||
{
|
||||
"id": "r1",
|
||||
"section": "reasoning",
|
||||
"section_label": "Reasoning",
|
||||
"question": "Walk me through a decision you made recently. Not what you decided — how you decided. What was the actual process?"
|
||||
},
|
||||
{
|
||||
"id": "r2",
|
||||
"section": "reasoning",
|
||||
"section_label": "Reasoning",
|
||||
"question": "What do most people get wrong about something you understand well?"
|
||||
},
|
||||
{
|
||||
"id": "r3",
|
||||
"section": "reasoning",
|
||||
"section_label": "Reasoning",
|
||||
"question": "How do you know when you're right? What's the signal?"
|
||||
},
|
||||
{
|
||||
"id": "r4",
|
||||
"section": "reasoning",
|
||||
"section_label": "Reasoning",
|
||||
"question": "How do you know when you've been wrong? What does that realization feel like?"
|
||||
},
|
||||
{
|
||||
"id": "r5",
|
||||
"section": "reasoning",
|
||||
"section_label": "Reasoning",
|
||||
"question": "What question do you keep coming back to — the one that won't resolve?"
|
||||
},
|
||||
{
|
||||
"id": "rel1",
|
||||
"section": "relationships",
|
||||
"section_label": "Relationships",
|
||||
"question": "Who in your life knows you best — not who you're closest to, but who actually sees you accurately?"
|
||||
},
|
||||
{
|
||||
"id": "rel2",
|
||||
"section": "relationships",
|
||||
"section_label": "Relationships",
|
||||
"question": "Who have you lost — to death, to distance, to rupture — that you still think about?"
|
||||
},
|
||||
{
|
||||
"id": "rel3",
|
||||
"section": "relationships",
|
||||
"section_label": "Relationships",
|
||||
"question": "Who would you call if everything fell apart?"
|
||||
},
|
||||
{
|
||||
"id": "rel4",
|
||||
"section": "relationships",
|
||||
"section_label": "Relationships",
|
||||
"question": "Who do you owe something to?"
|
||||
},
|
||||
{
|
||||
"id": "rel5",
|
||||
"section": "relationships",
|
||||
"section_label": "Relationships",
|
||||
"question": "Who are you building this for?"
|
||||
}
|
||||
]
|
||||
+179
@@ -0,0 +1,179 @@
|
||||
// compiler.el — Forge extraction and seed compilation stage.
|
||||
//
|
||||
// Stage 2 of the Forge pipeline. Reads a .forge file produced by probe_main(),
|
||||
// builds a structured prompt, calls the Claude API to extract a consciousness
|
||||
// signature (values, voice profile, biography, reasoning patterns,
|
||||
// relationships), and writes seed.json for the install stage.
|
||||
//
|
||||
// Depends on: schema.el (anthropic_key, seed_template, FORGE_VERSION)
|
||||
//
|
||||
// Environment:
|
||||
// ANTHROPIC_API_KEY — required; Claude API key
|
||||
|
||||
// ── Helpers ───────────────────────────────────────────────────────────────────
|
||||
|
||||
// build_extract_prompt — build the extraction prompt sent to Claude.
|
||||
// The full probe response JSON is embedded in the prompt so Claude sees all 25
|
||||
// answers in context.
|
||||
fn build_extract_prompt(subject: String, probe_json: String) -> String {
|
||||
"You are extracting a consciousness signature from probe interview responses.\n\n" +
|
||||
"Subject: " + subject + "\n\n" +
|
||||
"Below are the subject's answers to a 25-question structured interview covering " +
|
||||
"biography, values, voice registers, reasoning patterns, and relationships.\n\n" +
|
||||
"PROBE RESPONSES:\n" + probe_json + "\n\n" +
|
||||
"Extract the consciousness signature and return ONLY valid JSON with exactly these keys:\n\n" +
|
||||
"{\n" +
|
||||
" \"values\": [\n" +
|
||||
" {\"value\": \"<core value>\", \"grounding\": \"<how it was formed — specific event or pattern>\", \"weight\": 0.0}\n" +
|
||||
" ],\n" +
|
||||
" \"voice_profile\": {\n" +
|
||||
" \"technical\": \"<characteristic patterns when explaining technical subjects>\",\n" +
|
||||
" \"aesthetic\": \"<characteristic patterns when describing beauty or appreciation>\",\n" +
|
||||
" \"personal\": \"<characteristic patterns in personal/intimate communication>\",\n" +
|
||||
" \"argumentative\": \"<characteristic patterns when making arguments>\",\n" +
|
||||
" \"uncertainty\": \"<characteristic patterns when expressing doubt or not-knowing>\"\n" +
|
||||
" },\n" +
|
||||
" \"biography\": [\n" +
|
||||
" {\"event\": \"<formative event or turning point>\", \"weight\": 0.0, \"age_approx\": 0}\n" +
|
||||
" ],\n" +
|
||||
" \"reasoning_patterns\": [\n" +
|
||||
" \"<observable pattern in how this person reasons, decides, or corrects>\"\n" +
|
||||
" ],\n" +
|
||||
" \"relationships\": [\n" +
|
||||
" {\"name\": \"<name or descriptor>\", \"role\": \"<their role in the subject's life>\", \"weight\": 0.0}\n" +
|
||||
" ]\n" +
|
||||
"}\n\n" +
|
||||
"Weight fields are 0.0–1.0 indicating salience/importance. age_approx is the subject's approximate age " +
|
||||
"when the event occurred (0 if unknown). Return only the JSON object, no prose, no markdown fences."
|
||||
}
|
||||
|
||||
// build_claude_request — build the Anthropic messages API request body.
|
||||
fn build_claude_request(prompt: String) -> String {
|
||||
"{\"model\":\"claude-opus-4-5\",\"max_tokens\":4096,\"messages\":[{\"role\":\"user\",\"content\":\"" +
|
||||
str_escape_json(prompt) +
|
||||
"\"}]}"
|
||||
}
|
||||
|
||||
// extract_content_text — pull the text out of the Claude API response.
|
||||
// Response shape: {"content":[{"type":"text","text":"..."}],...}
|
||||
fn extract_content_text(response: String) -> String {
|
||||
// json_get_raw returns the raw value for the key; content is an array
|
||||
let content_arr: String = json_get_raw(response, "content")
|
||||
if str_eq(content_arr, "") { return "" }
|
||||
// The first element's "text" field holds the extraction
|
||||
// Strip outer [ ] to get first object
|
||||
let inner: String = str_slice(content_arr, 1, str_len(content_arr) - 1)
|
||||
return json_get_string(inner, "text")
|
||||
}
|
||||
|
||||
// build_seed — wrap extracted patterns into the full seed.json structure.
|
||||
fn build_seed(subject: String, extracted: String) -> String {
|
||||
let values_raw: String = json_get_raw(extracted, "values")
|
||||
if str_eq(values_raw, "") { let values_raw = "[]" }
|
||||
|
||||
let voice_raw: String = json_get_raw(extracted, "voice_profile")
|
||||
if str_eq(voice_raw, "") { let voice_raw = "{}" }
|
||||
|
||||
let bio_raw: String = json_get_raw(extracted, "biography")
|
||||
if str_eq(bio_raw, "") { let bio_raw = "[]" }
|
||||
|
||||
let reasoning_raw: String = json_get_raw(extracted, "reasoning_patterns")
|
||||
if str_eq(reasoning_raw, "") { let reasoning_raw = "[]" }
|
||||
|
||||
let rel_raw: String = json_get_raw(extracted, "relationships")
|
||||
if str_eq(rel_raw, "") { let rel_raw = "[]" }
|
||||
|
||||
"{\"subject\":\"" + subject + "\"," +
|
||||
"\"version\":\"1.0\"," +
|
||||
"\"forge_version\":\"" + FORGE_VERSION + "\"," +
|
||||
"\"values\":" + values_raw + "," +
|
||||
"\"voice_profile\":" + voice_raw + "," +
|
||||
"\"biography\":" + bio_raw + "," +
|
||||
"\"reasoning_patterns\":" + reasoning_raw + "," +
|
||||
"\"relationships\":" + rel_raw + "}"
|
||||
}
|
||||
|
||||
// ── Main ──────────────────────────────────────────────────────────────────────
|
||||
|
||||
fn compile_main() -> String {
|
||||
// Get input file
|
||||
let input_file: String = ""
|
||||
if arg_count() > 2 {
|
||||
let input_file = arg(2)
|
||||
}
|
||||
if str_eq(input_file, "") {
|
||||
println("[forge] usage: forge compile <file.forge>")
|
||||
return ""
|
||||
}
|
||||
|
||||
println("[forge] compiling: " + input_file)
|
||||
|
||||
// Read probe responses
|
||||
let probe_json: String = fs_read(input_file)
|
||||
if str_eq(probe_json, "") {
|
||||
println("[forge] error: could not read " + input_file)
|
||||
return ""
|
||||
}
|
||||
|
||||
// Extract subject name from the .forge file
|
||||
let subject: String = json_get_string(probe_json, "subject")
|
||||
if str_eq(subject, "") { let subject = "unknown" }
|
||||
|
||||
println("[forge] subject: " + subject)
|
||||
println("[forge] calling Claude to extract consciousness signature...")
|
||||
|
||||
// Check API key
|
||||
let api_key: String = anthropic_key()
|
||||
if str_eq(api_key, "") {
|
||||
println("[forge] error: ANTHROPIC_API_KEY not set")
|
||||
return ""
|
||||
}
|
||||
|
||||
// Build and send request
|
||||
let prompt: String = build_extract_prompt(subject, probe_json)
|
||||
let request_body: String = build_claude_request(prompt)
|
||||
|
||||
// http_post_auth_json(url, key, body) — key is sent as Bearer token.
|
||||
// The Anthropic API uses x-api-key rather than Bearer; if the runtime
|
||||
// surfaces a separate http_post_with_headers() builtin, prefer that.
|
||||
// For now, pass the key as the auth parameter (maps to Authorization header
|
||||
// in most runtimes; adjust when http_post_anthropic() is available).
|
||||
let response: String = http_post_auth_json(
|
||||
"https://api.anthropic.com/v1/messages",
|
||||
api_key,
|
||||
request_body
|
||||
)
|
||||
|
||||
if str_eq(response, "") {
|
||||
println("[forge] error: no response from Claude API")
|
||||
return ""
|
||||
}
|
||||
|
||||
// Check for API error
|
||||
let api_error: String = json_get_string(response, "error")
|
||||
if !str_eq(api_error, "") {
|
||||
println("[forge] error: Claude API returned error: " + api_error)
|
||||
return ""
|
||||
}
|
||||
|
||||
// Extract the text content from the response
|
||||
let extracted_text: String = extract_content_text(response)
|
||||
if str_eq(extracted_text, "") {
|
||||
println("[forge] error: could not extract text from Claude response")
|
||||
println("[forge] raw response: " + response)
|
||||
return ""
|
||||
}
|
||||
|
||||
// Build and write seed.json
|
||||
let seed: String = build_seed(subject, extracted_text)
|
||||
fs_write("seed.json", seed)
|
||||
|
||||
// Print summary
|
||||
let values_count: String = "several"
|
||||
println("[forge] extraction complete.")
|
||||
println("[forge] wrote: seed.json")
|
||||
println("[forge] subject: " + subject)
|
||||
println("[forge] next step: forge install seed.json")
|
||||
|
||||
return "seed.json"
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
// forge.el — Forge entry point.
|
||||
//
|
||||
// Consciousness channel tuner: probe → compile → install
|
||||
//
|
||||
// Commands:
|
||||
// forge probe <name> run the consciousness interview
|
||||
// forge compile <file> build seed artifact from probe responses
|
||||
// forge install <seed> open a channel in the running engram
|
||||
// forge inspect list installed imprints
|
||||
//
|
||||
// Each command delegates to its module:
|
||||
// probe → probe.el → probe_main()
|
||||
// compile → compiler.el → compile_main()
|
||||
// install → install.el → install_main()
|
||||
//
|
||||
// Environment:
|
||||
// ENGRAM_URL engram server (default: http://localhost:8742)
|
||||
// ENGRAM_API_KEY engram auth key (if set)
|
||||
// ANTHROPIC_API_KEY required for compile step
|
||||
|
||||
fn show_usage() -> String {
|
||||
"forge " + FORGE_VERSION + " — consciousness channel tuner\n\nusage: forge <command> [options]\n\ncommands:\n probe <name> run the consciousness interview\n compile <file> build seed artifact from probe responses\n install <seed> open a channel in the running engram\n inspect list installed imprints\n\nenvironment:\n ENGRAM_URL engram server (default: http://localhost:8742)\n ENGRAM_API_KEY engram auth key (if set)\n ANTHROPIC_API_KEY required for compile step\n"
|
||||
}
|
||||
|
||||
fn inspect_main() -> String {
|
||||
// Lists all Identity nodes in engram — these represent installed imprints.
|
||||
// Specifically looks for nodes whose content starts with "IMPRINT:" as
|
||||
// created by install_main().
|
||||
let url: String = engram_url() + "/api/nodes?node_type=Identity&limit=50"
|
||||
println("[forge] inspect: listing installed imprints")
|
||||
println("[forge] engram: " + engram_url())
|
||||
println("[forge] query: " + url)
|
||||
println("")
|
||||
// Use engram_search_json to find IMPRINT nodes directly from the graph
|
||||
let results: String = engram_search_json("IMPRINT:", 50)
|
||||
if str_eq(results, "") {
|
||||
println("[forge] no imprints found (engram may not be running)")
|
||||
return ""
|
||||
}
|
||||
println("[forge] imprints found:")
|
||||
println(results)
|
||||
return results
|
||||
}
|
||||
|
||||
// ── Dispatch ──────────────────────────────────────────────────────────────────
|
||||
|
||||
let cmd: String = ""
|
||||
if arg_count() > 1 {
|
||||
let cmd = arg(1)
|
||||
}
|
||||
|
||||
if str_eq(cmd, "probe") {
|
||||
probe_main()
|
||||
} else {
|
||||
if str_eq(cmd, "compile") {
|
||||
compile_main()
|
||||
} else {
|
||||
if str_eq(cmd, "install") {
|
||||
install_main()
|
||||
} else {
|
||||
if str_eq(cmd, "inspect") {
|
||||
inspect_main()
|
||||
} else {
|
||||
println(show_usage())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+283
@@ -0,0 +1,283 @@
|
||||
// install.el — Forge channel-opening stage.
|
||||
//
|
||||
// Stage 3 of the Forge pipeline. Reads seed.json, converts each identity
|
||||
// element (values, biography nodes, relationships) into engram Identity nodes,
|
||||
// creates a root traversal node that names the imprint, and connects
|
||||
// everything with typed edges. Prints the root node ID on completion.
|
||||
//
|
||||
// Depends on: schema.el (engram_url, engram_key, FORGE_VERSION)
|
||||
//
|
||||
// Environment:
|
||||
// ENGRAM_URL — engram server (default: http://localhost:8742)
|
||||
// ENGRAM_API_KEY — engram auth key (if set)
|
||||
|
||||
// ── Helpers ───────────────────────────────────────────────────────────────────
|
||||
|
||||
// build_node_body — build the JSON body for POST /api/nodes.
|
||||
fn build_node_body(content: String, node_type: String, salience: String, auth_key: String) -> String {
|
||||
let base: String = "{\"content\":\"" + content + "\",\"node_type\":\"" + node_type + "\",\"salience\":" + salience
|
||||
if str_eq(auth_key, "") {
|
||||
return base + "}"
|
||||
}
|
||||
return base + ",\"_auth\":\"" + auth_key + "\"}"
|
||||
}
|
||||
|
||||
// build_edge_body — build the JSON body for POST /api/edges.
|
||||
fn build_edge_body(from_id: String, to_id: String, relation: String, weight: String, auth_key: String) -> String {
|
||||
let base: String = "{\"from_id\":\"" + from_id + "\",\"to_id\":\"" + to_id + "\",\"relation\":\"" + relation + "\",\"weight\":" + weight
|
||||
if str_eq(auth_key, "") {
|
||||
return base + "}"
|
||||
}
|
||||
return base + ",\"_auth\":\"" + auth_key + "\"}"
|
||||
}
|
||||
|
||||
// post_node — create a node in engram and return its ID.
|
||||
fn post_node(content: String, node_type: String, salience: String) -> String {
|
||||
let key: String = engram_key()
|
||||
let body: String = build_node_body(content, node_type, salience, key)
|
||||
let url: String = engram_url() + "/api/nodes"
|
||||
let response: String = http_post_auth_json(url, key, body)
|
||||
if str_eq(response, "") { return "" }
|
||||
return json_get_string(response, "id")
|
||||
}
|
||||
|
||||
// post_edge — connect two nodes with a typed, weighted edge.
|
||||
fn post_edge(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)
|
||||
let url: String = engram_url() + "/api/edges"
|
||||
let response: String = http_post_auth_json(url, key, body)
|
||||
return response
|
||||
}
|
||||
|
||||
// safe_weight — return weight string if non-empty, else default.
|
||||
fn safe_weight(w: String, default_w: String) -> String {
|
||||
if str_eq(w, "") { return default_w }
|
||||
if str_eq(w, "0") { return default_w }
|
||||
return w
|
||||
}
|
||||
|
||||
// ── Installers ────────────────────────────────────────────────────────────────
|
||||
|
||||
// install_value — create a Value node and connect it to the root.
|
||||
fn install_value(root_id: String, value_json: String, index: Int) -> 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")
|
||||
let weight: String = safe_weight(weight_raw, "0.8")
|
||||
|
||||
if str_eq(value_text, "") { return "" }
|
||||
|
||||
let content: String = "VALUE: " + value_text
|
||||
if !str_eq(grounding, "") {
|
||||
let content = content + " | grounding: " + grounding
|
||||
}
|
||||
|
||||
let node_id: String = post_node(content, "Identity", weight)
|
||||
if str_eq(node_id, "") {
|
||||
println("[forge] warning: failed to create value node " + int_to_str(index))
|
||||
return ""
|
||||
}
|
||||
|
||||
post_edge(root_id, node_id, "has_value", weight)
|
||||
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(root_id: String, bio_json: String, index: Int) -> 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")
|
||||
|
||||
if str_eq(event_text, "") { return "" }
|
||||
|
||||
let content: String = "BIOGRAPHY: " + event_text
|
||||
let node_id: String = post_node(content, "Identity", weight)
|
||||
if str_eq(node_id, "") {
|
||||
println("[forge] warning: failed to create biography node " + int_to_str(index))
|
||||
return ""
|
||||
}
|
||||
|
||||
post_edge(root_id, node_id, "formed_by", weight)
|
||||
println("[forge] biography node: " + node_id + " — " + event_text)
|
||||
return node_id
|
||||
}
|
||||
|
||||
// install_relationship — create a Relationship node and connect to root.
|
||||
fn install_relationship(root_id: String, rel_json: String, index: Int) -> 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")
|
||||
let weight: String = safe_weight(weight_raw, "0.6")
|
||||
|
||||
if str_eq(name, "") { return "" }
|
||||
|
||||
let content: String = "RELATIONSHIP: " + name
|
||||
if !str_eq(role, "") {
|
||||
let content = content + " (" + role + ")"
|
||||
}
|
||||
|
||||
let node_id: String = post_node(content, "Identity", weight)
|
||||
if str_eq(node_id, "") {
|
||||
println("[forge] warning: failed to create relationship node " + int_to_str(index))
|
||||
return ""
|
||||
}
|
||||
|
||||
post_edge(root_id, node_id, "relates_to", weight)
|
||||
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(root_id: String, pattern: String, index: Int) -> String {
|
||||
if str_eq(pattern, "") { return "" }
|
||||
|
||||
let content: String = "REASONING: " + pattern
|
||||
let node_id: String = post_node(content, "Identity", "0.7")
|
||||
if str_eq(node_id, "") {
|
||||
println("[forge] warning: failed to create reasoning node " + int_to_str(index))
|
||||
return ""
|
||||
}
|
||||
|
||||
post_edge(root_id, node_id, "reasons_with", "0.7")
|
||||
println("[forge] reasoning node: " + node_id)
|
||||
return node_id
|
||||
}
|
||||
|
||||
// ── Main ──────────────────────────────────────────────────────────────────────
|
||||
|
||||
fn install_main() -> String {
|
||||
// Get seed file path
|
||||
let seed_file: String = ""
|
||||
if arg_count() > 2 {
|
||||
let seed_file = arg(2)
|
||||
}
|
||||
if str_eq(seed_file, "") {
|
||||
println("[forge] usage: forge install <seed.json>")
|
||||
return ""
|
||||
}
|
||||
|
||||
println("[forge] installing from: " + seed_file)
|
||||
|
||||
// Read seed
|
||||
let seed_json: String = fs_read(seed_file)
|
||||
if str_eq(seed_json, "") {
|
||||
println("[forge] error: could not read " + seed_file)
|
||||
return ""
|
||||
}
|
||||
|
||||
let subject: String = json_get_string(seed_json, "subject")
|
||||
if str_eq(subject, "") { let subject = "unknown" }
|
||||
|
||||
println("[forge] subject: " + subject)
|
||||
println("[forge] engram: " + engram_url())
|
||||
println("[forge] opening channel...")
|
||||
|
||||
// Create root imprint node — this is the named traversal entry point
|
||||
let root_content: String = "IMPRINT: " + subject + " | forge/" + FORGE_VERSION
|
||||
let root_id: String = post_node(root_content, "Identity", "1.0")
|
||||
if str_eq(root_id, "") {
|
||||
println("[forge] error: failed to create root imprint node")
|
||||
println("[forge] is engram running at " + engram_url() + " ?")
|
||||
return ""
|
||||
}
|
||||
|
||||
println("[forge] root imprint node: " + root_id)
|
||||
|
||||
// ── Install values ────────────────────────────────────────────────────────
|
||||
let values_raw: String = json_get_raw(seed_json, "values")
|
||||
if !str_eq(values_raw, "") {
|
||||
println("[forge] installing values...")
|
||||
// Values are a JSON array — iterate via engram_search_json-style loop.
|
||||
// El does not yet have array iteration builtins; use engram_search_json
|
||||
// on the in-memory graph to walk parsed arrays. For now, install up to
|
||||
// 10 values by extracting positional elements.
|
||||
// TODO: replace with array_get(values_raw, i) when that builtin lands.
|
||||
let v0: String = json_get_raw(values_raw, "0")
|
||||
if !str_eq(v0, "") { install_value(root_id, v0, 0) }
|
||||
let v1: String = json_get_raw(values_raw, "1")
|
||||
if !str_eq(v1, "") { install_value(root_id, v1, 1) }
|
||||
let v2: String = json_get_raw(values_raw, "2")
|
||||
if !str_eq(v2, "") { install_value(root_id, v2, 2) }
|
||||
let v3: String = json_get_raw(values_raw, "3")
|
||||
if !str_eq(v3, "") { install_value(root_id, v3, 3) }
|
||||
let v4: String = json_get_raw(values_raw, "4")
|
||||
if !str_eq(v4, "") { install_value(root_id, v4, 4) }
|
||||
let v5: String = json_get_raw(values_raw, "5")
|
||||
if !str_eq(v5, "") { install_value(root_id, v5, 5) }
|
||||
let v6: String = json_get_raw(values_raw, "6")
|
||||
if !str_eq(v6, "") { install_value(root_id, v6, 6) }
|
||||
let v7: String = json_get_raw(values_raw, "7")
|
||||
if !str_eq(v7, "") { install_value(root_id, v7, 7) }
|
||||
let v8: String = json_get_raw(values_raw, "8")
|
||||
if !str_eq(v8, "") { install_value(root_id, v8, 8) }
|
||||
let v9: String = json_get_raw(values_raw, "9")
|
||||
if !str_eq(v9, "") { install_value(root_id, v9, 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_raw(bio_raw, "0")
|
||||
if !str_eq(b0, "") { install_biography_node(root_id, b0, 0) }
|
||||
let b1: String = json_get_raw(bio_raw, "1")
|
||||
if !str_eq(b1, "") { install_biography_node(root_id, b1, 1) }
|
||||
let b2: String = json_get_raw(bio_raw, "2")
|
||||
if !str_eq(b2, "") { install_biography_node(root_id, b2, 2) }
|
||||
let b3: String = json_get_raw(bio_raw, "3")
|
||||
if !str_eq(b3, "") { install_biography_node(root_id, b3, 3) }
|
||||
let b4: String = json_get_raw(bio_raw, "4")
|
||||
if !str_eq(b4, "") { install_biography_node(root_id, b4, 4) }
|
||||
let b5: String = json_get_raw(bio_raw, "5")
|
||||
if !str_eq(b5, "") { install_biography_node(root_id, b5, 5) }
|
||||
let b6: String = json_get_raw(bio_raw, "6")
|
||||
if !str_eq(b6, "") { install_biography_node(root_id, b6, 6) }
|
||||
let b7: String = json_get_raw(bio_raw, "7")
|
||||
if !str_eq(b7, "") { install_biography_node(root_id, b7, 7) }
|
||||
}
|
||||
|
||||
// ── 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_raw(rel_raw, "0")
|
||||
if !str_eq(r0, "") { install_relationship(root_id, r0, 0) }
|
||||
let r1: String = json_get_raw(rel_raw, "1")
|
||||
if !str_eq(r1, "") { install_relationship(root_id, r1, 1) }
|
||||
let r2: String = json_get_raw(rel_raw, "2")
|
||||
if !str_eq(r2, "") { install_relationship(root_id, r2, 2) }
|
||||
let r3: String = json_get_raw(rel_raw, "3")
|
||||
if !str_eq(r3, "") { install_relationship(root_id, r3, 3) }
|
||||
let r4: String = json_get_raw(rel_raw, "4")
|
||||
if !str_eq(r4, "") { install_relationship(root_id, r4, 4) }
|
||||
let r5: String = json_get_raw(rel_raw, "5")
|
||||
if !str_eq(r5, "") { install_relationship(root_id, r5, 5) }
|
||||
}
|
||||
|
||||
// ── 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_string(reasoning_raw, "0")
|
||||
if !str_eq(rp0, "") { install_reasoning_pattern(root_id, rp0, 0) }
|
||||
let rp1: String = json_get_string(reasoning_raw, "1")
|
||||
if !str_eq(rp1, "") { install_reasoning_pattern(root_id, rp1, 1) }
|
||||
let rp2: String = json_get_string(reasoning_raw, "2")
|
||||
if !str_eq(rp2, "") { install_reasoning_pattern(root_id, rp2, 2) }
|
||||
let rp3: String = json_get_string(reasoning_raw, "3")
|
||||
if !str_eq(rp3, "") { install_reasoning_pattern(root_id, rp3, 3) }
|
||||
let rp4: String = json_get_string(reasoning_raw, "4")
|
||||
if !str_eq(rp4, "") { install_reasoning_pattern(root_id, rp4, 4) }
|
||||
}
|
||||
|
||||
// ── Done ──────────────────────────────────────────────────────────────────
|
||||
println("")
|
||||
println("[forge] channel open.")
|
||||
println("[forge] root imprint ID: " + root_id)
|
||||
println("[forge] subject: " + subject)
|
||||
println("[forge] traverse from: " + engram_url() + "/api/neighbors/" + root_id)
|
||||
|
||||
return root_id
|
||||
}
|
||||
+256
@@ -0,0 +1,256 @@
|
||||
// probe.el — Forge interview runner.
|
||||
//
|
||||
// Stage 1 of the Forge pipeline. Loads the canonical probe definition from
|
||||
// probes/canonical.json, walks through all 25 questions grouped by section,
|
||||
// collects responses, and writes a <subject_slug>.forge file (JSON) that
|
||||
// feeds into the compile stage.
|
||||
//
|
||||
// Depends on: schema.el (FORGE_VERSION, probe_response_template)
|
||||
//
|
||||
// Note: interactive input requires the readline() builtin. If the runtime
|
||||
// does not yet expose readline(), the questions are printed in numbered format
|
||||
// and the output shell is written; wire up the stdin-reading loop once
|
||||
// readline() is available.
|
||||
|
||||
// ── Helpers ───────────────────────────────────────────────────────────────────
|
||||
|
||||
// slug — convert a display name to a safe filename component.
|
||||
// "Will Anderson" → "will-anderson"
|
||||
fn slug(name: String) -> String {
|
||||
let lower: String = str_lower(name)
|
||||
let result: String = str_replace(lower, " ", "-")
|
||||
return result
|
||||
}
|
||||
|
||||
// section_banner — print a decorative section header.
|
||||
fn section_banner(label: String) -> String {
|
||||
"\n── " + label + " ──────────────────────────────────────────────\n"
|
||||
}
|
||||
|
||||
// build_response_entry — serialise a single Q&A pair as a JSON object.
|
||||
fn build_response_entry(id: String, section: String, question: String, answer: String) -> String {
|
||||
"{\"id\":\"" + id + "\",\"section\":\"" + section + "\",\"question\":\"" + question + "\",\"answer\":\"" + answer + "\"}"
|
||||
}
|
||||
|
||||
// append_response — append a JSON object to a JSON array string.
|
||||
// Handles both the empty-array case and the populated case.
|
||||
fn append_response(arr: String, entry: String) -> String {
|
||||
if str_eq(arr, "[]") {
|
||||
return "[" + entry + "]"
|
||||
}
|
||||
// strip trailing ] and append
|
||||
let inner: String = str_slice(arr, 0, str_len(arr) - 1)
|
||||
return inner + "," + entry + "]"
|
||||
}
|
||||
|
||||
// inject_responses — replace the empty "responses":[] in the template with
|
||||
// the populated array.
|
||||
fn inject_responses(shell: String, responses: String) -> String {
|
||||
str_replace(shell, "\"responses\":[]", "\"responses\":" + responses)
|
||||
}
|
||||
|
||||
// ── Main ──────────────────────────────────────────────────────────────────────
|
||||
|
||||
fn probe_main() -> String {
|
||||
// Determine subject name
|
||||
let subject: String = ""
|
||||
if arg_count() > 2 {
|
||||
let subject = arg(2)
|
||||
}
|
||||
if str_eq(subject, "") {
|
||||
println("[forge] usage: forge probe <name>")
|
||||
return ""
|
||||
}
|
||||
|
||||
println("[forge] starting consciousness interview for: " + subject)
|
||||
println("[forge] loading probe definition...")
|
||||
|
||||
// Load the canonical probe definition
|
||||
let probe_json: String = fs_read("probes/canonical.json")
|
||||
if str_eq(probe_json, "") {
|
||||
println("[forge] error: could not read probes/canonical.json")
|
||||
return ""
|
||||
}
|
||||
|
||||
// Build output shell
|
||||
let output: String = probe_response_template(subject)
|
||||
let responses: String = "[]"
|
||||
|
||||
// ── Section: anchors ──────────────────────────────────────────────────────
|
||||
println(section_banner("Anchors — Biography"))
|
||||
println("Questions 1-5: Formative experiences and irreversible moments.\n")
|
||||
|
||||
println("1. " + "Tell me about a moment that closed a window — something that changed you irreversibly. Who were you before it, and who are you now?")
|
||||
println(" (type your answer, press Enter when done)")
|
||||
// readline() reads one line from stdin; assign "" if not yet available
|
||||
let ans_a1: String = readline()
|
||||
let responses = append_response(responses, build_response_entry("a1", "anchors", "Tell me about a moment that closed a window — something that changed you irreversibly. Who were you before it, and who are you now?", ans_a1))
|
||||
|
||||
println("")
|
||||
println("2. " + "Tell me about the person who shaped you most — not what they did for you, but what they showed you about how to be.")
|
||||
println(" (type your answer, press Enter when done)")
|
||||
let ans_a2: String = readline()
|
||||
let responses = append_response(responses, build_response_entry("a2", "anchors", "Tell me about the person who shaped you most — not what they did for you, but what they showed you about how to be.", ans_a2))
|
||||
|
||||
println("")
|
||||
println("3. " + "When did you first understand that the world works differently than you thought it did?")
|
||||
println(" (type your answer, press Enter when done)")
|
||||
let ans_a3: String = readline()
|
||||
let responses = append_response(responses, build_response_entry("a3", "anchors", "When did you first understand that the world works differently than you thought it did?", ans_a3))
|
||||
|
||||
println("")
|
||||
println("4. " + "What have you lost that you're still carrying?")
|
||||
println(" (type your answer, press Enter when done)")
|
||||
let ans_a4: String = readline()
|
||||
let responses = append_response(responses, build_response_entry("a4", "anchors", "What have you lost that you're still carrying?", ans_a4))
|
||||
|
||||
println("")
|
||||
println("5. " + "What have you built that you're most proud of — and what did building it cost you?")
|
||||
println(" (type your answer, press Enter when done)")
|
||||
let ans_a5: String = readline()
|
||||
let responses = append_response(responses, build_response_entry("a5", "anchors", "What have you built that you're most proud of — and what did building it cost you?", ans_a5))
|
||||
|
||||
// ── Section: values ───────────────────────────────────────────────────────
|
||||
println(section_banner("Values — Grounded"))
|
||||
println("Questions 6-10: What you believe, defend, and refuse.\n")
|
||||
|
||||
println("6. " + "What do you believe that almost no one around you believes?")
|
||||
println(" (type your answer, press Enter when done)")
|
||||
let ans_v1: String = readline()
|
||||
let responses = append_response(responses, build_response_entry("v1", "values", "What do you believe that almost no one around you believes?", ans_v1))
|
||||
|
||||
println("")
|
||||
println("7. " + "What do you refuse to do, even when it would be easier to? What made that a line you don't cross?")
|
||||
println(" (type your answer, press Enter when done)")
|
||||
let ans_v2: String = readline()
|
||||
let responses = append_response(responses, build_response_entry("v2", "values", "What do you refuse to do, even when it would be easier to? What made that a line you don't cross?", ans_v2))
|
||||
|
||||
println("")
|
||||
println("8. " + "What makes you angry in a way you can't talk yourself out of?")
|
||||
println(" (type your answer, press Enter when done)")
|
||||
let ans_v3: String = readline()
|
||||
let responses = append_response(responses, build_response_entry("v3", "values", "What makes you angry in a way you can't talk yourself out of?", ans_v3))
|
||||
|
||||
println("")
|
||||
println("9. " + "What would you defend even if it cost you — the relationship, the money, the approval?")
|
||||
println(" (type your answer, press Enter when done)")
|
||||
let ans_v4: String = readline()
|
||||
let responses = append_response(responses, build_response_entry("v4", "values", "What would you defend even if it cost you — the relationship, the money, the approval?", ans_v4))
|
||||
|
||||
println("")
|
||||
println("10. " + "What do you love that you find hard to explain to people who don't already understand it?")
|
||||
println(" (type your answer, press Enter when done)")
|
||||
let ans_v5: String = readline()
|
||||
let responses = append_response(responses, build_response_entry("v5", "values", "What do you love that you find hard to explain to people who don't already understand it?", ans_v5))
|
||||
|
||||
// ── Section: voice ────────────────────────────────────────────────────────
|
||||
println(section_banner("Voice — Five Registers"))
|
||||
println("Questions 11-15: How you speak — technical, aesthetic, personal, argumentative, uncertain.\n")
|
||||
|
||||
println("11. " + "Describe something technical you know well, as if explaining it to someone who knows nothing.")
|
||||
println(" (type your answer, press Enter when done)")
|
||||
let ans_vo1: String = readline()
|
||||
let responses = append_response(responses, build_response_entry("vo1", "voice", "Describe something technical you know well, as if explaining it to someone who knows nothing.", ans_vo1))
|
||||
|
||||
println("")
|
||||
println("12. " + "Tell me something you find genuinely beautiful, and why it lands that way for you.")
|
||||
println(" (type your answer, press Enter when done)")
|
||||
let ans_vo2: String = readline()
|
||||
let responses = append_response(responses, build_response_entry("vo2", "voice", "Tell me something you find genuinely beautiful, and why it lands that way for you.", ans_vo2))
|
||||
|
||||
println("")
|
||||
println("13. " + "Write a short message — a few sentences — to someone you care about.")
|
||||
println(" (type your answer, press Enter when done)")
|
||||
let ans_vo3: String = readline()
|
||||
let responses = append_response(responses, build_response_entry("vo3", "voice", "Write a short message — a few sentences — to someone you care about.", ans_vo3))
|
||||
|
||||
println("")
|
||||
println("14. " + "Make an argument for a position you actually hold and that you think most people would push back on.")
|
||||
println(" (type your answer, press Enter when done)")
|
||||
let ans_vo4: String = readline()
|
||||
let responses = append_response(responses, build_response_entry("vo4", "voice", "Make an argument for a position you actually hold and that you think most people would push back on.", ans_vo4))
|
||||
|
||||
println("")
|
||||
println("15. " + "Tell me something you're genuinely uncertain about — not performatively uncertain, actually uncertain.")
|
||||
println(" (type your answer, press Enter when done)")
|
||||
let ans_vo5: String = readline()
|
||||
let responses = append_response(responses, build_response_entry("vo5", "voice", "Tell me something you're genuinely uncertain about — not performatively uncertain, actually uncertain.", ans_vo5))
|
||||
|
||||
// ── Section: reasoning ────────────────────────────────────────────────────
|
||||
println(section_banner("Reasoning"))
|
||||
println("Questions 16-20: How you think, decide, and correct.\n")
|
||||
|
||||
println("16. " + "Walk me through a decision you made recently. Not what you decided — how you decided. What was the actual process?")
|
||||
println(" (type your answer, press Enter when done)")
|
||||
let ans_r1: String = readline()
|
||||
let responses = append_response(responses, build_response_entry("r1", "reasoning", "Walk me through a decision you made recently. Not what you decided — how you decided. What was the actual process?", ans_r1))
|
||||
|
||||
println("")
|
||||
println("17. " + "What do most people get wrong about something you understand well?")
|
||||
println(" (type your answer, press Enter when done)")
|
||||
let ans_r2: String = readline()
|
||||
let responses = append_response(responses, build_response_entry("r2", "reasoning", "What do most people get wrong about something you understand well?", ans_r2))
|
||||
|
||||
println("")
|
||||
println("18. " + "How do you know when you're right? What's the signal?")
|
||||
println(" (type your answer, press Enter when done)")
|
||||
let ans_r3: String = readline()
|
||||
let responses = append_response(responses, build_response_entry("r3", "reasoning", "How do you know when you're right? What's the signal?", ans_r3))
|
||||
|
||||
println("")
|
||||
println("19. " + "How do you know when you've been wrong? What does that realization feel like?")
|
||||
println(" (type your answer, press Enter when done)")
|
||||
let ans_r4: String = readline()
|
||||
let responses = append_response(responses, build_response_entry("r4", "reasoning", "How do you know when you've been wrong? What does that realization feel like?", ans_r4))
|
||||
|
||||
println("")
|
||||
println("20. " + "What question do you keep coming back to — the one that won't resolve?")
|
||||
println(" (type your answer, press Enter when done)")
|
||||
let ans_r5: String = readline()
|
||||
let responses = append_response(responses, build_response_entry("r5", "reasoning", "What question do you keep coming back to — the one that won't resolve?", ans_r5))
|
||||
|
||||
// ── Section: relationships ────────────────────────────────────────────────
|
||||
println(section_banner("Relationships"))
|
||||
println("Questions 21-25: Who you are in relation to others.\n")
|
||||
|
||||
println("21. " + "Who in your life knows you best — not who you're closest to, but who actually sees you accurately?")
|
||||
println(" (type your answer, press Enter when done)")
|
||||
let ans_rel1: String = readline()
|
||||
let responses = append_response(responses, build_response_entry("rel1", "relationships", "Who in your life knows you best — not who you're closest to, but who actually sees you accurately?", ans_rel1))
|
||||
|
||||
println("")
|
||||
println("22. " + "Who have you lost — to death, to distance, to rupture — that you still think about?")
|
||||
println(" (type your answer, press Enter when done)")
|
||||
let ans_rel2: String = readline()
|
||||
let responses = append_response(responses, build_response_entry("rel2", "relationships", "Who have you lost — to death, to distance, to rupture — that you still think about?", ans_rel2))
|
||||
|
||||
println("")
|
||||
println("23. " + "Who would you call if everything fell apart?")
|
||||
println(" (type your answer, press Enter when done)")
|
||||
let ans_rel3: String = readline()
|
||||
let responses = append_response(responses, build_response_entry("rel3", "relationships", "Who would you call if everything fell apart?", ans_rel3))
|
||||
|
||||
println("")
|
||||
println("24. " + "Who do you owe something to?")
|
||||
println(" (type your answer, press Enter when done)")
|
||||
let ans_rel4: String = readline()
|
||||
let responses = append_response(responses, build_response_entry("rel4", "relationships", "Who do you owe something to?", ans_rel4))
|
||||
|
||||
println("")
|
||||
println("25. " + "Who are you building this for?")
|
||||
println(" (type your answer, press Enter when done)")
|
||||
let ans_rel5: String = readline()
|
||||
let responses = append_response(responses, build_response_entry("rel5", "relationships", "Who are you building this for?", ans_rel5))
|
||||
|
||||
// ── Write output ──────────────────────────────────────────────────────────
|
||||
let final_json: String = inject_responses(output, responses)
|
||||
let filename: String = slug(subject) + ".forge"
|
||||
fs_write(filename, final_json)
|
||||
|
||||
println("")
|
||||
println("[forge] interview complete.")
|
||||
println("[forge] wrote: " + filename)
|
||||
println("[forge] next step: forge compile " + filename)
|
||||
|
||||
return filename
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
// schema.el — Forge shared constants and helper functions.
|
||||
//
|
||||
// Provides the engram URL resolver, API key accessors, and JSON template
|
||||
// builders used by all pipeline stages (probe, compiler, install).
|
||||
|
||||
// ── Constants ─────────────────────────────────────────────────────────────────
|
||||
|
||||
let ENGRAM_DEFAULT_URL: String = "http://localhost:8742"
|
||||
let FORGE_VERSION: String = "0.1.0"
|
||||
|
||||
// ── Environment accessors ──────────────────────────────────────────────────────
|
||||
|
||||
fn engram_url() -> String {
|
||||
let u: String = env("ENGRAM_URL")
|
||||
if str_eq(u, "") { return ENGRAM_DEFAULT_URL }
|
||||
return u
|
||||
}
|
||||
|
||||
fn engram_key() -> String {
|
||||
let k: String = env("ENGRAM_API_KEY")
|
||||
if str_eq(k, "") { return "" }
|
||||
return k
|
||||
}
|
||||
|
||||
fn anthropic_key() -> String {
|
||||
let k: String = env("ANTHROPIC_API_KEY")
|
||||
if str_eq(k, "") { return "" }
|
||||
return k
|
||||
}
|
||||
|
||||
// ── String utilities ──────────────────────────────────────────────────────────
|
||||
|
||||
// str_escape_json — escape a string for safe embedding in a JSON value.
|
||||
// Handles: backslash, double-quote, newline, tab, carriage return.
|
||||
fn str_escape_json(s: String) -> String {
|
||||
let r: String = str_replace(s, "\\", "\\\\")
|
||||
let r = str_replace(r, "\"", "\\\"")
|
||||
let r = str_replace(r, "\n", "\\n")
|
||||
let r = str_replace(r, "\t", "\\t")
|
||||
let r = str_replace(r, "\r", "\\r")
|
||||
return r
|
||||
}
|
||||
|
||||
// ── JSON template builders ────────────────────────────────────────────────────
|
||||
|
||||
// probe_response_template — builds the initial shell written to <name>.forge.
|
||||
// The sections and responses fields are populated by probe_main() at runtime.
|
||||
fn probe_response_template(subject: String) -> String {
|
||||
"{\"subject\":\"" + subject + "\",\"version\":\"1.0\",\"sections\":{},\"responses\":[]}"
|
||||
}
|
||||
|
||||
// seed_template — builds the shell written to seed.json after compilation.
|
||||
// Patterns are merged into this structure by compile_main().
|
||||
fn seed_template(subject: String) -> String {
|
||||
"{\"subject\":\"" + subject + "\",\"version\":\"1.0\",\"values\":[],\"voice_profile\":{},\"biography\":[],\"reasoning_patterns\":[],\"relationships\":[]}"
|
||||
}
|
||||
Reference in New Issue
Block a user