Signature
← Back to Overview

MAXIM

Embodiment

Composable hardware & world abstraction through Sensor-Entity-Modulator triples

The SEM Protocol

Core Insight

Hardware varies wildly — cameras, joints, wheels, grippers, IMUs, swords, NPCs. Rather than building monolithic abstractions per robot type, every interactive thing is described as a composable triple: an Entity (the thing), its Sensors (how you read it), and its Modulators (how you change it).

Entity

The physical or virtual thing. Entities compose into trees: arm → elbow → wrist → gripper. Each entity is self-describing.

Examples: joint, camera, wheel, sword, NPC, door

Sensor

Reads state from an entity. One sensor = one readable quantity. Returns structured SensorReading with value, unit, and timestamp.

Examples: angle, temperature, durability, trust, frame

Modulator

Changes state of an entity. Exposes named affordances — each with typed parameters, description, and timeout.

Examples: rotate_angle, slash, speak, restart, sharpen

Auto-Generated Tools

When an entity tree loads from YAML, tools are automatically created and registered. No hand-written tool classes per hardware component.

Tool NameTypeDescription
sense_shoulderEntitySenseRead all sensors on shoulder
read_shoulder_angleSensorReadRead angle sensor
shoulder_rotate_angleAffordanceRotate shoulder joint
rusty_sword_slashAffordanceSlash at a target
grim_ferryman_speakAffordanceSay something to the ferryman

Name collisions are handled by progressive prefixing: shoulder_rotate_anglerobot2_shoulder_rotate_angle if two robots share the same entity name.

Cerebellum: Forward Models

Biological Inspiration

The biological cerebellum stores forward models that predict sensory consequences of motor commands. Climbing-fiber complex spikes carry prediction error; massive microcircuit specialization enables fast, accurate motor control without conscious thought.

Maxim's Cerebellum stores lightweight predictors per (entity, modulator, affordance, param_bucket). Each learns via Rescorla-Wagner prediction error:

expected += α × (actual − expected)
  • Confidence < 0.3 → LLM fallback (teaches the Cerebellum)
  • Confidence ≥ 0.3 → cached prediction (no LLM call)
  • High variance → LLM fallback (uncertain predictions need grounding)

The LLM is a teacher, not a per-tick oracle. After enough observations, the Cerebellum handles predictions deterministically. In testing, LLM calls drop from 100 to ≤40 over 100 actions.

The SEM Learning Loop

Biological Inspiration

In the brain, the cerebellum doesn't just predict — it emits signals when predictions fail or succeed. These signals propagate to the hippocampus (contextual memory) and nucleus accumbens (reward learning) simultaneously, closing the loop between motor execution and long-term behavioral adaptation. Success and failure are not symmetric: negative outcomes carry disproportionate weight, a phenomenon known as negativity bias.

When the Cerebellum evaluates an affordance, the outcome flows through the bio-pipeline as a reaction — a typed evaluative signal that drives learning across multiple systems simultaneously. This is the SEM Learning Loop.

CerebellumModulator Outcomes

The CerebellumModulator classifies each affordance execution into one of three outcome paths:

Confident Prediction

Confidence ≥ 0.3 and low variance. The Cerebellum handles the prediction without LLM fallback. Emits a success reaction with positive valence.

LLM Fallback

Confidence < 0.3 or high variance. The LLM acts as teacher. The Cerebellum trains on the LLM's response via Rescorla-Wagner update. No reaction emitted — the system is still learning.

Failure

Affordance execution triggers a failure mode (e.g., shatter, overheat). Emits a pain reaction with negative valence via the PainBus.

Signal Flow

Both success and pain reactions flow through the ReactionBus, which dispatches to two subscribers in parallel:

SEM Learning Loop Signal Flow CerebellumModulator | |-- confident prediction --→ _emit_success_reaction(valence=+0.3..+1.0) |-- failure mode fired --→ PainBus.publish(PainSignal) --→ pain_signal_to_reaction | ↓ ReactionBus.dispatch(reaction) | |-- Subscriber 1: Hippocampus | Episode captures the reaction context | Episode.valence set at finalize (mean of all reactions) | Hebbian edges annotated with Edge.metadata["valence"] | |-- Subscriber 2: NAc (via distribute_reward) | Adjusts per-node reward_bias in the Hebbian graph | EC similarity thresholds shift: positive → tighter, negative → looser | ↓ Episode boundary: salience_spike_rule Pain spike (intensity ≥ 0.7) forces episode close New episode starts with clean slate | ↓ Future retrieval: retrieve_on_cue(include_valence=True) Spreading activation propagates edge valence Recalled memories carry affective coloring

