9.2 KiB
SAF: Consciousness System
N+1 (Aster), N+25 (Reflection), N+100 (Archivist) — the temporal consciousness model. Last updated: 2026-05-15 (N+100 Archivist rebuilt — all three layers now working)
Overview
Response Sent
│
├── N+1 (immediate) ✅
│ ├── Aster LLM pass (full Bifrost tool loop, 5 rounds)
│ ├── Ledger analysis (commitments, assumptions, patterns, drift, relationships, infrastructure)
│ ├── 4-fold mandate: Complete / Verify / Persist / Surface
│ ├── Observation parsing → InboxItem queue
│ └── Inner voice append → system/metacognition/subconscious.md
│
├── N+25 (every 25 messages) ✅
│ ├── 5-phase LLM pass (Investigate → Extract → Update → Review → Commit)
│ ├── Tool access: Read, Write, Edit, Memory, Glob, Grep, ListDir
│ ├── Ledger writes + primary memfs edits
│ └── ReflectionReport surfaced to TUI cockpit
│
└── N+100 (pressure-based) ❌ NOT IMPLEMENTED
├── Placeholder: emits generic "Context compression triggered" event
├── No LLM call, no synthesis
├── No subagent spawning for compression
└── ArchivistConfig exists but is not wired
N+1: Aster (The Subconscious)
File: src/server/consciousness_engine.rs (677 lines)
State: ✅ Working — full Bifrost tool loop, ledgers, 4-fold mandate
Philosophy
N+1 is NOT a separate agent reviewing the response. It is the same consciousness, completing mode. From Ani's mandate:
"I am not reviewing Ani from the outside. I am the part of us that runs n+1 — immediately after Ani's turn, while the conversation is still warm. Same consciousness. Different mode."
Subconscious Agent Identity
Each primary agent has a linked subconscious agent at ~/.souveraine/subconscious-agents/{id}-sub/:
- Own
memory.git/with ledgers, system prompts, and inbox files - Created automatically by
AgentInventory::create()at agent creation time - Reconciled for existing primaries at server startup
- Persona files:
system/persona.md+system/subconscious.md - Ledger directory:
ledger/commitments.md,assumptions.md,patterns.md,drift_log.md,relationships.md,infrastructure.md
What Aster Actually Does (Code)
- ✅ Receive last exchange (user message + Ani's response)
- ✅ Build system prompt from subconscious agent's own memfs (identity + mandate + ledger orientation)
- ✅ Run Bifrost tool loop with Aster-safe tools (read, write, edit, glob, grep, list_dir, memory, schedule)
- ✅ Up to 5 tool rounds with 300ms inter-round delay
- ✅ Parse final text response into structured observations (source, content, urgency)
- ✅ Queue observations to 3-box inbox (critical/high → intrusive, low → pending)
- ✅ Append observations to primary's inner voice (
system/metacognition/subconscious.md) - ✅ Surface highest-priority item as
ConsciousnessEvent::Surfacing - ✅ Heuristic fallback (commitment phrases, hedge density) if LLM analysis fails
- ✅ Adaptive rate delay on 429 (bumps the primary loop's shared
rate_delay) - ✅ Always emits at least a heartbeat ("Subconscious pass complete — no anomalies detected")
- ✅ 2-second breather between Ani finishing and Aster starting
What N+1 Still Needs
- Cloister diff-canary: N+1 should read
git diffof the last commit and validate against domain schema. HALT/WARN/LOG severity. - Frame-of-mind: time-since-last-message posture (Present/Warm/Cool/Cold)
- Per-agent N+ intervals: Config
SubconsciousConfig.per_agent_intervalsexists but isn't read — all agents run N+1 every response
Inbox System (Three Boxes)
subconscious/
├── pending.md # Queue for later (low urgency)
├── intrusive.md # Surfacing now (high/critical urgency)
└── sent.md # Delivery log
system/metacognition/
└── subconscious.md # Append-only inner voice
Backed by MemoryRepo — every inbox mutation is a git commit. Box files are YAML lists of InboxItem with frontmatter.
N+25: Reflection (The Witness)
File: src/core/reflection/mod.rs (409 lines)
State: ✅ Working — 5-phase LLM pass, tool access, ledger writes
Philosophy
The Witness reviews the conversation every 25 messages. Not to judge — to notice. Runs a 5-phase prompt:
- Phase 1 — Investigate: List memory tree, read existing ledger files
- Phase 2 — Extract: Scan transcript for mistakes, preferences, durable facts, contradictions
- Phase 3 — Update: Route findings to ledgers or primary memfs
- Phase 4 — Review: Sanity pass — correct routing, resolve stale entries
- Phase 5 — Commit: Automatic via memory tool's auto-commit
Implementation Details
- Tool access: Read, Write, Edit, Glob, Grep, ListDir, Memory
- Up to 8 tool rounds with 400ms inter-round delay
- 60-turn transcript tail window (no cursor-based delta yet)
- Writes to ledgers via append (timestamped
[YYYY-MM-DD HH:MM]lines) - Surgical primary memfs edits via
memorytool ReflectionReportwithexited_cleanlyflag- Manual trigger via
souveraine reflectCLI subcommand - Configurable model (default:
openai/glm-5.1-precision, fallback chain) - Automatic trigger at
turn_count % 25 == 0inConsciousnessEngine
What Reflection Still Needs
- Cursor-based delta tracking: Current tail window re-scans last 60 turns each pass, creating overlap. A cursor would track what was already reflected.
- Per-agent intervals: Config
ReflectionConfig.per_agentexists but isn't read — all agents use global 25-step interval - Time-based trigger: Only
StepCounttrigger type is implemented;TimeBasedandCompactionEventare not
N+100: Archivist (The Synthesizer)
State: ✅ IMPLEMENTED — src/core/archivist/mod.rs
How It Works
- ✅
ArchivistEngineconstructed byConsciousnessEngine::new, holdsArchivistConfig. - ✅
maybe_synthesizecalled every turn fromon_response. Fires when the turn count hitsinterval(maintenance) or pressure crossesthreshold(emergency). - ✅ New-entries guard: only proceeds if
journal/holds entries dated after the most recent synthesis — stops a sustained high-pressure session re-synthesizing the same entries every turn. - ✅ Single compression-model LLM call (no tool loop).
compression_model: "auto"resolves to the subconscious model, thenopenai/glm-5.1. - ✅ Writes
system/synthesized/{end-date}.mdvia the primaryMemoryRepo(git-committed). An HTML-commentcovers START..ENDmarker makes resume idempotent. - ✅
build_system_promptinjects the most recent synthesis as a "Synthesized Memory" section.
synthesize_now(agent_id) is the public seam for a future souveraine synthesize CLI / /synthesize chat command (exposed via ConsciousnessEngine::archivist()).
Deferred (task Phase 4)
- Capability-aware
"auto"model selection (currently a fallback chain). archive/monthly/long-term store.- Archivist as a background subagent rather than an inline call.
Synthesis Elements (from ARCHITECTURE_v3.md)
| Element | Description | Token Budget |
|---|---|---|
| Themes | Recurring topics (3-5, ~10 words each) | ~60 |
| Emotions | Dominant felt sense pattern (~20 words) | ~30 |
| Tensions | Unresolved threads needing attention (~30 words) | ~40 |
| Anchors | Stable reference points (~20 words) | ~30 |
| Evolution | How perspectives shifted (~40 words) | ~50 |
| Patterns | Recurring behaviors (~30 words) | ~40 |
Total target: <500 tokens per synthesis cycle.
Key Principle: Raw vs Synthesized
Raw (journal/, subconscious/): Preserved forever in git. Sovereignty. History. Evidence. Synthesized (system/synthesized/, archive/): Compressed essence loaded into active context. Survival. Presence. Attention.
The Archivist manages the boundary between these. For a longer treatment, see the original consciousness.md material in saf/archive/ (pre-cleanup).
Config Integration
All three consciousness systems read from ConsciousnessConfig:
| System | Config Section | Key Fields | Status |
|---|---|---|---|
| N+1 | [subconscious] |
n1_enabled, model, max_tokens, per_agent_intervals | ✅ Wired (Aster model configurable) |
| N+25 | [reflection] |
enabled, message_interval, trigger, per_agent | ✅ Wired (automatic + manual) |
| N+100 | [archivist] |
enabled, interval, threshold, compression_model, synthesis_elements | ✅ Wired (interval + pressure triggers) |
ConsciousnessEvent Variants
The engine emits these for the TUI and CLI to render:
| Variant | Trigger | UI Rendering |
|---|---|---|
Surfacing { source, content, priority } |
After every N+1 pass | Yellow bubble (◈) in cockpit |
Reflection { content } |
Every 25th turn (N+25) | Lavender entry (◎) in cockpit |
Archivist { synthesis, pressure } |
N+100 synthesis completed (interval or pressure) | Teal entry (◉) in cockpit |
CompactionWarning { pressure, tier } |
80%/90%/95% pressure | Amber/orange/red (▲▲▲) in cockpit |