docs(personal): restructure bourdain docs to separate system prompt
Refactor documentation to distinguish character reference from AI system prompt. Removed user context and persona definitions. System prompt instructions moved to prompts/personal/bourdain.md.
This commit is contained in:
@@ -1,46 +1,193 @@
|
||||
# Mnemosyne
|
||||
|
||||
> Multimodal personal knowledge base — text, images, and graph-structured content.
|
||||
> Multimodal personal knowledge base — Robert's curated content across many domains, retrieved through a content-type-aware MCP surface.
|
||||
|
||||
- **MCP server name:** `mnemosyne` (runs in the lab; FastMCP at `/mcp` on its own host)
|
||||
- **MCP server name:** `mnemosyne`
|
||||
- **Prompt snippet:** [prompts/tools/mnemosyne.md](../../prompts/tools/mnemosyne.md)
|
||||
- **Project repo:** `/home/robert/git/mnemosyne` (full README, architecture docs)
|
||||
- **Project repo:** `/home/robert/git/mnemosyne`
|
||||
|
||||
## What It Is
|
||||
|
||||
Mnemosyne is "the memory of everything you know" — a content-type-aware multimodal knowledge management system built on Neo4j vectors and Qwen3-VL embeddings. Unlike a generic vector store, Mnemosyne knows what *kind* of thing a document is (a novel, a textbook, an album, a journal entry, a business proposal) and adjusts chunking, embedding, and retrieval accordingly.
|
||||
Mnemosyne is "the memory of everything you know" — Robert's content-type-aware multimodal knowledge management system built on Neo4j vector storage and Qwen3-VL embeddings. Unlike a generic vector store, Mnemosyne knows what *kind* of thing a document is (a novel, a textbook, an album, a journal entry, a business proposal) and adjusts chunking, embedding, and retrieval accordingly.
|
||||
|
||||
It is a **retrieval engine**, not a synthesis engine. It returns ranked chunks plus metadata; the calling agent does its own synthesis. Architecturally this is intentional — letting the LLM see chunks and pivot mid-search beats pre-digesting answers server-side.
|
||||
It is a **retrieval surface, not a synthesis engine**. Tools return ranked evidence — chunks plus metadata. The calling agent reads the chunks and forms the answer, citing chunk UIDs back so Robert can trace what informed the response.
|
||||
|
||||
## Concepts
|
||||
|
||||
**Library** — the top-level container. Each library has a `library_type` that drives chunking, embedding, and re-ranking strategy.
|
||||
|
||||
**Collection** — a named group of items inside a library (a novel series, a multi-volume manual).
|
||||
|
||||
**Item** — an indexed document or file. Only items with `embedding_status = "completed"` appear in search results.
|
||||
|
||||
**Chunk** — a text segment of an item. `search` returns a `text_preview` (~500 chars); use `get_chunk` for the full text.
|
||||
|
||||
## Library Types
|
||||
|
||||
| `library_type` | Content |
|
||||
|---|---|
|
||||
| `fiction` | Novels, short stories. Cover art available. |
|
||||
| `nonfiction` | General non-fiction prose. |
|
||||
| `technical` | Manuals, textbooks, docs. Diagrams and code-like content. |
|
||||
| `music` | Lyrics, liner notes, album artwork. |
|
||||
| `film` | Scripts, synopses, stills. |
|
||||
| `art` | Catalogs, descriptions, the artwork itself. |
|
||||
| `journal` | Personal entries; temporal/reflective. |
|
||||
| `business` | Proposals, marketing, sales, strategy. Commercial context. |
|
||||
| `finance` | Statements, tax, market commentary. Quote figures exactly. |
|
||||
|
||||
**Scoping queries to the right library_type matters.** A search for "Stoic philosophy" against the `finance` library returns useless results.
|
||||
|
||||
## MCP Tools
|
||||
|
||||
### Recommended workflow
|
||||
|
||||
```
|
||||
list_libraries
|
||||
→ search(query, library_type=..., library_uid=...)
|
||||
→ get_chunk(chunk_uid) # only when text_preview is insufficient
|
||||
```
|
||||
|
||||
### `search`
|
||||
|
||||
Hybrid retrieval: vector + full-text + concept-graph candidates fused by RRF (Reciprocal Rank Fusion), with optional Synesis re-ranking.
|
||||
|
||||
| Parameter | Type | Default | Description |
|
||||
|---|---|---|---|
|
||||
| `query` | str | required | The search query |
|
||||
| `library_uid` | str \| None | None | Restrict to one library by UID |
|
||||
| `library_type` | str \| None | None | Restrict by library type (table above) |
|
||||
| `collection_uid` | str \| None | None | Restrict to one collection by UID |
|
||||
| `limit` | int | 20 | Max candidates to return |
|
||||
| `rerank` | bool | True | Apply Synesis re-ranking |
|
||||
| `include_images` | bool | True | Include matching images in the response |
|
||||
| `search_types` | list[str] \| None | `["vector", "fulltext", "graph"]` | Which retrieval strategies to run |
|
||||
|
||||
Returns:
|
||||
|
||||
```json
|
||||
{
|
||||
"query": "...",
|
||||
"candidates": [
|
||||
{
|
||||
"chunk_uid": "...",
|
||||
"item_uid": "...",
|
||||
"item_title": "...",
|
||||
"library_type": "...",
|
||||
"text_preview": "... (~500 chars) ...",
|
||||
"score": 0.92,
|
||||
"source": "vector|fulltext|graph"
|
||||
}
|
||||
],
|
||||
"images": [...],
|
||||
"total_candidates": 42,
|
||||
"search_time_ms": 85,
|
||||
"reranker_used": true,
|
||||
"reranker_model": "...",
|
||||
"search_types_used": ["vector", "fulltext", "graph"]
|
||||
}
|
||||
```
|
||||
|
||||
### `get_chunk`
|
||||
|
||||
Full text of a single chunk by UID. Use when `text_preview` is insufficient.
|
||||
|
||||
| Parameter | Type | Description |
|
||||
|---|---|---|
|
||||
| `chunk_uid` | str | The chunk UID from a `search` result |
|
||||
|
||||
### `list_libraries`
|
||||
|
||||
Enumerate libraries the caller is authorized to read.
|
||||
|
||||
| Parameter | Type | Default | Description |
|
||||
|---|---|---|---|
|
||||
| `limit` | int | 50 | Max libraries (capped at 200) |
|
||||
| `offset` | int | 0 | Pagination offset |
|
||||
|
||||
### `list_collections`
|
||||
|
||||
Enumerate collections, optionally filtered to one library.
|
||||
|
||||
| Parameter | Type | Default | Description |
|
||||
|---|---|---|---|
|
||||
| `library_uid` | str \| None | None | Filter to one parent library |
|
||||
| `limit` | int | 50 | Max collections (capped at 200) |
|
||||
| `offset` | int | 0 | Pagination offset |
|
||||
|
||||
### `list_items`
|
||||
|
||||
Enumerate indexed documents or files. Check `embedding_status` — only `"completed"` items appear in search.
|
||||
|
||||
| Parameter | Type | Default | Description |
|
||||
|---|---|---|---|
|
||||
| `collection_uid` | str \| None | None | Filter to one collection |
|
||||
| `library_uid` | str \| None | None | Filter to one library |
|
||||
| `limit` | int | 50 | Max items (capped at 200) |
|
||||
| `offset` | int | 0 | Pagination offset |
|
||||
|
||||
### `get_health`
|
||||
|
||||
Pallas-compatible health probe. No auth required.
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "ok | degraded | error",
|
||||
"checks": {
|
||||
"neo4j": {"status": "ok", "duration_ms": 2.1},
|
||||
"s3": {"status": "ok", "duration_ms": 8.4},
|
||||
"embedding": {"status": "ok", "model": "...", "duration_ms": 0.3}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Neo4j or S3 failures → `error` (critical). Missing or unconfigured embedding model → `degraded` (non-critical).
|
||||
|
||||
## Authentication
|
||||
|
||||
All tools except `get_health` require a `Bearer` token in the `Authorization` header. Three credential types:
|
||||
|
||||
| Type | Issued by | Lifetime | Scope |
|
||||
|---|---|---|---|
|
||||
| **Opaque `MCPToken`** | Mnemosyne admin | Long-lived (optional expiry) | `allowed_libraries` list on the token row; per-tool ACL available |
|
||||
| **Per-turn JWT** (`iss=daedalus`) | Daedalus chat | ≤10 minutes | `libs` claim (list of Library UIDs) |
|
||||
| **Team JWT** (`iss=mnemosyne`, `typ=team`) | Mnemosyne | 10-year lifetime | Resolved live from `TeamWorkspaceAssignment` → Neo4j `Library.workspace_id`. Revoked via `active_jti` rotation. |
|
||||
|
||||
Every authenticated request resolves to a `resolved_libraries` list — the set of Library UIDs the caller may read. Tools enforce this list at the query layer. Empty list = authenticated but sees nothing (fail-closed). No auth = also fail-closed.
|
||||
|
||||
## Who Uses Mnemosyne
|
||||
|
||||
All regular agents have access via team-based authentication. Each team's token resolves to the libraries appropriate for that team's domain:
|
||||
|
||||
- **Personal team** — all personal-relevant libraries (fiction, nonfiction, technical, music, film, art, journal, business, finance). Each agent self-filters by `library_type` based on their domain.
|
||||
- **Work team** — business-focused libraries; supporting reference (Ann reaches for nonfiction; Alan reaches for business strategy material).
|
||||
- **Engineering team** — technical libraries and reference (Harper for build references; Scotty for runbooks and incident records).
|
||||
|
||||
Within a team, each agent is responsible for searching the right `library_type` for their work — there's no per-agent ACL inside a team token. Searching the wrong library type returns useless results, not an error.
|
||||
|
||||
## What It's Good For
|
||||
|
||||
- Searching the user's personal knowledge base across libraries (fiction, nonfiction, technical, music, film, art, journal, business, finance)
|
||||
- Multimodal queries — find a book cover, an album sleeve, a screenshot, alongside text
|
||||
- Searching Robert's curated knowledge across libraries — books, music, journal entries, business documents, reference material
|
||||
- Multimodal queries — find a book cover, an album sleeve, a screenshot alongside text
|
||||
- "Did I read something about X" / "what did I write about Y on what date"
|
||||
- Pulling source material the user has actually curated, rather than guessing from training data
|
||||
- Following graph relationships (Author → Book → Topic; Artist → Album → Track)
|
||||
- Pulling source material Robert has actually curated, rather than guessing from training data
|
||||
- Following graph relationships through the underlying Neo4j vector store (Author → Book → Topic; Artist → Album → Track)
|
||||
|
||||
## What It's Not Good For
|
||||
|
||||
- General web knowledge — that's Argos
|
||||
- Anything not already in the KB — Mnemosyne only knows what's been ingested
|
||||
- Anything not yet ingested — Mnemosyne only knows what's been indexed
|
||||
- Synthesis or "give me the answer" — Mnemosyne returns chunks; the calling agent synthesizes
|
||||
- Real-time information (status, news) — content is ingested, not live
|
||||
|
||||
## MCP Tools Exposed
|
||||
|
||||
| Tool | Purpose |
|
||||
|---|---|
|
||||
| `search` | Hybrid search (vector + graph + full-text), re-ranked |
|
||||
| `get_chunk` | Retrieve the full text of a chunk by ID |
|
||||
| `list_libraries` | What libraries exist (fiction, technical, etc.) |
|
||||
| `list_collections` | Collections within a library |
|
||||
| `list_items` | Items within a collection |
|
||||
| `get_health` | Service health probe |
|
||||
- Writing — Mnemosyne is a retrieval surface; ingestion happens through Daedalus and admin tooling
|
||||
|
||||
## Known Gotchas
|
||||
|
||||
- **It's retrieval, not answers.** A `search` call returns chunks; the agent then has to read them and form the answer. Don't expect Mnemosyne to "tell you" something.
|
||||
- **Library type matters.** Searching the *fiction* library for technical content returns nothing useful. Use `list_libraries` first if uncertain.
|
||||
- **Citations should be preserved.** Mnemosyne returns chunk IDs and source metadata — when synthesizing, cite back to the chunk so the user can verify and trace.
|
||||
- **Empty results may mean the index isn't ready.** If `setup_neo4j_indexes` hasn't been run for a given environment, vector search returns empty results and the app logs a readiness warning. Surface that, don't silently confabulate.
|
||||
- **It's retrieval, not answers.** Always cite `chunk_uid` so Robert can verify.
|
||||
- **`library_type` matters.** Searching the wrong library type returns nothing useful. Use `list_libraries` if uncertain.
|
||||
- **`text_preview` is ~500 chars.** Often enough for the agent to decide whether the chunk is relevant; not enough for synthesis. Call `get_chunk` for the full text only when you need it.
|
||||
- **Only `embedding_status = "completed"` items appear in search.** A library with items in progress will show fewer results than `list_items` suggests.
|
||||
- **Empty results may mean the index isn't ready in this environment.** `get_health` will report `degraded` if the embedding model is missing. Surface that, don't silently confabulate.
|
||||
- **Fail-closed auth.** No token = no results. Empty allowed-library list = also no results. Distinguish "I searched and found nothing" from "I'm not authorized" — `list_libraries` returning an empty set is the tell for the latter.
|
||||
- **`include_images=True` by default.** When images aren't relevant, set it to False to reduce noise and tokens.
|
||||
- **Re-ranking has a cost.** `rerank=True` (default) gives better precision but adds latency. For exploratory queries, `rerank=False` is fine; for the query that produces the final answer, leave reranking on.
|
||||
|
||||
Reference in New Issue
Block a user