| title | Analysis — MIRA-OSS v1 rev 2 (taylorsatula) | ||||
|---|---|---|---|---|---|
| date | 2026-03-30 | ||||
| type | analysis | ||||
| system | mira-OSS | ||||
| source |
|
||||
| related |
|
MIRA is a self-hosted, event-driven conversational AI system built around the constraint of one continuous conversation forever. It maintains persistent long-term memory with autonomous lifecycle management (extraction, linking, consolidation, decay), a modular "working memory" system prompt composer, behavioral adaptation via "Text-Based LoRA," and a background agent system for speculative context gathering. The system uses PostgreSQL (pgvector + BM25 full-text search) as its primary store, Valkey (Redis-compatible) for caching and trinket state, and HashiCorp Vault for credential management.
This file is a deep dive over the vendored snapshot in vendor/mira-OSS (commit f8b13b9, version 2026.03.30-major). It supersedes the prior analysis of commit ee44b18 (version 2026.03.07-major).
Summary of substantive changes (not just bugfixes/cleanup):
| Area | Change | Impact |
|---|---|---|
| Background agent system | New agents/ directory: LLM-in-a-loop "forage" agent running in daemon threads with shared tools, quality rubric, and ForageTrinket for result surfacing |
First system in this repo with autonomous sub-agent collaboration during conversation |
| User model synthesis | Assessment extraction (alignment/misalignment/contextual_pass signals) → critic validation loop (Haiku, 3 attempts) → XML user model stored on users.user_model, every 7 use-days |
Replaces prior blind feedback extraction; anchored to system prompt sections |
| Portrait synthesis | 150–250 word prose portrait from recent collapsed summaries, every 10 use-days, injected as {user_context} |
User-facing identity continuity |
| Verbose refinement ablated | Removed trim/split pipeline for memories >70 chars (sync path had KeyError bug proving it never ran) | Clean ablation: dropped columns, constraints, LLM configs, pricing entries |
| Relationship classification → Haiku | Downgraded from Sonnet to Haiku-4-5-20251001 for 2-text classification | Cost optimization; well-scoped task for "big fast idiot" |
| Segment pause/resume | Explicit paused state; paused segments never timeout; auto-resume on next message |
User-controlled conversation suspension |
| Extraction pipeline restructure | ExtractionEngine (payloads) / MemoryProcessor (pure data, no side effects) / ExecutionStrategy ABC (shared _process_and_store_memories) |
Eliminates batch/immediate code duplication |
| 3-axis linking | Vector similarity + entity co-occurrence + TF-IDF term overlap | TF-IDF catches orphan memories (no entities, distant embeddings) |
| Hub discovery formalized | Dedicated HubDiscoveryService replacing ad-hoc entity boosting |
Proper entity → memories → ranking pipeline |
| 16 tools (up from 11) | Added: forage, imagegen (Gemini), punchclock, pager (Lattice federation), square, kasa (smart home) + code execution beta | Broader tool surface; IoT/commerce integration |
| Account tier system | account_tiers table with provider/endpoint/api_key columns |
Multi-provider support (Anthropic + generic/Ollama) |
| Context overflow remediation | Embedding-based drift pruning → oldest-first fallback, tool pair safety, 3 retries | Handles token budget overflow gracefully |
| Immutable domain models | Frozen dataclasses for ContinuumState/Message; Continuum as aggregate root; Unit of Work pattern | Prevents silent mutations; atomic DB→cache persistence |
| StatefulTrinket formalization | Base class with Valkey persistence, TTL _expire_items() per turn, centralized segment collapse cleanup |
ForageTrinket/PeanutGalleryTrinket auto-expire stale results |
| Federation API | cns/api/federation.py — Lattice server-to-server messaging |
Multi-instance communication |
| Subcortical context reduction | 3 user/assistant pairs (down from 6), based on MI analysis (2.34× → 1.1× context bleed) | Tighter retrieval signal |
| Preprocess consolidation | preprocess_content_blocks() as canonical shared function (assessment, summary, peanut gallery) |
No more duplicated media/tool stripping logic |
MIRA is a full-stack conversational agent (FastAPI + Hypercorn), not a library. It includes:
- HTTP + WebSocket chat API
- Authentication (WebAuthn + magic link; single-user OSS mode)
- Multi-user isolation (PostgreSQL Row Level Security)
- 16 built-in tools (web search, email, contacts, maps, weather, reminders, memory manipulation, domain docs, image generation, smart home, commerce, time tracking, federation messaging, background research)
- Dynamic tool loading/unloading with two lifetimes (ephemeral per-turn, pinned per-session)
- Background agent for speculative context gathering ("forage")
- A hosted version at miraos.org with web/macOS interfaces
The codebase is organized into five core subsystems:
- CNS (Central Nervous System): conversation orchestration, the "Continuum" aggregate, LLM interaction, user model synthesis
- LT_Memory: long-term memory extraction, linking, consolidation, retrieval, decay scoring
- Working Memory: event-driven system prompt composition via modular "trinkets"
- Tools: self-registering tool framework with per-tool config and dependency injection
- Agents: background LLM-in-a-loop modules for autonomous speculative work
All inter-component communication goes through an EventBus (pub/sub, synchronous). Key event flow:
- User message →
ContinuumOrchestrator.process_message() - Subcortical layer (pre-LLM): query expansion (replaces original), entity extraction (spaCy), complexity assessment, memory retention evaluation — using 3 user/assistant pairs as context
- Memory surfacing: parallel hybrid search (BM25 + vector RRF) and hub-based entity discovery → merge → link traversal → rerank → cap at ~20 surfaced memories (~15 pinned + ~5 fresh)
- Working memory composition: trinkets contribute sections →
SystemPromptComposerassembles into cached/non-cached/notification-center/post-history blocks - LLM streaming response with tool execution loop (includes context overflow remediation)
- TurnCompletedEvent published (carries continuum object to prevent handler race conditions)
- On inactivity (~60 min):
SegmentCollapseEvent→ summary generation → memory extraction → assessment signal extraction → portrait synthesis (every 10 use-days) → cache invalidation
1. Working Memory (system prompt)
Modular "trinkets" (11 total) contribute to the system prompt via events:
| Trinket | Variable name | Placement | Purpose |
|---|---|---|---|
| Base prompt | base_prompt |
system (cached) | Core identity + {user_context} portrait |
| LoRA directives | behavioral_directives |
system (cached) | Behavioral adaptation from feedback synthesis |
| Tool availability | tool_availability |
system (cached) | Enabled tool descriptions |
| Location | location_context |
system (cached) | User location + weather |
| Conversation manifest | conversation_manifest |
system (cached) | Segment manifest |
| Domain docs | domaindoc |
post-history | Stable reference docs with section collapse/expand |
| DateTime | datetime_section |
notification center | Current time (fresh each turn) |
| Active reminders | active_reminders |
notification center | Scheduled reminders |
| Forage results | forage_results |
notification center | Background agent findings |
| Relevant memories | relevant_memories |
notification center | Surfaced LT memories |
| Peanut gallery | peanutgallery_guidance |
notification center | Metacognitive observer guidance |
The notification center is wrapped in <mira:hud> tags and explicitly marked as "runtime state, authoritative for current context." StatefulTrinkets (ForageTrinket, PeanutGalleryTrinket) persist to Valkey and auto-expire via TTL (_expire_items() each turn); all stateful trinkets are flushed centrally on segment collapse.
2. Short-term / segment memory
One continuous conversation thread (the "Continuum"). Segments can be active, paused, or collapsed:
- Active: current conversation; times out after inactivity (~60 min)
- Paused: user-suspended; never times out; auto-resumes on next message
- Collapsed: archived with first-person summary + 768d embedding
At collapse:
- LLM generates a first-person summary ("I debugged the IndexError...") with absolute timestamps
- Previous 5 summaries provided as context for narrative continuity
- Summary embeddings generated (768d, mdbr-leaf-ir-asym)
- Assessment signals extracted for user model synthesis
Session reconstruction on cache miss: collapse marker → summaries → behavioral primer → continuity (last 2 pairs) → session boundary → active messages.
3. Long-term memory (persistent)
Structured Memory objects stored in PostgreSQL with:
text,embedding(768d),importance_score(0.0–1.0)happens_at,expires_at(temporal fields)access_count,mention_count(behavioral signals)inbound_links,outbound_links(JSONB arrays ofMemoryLinkEntrywith typed relationships)entity_links(JSONB array ofEntityLinkEntry)annotations(JSONB array ofAnnotationEntry)activity_days_at_creation,activity_days_at_last_access(vacation-proof decay)source_segment_id(provenance back to extraction source)
Entities: named entities (PERSON, ORG, GPE, PRODUCT, EVENT, WORK_OF_ART, LAW, LANGUAGE, NORP, FAC) extracted via spaCy, stored in a dedicated entities table with link_count and last_linked_at. Entity matching uses PostgreSQL trigram fuzzy matching (pg_trgm), not embedding similarity. Entity extraction normalizes variations to canonical forms (PostgreSQL ← postgres/Postgres) via fuzzy clustering.
Memory links (typed relationships between memories):
- Types:
supports,conflicts,supersedes,refines,precedes,contextualizes,extraction_ref,null - Stored bidirectionally in
inbound_links/outbound_linksJSONB on each memory - Each link carries
type,confidence,reasoning,created_at, and optionalextraction_bond(3-word descriptor) - Relationship classification now uses Haiku-4-5-20251001 (cost-optimized for this well-scoped task)
Memory linking uses 3-axis candidate discovery:
- Vector similarity — cosine distance above threshold
- Entity co-occurrence — shared entities with embedding floor to suppress common-entity noise
- TF-IDF term overlap — catches orphan memories (no entities, distant embeddings) via rare shared terms
Domain docs ("DomainDocs"): stable text files that do not decay. Sections can be collapsed/expanded autonomously by the LLM. Used for behavioral directives, documentation, procedures. Changes reflected in real-time.
Triggered at segment collapse via SegmentCollapseEvent:
- Message loading: query boundary sentinel, load messages until next boundary → single
ProcessingChunk - Memory context snapshot: existing relevant memories retrieved for extraction context (enables dedup, linking, and consolidation detection)
- Payload construction (
ExtractionEngine): system + user prompts, formatted existing memories, short ID mapping (8-char hex → full UUID) - LLM extraction via Anthropic Batch API (50% cheaper) or immediate fallback (non-Anthropic endpoint or failover active). Produces
ExtractedMemoryobjects with text, importance, temporals, related memory IDs, linking hints, entities, and consolidation targets - Response processing (
MemoryProcessor, pure data — no side effects): JSON parsing withjson_repairfallback → UUID remapping → validation → deduplication (0.85 fuzzy text + 0.7 cosine vector) - Shared storage path (
_process_and_store_memories): store memories with embeddings → entity persistence (spaCy NER + pg_trgm matching) → extraction_ref link creation. Identical path for batch and immediate strategies - Post-processing (also via Batch API or immediate):
- Relationship classification (Haiku): LLM classifies pairs → bidirectional link creation
- Consolidation: connected-component clustering of similar memories (BFS) → LLM-driven merge/rewrite → link transfer + memory archival
- Entity GC: pg_trgm self-join finds similar name pairs → BFS grouping → LLM review for merge/delete/keep decisions
The scoring formula (lt_memory/scoring_formula.sql) is a single SQL expression with sigmoid transform:
final_score = sigmoid(raw_score × recency × temporal × expiration_trailoff − 2.0)
Components:
- Value score:
ln(1 + access_rate / 0.02) × 0.8, where access_rate uses momentum-decayed access count (5% fade per activity day) normalized by age - Hub score: diminishing returns on inbound link count (linear to 10, then logarithmic)
- Entity hub score: weighted entity links (type-weighted: PERSON=1.0, EVENT=0.9, ORG=0.8, etc.) with diminishing returns above 50 weighted links
- Mention score: explicit LLM references (strongest signal); linear to 5, then logarithmic
- Newness boost: 2.0 decaying to 0 over 15 activity days (grace period for new memories)
- Recency:
1 / (1 + days_since_access × 0.015)(~67 activity-day half-life) - Temporal multiplier: upcoming events get 2× (within 1 day) to 1.2× (within 14 days); past events decay over 45 days to a 0.4 floor
- Expiration trailoff: linear crash from 1.0 to 0.0 over 5 calendar days after
expires_at
Key design choice: activity days, not calendar days for decay calculations. This prevents vacation-induced memory degradation. Temporal events (happens_at, expires_at) still use calendar days since real-world deadlines don't pause.
Two-stage pipeline:
Stage 1 — Subcortical layer (pre-LLM processing, 3 user/assistant pairs as context):
- LLM rewrites user query into an expanded retrieval query (replaces original, not augments)
- spaCy extracts named entities from the query
- Complexity assessment (straightforward → medium effort; complex → high effort/thinking)
- Memory retention evaluation (which pinned memories to keep)
Stage 2 — Dual-path retrieval (parallel):
- Similarity pool: BM25 + vector hybrid search with Reciprocal Rank Fusion
- Intent-aware weighting (recall: BM25-heavy 0.6/0.4; explore: vector-heavy 0.3/0.7; exact: strong BM25 0.8/0.2; general: balanced 0.4/0.6)
- RRF with sigmoid normalization to spread scores into 0–1 range
- Searches both personal (RLS-scoped) and global memories
- Importance score floor filtering
- Hub-derived pool (
HubDiscoveryService): entity-driven discovery- Fuzzy match extracted entities to DB entities (pg_trgm)
- Cap matched entities to prevent explosion
- Collect all linked memories per matched entity (per-entity cap)
- Rank by expansion embedding similarity (ranking, not gating)
Pools are merged (dedup, similarity pool takes precedence), then:
- Debut boost: new memories (<10 activity days) with few entity links get ranking boost
- Supersedes penalty: memories with inbound "supersedes" links are soft-demoted
- Link traversal: attached linked memories with metadata (type, confidence, reasoning, depth)
- Rerank: type-weight × inherited_importance × confidence
- Access tracking: retrieved memories get
access_count/last_accessedupdated
Hard caps: ~15 pinned memories, ~5 fresh, ~20 total surfaced, ~2 linked per primary.
New in v1 rev 2. An autonomous sub-agent that runs in a background thread to speculatively gather context:
Architecture:
agents/forage.pyexports arun()function (procedural, not a class)- Spawned via
ForageToolin a daemon thread withcontextvars.copy_context()(inherits user isolation) - Uses the shared
ToolRepository— same tools as primary LLM (continuum_tool, memory_tool, web_tool) - Configurable model (default: qwen/qwen3-32b on Groq endpoint)
Loop mechanism:
- Build tool schemas from ToolRepository, resolve API key from Vault
- Call LLM with tools; if tool calls returned, execute them, send "Continue." heartbeat
- Repeat until agent stops calling tools (natural completion) or hits iteration/timeout cap
- On max iterations: force one final call without tools for summary
- Publish result via
UpdateTrinketEvent→ForageTrinket
Quality rubric (baked into system prompt): GROUNDED (backed by search results), RELEVANT (addresses query), SPECIFIC (concrete details), USEFUL (genuinely helps), HONEST (admits if nothing found).
Result lifecycle: pending → success/timeout/failed → dismissed. Errors auto-expire after 5 turns. Results refinable via refine_task_id. Every forage saves a JSON trace in user's data directory.
Integration: ForageTool dispatches agents; ForageTrinket manages result state in Valkey and surfaces content in the notification center HUD. Multiple concurrent forages supported (tracked by task_id).
After each segment collapse, a feedback extractor scans for three signal types:
- Prediction errors: MIRA made a wrong assumption
- Negative feedback: user expressed frustration or correction
- Positive feedback: user expressed appreciation or resonance
Signals accumulate in PostgreSQL. Every 7 use-days (not calendar days), a pattern synthesizer:
- Analyzes accumulated signals
- Evolves behavioral directives (patterns can be reinforced, refined, revised, or new)
- Writes directives to a
BEHAVIORAL DIRECTIVESsection in thepersonal_contextDomainDoc - These flow into the system prompt via the
LoraTrinketon every subsequent interaction
The synthesis is evolutionary (builds on previous synthesis), not replacement.
After each segment collapse, an assessment extractor evaluates the conversation against anonymized system prompt sections:
AssessmentSignal:
signal_type: 'alignment' | 'misalignment' | 'contextual_pass'
section_id: e.g., 'authenticity', 'collaboration'
strength: 'strong' | 'moderate' | 'mild'
evidence: concrete quote or behavior
Every 7 use-days, a user model synthesizer runs:
- Analyze accumulated assessment signals
- Generate candidate user model (Sonnet)
- Critic validation (Haiku, max 3 attempts): checks for observation laundering, personality labels, contradictions
- If failed: rerun synthesis with critic feedback
- Store as XML on
users.user_model
Separately, every 10 use-days, portrait synthesis generates a 150–250 word prose portrait from recent collapsed summaries (20 activity-day window, minimum 3 summaries). The portrait is injected into the base prompt as {user_context}.
A two-stage LLM pipeline that runs asynchronously after N turns (fire-and-forget, non-critical):
- Prerunner (fast model) filters seed memories for relevance
- Sonnet-class observer evaluates conversation state
- Returns one of: noop / compaction / concern / coaching
- Guidance injected via
PeanutGalleryTrinketwith TTL expiry (default 5 turns)
- PostgreSQL Row Level Security: all user data access automatically scoped via
SET app.current_user_idat connection checkout. B-tree index on user_id + IVFFlat on embedding combined by query planner.mira_adminrole hasBYPASSRLS - HashiCorp Vault: all secrets (API keys, DB URLs, auth secrets); AppRole auth; fail-fast if Vault is unreachable
- User context propagation:
contextvarsfor thread-safe user scoping;copy_context()for spawned threads (including forage agents) - Input validation: Pydantic at API boundaries, size limits (10MB docs, 5MB images, 20K char messages)
- Per-user credentials:
UserCredentialServicefor user-specific API keys (never exposed to LLM) - Distributed request locks: per-user via Valkey (60s TTL)
- Admin sessions: explicit
AdminSessionbypasses RLS for cross-user operations (scheduled jobs, batch polling)
Three-layer architecture:
- Activity tracking:
increment_user_activity_day()on first message of user's local day. Trackscumulative_activity_days+last_activity_date - Platform function:
get_users_due_for_job(interval)—MOD(cumulative_activity_days, interval) = 0with 2-day recency window. Stateless, no tracking table - Job registration: calendar-based
IntervalTrigger(days=1)jobs that callget_users_due_for_job()to select eligible users
Current jobs: extraction retry (6h calendar), batch polling (1m), consolidation (7 use-days), temporal score recalc (1 use-day), bulk score recalc (1 use-day), entity GC (7 use-days), batch cleanup (1 use-day), portrait synthesis (10 use-days, runs in collapse chain).
- Tuning test infrastructure with JSON + Markdown reports for extraction quality, consolidation, entity GC, subcortical performance
- No standardized benchmark harness (LoCoMo/LongMemEval/EverMemBench)
- Architecture oracle doc:
docs/MEMORY_ARCHITECTURE_ORACLE.md
-
"Earn Your Keep" decay model remains the most sophisticated in this repo. The multi-factor scoring formula with activity-day basis, momentum decay, hub centrality, mention tracking, and temporal multipliers is well-designed. The v1 rev 2 codebase is unchanged here, but the extraction pipeline restructure (shared
_process_and_store_memories) and Haiku classification reduce the cost of feeding the scoring system. -
Background agent system is genuinely novel among the folk systems. The forage agent is the first system in this repo with autonomous sub-agent collaboration — a background LLM that uses the same tools to speculatively gather context while the primary conversation continues. The quality rubric (GROUNDED, RELEVANT, SPECIFIC, USEFUL, HONEST) is a pragmatic approach to preventing speculative hallucination. The integration is clean: shared ToolRepository, contextvar propagation for user isolation, event-driven result surfacing via ForageTrinket.
-
3-axis linking catches what 2-axis misses. Adding TF-IDF term overlap to vector similarity + entity co-occurrence addresses a real gap: orphan memories with no entity links and distant embeddings that share rare meaningful terms. This is a practical improvement over the prior linking approach.
-
Assessment-anchored user modeling is more principled than blind feedback extraction. Evaluating conversation against anonymized system prompt sections (rather than just extracting "positive/negative" signals) produces more actionable observations. The critic validation loop (Haiku checking for observation laundering, personality labels, contradictions) adds a meaningful quality gate.
-
Verbose refinement ablation demonstrates good engineering discipline. Removing a pipeline that (a) contradicted the extraction prompt's design and (b) had a KeyError proving it never ran, rather than trying to fix it, is the right call. The clean ablation (columns, constraints, configs, pricing entries all removed) shows the "ablate, don't deprecate" philosophy working in practice.
-
Immutable domain models + Unit of Work pattern are a meaningful maturation. Frozen dataclasses prevent silent state mutations; the Unit of Work ensures atomic DB→cache persistence with DB as authoritative source on crash.
-
Context overflow remediation is a practical robustness addition. Embedding-based drift pruning (remove least-similar messages to current query) → oldest-first fallback → tool pair safety → retry is better than most systems' approach of "truncate from the front and hope."
-
No standardized benchmark remains the biggest gap. Despite sophisticated tuning test infrastructure, there's no LoCoMo/LongMemEval/EverMemBench-style evaluation. The system is tuned by feel and internal metrics. This makes it impossible to compare retrieval quality claims against the literature.
-
LLM extraction quality is unvalidated against ground truth. Extraction, relationship classification (now Haiku), consolidation, entity GC, assessment extraction, and user model synthesis all depend on LLM calls. The Haiku downgrade for relationship classification is justified by task scope, but quality was presumably verified internally — no external validation data is available.
-
Scoring formula complexity is a maintenance risk. The SQL expression is ~170 lines of nested CASEs, subqueries, and mathematical transforms. Constants are hardcoded in SQL (not in config). A single constant change has cascading effects on all memories.
-
No bi-temporal validity semantics. MIRA has only
expires_atandhappens_at. Corrections are handled viasupersedeslinks rather than validity intervals. Point-in-time queries ("what did I believe on January 15?") require link traversal rather than a simple temporal filter. -
Memory text is untyped. Memories are natural-language strings with no type discrimination (fact vs preference vs constraint vs procedure vs event). The system relies on the scoring formula and link types to differentiate behavior.
-
DomainDocs bypass importance scoring entirely. They don't decay and are always injected. The section collapse/expand mechanism mitigates token bloat but relies on the LLM to manage its own context.
-
No write gating for memory extraction. Memories are extracted automatically at segment collapse. There's no user confirmation step, no instruction/data boundary enforcement, and no quarantine for suspicious extractions. The
memory_toolallows user-initiated memory creation, but LLM-extracted memories are auto-committed. -
Forage agent inherits primary tool permissions. The background agent uses the same ToolRepository with the same user context. A poorly-constrained forage could trigger side-effectful tools (email, reminders). Currently constrained to
continuum_tool,memory_tool,web_toolby a constant, but this is a code-level constraint, not an architectural one. -
Prompt injection surface. Memories and forage results are injected into the notification center. While the
<mira:hud>wrapper and delimiter markers provide visual separation, retrieved memories and forage content carry user-originated text that could contain adversarial instructions. No taint tracking or sanitization. -
Entity GC uses LLM judgment. Merge/delete/keep decisions for entities rely on LLM calls. A bad judgment can merge distinct entities or delete a valid one, with cascading effects on hub discovery.
-
Singleton-heavy architecture. Many services use module-level singletons. Testing requires initialization in specific order. The
CNSIntegrationFactoryencodes the dependency graph, but it's implicit rather than declarative.
| Dimension | MIRA-OSS v1r2 | OpenClaw | ClawVault | memv | Gigabrain |
|---|---|---|---|---|---|
| Deployment model | Full-stack app (FastAPI) | Plugin/config suite | CLI tool (npm) | Library (PyPI) | Obsidian plugin |
| Storage | PostgreSQL + pgvector + Valkey + Vault | SQLite + FTS5 | Markdown files + graph JSON | SQLite + sqlite-vec + FTS5 | SQLite + JSON + weighted Jaccard |
| Memory types | Untyped text + typed links | Typed facts + relations + aliases | Typed entries + graph index | Semantic statements + episodes | 7 typed memories (USER_FACT, PREFERENCE, etc.) |
| Decay model | Multi-factor sigmoid (activity-day) | Activation/importance | Reindex/refresh | Bi-temporal validity | Stepped recency (1d/7d/30d/90d/365d) + 8-factor value scoring |
| Retrieval | BM25+vector RRF + entity hubs + 3-axis linking | FTS5 + embeddings | QMD hybrid | sqlite-vec + FTS5 + RRF | FTS + weighted Jaccard + class budgets |
| Write gating | None (auto-extract) | Curation habits | Sanitization + path safety | Confidence ≥ 0.7 filter | 7-stage pipeline with review queue |
| Benchmark harness | Internal tuning tests | 60-query benchmark | None | None | harness-lab-run.js with A/B comparison |
| Behavioral learning | Text-Based LoRA + user model synthesis | None | None | None | None |
| Background agents | Forage (LLM-in-a-loop, shared tools) | None | None | None | None |
| Security model | RLS + Vault + contextvars + AdminSession | Convention-based | Path sanitization | None (library) | Junk filter + XML-escape injection |
| Entity model | spaCy NER + pg_trgm + 3-axis linking | SQLite facts + aliases | Graph index | None | Person service + coreference |
-
Background agent collaboration is a new pattern for the catalog. The forage agent demonstrates that sub-agent work can share the same tool infrastructure and user isolation without creating a parallel tool ecosystem. The quality rubric (baked into the agent's system prompt, not a post-filter) is a pragmatic approach. The integration pattern (event bus → trinket → notification center) keeps the architecture clean. This is the first system in this repo where the primary LLM has an autonomous collaborator running in parallel.
-
Assessment-anchored user modeling is more structured than feedback extraction. Prior systems (including MIRA v1) extracted "positive/negative/prediction error" signals — broad buckets. Anchoring assessment to specific system prompt sections (anonymized) produces signals like "misalignment with 'collaboration' section, moderate strength, evidence: [quote]". The critic validation loop is an additional quality gate not seen in other systems.
-
3-axis linking is a practical improvement worth adopting. Adding TF-IDF term overlap to the standard vector + entity co-occurrence catches a real class of orphan memories. The embedding floor on entity co-occurrence (suppress common-entity noise) is also a good refinement.
-
Prior v1 contributions still hold: activity-day decay (best practice for personal memory), first-person summaries (preserves agent identity), hub-based entity discovery (practical alternative to full KG), Text-Based LoRA (concrete behavioral feedback loop), supersedes-as-link (alternative to invalidation-as-overwrite), Batch API for cost savings, production-grade RLS security.
-
Ablation discipline is worth noting. The verbose refinement removal demonstrates that it's better to remove a broken pipeline than to maintain dead code. The evidence (KeyError bug in sync path) backing the removal decision is the kind of rigor that prevents accrual of phantom subsystems.
- Background agents: shisad could adopt the pattern of sub-agents sharing the tool repository with context propagation, but would need to add the capability-scoped retrieval constraints that MIRA lacks (forage agent has unconstrained access to all three tools).
- Assessment-anchored feedback: the section-anchored signal extraction is more structured than MIRA v1's broad feedback categories. shisad's behavioral feedback loop could use a similar anchor-to-policy approach, with the addition of write gating on the resulting directives.
- 3-axis linking: shisad's planned knowledge graph could incorporate TF-IDF as a third linking axis for orphan node discovery.
- Security delta remains: MIRA's RLS + Vault is strong for multi-user isolation, but it still lacks instruction/data boundary enforcement, taint tracking, write gating on memory extraction, and capability-scoped retrieval for sub-agents. The forage agent's tool access is code-constrained (a list of tool names), not architecturally constrained.
- Evidence gap remains: no external benchmark evaluation means MIRA's retrieval quality claims are internal-only.
- Write gating: memories extracted by LLM should pass through a confirmation or quarantine step, especially for identity-level facts and procedural directives.
- Typed memory: even a simple type tag (fact/preference/constraint/procedure/event) would enable type-aware retrieval and governance.
- External benchmarks: running LoCoMo/LongMemEval against MIRA's retrieval pipeline would quantify quality.
- Taint/provenance on injected content: memories and forage results injected into the notification center should carry provenance markers and be placed in explicitly untrusted prompt regions.
- Capability scoping for sub-agents: the forage agent should have architecturally enforced tool restrictions, not just a code-level
AVAILABLE_TOOLSconstant. - Bi-temporal validity:
supersedeslinks provide correction semantics, but point-in-time queries and temporal filtering require explicitvalid_from/valid_untilintervals.