# 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, `limit` enforcement, 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-cleanup - `src/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**: 1. **Archivist model selection:** Should N+100 use a dedicated model (config: `archivist.compression_model`), or should the agent pick her own compression model? The `auto` value in config defaults means "let the system decide" — no algorithm written for that yet. 2. **N+1 model for Aster:** `openai/glm-5.1-precision` is the current default hardcoded in reflection.rs line 130. Should this be driven by config only (it is in `SubconsciousConfig.model` for 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. 3. **Cloister canary severity:** HALT vs WARN vs LOG on domain schema violation? Not designed. The current subconscious pass never inspects git diff. 4. **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.md` for current priorities - [ ] Check `docs/tasks/` for active task documents - [ ] Read `CLAUDE.md` for conventions (substrate, not harness) - [ ] Start with P1 items: Archivist (N+100) or Heartbeat N+1 wiring - [ ] Do NOT add `--force-compact` or `auto_compact_at_threshold` knobs - [ ] Update `saf/plan.md` with progress