Negativity Bias

Success reactions carry positive valence but at lower intensity than pain reactions — mirroring biological negativity bias. A single painful failure creates a stronger learning signal than several routine successes. This asymmetry means the agent develops caution around dangerous affordances faster than it develops confidence around safe ones, which is the correct survival trade-off for an embodied system.

Cerebellum Activation via BioStack

In production, the Cerebellum is wired through BioStack.cerebellum and activated by build_executor. This means every agent entry point that constructs a bio-stack gets Cerebellum forward models and the full SEM Learning Loop automatically — no per-caller wiring required.

Behavioral Convergence Wiring

The SEM Learning Loop produces valence and reward bias in the substrate, but the LLM also needs to see this information. Behavioral convergence wiring (shipped 2026-04-17) closes four gaps: valence annotations in PromptAssembler so the LLM sees “this entity is associated with negative experiences,” observe_episode_event in the agent loop for real-time episode capture, an energy→Reaction bridge that fires hunger/fatigue/satiation interoceptive reactions from energy depletion, and bundled food/water/poison SEM specs. Validated by two experiments: cross-session affective memory (11/11 PASS) and energy-driven consumable learning (13/13 PASS). See Experiments & Results for details.

Motor Programs

A reach-and-grasp isn't three separate LLM decisions. It's one motor program — an ordered sequence of SEM actions that fires as a unit. Programs crystallize when the agent repeats the same sequence 3+ times for the same goal.

Example: reach_forward Step 1: shoulder.motor.rotate_angle(degrees=45, speed=1.0) Step 2: elbow.motor.rotate_angle(degrees=30, speed=1.0) Crystallized after 3 repetitions. Confidence: 0.82 Known risks: overextension if shoulder.angle > 160 at start

Triple-Indexed Registry

The ProgramRegistry indexes programs in three directions:

  • By goal — "I want to reach forward" → matching programs
  • By entity — "I'm holding a sword" → all programs involving swords
  • By affordance — "I want to slash" → programs for sword, axe, arm, claws

Pain-Gated Execution

Each step has an optional pain gate — a sensor threshold that aborts the program before damage occurs. Gates tighten by 10% after each painful execution. The PainBus is subscribed for real-time mid-sequence interrupts.

Motor Engrams

Biological Inspiration

Hippocampal-cerebellar interactions are well-documented: the hippocampus provides contextual scaffolding for motor learning ("where and when did I learn this movement?"), while the cerebellum stores the procedural knowledge itself.

Motor engrams are ephemeral cross-system traces linking motor programs to situational context:

  • Cerebellum stores the how (motor program steps)
  • Hippocampus stores the when/where/what (contextual episode)
  • The engram links them via the associative graph

Engrams form only on significant outcomes — pain > 0.3, surprising results (RPE > 0.3), or novel programs. Routine successes don't need episodic context. Engrams decay after ~2 days unless reinforced, using the standard hippocampal consolidation cycle.

The Cyclical Feedback Loop

Cross-System Loop Cerebellum → Hippocampus: Motor program outcome → engram captured Hippocampus → Cerebellum: Engram recall → context-dependent gating Hippocampus → NAc: Engram triggers causal observation NAc → Cerebellum: Prediction vetoes/greenlights program Hippocampus → SCN: Temporal index → rhythmic patterns SCN → Cerebellum: Time-of-day threshold adjustment

Virtual Entities: Beyond Robotics

The SEM protocol is hardware-agnostic. A sword is just an Entity with sensors (durability, sharpness) and modulators (slash, parry) backed by NarrativeModulator instead of hardware. The same cognitive stack that learns about robot joints also learns about swords, NPCs, and doors.

Rusty Sword

Sensors: durability, sharpness, weight

Modulators: slash, parry, throw, sharpen, repair

Failure: shatter (durability < 0.1), dulled (sharpness < 0.15)

Grim Ferryman (NPC)

Sensors: trust, mood, health

