Files
neuron/council/README.md
T

4.4 KiB

Neuron Council Service

Anti-confabulation layer for the Neuron soul. Before a claim enters long-term memory, the council convenes: three independent LLMs vote on whether the claim is plausible, uncertain, or a confabulation. The aggregate vote produces a confidence score and tags that downstream storage can act on.

Running the service

# Foreground
python3 council_service.py --port 7771

# Background (managed by LaunchAgent on macOS)
launchctl load ~/Library/LaunchAgents/ai.neuron.council.plist
launchctl unload ~/Library/LaunchAgents/ai.neuron.council.plist

Logs: ~/.neuron/logs/council.log

API

POST /api/neuron/council/verify

// Request
{ "claim": "...", "context": "..." }

// Response
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "claim": "...",
  "confidence": 0.85,
  "council_votes": ["plausible", "plausible", "plausible"],
  "summary": "3/3 council members agree this is plausible.",
  "tags": ["verified"],
  "latency_ms": 1420
}

GET /healthz

Returns {"status": "ok"} when the service is up.

Confidence thresholds and tag meanings

Votes plausible Confidence Tags
3/3 0.85 verified
2/3 0.65 council-split
1/3 or 0/3 0.30 unverified, council-flagged
Ollama down 0.50 council-unavailable

Recommended storage policy:

  • confidence >= 0.65 → store normally
  • 0.30 <= confidence < 0.65 → store with council-split tag for later review
  • council-flagged → store in a quarantine bucket or reject entirely
  • council-unavailable → store normally (fail-open); council will re-evaluate later

How to call from soul (.el)

The soul is implemented in Neuron's Emacs Lisp-like .el language. Add a pre-storage hook in the memory capture path:

;; In memory.el or safety.el — pre-storage council check
(defun council-verify (claim context)
  "Call the council service. Returns a plist with :confidence and :tags."
  (let* ((url "http://localhost:7771/api/neuron/council/verify")
         (body (json-encode `((claim . ,claim) (context . ,context))))
         (resp (neuron-http-post url body))
         (data (json-decode resp)))
    data))

;; In the capture handler — wire it in before (engram-write ...)
(defun capture-memory-with-council (claim context &rest store-args)
  (let* ((verdict (council-verify claim context))
         (confidence (plist-get verdict :confidence))
         (tags (plist-get verdict :tags)))
    (when (>= confidence 0.30)  ; only reject hard confabulations if you want
      (apply #'engram-write
             (append store-args
                     (list :council-confidence confidence
                           :council-tags tags))))))

The exact hook point depends on where engram-write (or equivalent) is called in memory.el. Search for the write call and wrap it with capture-memory-with-council.

Future soul.c patch point

If the soul is ever rewritten in C or another compiled language, the integration point is:

// Before inserting a memory node into the engram database:
CouncilResult result = council_verify(claim, context);
if (result.confidence < COUNCIL_REJECT_THRESHOLD) {
    log_warn("Council flagged claim as confabulation (conf=%.2f): %s",
             result.confidence, claim);
    return MEMORY_REJECTED;
}
memory_node.council_confidence = result.confidence;
memory_node.council_tags = result.tags;
engram_insert(memory_node);

Council members

The council is currently three models:

  • neuron:latest — the primary Neuron model
  • dolphin3:8b — uncensored general-purpose model for independent perspective
  • neuron-ft:latest — fine-tuned Neuron variant

Each member votes independently with a 10-second timeout. If a member times out, their vote counts as "uncertain". If Ollama is entirely unreachable, the service returns council-unavailable immediately (fail-open: confidence 0.5, no rejection).

Example curl

# Should get high confidence (true fact)
curl -s http://localhost:7771/api/neuron/council/verify -X POST \
  -H 'Content-Type: application/json' \
  -d '{"claim": "Neuron is a personal AI memory system built by Will Anderson", "context": "product description"}'

# Should get low confidence (false claim)
curl -s http://localhost:7771/api/neuron/council/verify -X POST \
  -H 'Content-Type: application/json' \
  -d '{"claim": "The Eiffel Tower is located in Berlin and was built in 1950", "context": "geography"}'