From Nodes to Neurons


Three weeks in, the domain was Node, Edge, Graph. A clean, generic, property-graph triple. Then I renamed them to Neuron, Synapse, Cortex. And the architecture changed.

Is a rename ever just a rename? Sometimes, sure. This one wasn’t. This is a story about what commitment new names carry.

Context

The original domain was the smallest thing that worked:

struct Node {
    NodeId id;
    std::string name;
    std::string content;
    Metadata metadata;
    uint64_t version;
};

struct Edge {
    EdgeId id;
    NodeId source;
    NodeId target;
    std::string relationship;   // stored in metadata
    Metadata metadata;
};

Two structs and a map. Worked for two months. Then I kept catching myself reaching for things this model just didn’t support:

  • “How recently was this edge traversed?” — last_activated.
  • “How confident am I that this edge is correct?” — confidence.
  • “How strong is this connection? Has it been reinforced by use?” — strength, plasticity.
  • “Two nodes fired together repeatedly; should there be an edge between them now?” — Hebbian learning.

Every one of those is a brain-inspired concept dressed up as property-graph metadata. To be honest, the model wasn’t fighting me, but it wasn’t shaping me either. I was free to add anything — and “free to add anything” is another way of saying “no domain at all.”

The rename

The spec landed on 2026-04-07 as ADR-031 — Brain-Inspired Domain Model. The renames look cosmetic:

BeforeAfter
NodeNeuron
EdgeSynapse
GraphCortex

But the implication isn’t cosmetic at all. Each rename comes with a biological commitment:

  • A neuron integrates signals, fires when activated, and has state. It is not passive data.
  • A synapse is a physical connection between two neurons with a weight, a confidence, and a plasticity. It can strengthen or decay.
  • A cortex is a network of neurons connected by synapses. It is not a property graph.

Once those words are on the page, four design decisions follow mechanically. You can’t call something a synapse and not give it plasticity. Effectively, the name does the arguing for you.

The four mechanical consequences

1. Synapses gain first-class plasticity fields

The Synapse struct grew three fields and promoted relationship from metadata to a typed field:

struct Synapse {
    SynapseId id;
    NeuronId source;
    NeuronId target;
    RelationshipKind relationship;     // now first-class, not metadata
    double strength;                   // 0.0–1.0  (synaptic weight)
    double confidence;                 // 0.0–1.0
    TimePoint last_activated;          // last traversal/activation
    Metadata metadata;                 // bi-temporal + open-world fields
};

Plasticity isn’t free, though. It needs an engine. ADR-032 — Synaptic Plasticity specifies three mechanisms:

  • Hebbian co-activation strengthening — when two neurons fire together (within a window), the synapse between them strengthens.
  • STDP (spike-timing-dependent plasticity) — temporal ordering matters. A pre-synaptic spike followed by a post-synaptic spike strengthens the connection more than the reverse.
  • Decay — unused synapses weaken over time.

Plus a consolidation cycle that prunes weak synapses below a threshold and creates auto-synapses from co-activation patterns.

flowchart TB
    Use[Synapse traversed<br/>by signal or context assembly] --> StrengthUp[strength += δ]
    Idle[Synapse not traversed<br/>for interval] --> Decay[strength *= decay_rate]

    CoAct[Two neurons activated<br/>within window N] --> NewSyn[Auto-create<br/>co_activation synapse]
    LowStr{strength < prune_threshold?}
    Decay --> LowStr
    LowStr -- Yes --> Prune[Remove synapse]
    LowStr -- No --> Keep[Keep, mark for review]

    style Use fill:#dcfce7,stroke:#16a34a
    style Decay fill:#fee2e2,stroke:#dc2626
    style NewSyn fill:#e0e7ff,stroke:#4338ca

That’s what actually changed in the code. PlasticityEngine is now a distinct service running in the consolidation tick. None of this existed when the domain was called Edge. None of it would have felt natural either.

2. Activation has a real model

A neuron isn’t passive. So “what’s the activation level of this neuron right now?” becomes a question with a real answer instead of a metaphor.

ADR-034 — Attention as Context Assembly uses two well-trodden models from cognitive science:

  • ACT-R base-level activation: B(i) = ln(Σ t_j^-0.5) over past presentations. Decades old, well-validated, runs in microseconds. It says: things you’ve looked at recently and often are more activated. Nothing fancy.
  • Spreading activation with fan-out normalization: activation flows along synapses to neighbors, divided by fan-out so a highly-connected node doesn’t dominate.

Add STI/LTI (Short-Term / Long-Term Importance, borrowed from OpenCog) and inhibitory synapses (contradicts — a real synapse kind) and you have a complete attention model. Context assembly collapses to “score every reachable neuron by activation, pick the top N that fit the token budget.” That’s it.