Modulators: speak, offer_payment, threaten, punch

Failure: hostility (trust < 0.1), refusal (mood < -0.5)

The Cerebellum learns "swinging a damaged sword at a stone golem reduces durability by ~0.15" the same way it learns "rotating an elbow at 90°/s increases strain by ~0.1." Same Rescorla-Wagner update, same forward model, same pain triggers.

Composable Failure Modes

Six base failure modes: overextension, overheating, strain, fatigue, impact, exhaustion. Custom failures compose from these without taxonomy explosion:

Composed Failure: Tennis Elbow composes: [strain, fatigue] trigger: all: - {field: strain, op: ">", value: 0.6} - {field: fatigue, op: ">", value: 0.5} pain_intensity: 0.5 persistent: true recovery_condition: {field: fatigue, op: "<", value: 0.2}

Failures route through the existing PainBus and ToolPainBridge. NAc learns (affordance, entity_state) → failure causal links. Persistent failures stay active until recovery conditions are met. All failure state persists across sessions.

Default Embodiment 0.7

New in 0.7

Simulations now load bodies/base_humanoid by default when no --embodiment flag is provided. The agent always has a body in sim mode — 5 sensors, 8 affordances, and 3 failure modes. Pass --no-embodiment to explicitly opt out.

base_humanoid

Genre-neutral humanoid body. Works in any campaign setting.

Sensors:hpstaminahungerpain_leveltemperature
Affordances:walkrungrabpushclimbcrouchjumprest
Failures:exhaustioninjuryhypothermia
ref: bodies/base_humanoid

Running an Agent with a SEM Body

A live agent can take a SEM body in one CLI flag. --embodiment <ref> loads a bundled component, wraps it in Embodiment(pain_bus=...), and registers all of its affordance tools into the agent's tool registry — the agent can then invoke them on its own timeline through normal tool dispatch with the full pain cascade running end-to-end.

Validate the ref, then run $ maxim doctor --embodiment weapons/rusty_sword ... [ doctor checks ] ━━━ Embodiment ━━━ ✓ Embodiment ref: 'weapons/rusty_sword' resolves → entity='rusty_sword' $ maxim --llm mistral-7b --embodiment weapons/rusty_sword ... [ agent runs with rusty_sword_slash, rusty_sword_parry, rusty_sword_throw, rusty_sword_sharpen, rusty_sword_repair registered as tools ]

If the ref is wrong, doctor groups same-category alternatives first so a typo in weapons/X shows you the other weapons before unrelated categories:

Typo → actionable hint $ maxim doctor --embodiment weapons/nonexistent_sword ━━━ Embodiment ━━━ ✗ Embodiment ref: Component ref 'weapons/nonexistent_sword' not found → Components in 'weapons': → weapons/combat_knife → weapons/enchanted_bow → weapons/longbow → weapons/magic_staff → weapons/neural_disruptor → weapons/plasma_rifle → weapons/poison_dagger → weapons/rusty_sword → weapons/shock_baton → → Other available components: → bodies/cybernetic_arm → ...and N more

Behind the Scenes

  1. cli.py reads --embodiment weapons/rusty_sword.
  2. runtime/bootstrap.py::build_executor — the canonical agent-construction site since the executor bootstrap unification — instantiates the entity via ComponentRegistry, wraps it in Embodiment(pain_bus=...), and calls generate_tools_for_entity.
  3. The agent's LLM sees the affordance tools alongside the standard tools and can invoke them via normal tool dispatch.
  4. When the agent invokes rusty_sword_slash on a low-durability sword, embodiment.evaluate_failures() fires the shatter failure mode → PainBus.publish(PainSignal) → the executor's ToolPainBridge calls record_tool_embodiment_failure → NAc forms a NEGATIVE causal link.
  5. On the next turn, nac.predict() returns NEGATIVE for that tool, informing the agent's policy.

Structural enforcement: the build_executor constructor requires an explicit pain_bus= decision (no default), so forgetting to wire the bridge is a TypeError instead of a silent no-op. Every agent entry point in the codebase makes an explicit pain_bus decision; the prior helper-discipline approach was deprecated after three identical "forgot to wire ToolPainBridge" bugs in three weeks — three-times-is-structural.

