feat(cli): Claude-as-Neuron CLI tooling + soul-side handoff
Neuron Soul CI / build (pull_request) Successful in 5m10s
Neuron Soul CI / build (pull_request) Successful in 5m10s
Tooling built on Tim's machine to run Neuron from the terminal as a
Claude Code session (identity + graph memory + agency) instead of
relaying to the soul's /api/chat.
- cli/neuron_recall.py BM25 read over the engram snapshot + CLI memories
(works around pinned-only soul search)
- cli/neuron_remember.py reliable local memory writes with read-back verify
(works around the corrupting capture endpoint)
- cli/neuron-chat.py standalone direct-chat REPL with per-turn memory injection
- cli/neuron_mcp.py stdlib MCP server (chat/search) with graceful degradation
- cli/CLAUDE.md.example the operating identity that makes Claude Code run as Neuron
- cli/HANDOFF.md soul-side bugs to fix so this becomes unnecessary
Scaffolding/proposal - intended to be retired once the soul does native
retrieval, correct persistence, and a real CLI identity/voice surface.
Pairs with the runtime model-passthrough + UTF-8 fixes in the el repo.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
neuron_remember — Neuron's memory write path (save as you go).
|
||||
|
||||
Appends a memory to ~/.neuron/neuron-cli-memories.jsonl, a reliable local store
|
||||
that neuron_recall.py indexes alongside the graph. Used because the soul's own
|
||||
capture path corrupts/loses writes. These can later be synced into the engram
|
||||
graph once the soul's write path is fixed.
|
||||
|
||||
Usage:
|
||||
python3 ~/neuron_remember.py "Tim prefers X because Y" lesson
|
||||
python3 ~/neuron_remember.py "<observation>" # tier defaults to note
|
||||
|
||||
Tiers (Neuron's memory-philosophy): note -> lesson -> canonical
|
||||
"""
|
||||
import hashlib
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
|
||||
MEMS = os.path.expanduser("~/.neuron/neuron-cli-memories.jsonl")
|
||||
VALID_TIERS = ("note", "lesson", "canonical")
|
||||
|
||||
|
||||
def main():
|
||||
if len(sys.argv) < 2 or not sys.argv[1].strip():
|
||||
print("usage: neuron_remember.py \"<observation>\" [note|lesson|canonical]")
|
||||
return 1
|
||||
content = sys.argv[1].strip()
|
||||
tier = sys.argv[2].strip().lower() if len(sys.argv) > 2 else "note"
|
||||
if tier not in VALID_TIERS:
|
||||
tier = "note"
|
||||
|
||||
ts = int(time.time())
|
||||
mid = "ncli-" + hashlib.sha1(f"{ts}:{content}".encode()).hexdigest()[:12]
|
||||
rec = {"id": mid, "ts": ts, "tier": tier, "content": content}
|
||||
|
||||
os.makedirs(os.path.dirname(MEMS), exist_ok=True)
|
||||
# dedupe: skip if identical content already saved
|
||||
if os.path.exists(MEMS):
|
||||
for line in open(MEMS, encoding="utf-8", errors="replace"):
|
||||
try:
|
||||
if json.loads(line).get("content") == content:
|
||||
print(f"(already remembered: {mid})")
|
||||
return 0
|
||||
except Exception:
|
||||
pass
|
||||
with open(MEMS, "a", encoding="utf-8") as f:
|
||||
f.write(json.dumps(rec, ensure_ascii=False) + "\n")
|
||||
|
||||
# read-back verify (never claim a save that didn't land)
|
||||
ok = any(json.loads(l).get("id") == mid
|
||||
for l in open(MEMS, encoding="utf-8", errors="replace") if l.strip())
|
||||
total = sum(1 for l in open(MEMS, encoding="utf-8", errors="replace") if l.strip())
|
||||
print(f"{'saved' if ok else 'FAILED'} [{tier}] {mid} (neuron memories: {total})")
|
||||
return 0 if ok else 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Reference in New Issue
Block a user