Watch
1
0
Fork
You've already forked souveraine
0
souveraine/saf/archive/consciousness.md
Fimeg 0e780d5a05 saf: rebuild as a sectioned tree in the substrate voice
Old single-file SAF moved to saf/archive/.
2026-06-26 11:59:02 -04:00

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)

  1. Receive last exchange (user message + Ani's response)
  2. Build system prompt from subconscious agent's own memfs (identity + mandate + ledger orientation)
  3. Run Bifrost tool loop with Aster-safe tools (read, write, edit, glob, grep, list_dir, memory, schedule)
  4. Up to 5 tool rounds with 300ms inter-round delay
  5. Parse final text response into structured observations (source, content, urgency)
  6. Queue observations to 3-box inbox (critical/high → intrusive, low → pending)
  7. Append observations to primary's inner voice (system/metacognition/subconscious.md)
  8. Surface highest-priority item as ConsciousnessEvent::Surfacing
  9. Heuristic fallback (commitment phrases, hedge density) if LLM analysis fails
  10. Adaptive rate delay on 429 (bumps the primary loop's shared rate_delay)
  11. Always emits at least a heartbeat ("Subconscious pass complete — no anomalies detected")
  12. 2-second breather between Ani finishing and Aster starting

What N+1 Still Needs

  • Cloister diff-canary: N+1 should read git diff of 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_intervals exists 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 memory tool
  • ReflectionReport with exited_cleanly flag
  • Manual trigger via souveraine reflect CLI subcommand
  • Configurable model (default: openai/glm-5.1-precision, fallback chain)
  • Automatic trigger at turn_count % 25 == 0 in ConsciousnessEngine

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_agent exists but isn't read — all agents use global 25-step interval
  • Time-based trigger: Only StepCount trigger type is implemented; TimeBased and CompactionEvent are not

N+100: Archivist (The Synthesizer)

State: IMPLEMENTED — src/core/archivist/mod.rs

How It Works

  1. ArchivistEngine constructed by ConsciousnessEngine::new, holds ArchivistConfig.
  2. maybe_synthesize called every turn from on_response. Fires when the turn count hits interval (maintenance) or pressure crosses threshold (emergency).
  3. 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.
  4. Single compression-model LLM call (no tool loop). compression_model: "auto" resolves to the subconscious model, then openai/glm-5.1.
  5. Writes system/synthesized/{end-date}.md via the primary MemoryRepo (git-committed). An HTML-comment covers START..END marker makes resume idempotent.
  6. build_system_prompt injects 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