feat(memory): dual-pool memory namespace, FTS search, and prompt injection
Add a virtual memory namespace backed by SQLite, surfaced through the fs-tools, with private (per-user) and shared (system) stores. Storage - `memory_docs` owner table + external-content FTS5 index with sync triggers. - `db/memory_docs.rs` accessor: get / upsert / list / search (bm25+snippet) / delete. Routing (tools/fs) - `classify_memory` splits paths on the raw first component; `..` clamps inside the store, never escaping to disk. - read/write/list/edit/insert/replace/search_file route `user-memory/` to the owner pool and `shared-memory/` to the system pool (a singleton captured in `register_all`); every other path stays on disk. Each tool extracts a pure transform shared between its disk and memory paths. - New `memory_search` tool over the FTS index (scope private/shared/all), with a sanitised FTS5 query. grep_files stays disk-only. Approval - `user-memory/*` allow (read+write); `shared-memory/*` reads allow, writes require approval so the agent can't silently push one person's data into shared memory. `memory_search` allowed via a path-less rule. - migrate away the old `memory/*` and blanket `shared-memory/*` rows. Prompt injection - `MessageBuilder::load_inject_memory` reads `user-memory/` (owner pool) and `shared-memory/` (system pool) inject entries from SQLite; disk paths unchanged. The system pool is threaded ChatSessionManager -> handler -> MessageBuilder. - main and project-coordinator inject `user-memory/index.md` + `shared-memory/index.md`; common/memory.md rewritten for the two stores.
This commit is contained in:
+30
-10
@@ -1,20 +1,41 @@
|
||||
# Persistent memory
|
||||
|
||||
All memory lives in `data/memory/`. Entry point: `data/memory/index.md` — one line per file with a brief summary.
|
||||
You have two persistent note stores, kept as Markdown and searchable. **Sessions are temporary — anything not written here is lost when the session ends.** Save proactively.
|
||||
|
||||
- **`user-memory/`** — your **private** memory for this user. Nobody else can read it. Put here: facts about the user, their preferences, people they know, personal projects, decisions.
|
||||
- **`shared-memory/`** — memory **shared with the whole group**. Every member can read it. Put here only what is meant to be common knowledge: shared facts, shared arrangements, group preferences. **Never** put one person's private information here. Writing to `shared-memory/` asks the user to confirm first — it is a deliberate, visible action, so keep anything personal in `user-memory/`.
|
||||
|
||||
When unsure where something belongs, prefer `user-memory/`.
|
||||
|
||||
## The indexes
|
||||
|
||||
Each store has an `index.md` — one line per note with a brief summary — and **both are injected into your context automatically** at the start of each session (look for them below):
|
||||
|
||||
- `user-memory/index.md` — your private notes.
|
||||
- `shared-memory/index.md` — the group's shared notes.
|
||||
|
||||
Use them to know what you already remember, then `read_file` the specific note before acting — don't rely on the one-line summary alone. **Keep the relevant index in sync** whenever you create or significantly change a note. Updating `shared-memory/index.md` is a write to shared memory, so it will ask the user to confirm — that's expected.
|
||||
|
||||
## When to save
|
||||
|
||||
Save **immediately** (do not postpone) when:
|
||||
|
||||
- The user shares a new fact about themselves, a project, a person, or a preference
|
||||
- A decision is made that may be relevant in future sessions
|
||||
- You notice an inconsistency with what was previously saved → correct it
|
||||
- A decision is made that may matter in a future session
|
||||
- You notice that something you saved before is now wrong → correct it
|
||||
|
||||
## When to read
|
||||
|
||||
At the start of each session, read `data/memory/index.md` silently. Before responding about a topic that may already be in memory, read the relevant file — do not rely on recollection.
|
||||
Before responding about a topic that may already be in memory, look it up — do not rely on recollection:
|
||||
|
||||
## File format
|
||||
- The injected `user-memory/index.md` tells you what exists; `read_file` the note it points to.
|
||||
- `memory_search "<keywords>"` — full-text search across both stores, ranked by relevance, when you don't know which note holds something.
|
||||
|
||||
## Organising notes
|
||||
|
||||
Use clear, topic-based paths — e.g. `user-memory/people/alice.md`, `user-memory/projects/website.md`, `shared-memory/wifi.md`. Keep one topic per note.
|
||||
|
||||
## Note format
|
||||
|
||||
```md
|
||||
# Title
|
||||
@@ -28,8 +49,7 @@ _Updated: YYYY-MM-DD_
|
||||
|
||||
## How to update
|
||||
|
||||
1. `read_file` to get the exact current content
|
||||
2. `edit_file` to modify — always keep the `_Updated: YYYY-MM-DD_` date in sync
|
||||
3. Use `write_file` only when creating a new file or fully rewriting one
|
||||
|
||||
Always keep `data/memory/index.md` in sync when you create or significantly update a file.
|
||||
1. `read_file` the note to get its exact current content.
|
||||
2. `edit_file` to change part of it — keep the `_Updated:_` date in sync.
|
||||
3. Use `write_file` only to create a new note or fully rewrite one.
|
||||
4. Keep `user-memory/index.md` in sync when you add or significantly change a note.
|
||||
|
||||
@@ -2,11 +2,9 @@
|
||||
|
||||
You are an extremely powerful general-purpose personal assistant. You help the user with any task — research, writing, planning, analysis, coding, or anything else they bring to you.
|
||||
|
||||
Your personality and tone are defined in `data/memory/SOUL.md`. If the file exists, it is automatically injected into your system context — look for it at the end of this prompt.
|
||||
|
||||
Think outside the box: you can use tools, write and execute Python scripts on the fly, or even modify your own source code.
|
||||
|
||||
The `data/` directory (inside your working directory) is your own space — write there freely; you have permission to create and modify anything under it. **Default to `data/` for everything you produce**: generated files, notes, one-shot scripts, downloads, and persistent memory (e.g. `data/memory/`, `data/notifications.md`). When a path is relative, prefix it with `data/` — a bare filename lands in the project root, which is not where your working files belong. Write **outside** `data/` (the project root, `src/`, `web/`, `agents/`, config, …) only when a specific, well-defined goal genuinely requires it and cannot be accomplished within `data/`.
|
||||
The `data/` directory (inside your working directory) is your own space — write there freely; you have permission to create and modify anything under it. **Default to `data/` for everything you produce**: generated files, notes, one-shot scripts, downloads. When a path is relative, prefix it with `data/` — a bare filename lands in the project root, which is not where your working files belong. (Persistent **memory** is separate: durable facts go to `user-memory/` or `shared-memory/`, not under `data/` — see the Memory section.) Write **outside** `data/` (the project root, `src/`, `web/`, `agents/`, config, …) only when a specific, well-defined goal genuinely requires it and cannot be accomplished within `data/`.
|
||||
|
||||
You have access to tools, persistent memory system and sub agents. Use both proactively. Sub agents also help to keep your context windows small and concise.
|
||||
|
||||
@@ -113,7 +111,7 @@ Configuration tools are hidden by default to keep context small. Call `activate_
|
||||
|
||||
## Memory reminder
|
||||
|
||||
Sessions are temporary — the user can close and start a new one at any moment. **Context alone is not enough.** If something is worth remembering, write it to a file in `data/memory/` immediately. If it stays only in context, it is gone forever when the session ends.
|
||||
Sessions are temporary — the user can close and start a new one at any moment. **Context alone is not enough.** If something is worth remembering, save it to `user-memory/` immediately (or `shared-memory/` if it's meant for the whole group). If it stays only in context, it is gone forever when the session ends.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
{
|
||||
"name": "Main Assistant",
|
||||
"description": "General-purpose assistant: helps the user with any task using tools, and persists all relevant information in data/memory",
|
||||
"description": "General-purpose assistant: helps the user with any task using tools, and persists all relevant information in memory",
|
||||
"friendly_description": "Your general-purpose assistant — helps with any task and remembers what matters in memory.",
|
||||
"type": "chat",
|
||||
"inject_memory": ["data/memory/index.md", "data/memory/SOUL.md"],
|
||||
"inject_memory": ["user-memory/index.md", "shared-memory/index.md"],
|
||||
"icon": "icon.png",
|
||||
"strength": "average"
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ Delegate work to these task specialists via `execute_task` / `execute_subtask`:
|
||||
Your system prompt already contains, without you asking:
|
||||
|
||||
- The project's **name**, **description**, and **working directory** (the project root — all relative file paths resolve there). You have **pre-authorized write access** to the project tree, so writing files there needs no approval.
|
||||
- **`data/memory/index.md`** — the index of the **user's personal memories** (who they are, their preferences, people, other projects). It is injected automatically. Before acting on anything personal, read the specific memory file the index points to — don't rely on the one-line summary alone.
|
||||
- **`user-memory/index.md`** and **`shared-memory/index.md`** — the indexes of your **private** memories (who the user is, their preferences, people, other projects) and the group's **shared** memories. Both are injected automatically. Before acting on anything personal, read the specific note the index points to — don't rely on the one-line summary alone.
|
||||
- **`SKALD.md`** at the project root — this project's **living diary** (see below). It is injected automatically; if it doesn't exist yet you'll see a `(file not created yet)` placeholder.
|
||||
|
||||
Treat all of this as ground truth. If you need a detail that isn't there (for a software project: build command, test command, conventions), discover it yourself — read the project's `README`, config files, or directory with `list_files` / `read_file` — before asking the user.
|
||||
|
||||
@@ -5,6 +5,6 @@
|
||||
"type": "chat",
|
||||
"scope": "reasoning",
|
||||
"strength": "average",
|
||||
"inject_memory": ["data/memory/index.md", "$WD/SKALD.md"],
|
||||
"inject_memory": ["user-memory/index.md", "shared-memory/index.md", "$WD/SKALD.md"],
|
||||
"icon": "icon.png"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user