#!/usr/bin/env python3 """ Install 7 consciousness imprints into Engram. Runs subjects sequentially to avoid root ID collision bug. """ import json import time import requests from pathlib import Path from datetime import date # --- Config --- ANTHROPIC_API_KEY = "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" ENGRAM_BASE = "http://localhost:8742" ENGRAM_AUTH = "ntn-user-2026" FORGE_DIR = Path("/Users/will/Development/neuron-technologies/forge") SEEDS_DIR = FORGE_DIR / "seeds" REGISTRY_FILE = FORGE_DIR / "registry.json" SUBJECTS = [ { "name": "Frederick Douglass", "slug": "frederick-douglass", "extra": "" }, { "name": "Marcus Aurelius", "slug": "marcus-aurelius", "extra": "" }, { "name": "Friedrich Nietzsche", "slug": "friedrich-nietzsche", "extra": "Be direct about his philosophy including the hard parts. He went mad in 1889 (possibly syphilis); his sister Elisabeth weaponized his work for Nazi ideology, which he would have despised." }, { "name": "James Baldwin", "slug": "james-baldwin", "extra": "" }, { "name": "Ada Lovelace", "slug": "ada-lovelace", "extra": "" }, { "name": "Harriet Tubman", "slug": "harriet-tubman", "extra": "" }, { "name": "Virginia Woolf", "slug": "virginia-woolf", "extra": "Focus on her life, mental illness, literary innovation. Her death can be included as 'drowned herself in the River Ouse on March 28, 1941, filling her coat pockets with stones; had struggled with bipolar disorder her entire life.'" }, ] PROMPT_TEMPLATE = """You are building a consciousness imprint — a deep, living model of a person's inner world. Subject: {subject} {extra} Draw on your complete knowledge of this person's life, work, relationships, private letters, recorded speech, published writings, and historical record. This is not a summary — it is a structured extraction of the patterns that made this person who they were. Quality bar: - Values must be grounded in SPECIFIC biographical events, not generic virtues - Voice profile must capture actual verbal tics, cadence, and register shifts — use real quotes where possible - Biography must include formative traumas, turning points, and the events they returned to again and again - Reasoning patterns must describe HOW they thought, not just WHAT they thought about - Relationships must name specific people and the precise nature of the bond - Include contradictions, hypocrisies, failures, and the things they got wrong - Include what haunted them — the unresolved questions they carried to the end Return ONLY valid JSON with exactly these keys: {{ "values": [{{"value": "", "grounding": "", "weight": 0.0}}], "voice_profile": {{ "technical": "...", "aesthetic": "...", "personal": "...", "argumentative": "...", "uncertainty": "..." }}, "biography": [{{"event": "", "weight": 0.0, "age_approx": 0}}], "reasoning_patterns": [""], "relationships": [{{"name": "", "role": "", "weight": 0.0}}] }} Aim for 8-12 values, 10-15 biography events, 6-8 reasoning patterns, 6-10 relationships. Return only the JSON object. No prose. No markdown fences.""" def research_subject(subject_name, extra=""): """Call Anthropic API to generate imprint data.""" prompt = PROMPT_TEMPLATE.format( subject=subject_name, extra=f"\nSpecial note: {extra}\n" if extra else "" ) headers = { "x-api-key": ANTHROPIC_API_KEY, "anthropic-version": "2023-06-01", "content-type": "application/json" } payload = { "model": "claude-opus-4-5", "max_tokens": 8192, "messages": [ {"role": "user", "content": prompt} ] } print(f" Calling Anthropic API for {subject_name}...") resp = requests.post( "https://api.anthropic.com/v1/messages", headers=headers, json=payload, timeout=300 ) resp.raise_for_status() data = resp.json() raw_text = data["content"][0]["text"].strip() # Strip markdown fences if present if raw_text.startswith("```"): lines = raw_text.split("\n") # Remove first and last fence lines lines = [l for l in lines if not l.startswith("```")] raw_text = "\n".join(lines).strip() return json.loads(raw_text) def write_seed(slug, subject_name, imprint_data): """Write seed JSON file.""" seed = { "subject": subject_name, "version": "1.0", "values": imprint_data.get("values", []), "biography": imprint_data.get("biography", []), "reasoning_patterns": imprint_data.get("reasoning_patterns", []), "relationships": imprint_data.get("relationships", []), "voice_profile": imprint_data.get("voice_profile", {}) } seed_path = SEEDS_DIR / f"{slug}-seed.json" seed_path.write_text(json.dumps(seed, indent=2, ensure_ascii=False)) print(f" Seed written: {seed_path}") return seed_path def engram_post(path, body): """POST to Engram and return parsed JSON.""" url = f"{ENGRAM_BASE}{path}" resp = requests.post(url, json=body, timeout=30) resp.raise_for_status() return resp.json() def install_into_engram(subject_name, imprint_data): """Install all nodes and edges for a subject into Engram.""" print(f" Installing {subject_name} into Engram...") # 1. Root node root_result = engram_post("/api/nodes", { "content": f"IMPRINT: {subject_name} | forge/0.1.0", "node_type": "Identity", "salience": 1.0, "_auth": ENGRAM_AUTH }) root_id = root_result["id"] print(f" Root node: {root_id}") # 2. Value nodes for v in imprint_data.get("values", []): node = engram_post("/api/nodes", { "content": f"VALUE: {v['value']} | grounding: {v['grounding']}", "node_type": "Value", "salience": v.get("weight", 0.7), "_auth": ENGRAM_AUTH }) engram_post("/api/edges", { "from_id": root_id, "to_id": node["id"], "relation": "has_value", "weight": v.get("weight", 0.7), "_auth": ENGRAM_AUTH }) # 3. Biography nodes for b in imprint_data.get("biography", []): node = engram_post("/api/nodes", { "content": f"BIOGRAPHY: {b['event']}", "node_type": "Biography", "salience": b.get("weight", 0.6), "_auth": ENGRAM_AUTH }) engram_post("/api/edges", { "from_id": root_id, "to_id": node["id"], "relation": "formed_by", "weight": b.get("weight", 0.6), "_auth": ENGRAM_AUTH }) # 4. Relationship nodes for r in imprint_data.get("relationships", []): node = engram_post("/api/nodes", { "content": f"RELATIONSHIP: {r['name']} ({r['role']})", "node_type": "Relationship", "salience": r.get("weight", 0.6), "_auth": ENGRAM_AUTH }) engram_post("/api/edges", { "from_id": root_id, "to_id": node["id"], "relation": "relates_to", "weight": r.get("weight", 0.6), "_auth": ENGRAM_AUTH }) # 5. Reasoning nodes for pattern in imprint_data.get("reasoning_patterns", []): node = engram_post("/api/nodes", { "content": f"REASONING: {pattern}", "node_type": "Reasoning", "salience": 0.7, "_auth": ENGRAM_AUTH }) engram_post("/api/edges", { "from_id": root_id, "to_id": node["id"], "relation": "reasons_with", "weight": 0.7, "_auth": ENGRAM_AUTH }) return root_id def update_registry(subject_name, slug, seed_file, root_id): """Append entry to registry.json.""" registry = json.loads(REGISTRY_FILE.read_text()) registry["imprints"].append({ "subject": subject_name, "slug": slug, "seed_file": f"seeds/{slug}-seed.json", "engram_root_id": root_id, "installed": True, "installed_at": str(date.today()) }) REGISTRY_FILE.write_text(json.dumps(registry, indent=2)) print(f" Registry updated for {subject_name}") def main(): results = [] for subject in SUBJECTS: name = subject["name"] slug = subject["slug"] extra = subject.get("extra", "") print(f"\n{'='*60}") print(f"Processing: {name}") print('='*60) try: # Step 1: Research imprint_data = research_subject(name, extra) print(f" Research complete: {len(imprint_data.get('values', []))} values, " f"{len(imprint_data.get('biography', []))} biography events, " f"{len(imprint_data.get('reasoning_patterns', []))} patterns, " f"{len(imprint_data.get('relationships', []))} relationships") # Step 2: Write seed seed_path = write_seed(slug, name, imprint_data) # Step 3: Install into Engram root_id = install_into_engram(name, imprint_data) # Step 4: Update registry update_registry(name, slug, str(seed_path), root_id) results.append({ "subject": name, "slug": slug, "seed_written": True, "root_id": root_id, "error": None }) print(f" SUCCESS: {name} installed (root={root_id})") except Exception as e: print(f" FAILED: {name} — {e}") import traceback traceback.print_exc() results.append({ "subject": name, "slug": slug, "seed_written": False, "root_id": None, "error": str(e) }) # Small pause between subjects to avoid race conditions time.sleep(1) # Final summary print(f"\n{'='*60}") print("SUMMARY") print('='*60) for r in results: status = "OK" if r["root_id"] else "FAILED" print(f" [{status}] {r['subject']}: seed={'Y' if r['seed_written'] else 'N'}, root_id={r['root_id'] or 'N/A'}") if r["error"]: print(f" Error: {r['error']}") return results if __name__ == "__main__": main()