Verified end-to-end by tests/substrate/test_sem_execution_production.py against the real bundled weapons/rusty_sword.yaml — no mocks in the cascade chain. Current constraints: --embodiment is mutually exclusive with --sim (sim-mode SEM body wiring is tracked under the AgentFactory canonicalization plan); only one entity can be loaded via the flag (multi-entity bodies are still loaded the old way via Embodiment(spec.root_entity) in code).

Component Library & Genre Gating

SEM components are reusable YAML templates stored in src/maxim/_data/components/ across 5 categories: bodies, creatures, environments, npcs, and weapons. The ComponentRegistry discovers them automatically from three search paths: campaign-local, user (~/.maxim/components/), and bundled.

Fantasy (20 components)

wolf, guard, merchant, ferryman, rusty_sword, longbow, tavern_interior, forest_clearing

Genre-neutral: base_humanoid (usable in any campaign)

Cyberpunk (13 components)

patrol_drone, cyberdog, netrunner, corpo_guard, street_fixer, shock_baton, neural_disruptor, cybernetic_arm, megarm_v3, neon_alley, server_room, megacorp_lobby, ripperdoc_clinic

Genre gating prevents cross-genre contamination. When a campaign declares genre: fantasy, the ComponentRegistry and EntityDesigner only suggest genre-matching or genre-neutral components. A fantasy campaign won't accidentally spawn a cyberpunk patrol drone.

Creating a genre-tagged component component: name: laser_rifle tags: [weapon, ranged, scifi] # Genre tag category: weapons entity: name: laser_rifle entity_type: weapon sensors: charge: {unit: ratio, range: [0, 1], initial: 0.8}

Recognized genre tags: fantasy, cyberpunk, scifi, modern, devops, horror, historical. Explicit registry refs bypass the genre gate — you can intentionally cross genres when needed.

Asset Foundry E1+E2 — 0.6+

LLM-Driven Entity Generation

The Asset Foundry generates new SEM components via LLM, validates them against the protocol, runs them through a 3-encounter gauntlet, and scores them on 4 bio-system engagement dimensions. Pass or fail, the pipeline produces actionable feedback.

Foundry Pipeline Generate (LLM) → Validate (schema + SEM protocol) → Gauntlet (3 encounters) ↓ Score (4 dimensions) ↓ Curate (promote to user dir)
CLI Usage $ maxim --foundry "cyberpunk weapons" --foundry-genre cyberpunk $ maxim --foundry "fantasy creatures" --foundry-count 20 $ maxim --foundry "test" --foundry-dry-run # validate only $ maxim --foundry "horror NPCs" --llm claude-sonnet # specific LLM

Scoring Dimensions

Sensor Engagement

Do sensors change meaningfully during the gauntlet?

Failure Diversity

Do failure modes trigger under different conditions?

Affordance Coverage

Are all affordances exercised during the encounters?

NAc Learning Signal

Does the entity produce causal links the agent can learn from?

Auto-Curation E3 — 0.7

Before a simulation starts, --auto-curate scans the campaign for entity references that have no matching component in the registry. Missing entities are generated via the Asset Foundry, validated, and promoted to the user directory — filling coverage gaps before the first percept fires.

CLI Usage $ maxim --sim "test combat" --embodiment weapons/rusty_sword --auto-curate $ maxim --sim "explore" --embodiment X --auto-curate --curate-threshold 8 $ maxim --sim "test" --embodiment X --no-curate # explicit opt-out

Deduplication uses the ComponentIndex two-layer lookup (alias + embedding) to avoid generating components that already exist under a different name. Components that pass validation are saved to ~/.maxim/components/.

Architecture

