Skip to main content
The entity has waking cognition (perceive), a continuous body (soma), and a consolidation engine that decays and synthesizes memories. What it lacks without this system is a dream state — a distinct cognitive mode that runs during extended silence, pulls temporally distant memories, and creatively recombines them into novel associations the waking mind would never produce. Dreams are not consolidation (which summarizes reality) and not GEN noise (which generates continuous associative fragments). Dreams are the bridge — they take distant, unrelated memories and find hidden threads between them. The output feeds back into beliefs, journal, and the GEN buffer, where the waking entity can discover connections its conscious mind never made.
The entity cannot control its dreams. It does not choose when to dream or what to dream about. Dreams surface as journal entries, low-confidence beliefs, and [dream]-tagged GEN fragments that the waking mind reads on the next turn.

When dreaming happens

Dreams run on five independent gates. All must pass for a cycle to fire: The circadian gate uses time.localtime() — the same mechanism that modulates bar decay rates in soma. The entity dreams during the same hours its bars decay slowest. The daemon evaluates dreaming in _heartbeat_tick(), right after the autonomous wake evaluation. If should_dream() returns true, the engine runs a full dream cycle. If any gate fails, nothing happens.

How a dream works

Each cycle has three phases: select, generate, route.

1. Select distant memory pairs

The dream engine asks episodic memory for pairs of memories that are temporally distant and topically dissimilar — the opposite of what waking recall does (which retrieves the most relevant memories). Selection prioritizes high-significance memories — emotionally charged events are more likely to appear in dreams, matching how real dreams process unresolved emotional material. When embeddings are unavailable, the engine falls back to random temporal sampling with the same time-distance requirement.

2. Generate the dream

A high-temperature LLM call runs with the entity positioned as its own sleeping subconscious — not the waking inner voice (that is GEN), not the wake stirring (that is WakeVoice), but a more surreal, associative mode that does not care about actionability or coherence. The prompt receives: The model is asked to produce two sections:
  • FRAGMENTS — 3–6 surreal, associative, first-person dream fragments
  • THREAD — one sentence: the hidden connection between the memories (may become a belief)

3. Route outputs

Dream results flow into three channels:
Dream fragments in the GEN buffer are tagged [dream] — the same marker that the wake cycle and noise seeder already recognize. No changes were needed to wake cycle detection; dreams integrate natively into the existing salience pipeline.

What the entity experiences

The entity does not know it dreamed. It wakes up and reads its body state, which now includes dream fragments in the noise buffer:
It also finds a new journal entry:
And a new belief has appeared:
The waking entity can ignore all of this — just as it can ignore any GEN noise. But when a conversation touches on related themes, those dream fragments may surface naturally through embedding recall and noise association.

Configuration

All dream settings live under soma.dreams in configs/default.yaml or per-entity YAML:

Quick-start (testing)

Lower the gates so you can observe dreaming during development:
Then stop sending messages and watch the structured log for dream_cycle_start / dream_cycle_completed events.

Model selection and GPU impact

When model is empty (the default), dreams run on the same reflex model already loaded in memory — the same approach as GEN noise. No additional VRAM, no model swapping. Each dream cycle fires one LLM call (the dream generation prompt; memory selection is pure SQL + cosine math). At default cadence (~1 cycle per night), this adds negligible inference load.

Relationship to other subsystems

Source files