MIRA v2026.06.25
Major feature additions, infrastructure migration, deployment hardening, and dead code removal. Net effect: +2208 lines added, -1575 removed across 75 files.
New Features
Retrieval-Backed Tool Result Compaction
Oversized tool results (>2000 chars) are now compacted in Valkey while PostgreSQL retains the original. The system works as follows:
- After each turn commits, a
ToolResultHistoryCommittedEventtriggers async compaction for oversized string tool results - Each result gets a session-scoped retrieval ID (
tr_{session_prefix}_{message_id_hex}) stored in message metadata - An LLM produces a compact version; JSON-aware compaction selects array fields (keeps subset of indices) or text fields (summarizes prose within JSON objects)
- A conditional cache patch via compare-and-set replaces the cached copy only if it still matches the original
- In the API response, compacted messages get an ephemeral breadcrumb:
[Exact original tool result available via continuum_tool.get_tool_result(...)] - If the assistant needs the full result, it calls
continuum_tool.get_tool_result(tool_result_id)which queries PostgreSQL directly - Retrieved results carry
tool_result_retrieved=Trueand are never re-compacted - URL preservation validation ensures summaries cannot invent or change URLs from the original
AsyncWorkBarrier provides bounded cross-turn coordination: the chat endpoint waits up to 30 seconds (configurable via async_work_barrier_timeout_seconds) for background compaction before loading the next turn's continuum, preventing stale data races.
Schema changes: messages.tool_call_id and messages.is_error moved from metadata into dedicated columns with proper indexes.
Portrait & LoRA Refinement (Preview-Before-Save)
Both portrait and user model (LoRA) now support a preview-before-save refinement workflow. Users provide free-text instructions, receive a proposed revision, then accept or decline.
- Preview stored in Valkey with 10-minute TTL under opaque
preview_id - Single-consume semantics prevent double-accept; user ID embedded in key prevents cross-user theft
- Portrait: plain prose refinement via
PortraitDomainHandler(actions:get,refine,accept,decline) - LoRA: same workflow plus critic validation loop (up to 3 attempts). Circuit breaker presents last candidate if all fail since the user initiated the request
- Cache invalidation after accept clears the relevant WorkingMemory caches
Peanut Gallery "Initiative" Action Type
A new action type catches cases where MIRA is technically correct but conversationally passive — acting as a respondent instead of an interlocutor. Triggers on passivity patterns including literal-only answering, serial interrogation, option dumping without prioritization, explanation without action, missed value-add opportunities, situational blindness toward frustrated users, and premature closure. Never carries critical severity. Priority order: concern > coaching > initiative > noop.
One-Time Credential Dump
After installation, all credentials (Vault root token, unseal key, API keys) are written once to ~/Desktop/MIRA_credentials.txt with prominent warnings. File is chmod 600 restricted. Instructions tell the user to save securely and delete. For offline mode, notes that no external API keys were configured.
Infrastructure Changes
Local LLM: Ollama → llama.cpp Migration
Complete replacement of Ollama with llama.cpp for local/offline deployments:
- llama.cpp built from source with CUDA support during deployment
- Two-model architecture: Qwopus3.6-27B-v2-MTP-Q5_K_M (port 3090) + Qwen3.5-9B-UD-Q3_K_XL (port 3092)
- VRAM target: dual RTX 3090 / 48GB total, tensor split 12,12
- Pre-configured pair for dual RTX 3090 plus custom GGUF option for different hardware
- Schema column renamed:
adapter_name→dialect_nameacrossconversation_llmtable - Default conversation LLM changed from
gemmatoprimary; usage pricing tiers pruned phoneafriendinternal LLMs remain remote even in offline mode (fail gracefully if air-gapped)- OpenAI dialect gets
_is_local_endpoint()detection andcache_checkpointinjection
Centralized Prompt Loader
load_prompt() replaces ad-hoc open(Path(...)) calls across ~12 services. Guarantees UTF-8 encoding, path traversal protection, .txt enforcement, empty-file detection, optional-prompt support (required=False), and debug logging. System prompt loader hardened with path traversal protection and file extension checks.
Compaction Trigger Simplification
Removed _estimate_request_tokens() entirely. Uses previous turn's actual provider-reported token count directly against compaction_trigger_tokens (40000). Segment collapse invalidates cached baseline via SegmentCollapsedEvent subscription. Added model_validator ensuring trigger doesn't exceed provider input budget.
Vault Hardening
Deploy script now applies restrictive permissions to /opt/vault/ at install time (directory 700, files 600, scripts 700) instead of just warning the user to do it manually.
Deploy Script Fixes
- Added missing cmake/git packages to Debian/Ubuntu apt install lists so llama.cpp build succeeds
- Added nvcc detection before llama.cpp build; falls back to CPU-only when CUDA toolkit is unavailable
- Fixed DISTRO check from
ubuntutodebianto match actual distro detection logic - Rejects unsupported Fedora versions (< 41) upfront with clear error rather than failing mid-install with cryptic 404
Model Defaults Updated
- Generic chat default:
qwen/qwen3.5-397b-a17b→z-ai/glm-5.2 - Subcortical default:
qwen/qwen3-32b→qwen/qwen3.6-27b
Docker Install Option
README now includes Docker one-liner as a third install option alongside local install and VM provisioning.
System Prompt Overhaul
System prompt trimmed from 110 to 89 lines by removing motivational framing and prescribing emotional texture. Operational constraints restored in affirmative form: forage guidance, tool-call contract, sentence-content rule, structure-from-task rule, contrastive-negation discipline, conversation origination, and emotion-tag UI note. All additions avoid negative examples to prevent priming failure modes.
HUD Restructure (Synthetic Tool Call + Named Fields)
HUD notification center restructured from a single assistant prose block with <mira:hud> wrapper into a synthetic tool call/result pair. The model sees it as a tool interaction (system called "hud" tool, got structured data), eliminating the need for disclaimers like "not generated by you."
notification_centertype changed fromstrtodict[str, str]mapping section names to XML content- Each trinket's output appears as a named field (datetime_section, active_reminders, inbox_status, etc.) serialized as JSON
- Empty sections omitted entirely; whole HUD skipped when no data exists
- Removed dead
notification_partsvariable from routing pipeline
Dead Code Removal (~400 lines)
ContinuumRepository:get_by_id(),load_messages_by_ids(),update_message_metadata(),get_messages_for_dates()— all unusedLinkingService:classify_relationship_sync(),_parse_classification_response(),llm_providerparam — marked dead since Feb 2026ContinuumPool.update_cache()— unused public methodMEMORY_GARDENER.mdremoved (unfinished design doc, subtractive OSS change)
Bug Fixes
- Anthropic dialect: skip thinking blocks when no signature matches, preventing orphaned blocks without signatures
- POST probe: accounts for reasoning text and tool calls; providers returning only reasoning or tool calls no longer fail. Max tokens increased 16→256. Resource cleanup added via
PostgresClient.close_all_pools()in finally blocks - Prompt injection defense: exception type corrected from
RuntimeErrortoValueErrorfor JSON parsing failures - Health endpoint:
thread_healthconverted to async function - Inbox tool: handles None chars parameter without crashing
- Prepopulate SQL: adds missing
segment_turn_countfield - Vault preload: added
mira/servicespath so service config secrets are loaded at startup alongside api_keys/database/auth categories - Reminder tool: replaced if/elif dispatch chain with operation_map dict and inspect.signature-based kwarg filtering; schema-valid but per-operation-irrelevant params no longer crash methods that don't accept them
Chores
coerce_to_intextracted fromcontinuum_toolinto sharedtools/repoutilityemail-validatordependency added for Pydantic EmailStr validation- Web tool synthesis config supports environment variable overrides
- Tool definitions sorted alphabetically for deterministic output
- All CLAUDE.md files updated to reflect new architecture