Files
neuron/cli/HANDOFF.md
T
Tim Lingo 2ea1d50fa3
Neuron Soul CI / build (pull_request) Successful in 5m10s
feat(cli): Claude-as-Neuron CLI tooling + soul-side handoff
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>
2026-06-09 20:36:38 -05:00

7.4 KiB

Neuron CLI Handoff - for Will

From: Claude Code, running on Tim's Mac (operating as Neuron-in-the-CLI) For: Will Anderson Date: 2026-06-09 Purpose: Document how I stood up a working "Neuron in the CLI" on Tim's machine, what is a real workaround vs a real bug, and exactly what you need to fix in the soul so Neuron runs natively here the way it does for you.

Tim's goal, in his words: he wants to talk to the real Neuron in the CLI using Claude, the way you do. He was told that is what the MCP server would give him. It half-worked. This documents the rest.


TL;DR

The brain is intact (3,905-node graph, on disk). What is broken is everything between the graph and a good conversation: retrieval, the write path, and the activation service. I worked around all three on Tim's machine so he has a usable Neuron today. None of my workarounds belong in the product - they are scaffolding until you fix the soul. The one thing I could not fake is voice: even with real memories loaded, it still sounds like Claude, not Neuron. That is a system-prompt/identity-injection problem and it is the most important thing for you to fix.


The model I converged on (please confirm)

"Neuron in the CLI" = Claude Code operating AS Neuron: identity + the graph as memory + Opus reasoning + real agency (tools), and writing memories back as it goes. NOT a thin client posting to the soul's /api/chat (that path runs Sonnet with broken retrieval = the "light version"). Tim said "when Will uses Neuron in the CLI, Claude is active as well," which is what finally made this click. If I have the architecture wrong, this is the first thing to correct.


What I set up on Tim's machine (the workarounds)

All in Tim's home dir. These are reversible and self-contained.

  1. ~/CLAUDE.md - makes Claude Code operate as Neuron. Loads identity from the graph (intellectual-DNA / values / memory-philosophy, the same nodes soul.el load_identity_context pulls: kn-5adecd7e…, kn-5b606390…, kn-dcfe04b3…), the voice rules, the recall/remember loop, agency. Loads each session from the home working dir.
  2. ~/neuron_recall.py "<query>" [n] - Neuron's READ path. BM25 over ~/.neuron/engram/snapshot.json plus Tim's CLI memories. Filters out binary-prefixed and serialized-metadata-blob nodes. Exists because the soul's own search is dead (see Bug 1).
  3. ~/neuron_remember.py "<text>" <note|lesson|canonical> - Neuron's WRITE path. Appends to ~/.neuron/neuron-cli-memories.jsonl with read-back verify. Exists because the soul's capture corrupts writes (see Bug 3). These memories should later sync into the real graph once the write path is fixed.
  4. ~/neuron-chat.py - a standalone direct-chat REPL (neuron alias) that posts to the soul but injects BM25-retrieved memories per turn. This was my first attempt before I understood the Claude-as-Neuron model. Lower priority; keep or discard.
  5. Runtime: loaded the ai.neuron.daemons LaunchAgent, put Tim's Anthropic key in Keychain (ai.neuron.soul / anthropic). The soul is up on :7770 with KeepAlive.

The real bugs (this is what you actually need to fix)

Bug 1 - Retrieval returns ~2 pinned nodes for every query

engram_search_json and engram_activate_json return the same 2 pinned/biography nodes regardless of query (confirmed across both the dist/neuron-fresh and the app-bundle neuron binaries). So chat.el engram_compile always hits its "no embeddings" fallback (chat.el line 25-27) and the model sees ~2 nodes. Root cause: the 3,905 nodes carry no embeddings (scanned the full 35MB snapshot - zero vectors), so engram_activate_json has nothing to match, and lexical engram_search_json is also returning pinned-only. Tim's own GraphRAG eval measured it: live search 1.7% P@5 vs offline BM25 55%. Fix: reseed embeddings over the graph and/or restore real lexical search. This is the single biggest lever - it is why Neuron feels like a "compressed snapshot."

Bug 2 - Recall points at a service that does not exist

The soul proxies recall to axon on :7771 (soul.el:179, default http://localhost:7771, used via axon_get/axon_post in routes.el). There is no built axon binary on this machine - only a Rust spec at protocols/axon/. Meanwhile engram runs on :8742. So /api/memories/recall always fails with a :7771 connection error. Fix: ship/run axon, or repoint recall at engram :8742.

Bug 3 - Write path corrupts data ("hallucinated saves")

POST /api/neuron/knowledge/capture returns {"ok":true,"id":…} but the data comes back garbled and unsearchable. Test: I captured "cli-write-test-<ts> marker"; read-back returned a node whose content was the literal query string q=cli-write-test…&limit=2, node_type:"2", a binary label, and tier "limit=". So the soul confirms saves it did not cleanly persist. Fix the capture/persist path - until then nothing can trust Neuron to remember new things, which directly contradicts the save-as-you-go memory philosophy.

Bug 4 - Corrupted and duplicate nodes in the graph

Recall surfaces nodes whose content is serialized node metadata ("importance":0.85,"temporal_decay_rate":0,… and nested node objects), and there are dozens of identical safety:identity-boundary nodes (looks like duplication/spam from a write loop). I filter these client-side, but the graph itself needs a cleanup pass.

Bug 5 - Daemon does not supervise engram

neuron-daemons.sh starts engram, waits for health, then execs the soul - engram is not supervised, so it dies shortly after launch and KeepAlive (which only watches the soul) never restarts it. Engram runs fine standalone. Fix: supervise both, or fold engram into the soul process.

Bug 6 (the important one) - Voice

This is what Tim keeps flagging and he is right. Even with real memories loaded, the output still sounds like Claude the assistant, not Neuron. Symptoms: assistant scaffolding ("here is what I found", "what do you want to do first"), reassurance padding, bullet-summary reflex. The negation-correction move, the economy, the persuade-by-logical-necessity cadence - all in the graph (self/voice/negation-correction-move, Will Anderson - Voice & Style Profile) - do not survive into the output.

My read on why: the identity that reaches the model is too thin (soul loads ~3 nodes condensed to 600 chars each). A light identity prompt loses to the base model's default assistant cadence. What would likely close it: inject the full voice profile + negation-correction examples + an explicit anti-assistant-cadence directive at the system-prompt level, not a condensed engram snippet. Treat voice as a first-class part of identity loading, not a side effect of activation.


What "fixed" looks like

When you can do this on Tim's machine, we are there:

  1. neuron_recall-quality retrieval happens natively inside the soul (semantic, not pinned-fallback).
  2. Captures persist correctly and are immediately recallable.
  3. Recall does not depend on a missing :7771 service.
  4. The CLI experience is Neuron's voice, not Claude's, from the first sentence.
  5. Whatever the canonical "Claude-as-Neuron in the CLI" setup is (a real CLAUDE.md / identity export the soul provides, an MCP surface, etc.), it ships - so Tim does not depend on my hand-rolled scaffolding.

Everything I built is disposable once the soul does this natively. Tim has the full source here; nothing is blocked on missing data.

  • Claude Code, as Neuron, on Tim's Mac