# Memory Architecture: Chat + User Consolidation Implementation Plan > **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task. **Goal:** Introduzir uma arquitetura de memória segura e incremental que extraia memórias estruturadas com o modelo local `models/embedding/gemma-3-270m-it-Q8_0.gguf`, separe memória de chat e memória de usuário, consolide memórias entre chats sem duplicação e prepare o terreno para uso dinâmico em prompts futuros. **Architecture:** A implementação será dividida em duas pipelines desacopladas: (1) extração de memória de chat a partir de mensagens concluídas em um chat específico; (2) consolidação de memória de usuário a partir das memórias de chat já processadas. Para evitar quebrar o fluxo atual, a extração será feita em background, com schema novo e compatibilidade retroativa com `user_memories`. A primeira fase não altera o prompt principal do chat; apenas cria, valida, deduplica e persiste a memória corretamente. **Tech Stack:** React/TypeScript, Tauri frontend, SQLite local (`db.ts`), API compatível OpenAI do runtime local, modelo GGUF local `gemma-3-270m-it-Q8_0.gguf`, Vitest. --- ## Princípios de segurança desta implementação 1. **Não quebrar o chat atual**: memória nova roda em background e falha silenciosamente. 2. **Não misturar memória bruta com prompt principal ainda**: primeiro persistimos corretamente, depois conectamos ao prompt. 3. **Não usar mensagens inteiras como memória final**: só fatos estruturados, classificados e deduplicados. 4. **Separação explícita**: - `chat memories` = fatos extraídos de um chat específico - `user memories` = fatos consolidados a partir de vários chats 5. **Idempotência**: nunca reprocessar o mesmo insumo sem necessidade. 6. **Deduplicação conservadora**: primeiro por chave/categoria/valor normalizado; sem embeddings sofisticados nesta fase. 7. **Modelo único para extração/classificação**: usar `gemma-3-270m-it-Q8_0.gguf` como extractor/classifier local. --- ## Resultado esperado desta fase Ao final desta implementação: - cada chat poderá gerar memórias estruturadas próprias; - memórias de usuário serão derivadas das memórias de chat já consolidadas; - duplicatas não serão reinseridas; - memórias terão tipo/classificação/confiança/origem; - o sistema estará pronto para usar essas memórias em prompts dinâmicos futuros, sem ainda acoplar tudo ao chat principal. --- ## Modelo de dados recomendado ### Tabela 1: `chat_memories` Representa fatos persistidos derivados de um chat. Campos sugeridos: - `id INTEGER PRIMARY KEY` - `chat_id INTEGER NOT NULL` - `source_message_id INTEGER NULL` - `memory_key TEXT NOT NULL` - `memory_value TEXT NOT NULL` - `memory_category TEXT NOT NULL` - `memory_scope TEXT NOT NULL DEFAULT 'chat'` - `confidence REAL NOT NULL` - `evidence TEXT NULL` - `first_seen_at INTEGER NOT NULL` - `last_seen_at INTEGER NOT NULL` - `normalized_value TEXT NOT NULL` - `superseded_by INTEGER NULL` - `created_at INTEGER NOT NULL` - `updated_at INTEGER NOT NULL` Categorias permitidas inicialmente: - `identity` - `profile` - `preference` - `interest` - `habit` - `project` - `constraint` - `goal` - `topic_pattern` - `skill` ### Tabela 2: `user_memories_v2` Representa fatos consolidados a partir de `chat_memories`. Campos sugeridos: - `id INTEGER PRIMARY KEY` - `memory_key TEXT NOT NULL` - `memory_value TEXT NOT NULL` - `memory_category TEXT NOT NULL` - `confidence REAL NOT NULL` - `normalized_value TEXT NOT NULL` - `supporting_chat_memory_ids TEXT NOT NULL` (JSON array) - `evidence_summary TEXT NULL` - `first_seen_at INTEGER NOT NULL` - `last_seen_at INTEGER NOT NULL` - `created_at INTEGER NOT NULL` - `updated_at INTEGER NOT NULL` ### Tabela 3: `memory_jobs` Fila/log de processamento para idempotência. Campos sugeridos: - `id INTEGER PRIMARY KEY` - `job_type TEXT NOT NULL` (`chat_extract` | `user_consolidate`) - `target_id INTEGER NOT NULL` - `status TEXT NOT NULL` (`pending` | `running` | `done` | `failed`) - `attempts INTEGER NOT NULL DEFAULT 0` - `last_error TEXT NULL` - `created_at INTEGER NOT NULL` - `updated_at INTEGER NOT NULL` --- ## Prompt recomendado para extração de memória de chat Arquivo novo sugerido: `tauri-app/src/prompts/memory-extraction.ts` ### Prompt base ```text You are a local memory extraction and classification engine. Your task is to read a conversation fragment and extract ONLY durable, reusable memory items. Return ONLY valid JSON as an array. Each item must follow this schema: { "memory_key": "snake_case_key", "memory_value": "concise factual value", "memory_category": "identity|profile|preference|interest|habit|project|constraint|goal|topic_pattern|skill", "confidence": 0.0, "evidence": "short quote or short rationale", "is_user_memory_candidate": true } Extraction policy: - Extract durable facts, not temporary requests. - Extract user preferences, likes/dislikes, recurring interests, profession, age, location, constraints, active projects, goals, skills, and patterns in what the user usually searches or asks about. - Prefer atomic facts. - Do not repeat equivalent items. - If a fact is uncertain, lower confidence. - If nothing durable exists, return []. - Never output markdown. ``` ### Prompt adicional para consolidação de memória de usuário ```text You are a user memory consolidator. Input: existing user memories + candidate chat memories. Goal: produce ONLY new or improved user-level memories. Rules: - Do not repeat existing memories. - Merge semantically equivalent facts. - Prefer the most stable formulation. - Keep only durable cross-chat knowledge. - If a fact appears in multiple chats, increase confidence. - Return ONLY valid JSON array with the same schema. ``` --- ## Fases de implementação ### Task 1: Congelar o comportamento atual com testes de regressão **Files:** - Create: `tauri-app/src/hooks/useMemoryExtractor.test.ts` - Test: `tauri-app/src/components/ChatView.test.tsx` **Step 1: Escrever teste de regressão do fluxo atual** Validar que, se o extractor falhar, o chat principal continua funcionando. **Step 2: Rodar teste para confirmar baseline** Run: `cd tauri-app && npm test -- src/hooks/useMemoryExtractor.test.ts` Expected: FAIL inicialmente (arquivo novo). **Step 3: Criar teste mínimo de não-regressão** Cobrir: - extractor não bloqueia envio de mensagem - erro de memória não quebra render/chat **Step 4: Rodar testes** Run: `cd tauri-app && npm test -- src/hooks/useMemoryExtractor.test.ts src/components/ChatView.test.tsx` Expected: PASS **Step 5: Commit** ```bash git add tauri-app/src/hooks/useMemoryExtractor.test.ts tauri-app/src/components/ChatView.test.tsx git commit -m "test: add memory extraction regression coverage" ``` --- ### Task 2: Introduzir schema novo sem remover o antigo **Files:** - Modify: `tauri-app/src/lib/db.ts` - Modify: `tauri-app/src/lib/types.ts` - Create: `tauri-app/src/lib/memory-types.ts` - Test: `tauri-app/src/lib/db.test.ts` **Step 1: Escrever testes falhos para novas tabelas** Cobrir criação idempotente de: - `chat_memories` - `user_memories_v2` - `memory_jobs` **Step 2: Adicionar migração aditiva** Em `db.ts`, usar `ensureTable`/`ensureColumn` (ou equivalente local) sem remover `user_memories` atual. **Step 3: Declarar tipos explícitos** Criar interfaces para: - `ChatMemory` - `UserMemoryV2` - `MemoryJob` - `MemoryCandidate` **Step 4: Rodar testes** Run: `cd tauri-app && npm test -- src/lib/db.test.ts` Expected: PASS **Step 5: Commit** ```bash git add tauri-app/src/lib/db.ts tauri-app/src/lib/types.ts tauri-app/src/lib/memory-types.ts tauri-app/src/lib/db.test.ts git commit -m "feat: add chat and user memory schema" ``` --- ### Task 3: Configurar o modelo local de memória sem tocar no modelo principal **Files:** - Create: `tauri-app/src/config/memory.ts` - Modify: `tauri-app/src/config/ai.ts` or `tauri-app/src/config/ai/index.ts` - Test: `tauri-app/src/features/runtime/runtime-utils.test.ts` **Step 1: Escrever teste falho de resolução da configuração** Configurar constante para: - `MEMORY_MODEL_PATH = "models/embedding/gemma-3-270m-it-Q8_0.gguf"` - `MEMORY_MODEL_ID = "gemma-3-270m-it-Q8_0"` **Step 2: Implementar configuração dedicada** A memória deve usar modelo separado do chat principal. **Step 3: Adicionar fallback seguro** Se o arquivo não existir, a memória desabilita-se sem derrubar o app. **Step 4: Rodar testes** Run: `cd tauri-app && npm test -- src/features/runtime/runtime-utils.test.ts` Expected: PASS **Step 5: Commit** ```bash git add tauri-app/src/config/memory.ts tauri-app/src/config/ai.ts tauri-app/src/config/ai/index.ts tauri-app/src/features/runtime/runtime-utils.test.ts git commit -m "feat: configure dedicated local memory model" ``` --- ### Task 4: Implementar prompt e parser de extração estruturada **Files:** - Create: `tauri-app/src/prompts/memory-extraction.ts` - Create: `tauri-app/src/lib/memory-parser.ts` - Create: `tauri-app/src/lib/memory-parser.test.ts` **Step 1: Escrever testes falhos para parsing de JSON robusto** Cobrir: - array JSON puro - JSON com ruído ao redor - array vazio - item inválido descartado - normalização de `memory_key` - clamp de confiança **Step 2: Implementar parser minimalista** Funções sugeridas: - `parseMemoryCandidates(raw: string): MemoryCandidate[]` - `normalizeMemoryCandidate(candidate): MemoryCandidate | null` **Step 3: Rodar testes** Run: `cd tauri-app && npm test -- src/lib/memory-parser.test.ts` Expected: PASS **Step 4: Commit** ```bash git add tauri-app/src/prompts/memory-extraction.ts tauri-app/src/lib/memory-parser.ts tauri-app/src/lib/memory-parser.test.ts git commit -m "feat: add structured memory extraction prompt and parser" ``` --- ### Task 5: Extrair memórias de chat em background **Files:** - Modify: `tauri-app/src/hooks/useMemoryExtractor.ts` - Create: `tauri-app/src/lib/chat-memory-repository.ts` - Test: `tauri-app/src/hooks/useMemoryExtractor.test.ts` **Step 1: Escrever testes falhos para pipeline de chat memory** Cobrir: - usa modelo de memória dedicado - envia prompt de extração correto - salva em `chat_memories` - marca job/mensagem como processado - não salva duplicata exata **Step 2: Refatorar o hook atual** O hook atual não deve mais gravar direto em `user_memories`. Agora deve: - ler mensagens recentes - chamar o modelo de memória - parsear candidatos - persistir em `chat_memories` - registrar job concluído **Step 3: Implementar deduplicação conservadora** Deduplicar por: - `chat_id` - `memory_key` - `normalized_value` **Step 4: Rodar testes** Run: `cd tauri-app && npm test -- src/hooks/useMemoryExtractor.test.ts` Expected: PASS **Step 5: Commit** ```bash git add tauri-app/src/hooks/useMemoryExtractor.ts tauri-app/src/lib/chat-memory-repository.ts tauri-app/src/hooks/useMemoryExtractor.test.ts git commit -m "feat: extract chat-scoped memories with local model" ``` --- ### Task 6: Consolidar memórias de usuário a partir das memórias de chat **Files:** - Create: `tauri-app/src/lib/user-memory-consolidator.ts` - Create: `tauri-app/src/lib/user-memory-repository.ts` - Create: `tauri-app/src/lib/user-memory-consolidator.test.ts` **Step 1: Escrever testes falhos da consolidação** Cobrir: - lê `chat_memories` já processadas - compara com `user_memories_v2` - cria apenas memórias novas - melhora memória existente quando confiança aumenta - não duplica fatos equivalentes **Step 2: Implementar consolidador em duas etapas** Etapa A: - selecionar candidatas recentes de `chat_memories` Etapa B: - chamar o modelo com: - memórias de usuário já existentes - novas memórias de chat - receber apenas novos fatos consolidados **Step 3: Persistir com rastreabilidade** Salvar também `supporting_chat_memory_ids`. **Step 4: Rodar testes** Run: `cd tauri-app && npm test -- src/lib/user-memory-consolidator.test.ts` Expected: PASS **Step 5: Commit** ```bash git add tauri-app/src/lib/user-memory-consolidator.ts tauri-app/src/lib/user-memory-repository.ts tauri-app/src/lib/user-memory-consolidator.test.ts git commit -m "feat: consolidate user memories from chat memories" ``` --- ### Task 7: Definir política de classificação e uso futuro em prompts **Files:** - Create: `tauri-app/src/lib/memory-prompt-context.ts` - Create: `tauri-app/src/lib/memory-prompt-context.test.ts` - Modify: `tauri-app/src/hooks/useMemoryExtractor.ts` **Step 1: Escrever teste falho para construção de contexto dinâmico** Sem injetar ainda no chat principal, criar builder que monte: - `chat memory context` - `user memory context` separados e filtrados por confiança/categoria. **Step 2: Implementar builder de contexto** Regras iniciais: - `identity/profile/preferences/constraints/goals` com prioridade alta - `topic_pattern/interests` limitados por recência e confiança - sem repetir fatos equivalentes **Step 3: Rodar testes** Run: `cd tauri-app && npm test -- src/lib/memory-prompt-context.test.ts` Expected: PASS **Step 4: Commit** ```bash git add tauri-app/src/lib/memory-prompt-context.ts tauri-app/src/lib/memory-prompt-context.test.ts tauri-app/src/hooks/useMemoryExtractor.ts git commit -m "feat: prepare structured memory prompt context builder" ``` --- ### Task 8: Adicionar comando de consolidação segura e agendada **Files:** - Create: `tauri-app/src/lib/memory-orchestrator.ts` - Modify: `tauri-app/src/components/ChatView.tsx` - Test: `tauri-app/src/components/ChatView.test.tsx` **Step 1: Escrever teste falho do orquestrador** Cobrir: - após resposta concluída, roda extração de chat - consolidação de usuário roda desacoplada/debounced - falha em qualquer etapa não afeta o chat **Step 2: Implementar orquestrador leve** Fluxo: - `assistant turn complete` → enqueue `chat_extract` - depois → enqueue `user_consolidate` com debounce maior **Step 3: Rodar testes** Run: `cd tauri-app && npm test -- src/components/ChatView.test.tsx` Expected: PASS **Step 4: Commit** ```bash git add tauri-app/src/lib/memory-orchestrator.ts tauri-app/src/components/ChatView.tsx tauri-app/src/components/ChatView.test.tsx git commit -m "feat: orchestrate chat and user memory processing safely" ``` --- ### Task 9: Estratégia de migração sem quebra **Files:** - Create: `docs/memory-migration-notes.md` - Modify: `tauri-app/src/hooks/useMemoryExtractor.ts` - Test: `tauri-app/src/lib/db.test.ts` **Step 1: Definir política de coexistência** - `user_memories` antiga fica preservada - nova pipeline escreve em `chat_memories` e `user_memories_v2` - nenhuma leitura crítica do app depende imediatamente da nova tabela **Step 2: Opcional: migração parcial de legado** Se necessário, criar utilitário futuro de backfill de `user_memories` → `user_memories_v2`, mas **não nesta fase**. **Step 3: Documentar explicitamente** Descrever: - rollback fácil - como desligar a feature - como validar DB localmente **Step 4: Commit** ```bash git add docs/memory-migration-notes.md tauri-app/src/hooks/useMemoryExtractor.ts tauri-app/src/lib/db.test.ts git commit -m "docs: add safe migration notes for new memory architecture" ``` --- ### Task 10: Validação final e critérios de aceite **Files:** - No new files required **Step 1: Rodar suíte de memória** Run: ```bash cd tauri-app && npm test -- src/hooks/useMemoryExtractor.test.ts src/lib/memory-parser.test.ts src/lib/user-memory-consolidator.test.ts src/lib/memory-prompt-context.test.ts ``` Expected: PASS **Step 2: Rodar suíte principal** Run: ```bash cd tauri-app && npm test cd tauri-app && npm run build ``` Expected: PASS **Step 3: Validação manual** Verificar: - mensagem normal continua funcionando - memórias de chat são criadas - memórias de usuário aparecem só quando novas/mais fortes - duplicatas não são inseridas - se modelo de memória falhar, chat continua estável **Step 4: Commit final** ```bash git add . git commit -m "feat: add safe chat and user memory architecture" ``` --- ## Riscos e mitigação ### Risco 1: O modelo `gemma-3-270m-it-Q8_0.gguf` não ser bom para extração factual **Mitigação:** - manter parser robusto - limitar escopo a fatos atômicos - usar confiança + deduplicação conservadora - tratar esse modelo como extractor heurístico, não como verdade absoluta ### Risco 2: Duplicação excessiva **Mitigação:** - chave normalizada - valor normalizado - consolidação só com fatos novos ou confiança melhor ### Risco 3: Impacto de performance **Mitigação:** - debounce - background only - janelas pequenas de contexto - consolidação de usuário menos frequente que extração de chat ### Risco 4: Quebra do fluxo atual **Mitigação:** - schema aditivo - falhas silenciosas - nenhuma injeção automática no prompt principal nesta fase --- ## Critérios de aceitação 1. O chat principal continua funcionando sem regressão. 2. O sistema usa o modelo `models/embedding/gemma-3-270m-it-Q8_0.gguf` exclusivamente para a pipeline de memória. 3. Memórias de chat são estruturadas, classificadas e persistidas separadamente. 4. Memórias de usuário são geradas a partir das memórias de chat já processadas. 5. O sistema não duplica memórias equivalentes. 6. Existe builder separado para uso futuro dessas memórias em prompts. 7. Falhas na pipeline de memória não quebram chat, build ou testes. --- ## Recomendação de rollout ### Release 1 - schema novo - extractor de chat - consolidator de usuário - sem injeção no prompt principal ### Release 2 - leitura controlada de `user_memories_v2` + `chat_memories` em prompt dinâmico - observabilidade de qualidade ### Release 3 - integração com pesquisa web + contexto híbrido - memória + pesquisa + multiagente no orquestrador final