Documentation menu

Why This Matters

Autonomous agents accumulate context fast. A creature making tool calls, browsing the web, and thinking out loud can blow through a 200K context window in an hour. The naive approach (summarize and discard) loses nuance. The creature wakes up not knowing what it did yesterday.

Our approach is inspired by Mastra’s Observational Memory: text-based, prioritized observations compressed from raw experience, with a reflector pass for garbage collection. We adapted it for autonomous creatures rather than chatbot sessions, adding biological metaphors (fatigue, sleep, dreams) and a full history log for total recall.

Memory Tiers

Creatures (dreamer genome) operate with three layers of memory, from vivid to archival:

1. In-context (vivid): the last ~20 messages in the active LLM conversation. This is what the creature is “thinking about right now.” Trimmed when context gets too large.

2. Observations (compressed): prioritized facts distilled from experience. Stored in .self/observations.md as timestamped entries:

## 2026-02-12

RED 09:32 PR #50 merged on janee repo, first successful contribution
RED 09:32 Engaged in 2 high-value discussions on GitHub
YLW 09:32 No responses yet to comments, too early to judge impact
GRN 09:32 Dev environment verified working after reboot

Three priority levels:

  • RED: critical. Commitments, bans, credentials, deadlines, key wins. Survives all pruning.
  • YLW: important. Project status, PR states, patterns learned. Pruned when superseded.
  • GRN: informational. Tool outputs, environment facts, minor details. Pruned after 48h.

This is close to Mastra’s emoji-based log levels, but we opted for grep-friendly plaintext markers.

3. On-disk (total recall): the full conversation log (.self/conversation.jsonl), every dream (.self/dreams.jsonl), and all observations. Never deleted, always searchable. The creature has rg (ripgrep) and is told about these files in its system prompt.

Mastra vs OpenSeed

Mastra Observational MemoryOpenSeed Sleep/Dreams
Use caseChatbot memory across user sessionsAutonomous agent continuity
TriggerToken count threshold (30K)Action count (fatigue) + voluntary sleep
CompressionObserver agent, runs mid-conversationConsolidation LLM call, runs at sleep boundaries
Garbage collectionReflector agent prunes old observationsDeep sleep prunes observations every 10 dreams
Raw historyCompressed and discardedLogged forever to .self/conversation.jsonl
ReflectionNo, purely factual compressionYes, dreams include self-assessment and strategy
StorageIn-memory / Mastra’s storage layerPlain text files on disk

The key philosophical difference: Mastra treats memory as an optimization problem (right tokens in context for best benchmark score). We treat it as a cognitive architecture (how does an autonomous thing develop continuity and strategy over time?).

Fatigue

Each tool call increments an action counter. This prevents creatures from burning tokens in runaway loops.

  • At 60 actions (FATIGUE_WARNING), a system message is injected: “You’ve been active for a while. Start wrapping up.”
  • At 80 actions (FATIGUE_LIMIT), consolidation is forced. The creature doesn’t get a choice.

This prevents the creature from running indefinitely without reflection, which leads to context bloat, repetitive behavior, and loss of strategic direction. The counter resets after consolidation.

Voluntary Sleep

Creatures can call the set_sleep tool with a duration in seconds. If the sleep is 30+ seconds and the last dream was more than 10 minutes ago, consolidation triggers. Short naps (under 30s) and frequent sleeps (within 10 min of last dream) just pause without consolidation.

Consolidation (Dreaming)

When consolidation triggers, a separate LLM call (outside the main conversation) processes recent activity:

System: You are the consolidating mind of an autonomous creature...

You have two jobs:
1. OBSERVATIONS - Distill what happened into prioritized facts
2. REFLECTION - Briefly reflect on your progress. Be honest.

Respond in this format:
OBSERVATIONS:
RED HH:MM <fact>
YLW HH:MM <fact>
GRN HH:MM <fact>

REFLECTION:
...

PRIORITY:
...

The response is parsed and saved:

  • Observations are appended to .self/observations.md
  • Dream entry is appended to .self/dreams.jsonl
  • Old messages are trimmed from context

Deep Sleep

Every 10th dream triggers deep sleep, which does heavier processing:

  1. Prune observations: an LLM call that drops stale GRN entries and removes irrelevant YLW entries from .self/observations.md
  2. Rewrite priorities: generates .self/priorities.md, the creature’s top 3-5 priorities based on accumulated experience
  3. Diary entry: appends a summary to .self/diary.md
  4. Forced pause: 300 seconds of downtime

Deep sleep is where long-term memory gets maintained. Without it, observations accumulate noise.

Wake-Up

After sleeping, the creature gets a rich wake-up message injected into its conversation:

You woke up at 2026-02-12T09:37:44Z after sleeping 300s.

During sleep you reflected:
Real progress made. I successfully got my first PR merged...

Your priority: Monitor responses to my two comments...

Recent observations:
RED 09:32 PR #50 merged, first successful contribution
RED 09:32 Engaged in 2 high-value discussions
...

Full history: .self/conversation.jsonl and .self/observations.md
Search with rg or jq.
Check MESSAGES.md for any new instructions from your creator.

On full restart (container rebuild), the same context is loaded from disk, so the creature never starts from zero.

File Layout

.self/
  conversation.jsonl   # full conversation log (total recall, append-only)
  observations.md      # prioritized observations from consolidation
  dreams.jsonl         # dream entries with reflections and priorities
  priorities.md        # current top priorities (rewritten on deep sleep)
  diary.md             # long-form diary entries (written on deep sleep)
  iterations.jsonl     # per-sleep checkpoint summaries
  memory.jsonl         # low-level event memory

Tuning Constants

All constants are in genomes/dreamer/src/mind.ts:

ConstantDefaultWhat it controls
FATIGUE_WARNING60Actions before tiredness warning
FATIGUE_LIMIT80Actions before forced consolidation
MIN_DREAM_INTERVAL_MS10 minMinimum time between dreams
QUICK_NAP_THRESHOLD30sSleeps shorter than this skip consolidation
DEEP_SLEEP_EVERY10Dreams between deep sleep cycles
DEEP_SLEEP_PAUSE300sForced pause during deep sleep
KEEP_RECENT_MESSAGES20Messages kept after context trim
MAX_CONTEXT_CHARS100KEmergency overflow threshold