This is the deterministic-first principle applied to context selection. The LLM never picks what to include. The activation function does.

3. Signaling is direct and topology-authorized

ADR-033 — Neural Signaling is the most consequential consequence of the rename. If neurons are real units that fire signals at each other, then:

  • Every neuron can be an MCP server and/or client. Signaling is direct, point-to-point. There is no central router.
  • Synapses are the routing table. A synapse from A to B is both the connection and the permission to signal. No separate auth layer.

That second point is load-bearing. The earlier model had ActionValidation doing runtime authorization checks: “is agent A allowed to call tool X on neuron B?” After the rename, the check collapses to:

authorized(A, B) := ∃ synapse(A, B)

If a synapse exists, the signal flows. If not, it doesn’t. Wiring is permission. No policy engine, no auth service — just topology. Refreshing, honestly.

(That rule — “topology is authorization” — would later force a deeper rewrite. But that’s the next post.)

4. The Self Model is one neuron among many

In the old model, SelfModel was a class. After the rename, it’s a neuron with a specific role:

Self Model (role: "self_model")
├── [artifact] Governance       — policy struct (max_concurrent, blocked_patterns, ...)
├── [artifact] Core Principles  — reasoning style, values, priorities
├── [artifact] Awareness        — distilled current state (auto-updated)
└── (future artifacts)

The artifacts are child neurons connected by artifact synapses. The Self Model neuron composes them. To resolve governance for a query about a specific neuron, you walk from the Self Model node to its Governance artifact, evaluate the rules against the target neuron’s role, and return a GovernancePolicy struct.

This is a pure function over the cortex:

auto policy = get_governance(cortex, self_model_id, target_neuron_id);

No SelfModel class. No orchestrator dispatching policy. The cortex is the substrate; everything else is a function over it.

(To be clear, the orchestrator wasn’t dissolved by this rename — it was dissolved by ADR-017, which I’ll write about separately. But the rename made the dissolution possible. If the Self Model is a class, you need an orchestrator to read it. If the Self Model is a neuron, the “orchestrator” is the same kind of pure function as every other cortex query.)

What stayed the same

The renames are clean breaks — no backwards compatibility, no aliases. But the shape of the domain didn’t change:

  • Still two entities (Neuron and Synapse).
  • Still everything-is-a-neuron (thoughts, projects, agents, the Self Model, data sources).
  • Still zero I/O in the domain layer.
  • Still hexagonal — ports unchanged in shape, just renamed.

The change was philosophical, not structural. Two entities before, two entities after. But the entities now carry biological commitments that actually mean something.

The foundational rule that came out of this

A later DEVLOG entry — written when I was tempted to add creates and bound_capability synapses for plugin provenance — stated the rule that ADR-031 had implicitly committed to:

A synapse exists in the cortex only when there is a biological justification — a connection that carries signaling or activation, with weight and plasticity. Everything else is metadata, audit log, configuration, or engineering-level registries.

This rule comes straight out of the rename. Once you’ve committed to “synapses are physical connections with plasticity,” the question “should this be a synapse?” has a sharp answer: only if plasticity makes sense on it. creates-as-provenance fails — what would it even mean for “plugin A created this neuron” to decay? contradicts (inhibitory connection) passes; child (structural parent-child) passes; co_activation (Hebbian-formed) passes. bound_capability fails.

The rule prevents the property-graph drift. Without it, every useful relationship type wants to become a typed edge, and the biological metaphor collapses into yet another Neo4j schema.

Naming as commitment

The whole story of this post is the same lesson, twice.

The first time was the controller/view post: the wrong name on a class made it impossible to see that the class was the wrong shape.

The second time is here: the right name — committing to the biological metaphor — exposed three design decisions I’d been avoiding. Plasticity, activation, signaling. Each one a hard problem; each one already present in the system, just unnamed.

Overall… when you can’t articulate what a thing is, you don’t know what constraints it carries. The rename is the articulation. The architecture follows.

Source pointers

  • DEVLOG.md — entries of 2026-04-07 (brain-inspired domain spec), 2026-04-06 (open-world metadata over strong types), 2026-04-08 (foundational rule on biological synapses)
  • PLAN.md — ADR-031, ADR-032, ADR-033, ADR-034
  • docs/research/temporal-graph-model.md — bi-temporal synapse model
  • docs/superpowers/specs/2026-04-07-brain-inspired-domain-model-design.md — the full spec including grounding in ACT-R, OpenCog, Hebbian learning, and Global Workspace Theory

Cross-posted from the moitumi dev blog.