# Plan: Behavioral Memory — How I Do Stuff **Goal:** Maven builds a rich behavioral model of the user over time: habits, routines, preferences, recurring tasks, deadlines, and commitments. She uses this model to proactively propose plans, surface reminders, and adjust her behavior — all grounded in the existing fact/event/note stores. **Done when:** - `internal/memory/behavior.go` — behavioral model builder reads facts, events, notes, nudges, reminders, tools, calendar events - Model is exposed as a structured profile: `{"routines": [...], "preferences": {...}, "recurring_tasks": [...], "typical_schedule": {...}}` - LLM generates this profile periodically (daily) and stores it as a note/fact - Proactive loop uses the profile to propose daily plans: "сегодня ты обычно делаешь X, Y, Z. напомнить?" - Profile is queryable via voice: "что я обычно делаю по вторникам?" - Profile updates on fact write — not just periodic — so a new "walk" fact immediately adjusts the walking schedule **Scope:** - `internal/memory/behavior.go` — behavior builder - `internal/memory/profile.go` — profile data structures (routines, preferences, schedule, commitments) - Reuses `internal/llm.Client` for profile generation - Reuses `internal/pattern/detector.go` for interval detection on behavioral data - Extends `internal/router/intent.go` — `IntentQuery` extended with behavioral sub-queries - Reuses `internal/delivery.Dispatcher` for surfacing proposals as nudges **Steps:** 1. Design profile schema: `BehaviorProfile` struct with `Routines []Routine`, `Preferences map[string]string`, `RecurringTasks []Task`, `WeeklySchedule map[string][]Activity` 2. Create `internal/memory/behavior.go` — `Builder` that reads `store.RecentFacts(1000)`, `store.EventsFor` (all action+object combos), `store.RecentNotes(500)`, `store.ListReminders` 3. Implement profile generation — prompt for `llm.Client` that takes raw facts and outputs a structured JSON profile; stores result as a fact (`kind=config, key=behavior_profile`) 4. Create `internal/memory/planner.go` — reads the profile each morning (via routine cron `"0 8 * * *"`) and proposes a daily plan through `dispatcher.DispatchNudge` 5. Add real-time updates — when a fact is written via `WriteFact`, the behavior builder incrementally updates the relevant profile section (append-only, no full rebuild) 6. Wire voice query — `"что я обычно делаю?"` routes to `IntentQuery` → behavior profile lookup → LLM-phrased answer 7. Add IPC read method `MethodGetBehaviorProfile` so mavweb can display it on `/dash` 8. Test with synthetic fact history — verify weekly schedule is correctly inferred --- ## Status (2026-08-01) — partially shipped, deliberately narrowed Shipped on `overnight/behavior-profile`: - `internal/memory/behavior.go` — `BuildProfile` counts habits per weekday out of self-facts: distinct-day counts (`MinHabitDays = 2`), a median time-of-day, and `FormatWeekdayRU` / `FormatOverallRU` for the spoken answer. - `internal/router/habit.go` — `ParseHabitQuery`, which requires a habit marker ("обычно", "каждую", "привычки", …) and parses the weekday deterministically. - `cmd/mavend/actions_query.go` — a `habits` query source, so "что я обычно делаю по вторникам?" is answered. **Not shipped, and not to be shipped as written:** - *Step 3, LLM-generated profile stored as a fact.* The profile is COUNTED, not generated. A 1.7B asked to summarise a year of habits produces fluent claims about the owner's life that no row supports, and a wrong claim about him is the most expensive kind of wrong maven can be. Counting is verifiable and cheap. - *Step 5, incremental updates on fact write.* There is no cache to keep fresh — the profile is recomputed on the question, so a new fact is already in the next answer. A cached profile that can disagree with its own rows is two truths. - *Step 4, proactive daily plan proposals via the dispatcher.* Maven is not a nag, and a nudge at 08:00 every day proposing the day is the definition of one. The sanctioned path from "she noticed a pattern" to "she acts on it" already exists: `internal/pattern/detector.go` proposes a routine, and the owner accepts it on `/routines`. It goes through him. Still open, if wanted later: `MethodGetBehaviorProfile` + a `/dash` panel (step 7). The counted profile needs no new IPC method to be *asked* about — the query source reads `RecentFacts` over the existing surface — so this is a display concern only.