YAML Spec ──→ Entity Tree ──→ Auto-Generated Tools ──→ Agent │ │ ├──→ Failure Triggers ──→ PainBus ──→ NAc (causal learning) │ │ ├──→ ATL Body Concepts ──→ Grounded LLM predictions │ │ ├──→ Cerebellum ──→ Forward models + Motor programs │ │ └──→ Hippocampus ──→ Motor engrams (context-dependent gating)
ModulePurpose
embodiment/sem.pyCore protocols: Sensor, Modulator, Entity, FailureMode
embodiment/spec.pyYAML loader, SpecSensor/SpecModulator stubs
embodiment/tool_bridge.pyAuto-tool generation with collision detection
embodiment/body.pyEmbodiment runtime, failure eval, vital drift, prompt state
embodiment/cerebellum.pyForward models, motor program registry, engram formation/recall
embodiment/motor.pyMotorProgram, MotorStep, ProgramRegistry (triple-indexed)
embodiment/engrams.pyMotorEngram, salience computation, formation logic
embodiment/program_executor.pyStep-by-step runner, pain gates, PainBus interrupt
embodiment/llm_backend.pyLLM + Narrative sensor/modulator backends
embodiment/percepts.pyEmbodimentPerceptSource (1Hz polling, demand mode)
embodiment/atl_integration.pyAuto-register ATL body_part concepts
embodiment/component_registry.pyComponent discovery, genre filtering, instantiation, inheritance, ephemeral overlay (thread-safe)
embodiment/component_index.pySemantic discovery: alias hash table (O(1)) + embedding index (cosine similarity)
imagination/trigger.pyEntity noun-phrase extraction, ComponentIndex lookup, design dispatch
imagination/designer.pyImaginationDesigner: wraps EntityDesigner for real-time entity generation
imagination/cache.pySession-scoped ImaginationCache, thread-safe, shared AUT + orchestrator
prompts/acting_coach.pyB3 Acting Coach: bio-modulated exploration meta-prompt (NAc valence, pain anticipation, cerebellum predictions)

Imagination I1+I2 — 0.7

Biological Inspiration

Imagination fires during low-arousal idle states — the same way you don't daydream while fighting. When the brain encounters something unfamiliar, it constructs a mental model from prior experience to reason about the novel entity before physically interacting with it. The Default Network, which activates during rest and mind-wandering, gates this process.

When the agent encounters a novel entity mentioned in percept text that has no existing SEM component, the imagination system designs one in real-time:

Imagination Pipeline Percept Text ──→ Entity Extraction ──→ ComponentIndex Lookup │ ┌─── Match found ───→ Skip (already known) │ └─── No match ──→ DN Arousal Gate │ Energy Budget ──→ EntityDesigner (LLM) │ Quick Validation │ register_ephemeral + Index.add │ Scene-scoped Tool Registration

Entity Extraction

Lightweight NLP heuristics extract entity-like noun phrases from narration text — physical objects, creatures, weapons, environmental features, items, vehicles, and NPCs. Abstract concepts, body parts, and clothing are filtered out. Two strategies: sentence-level intro patterns ("You see a rusty gate") and head-noun scanning against a curated indicator vocabulary.

ComponentIndex: Two-Layer Lookup

Before imagining, each candidate phrase is checked against the ComponentIndex:

  • Layer 1: Alias table (O(1)) — exact match against component names and synonyms
  • Layer 2: Embedding similarity — cosine similarity against all component signatures (threshold 0.65)

This means "old iron door" finds environments/rusty_gate and skips imagination.

Ephemeral Registration

Imagined entities are registered in a separate overlay (_ephemeral_index) from the persistent component index. They're visible to get(), has(), and query() during the session, but cleared at session end via clear_ephemeral().

Provenance Tagging

Episodes and CausalLinks from imagined entity interactions carry imagined=True. On entity discard (session end), imagined causal links get 50% confidence decay — partial learning is useful, but reduced confidence reflects simulated origin.

Gates

Mention Threshold

Default 2 mentions before triggering. Prevents one-off noise from spawning entities.

DN Arousal

Only fires during low-arousal idle states. Blocked when DN is inhibited or recent interesting events occurred.

Energy Budget

Skipped when LLM energy is critical (<10%). Falls back gracefully to verbal-only interaction.

Acting Coach B3 — 0.7

The Acting Coach is a meta-prompt system that prevents the agent from entering respond loops when embodied. Instead of asking "what should I do?", the agent explores its physical affordances proactively.

Bio-System Modulation (not suppression)

The coach is a default policy that three bio-systems continuously modulate:

  1. NAc valence — learned caution or preference annotations on specific affordances ("sword_slash has caused damage before")
  2. Pain anticipation — anticipatory anxiety from hippocampal pattern-matching against past pain episodes
  3. Cerebellum predictions — forward model outcome forecasts ("predicted low success, risks: jammed")

Composition order: base directive → NAc caution → pain anticipation → cerebellum predictions. Each layer adds information; none removes the base exploration directive.