# memories/ — Persistent Agent Learnings

See @../../CLAUDE.md for project-wide patterns.

## Constraints
- **50 memories per project** (strict cap, eviction on overflow)
- **500 characters max** per memory (enforced at Pydantic + DB CHECK constraint level)
- **6 categories**: env, pattern, gotcha, test, dependency, general
- Content is `.strip()`ed before length validation — whitespace doesn't count

## LRU Eviction
When saving the 51st memory: `DELETE WHERE id = (SELECT id ORDER BY access_count ASC, created_at ASC LIMIT 1)`.
- Least-accessed die first; on tie, oldest-created dies first
- New memories start at `access_count = 0` — immediately vulnerable to eviction if project is full

## recall_memories vs list_memories
| | recall_memories | list_memories |
|---|---|---|
| Method | POST | GET |
| Side effect | Increments access_count + updated_at | None |
| Sort | access_count DESC (most useful first) | updated_at DESC (most recent first) |
| Use case | Start of task — load context, boost memory survival | Browsing/auditing without affecting eviction |

## Gotchas
- `recall_memories` is POST because it mutates (access_count) — not a read-only operation
- `source_task_id` FK is nullable and NOT validated for existence — memory can reference a deleted task
- Category is validated BEFORE querying — invalid category → 400 (not empty result)
- No concurrent eviction protection — two simultaneous `save_memory` calls could both evict

## MCP Tools (4)
`save_memory`, `recall_memories`, `forget_memory`, `list_memories`
