SAF (souveraine architecture files) is now the in-repo doc set. working notes (CLAUDE.md, docs/) stay on disk, gitignored.
6.9 KiB
SAF: Execution Plan
Ordered by impact, sequenced for "real harness today." Last updated: 2026-05-12 (Full audit — several stages now complete, new tasks emerged)
Overview — What Shipped Since May 6
The following was all completed between May 6 and May 12, across ~6,000 new lines of Rust:
- Stage 3 — TUI Chat: full wired chat with bubbles, tool cards, cockpit (thinking + subconscious panes), schedules editor, portraits, presence mode, markdown rendering
- Stage 4 — LocalBackend: in-process engine with auto-fallback, SubagentRunner, TurnInjector, CronSensor/HeartbeatHandler wiring
- Stage 5A — Memory module: git-backed MemFS with 8 subcommands, frontmatter, auto-commit,
limitenforcement, ledgers - Stage 5B — N+1 Aster pass: full Bifrost tool loop (5 rounds), subconscious agent identity, ledger orientation, 4-fold mandate prompt
- Stage 5C — N+25 Reflection engine: 5-phase LLM pass with tool access, wired at every 25th turn
- Stage 5D — Compaction engine: 4 strategies (Microcompact/SlidingWindow/Summary/Cull), audit trail
- Stage 5E — Skills system: 4-tier discovery, injected into system prompt
- Stage 5F — Nervous system: EventBus, CronSensor, HeartbeatHandler, EventLog
- Stage 5G — Seed identity: Ed25519 per-agent keypair + CLI subcommand
- Stage 5H — Credentials: OS keyring + env var fallback
- Stage 5I — Auth middleware: bearer-token API protection for memory routes
- Stage 5J — Conversation persistence: event-sourced disk store with load/save/archive
What's Still TODO (Priority Order)
P1 — N+100 Archivist (Missing)
Files to create/modify:
src/core/archivist/mod.rs— NEW: rebuild the Archivist module post-cleanupsrc/server/consciousness_engine.rs— Wire N+100 pass instead of placeholder pressure check
The original core::archivist/ was removed from compilation (May 6) and never rebuilt. At 0.7+ pressure, the consciousness engine emits a ConsciousnessEvent::Archivist with a generic "Context compression triggered" string. No actual synthesis, no LLM call. The ArchivistConfig (enabled, interval, threshold, compression_model, synthesis_elements) exists in config but nothing reads it.
Target architecture: Smaller/faster model (e.g. qwen2.5-7b) calls Bifrost with a synthesis prompt, writes structured output (Themes/Emotions/Tensions/Anchors/Evolution/Patterns) to system/synthesized/{date}.md. Raw journal entries stay in git forever.
P1 — N+1 After Heartbeat Turns
File: src/core/nervous/handler.rs
TurnInjector::inject_background_turn in LocalBackend drains the stream silently but never calls ConsciousnessEngine::on_response after the turn completes. This means scheduled turns from the cron system never get Aster analysis. The fix is to hook into the post-turn processing path so heartbeat-injected turns also pass through the subconscious.
P2 — Remote Git Sync (push/pull)
Files: src/core/memory/mod.rs
Neither push() nor pull() exist on MemoryRepo. The real agent's .git/config may already have a remote configured. The auto_push config option exists but is never read. Needed for: off-machine backup, letting Ani on the home server sync memory to a remote, federation foundation.
P2 — Per-Agent Context Limit Fix
Status: 🟡 Partially resolved
ConsciousnessEngine now looks up the agent's llm_config.context_window (commit 79a23bb). The context_limit field is correctly read per-agent. What's still hardcoded: the 128_000 fallback in pressure_for_session() when agents.get() fails. No per-agent compaction thresholds (all agents share the global 80/90/95% tiers).
P2 — Subagent Pool (Lifecycle Manager)
Files: src/core/subagent/mod.rs (25 lines, stub)
The SubagentPool exists as a struct with new(). No lifecycle tracking, no concurrency limits, no heartbeat monitoring. The LocalSubagentRunner handles individual spawns correctly but there's no central pool to:
- Limit concurrent forks
- Track parent-child relationships
- Kill orphaned subagents
- Report pool health
P3 — Sensorium Unification
Files: src/core/sensorium/mod.rs (154 lines, trait + types only)
Sensorium trait exists with BandwidthClass (High/Medium/Low/Minimal) and DiscoveryLevel. Not wired into any backend. Would enable bandwidth-aware SSE events, progressive UI discovery, and context-adaptive interaction. The TuiSensorium, MobileSensorium, and Coordinator from CLAUDE.md are not built.
P3 — Chain Orchestrator (Talking vs Thinking)
Files: src/core/chain/mod.rs (50 lines, stub)
ChainOrchestrator was supposed to manage Talking (reactive, fast) vs Thinking (reflective, slow) chains. Never implemented beyond struct + new().
P4 — Federation Transport
Files: saf/atproto-federation.md (research), src/core/nervous/mod.rs (seed_id pre-wired)
WebSocket bridge between EventBus instances on different machines. ATProto-ready DID identity model. The seed_id field on SensorEvent is pre-wired as the federation identity marker. Not started.
P4 — OSSUI Integration
File: src/api/mod.rs (web routes)
Server has web/dist/ SPA fallback wired. No actual UI built there. Rebrand ex-letta-oss-ui as Souveraine web interface.
P4 — Cloister Diff-Canary
Location: Not yet scoped
N+1 should read git diff of the last commit and validate against domain schema. HALT/WARN/LOG severity. From docs/CONSCIOUSNESS_CYCLE.md § Cloister Security Model.
Remaining Design Decisions
These were deferred in prior sessions and are still unresolved:
-
Archivist model selection: Should N+100 use a dedicated model (config:
archivist.compression_model), or should the agent pick her own compression model? Theautovalue in config defaults means "let the system decide" — no algorithm written for that yet. -
N+1 model for Aster:
openai/glm-5.1-precisionis the current default hardcoded in reflection.rs line 130. Should this be driven by config only (it is inSubconsciousConfig.modelfor the engine, but the reflection engine has its own fallback chain)? Current resolution: the consciousness engine passes the config value through; the reflection engine's hardcoded default is a fallback. -
Cloister canary severity: HALT vs WARN vs LOG on domain schema violation? Not designed. The current subconscious pass never inspects git diff.
-
lifetime_active_seconds granularity: Currently ticks in 30s buckets. Useful for uptime percent but not fine-grained enough for "how long has this agent been running this session." No per-session wall-clock tracking.
Resumption Checklist
When a new model picks up:
- Read
saf/plan.mdfor current priorities - Check
docs/tasks/for active task documents - Read
CLAUDE.mdfor conventions (substrate, not harness) - Start with P1 items: Archivist (N+100) or Heartbeat N+1 wiring
- Do NOT add
--force-compactorauto_compact_at_thresholdknobs - Update
saf/plan.mdwith progress