Skip to content

Latest commit

 

History

History
173 lines (114 loc) · 9.69 KB

File metadata and controls

173 lines (114 loc) · 9.69 KB
title Cortex
description System-level observer that maintains memory bulletins and monitors agent health.

The Cortex

The cortex is the system's awareness of itself. Every other process in Spacebot is focused on a specific job — channels talk to users, branches think, workers execute, compactors manage context. None of them see the whole picture. The cortex does.

The Memory Bulletin

The cortex's primary responsibility is generating the memory bulletin — a periodically refreshed, LLM-curated summary of what the agent currently knows. This bulletin is injected into every channel's system prompt, giving all conversations ambient awareness without needing to explicitly recall memories.

This is what makes Spacebot feel like it actually knows you. Without the bulletin, a fresh conversation would start cold — the agent would need a branch to recall memories before it could reference anything about the user, their projects, or recent decisions. With the bulletin, every conversation inherits a baseline context from the moment it starts.

How It Works

Bulletin generation is a two-phase process: programmatic retrieval, then LLM synthesis.

On a configurable interval (default: 60 minutes), the cortex:

  1. Retrieves memory data across eight predefined sections by querying the memory store directly (no LLM needed for retrieval):
    • Identity & Core Facts — typed search for Identity memories, sorted by importance
    • Recent Memories — temporal search for the most recent memories across all types
    • Decisions — typed search for Decision memories, sorted by recency
    • High-Importance Context — importance-sorted search across all types
    • Preferences & Patterns — typed search for Preference memories
    • Active Goals — typed search for Goal memories, sorted by recency
    • Recent Events — typed search for Event memories, sorted by recency
    • Observations — typed search for Observation memories
  2. Synthesizes the raw sections into a cohesive briefing via a single LLM call. The LLM receives the pre-gathered data and produces a concise summary (~500 words, configurable). No tool calls, no multi-turn — just one synthesis pass.
  3. The bulletin is cached in RuntimeConfig::memory_bulletin via ArcSwap
  4. Every channel reads it on every turn — lock-free, zero-copy via Arc

This design avoids the problem of an LLM formulating search queries without conversation context. The retrieval phase uses SearchMode::Typed, SearchMode::Recent, and SearchMode::Important — metadata-based modes that query SQLite directly without needing vector embeddings or search terms. The LLM only gets involved for the part it's good at: turning structured data into readable prose.

The first bulletin is generated immediately on startup. Subsequent runs happen every bulletin_interval_secs. If a generation fails, the previous bulletin is preserved. If the memory graph is empty, an empty bulletin is stored without invoking the LLM.

What Channels See

The bulletin is injected into the system prompt between identity context and the channel prompt:

## Soul
[from SOUL.md]

## Identity
[from IDENTITY.md]

## User
[from USER.md]

## Memory Context                    ← this is the bulletin
[A concise briefing synthesized from eight memory dimensions:
identity, recent, decisions, high-importance, preferences, goals,
events, and observations. Organized by relevance and actionability.]

## [Channel prompt follows...]

Not a wall of raw search results. Not every memory in the database. A curated, contextualized briefing that reads like a colleague's handoff notes.

Why This Replaces MEMORY.md

OpenClaw (and systems like it) use a MEMORY.md file that the LLM manually maintains — editing a markdown file to track what it knows. This has several problems:

  • The LLM has to decide when to update the file and what to include
  • The file grows unbounded or gets pruned arbitrarily
  • There's no structure, no graph, no importance scoring
  • Different conversations fight over the same file
  • It's a single flat document trying to capture a graph of relationships

Spacebot's approach separates storage from presentation. Memories are structured objects in a graph database with typed metadata, associations, and importance scores. The bulletin is a view of that graph — a periodically refreshed snapshot curated by an LLM that can search, rank, and contextualize. The underlying graph is rich and queryable; the bulletin is the digestible summary.

Bulletin vs Branch Recall

These serve different purposes:

The bulletin provides ambient awareness. It's the same for every channel on every turn. It contains the most important, most recent, most relevant context — what any conversation would benefit from knowing. It's refreshed hourly, not per-message.

Branch recall provides targeted memory retrieval. When a conversation needs specific information ("what did we decide about the auth system?"), a branch is spawned to search the memory graph with a focused query. Branch recall is on-demand, per-conversation, and returns detailed results.

The bulletin doesn't replace recall — it reduces how often recall is needed. A channel that already knows the user's name, their current project, and recent decisions from the bulletin doesn't need to spawn a branch for basic context.

Future Responsibilities

The bulletin is the cortex's first and most impactful responsibility. The following capabilities are designed but not yet implemented:

System Health Monitoring

The cortex monitors running processes and keeps the system clean:

  • Worker supervision — detect hanging workers, kill error loops, clean up stale state
  • Branch supervision — kill stale branches, track latency trends
  • Channel health — flag channels approaching context limits faster than compactors can manage
  • Circuit breakers — after 3 consecutive failures of the same type, disable the failing component

Memory Coherence

The cortex sees memory activity across all channels and maintains the graph:

  • Consolidation — merge overlapping memories, create cross-channel associations
  • Maintenance — decay old memories, prune low-importance orphans, recompute centrality
  • Observations — generate observation-type memories from cross-channel patterns

The Signal Bus

All processes emit events to a shared broadcast channel. The cortex maps events to high-level signals (channel started, worker completed, memory saved, compaction triggered, error occurred). These are buffered in a rolling window for pattern detection.

Channel A emits: WorkerComplete { result: "...", ... }   → cortex maps to WorkerCompleted signal
Worker 7 emits: StatusUpdate { status: "stuck on..." }   → cortex maps to WorkerStatusUpdate signal
Branch 3 emits: ToolCompleted { tool: "memory_save" }    → cortex maps to MemorySaved signal

How It Differs From Other Processes

Property Channel Branch Worker Cortex
Sees conversations Yes Yes (forked) No No
Talks to users Yes No No No
Has personality Yes Inherited No No
Scope One conversation One thought One task Entire system
Lifecycle Long-lived Seconds Minutes to hours Always running
Context growth High (needs compaction) Moderate (disposable) Moderate (disposable) Low (fresh per run)

The cortex is the only singleton in the system (per agent). There's one cortex per agent, regardless of how many channels, branches, or workers are running.

Cortex vs Cron Jobs

Cron jobs are user-defined scheduled tasks. "Check my inbox every 30 minutes." They run on schedules, get fresh channels with full capabilities, and produce user-facing output.

The cortex is the system's internal loop. It maintains system health, memory coherence, and the memory bulletin. It runs continuously, doesn't produce user-facing output, and isn't user-configured beyond tuning intervals.

Cortex vs Compactor

Compactors are per-channel, programmatic monitors. They watch one channel's context size and trigger compaction workers. They're not LLM processes.

The cortex is an LLM-assisted process that sees across all channels. It doesn't manage context size (that's the compactor's job). It manages the memory bulletin, and will eventually handle memory coherence and system health.

Configuration

[defaults.cortex]
# Base tick interval for health monitoring (future).
tick_interval_secs = 30

# How often to regenerate the memory bulletin.
bulletin_interval_secs = 3600

# Target word count for the memory bulletin.
bulletin_max_words = 500

# Worker is considered hanging if no status update for this long.
worker_timeout_secs = 300

# Branch is considered stale after this duration.
branch_timeout_secs = 60

# Consecutive failures before circuit breaker trips.
circuit_breaker_threshold = 3

Failure Modes

What if the cortex bulletin fails? The previous bulletin is preserved. Channels keep operating with the last successfully generated bulletin. If the cortex has never generated a bulletin (fresh install, empty memory graph), channels run without a memory context section — the system works fine, just without ambient awareness.

What if the cortex crashes? The system keeps running. Channels still talk to users, branches still think, workers still execute. The bulletin goes stale but remains in RuntimeConfig. On restart, a new bulletin is generated immediately.

What if the memory graph is empty? The cortex generates a bulletin that says so (or an empty one). This is the normal state for a new agent. As memories accumulate through conversation, ingestion, or compaction, subsequent bulletin runs will have material to work with.