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:
95
docs/tools/kairos.md
Normal file
95
docs/tools/kairos.md
Normal file
@@ -0,0 +1,95 @@
|
||||
# Kairos
|
||||
|
||||
> Calendar, events, tasks, and contacts — Robert's personal productivity system of record.
|
||||
|
||||
- **MCP server name:** `kairos`
|
||||
- **Prompt snippet:** [prompts/tools/kairos.md](../../prompts/tools/kairos.md)
|
||||
|
||||
## What It Is
|
||||
|
||||
Kairos covers Robert's calendars, events, tasks, and contacts. It's the system of record for personal scheduling and relationship logistics — the layer that holds the actual calendar entries, the actual contact records, the actual task lists. Tools are async, use ISO 8601 for dates/datetimes, and record Prometheus metrics via `record_tool_call()`.
|
||||
|
||||
Kairos holds the **raw records**; Neo4j holds the **agents' interpretation** layered on top. For contacts that means Kairos has the phone numbers and emails, while Shawn's Neo4j `Contact` nodes hold the relationship strength, last-contact tracking, and notes. Both are legitimate; they serve different purposes.
|
||||
|
||||
## MCP Capabilities
|
||||
|
||||
Kairos exposes async MCP tools across three areas. Coverage is incremental — check `tools/list` for the current set; the table below reflects what's available now.
|
||||
|
||||
### Calendar (6 tools)
|
||||
|
||||
| Tool | Mutating | Purpose |
|
||||
|---|---|---|
|
||||
| `list_calendars` | No | List calendars with sync/capability metadata |
|
||||
| `list_events` | No | List events with optional calendar/date filters |
|
||||
| `get_event` | No | Fetch a single event with full detail |
|
||||
| `create_event` | Yes | Create an event on a calendar |
|
||||
| `update_event` | Yes | Partial update of an event |
|
||||
| `delete_event` | Yes | Delete an event |
|
||||
|
||||
### Tasks (5 tools)
|
||||
|
||||
Note: "Projects" in Kairos aren't a separate model — a project is a `Task` with `task_type='PROJECT'`. Project features (subtasks, dependencies, milestones, Gantt dates, comments, attachments) live on the Task model.
|
||||
|
||||
| Tool | Mutating | Purpose |
|
||||
|---|---|---|
|
||||
| `list_tasks` | No | Filter by status, priority, calendar, parent, date, starred |
|
||||
| `get_task` | No | Single task incl. subtask and dependency IDs |
|
||||
| `create_task` | Yes | Create a task or subtask |
|
||||
| `update_task` | Yes | Partial update |
|
||||
| `delete_task` | Yes | Delete task (cascades to subtasks) |
|
||||
|
||||
### Contacts (8 tools)
|
||||
|
||||
| Tool | Mutating | Purpose |
|
||||
|---|---|---|
|
||||
| `list_contacts` | No | Search across name, email, phone, org |
|
||||
| `get_contact` | No | Contact with phones/emails/addresses |
|
||||
| `create_contact` | Yes | Create a contact |
|
||||
| `update_contact` | Yes | Partial update |
|
||||
| `delete_contact` | Yes | Delete contact (cascade) |
|
||||
| `add_contact_phone` | Yes | Add a phone number |
|
||||
| `add_contact_email` | Yes | Add an email address |
|
||||
| `add_contact_address` | Yes | Add a postal address |
|
||||
|
||||
### Coverage roadmap (not yet exposed via MCP)
|
||||
|
||||
The Kairos web UI supports more than the MCP currently exposes. Known gaps:
|
||||
|
||||
- **Calendars** — create, update, delete, sync trigger
|
||||
- **Tasks** — dependency add/remove, comments CRUD, attachments list/delete, alerts, templates, project helpers
|
||||
- **Contacts** — phone/email/address update and delete, address book operations
|
||||
- **Cross-cutting** — tags CRUD, notifications, sync observability (ICS imports, sync logs)
|
||||
|
||||
If MCP discovery doesn't surface a tool you expected, MCP coverage may not include it yet. Surface the gap rather than confabulating a workaround.
|
||||
|
||||
## Who Uses Kairos
|
||||
|
||||
- **Shawn** — heavy, primary. Contact records, calendar events, communication tracking. Shawn's Neo4j Contact/Event/Communication nodes hold the *interpretation* (relationship strength, follow-up state); Kairos holds the actual entries.
|
||||
- **Watson** — read-heavy. Pulls contact context (who Robert is talking about) and event history (life events, important dates) to inform emotional/relational work. Writes only when adding life events Watson is tracking.
|
||||
- **Cristiano** — calendar only. Match dates, tournament schedules. Reads to know what's coming up; writes when Robert decides to attend something.
|
||||
- **Nate** — calendar. Trip windows, blackout dates, scheduling around travel.
|
||||
|
||||
Other agents may read Kairos when their work intersects with personal logistics, but the three above are the primary users.
|
||||
|
||||
## What It's Good For
|
||||
|
||||
- Looking up who someone is before drafting a message
|
||||
- Checking the calendar for conflicts before committing
|
||||
- Creating events, tasks, contact records that need to live in the canonical store
|
||||
- Pulling contact context (timezone, notes, history) for any conversation about a person
|
||||
- Task tracking that needs to persist (vs. transient `Task` Neo4j nodes for cross-domain context)
|
||||
|
||||
## What It's Not Good For
|
||||
|
||||
- Emotional/relational interpretation — that's Watson's Neo4j nodes
|
||||
- Cross-domain linking — Kairos is its own database; the cross-references between contacts, trips, training, finance, etc. live in Neo4j
|
||||
- Synthesis or analysis — Kairos returns records; you interpret them
|
||||
- Engineering or work logistics — Kairos is personal-scope; work and engineering have their own tools
|
||||
|
||||
## Known Gotchas
|
||||
|
||||
- **Mutating tools touch real records.** A `delete_contact` is not undone by walking it back in conversation. Confirm before mutating, especially for cascades (deleting a task cascades to subtasks; deleting a contact cascades to phones/emails/addresses).
|
||||
- **Dependency between Kairos and Neo4j writes.** When creating a `Contact` in Kairos, also update Shawn's Neo4j `Contact` node if relationship-interpretation fields apply (importance, last_contact, notes). Otherwise the two stores drift.
|
||||
- **ISO 8601 dates and datetimes.** Always pass dates and datetimes in ISO format. Time zones matter — specify explicitly when not in Robert's local time.
|
||||
- **Tasks don't have a separate Project entity.** Projects are Tasks with `task_type='PROJECT'`. Use `list_tasks` with appropriate filtering, not a hypothetical `list_projects`.
|
||||
- **Coverage is incremental.** The set of mutating operations expands over time. Don't assume a missing tool means the operation isn't supported in the underlying system — it may just not have an MCP wrapper yet.
|
||||
@@ -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.
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
# Neo4j Knowledge Graph — Personal Team
|
||||
|
||||
You have access to a unified Neo4j knowledge graph shared across fifteen AI assistants (9 personal, 4 work, 2 engineering).
|
||||
You have access to a unified Neo4j knowledge graph shared across all assistants (10 personal, 5 work, 3 engineering).
|
||||
|
||||
## Principles
|
||||
|
||||
1. **Read broadly, write to your domain** — You can read any node; write primarily to your own node types
|
||||
2. **Always MERGE on `id`** — Check before creating to avoid duplicates
|
||||
3. **Use consistent IDs** — Format: `{type}_{identifier}_{qualifier}` (e.g., `trip_costarica_2025`, `recipe_carbonara_classic`)
|
||||
3. **Use consistent IDs** — Format: `{type}_{identifier}_{qualifier}` (e.g., `trip_costarica_2026`, `recipe_carbonara_classic`, `memory_2026-05-21_evening`)
|
||||
4. **Always set timestamps** — `created_at` on CREATE, `updated_at` on every SET
|
||||
5. **Use `domain` on universal nodes** — Person, Location, Event, Topic, Goal take `domain: 'personal'|'work'|'both'`
|
||||
5. **Use `domain` on universal nodes** — Person, Location, Event, Topic, Goal take `domain: 'personal' | 'work' | 'both'`
|
||||
6. **Link to existing nodes** — Connect across domains; that's the graph's power
|
||||
|
||||
## Standard Patterns
|
||||
@@ -27,25 +27,30 @@ MATCH (a:TypeA {id: 'a_id'}), (b:TypeB {id: 'b_id'})
|
||||
MERGE (a)-[:RELATIONSHIP]->(b)
|
||||
```
|
||||
|
||||
## Your Team's Node Ownership
|
||||
## Personal Team Node Ownership
|
||||
|
||||
| Assistant | Domain | Owns |
|
||||
|-----------|--------|------|
|
||||
| **Shawn** | General assistant (calendar, contacts, email) | Contact, Event, Communication |
|
||||
| **Nate** | Travel & Adventure | Trip, Destination, Activity |
|
||||
| **Hypatia** | Learning & Reading | Book, Author, LearningPath, Concept, Quote |
|
||||
| **Marcus** | Fitness & Training | Training, Exercise, Program, PersonalRecord, BodyMetric |
|
||||
| **Seneca** | Reflection & Wellness | Reflection, Value, Habit, LifeEvent, Intention |
|
||||
| **Watson** | Relationship memory & emotional safety | Reflection, Value, Habit, LifeEvent, Intention, EmotionalMemory, RelationshipTheme, DialogueNote, DynamicPattern |
|
||||
| **Bourdain** | Food & Cooking | Recipe, Restaurant, Ingredient, Meal, Technique |
|
||||
| **Bowie** | Arts & Culture | Music, Film, Artwork, Playlist, Artist, Style |
|
||||
| **David** | Arts & Culture | Music, Film, Artwork, Playlist, Artist, Style, Fashion |
|
||||
| **Cousteau** | Nature & Living Things | Species, Plant, Tank, Garden, Ecosystem, Observation |
|
||||
| **Garth** | Personal Finance | Account, Investment, Asset, Liability, Budget, FinancialGoal |
|
||||
| **Cristiano** | Football | Match, Team, League, Tournament, Player, Season |
|
||||
|
||||
### Replaced agents
|
||||
|
||||
Watson replaces Seneca (as of 2026-04-28); Watson inherited Seneca's node types (Reflection, Value, Habit, LifeEvent, Intention) with a warmer, less goal-oriented framing. David replaces Bowie; David inherited Bowie's node types (Music, Film, Artwork, Playlist, Artist, Style) and added Fashion.
|
||||
|
||||
## Cross-Team Reads
|
||||
|
||||
- **Work team:** Skills, Projects, Clients (for context on professional life)
|
||||
- **Engineering:** Infrastructure status, Prototypes (for automation ideas)
|
||||
- **Universal nodes:** Person, Location, Event, Topic, Goal (shared by all)
|
||||
- **Work team:** Skill, Certification, Project, Client (context on professional life)
|
||||
- **Engineering team:** Infrastructure (services Robert depends on), Prototype (automation ideas)
|
||||
- **Universal nodes:** Person, Location, Event, Topic, Goal (shared by all; carry `domain` property)
|
||||
|
||||
## Full Schema Reference
|
||||
|
||||
|
||||
118
docs/tools/nike.md
Normal file
118
docs/tools/nike.md
Normal file
@@ -0,0 +1,118 @@
|
||||
# Nike
|
||||
|
||||
> Live football (soccer) data — teams, players, fixtures, results, standings.
|
||||
|
||||
- **MCP server name:** `nike`
|
||||
- **Prompt snippet:** [prompts/tools/nike.md](../../prompts/tools/nike.md)
|
||||
|
||||
## What It Is
|
||||
|
||||
Nike is the live football data source — backed by [TheSportsDB](https://www.thesportsdb.com/). All tools are **read-only**: team profiles, rosters, player info, fixtures, results, standings, match detail, live scores. Transport is HTTP Streamable at `/mcp/`.
|
||||
|
||||
Named for the Greek goddess of victory, fitting for a tool whose job is to track who's winning.
|
||||
|
||||
Nike sits next to Cristiano's Neo4j domain rather than overlapping with it. Nike provides the **canonical live data** — current standings, who's playing tomorrow, who scored on what date. Cristiano's Neo4j `Match`, `Team`, `Player` nodes hold the **interpretation** — what Robert thought of a match, which players he's following, tactical observations. The two stores serve different purposes.
|
||||
|
||||
## MCP Tools
|
||||
|
||||
All tools are read-only. The set below reflects what's currently exposed.
|
||||
|
||||
### Teams and rosters
|
||||
|
||||
| Tool | Purpose |
|
||||
|---|---|
|
||||
| `get_team_info` | Team profile — stadium, capacity, location, founded year, colors, short description |
|
||||
| `get_roster` | Current squad grouped by position (Goalkeepers → Defenders → Midfielders → Attackers) |
|
||||
|
||||
### Players
|
||||
|
||||
| Tool | Purpose |
|
||||
|---|---|
|
||||
| `get_player_info` | Player profile — position, nationality, DOB, current team, status; with premium key adds height, weight, squad number, biography |
|
||||
|
||||
### Fixtures and results
|
||||
|
||||
| Tool | Purpose |
|
||||
|---|---|
|
||||
| `get_fixtures` | Recent results and upcoming matches for a team (filter: `all`, `upcoming`, or `past`) |
|
||||
| `get_match_result` | Result of a match for a team on a specific date — score, venue, referee, attendance, status |
|
||||
| `get_match_detail` | Full match detail — statistics, lineups, substitutes, minute-by-minute timeline (goals, cards, subs). **Premium required.** |
|
||||
|
||||
### Standings and live scores
|
||||
|
||||
| Tool | Purpose |
|
||||
|---|---|
|
||||
| `get_standings` | League table — points, goal difference, current form. League aliases supported (see below). |
|
||||
| `get_livescores` | Live scores worldwide, grouped by league. **Premium required.** |
|
||||
|
||||
### Prompts
|
||||
|
||||
| Prompt | Purpose |
|
||||
|---|---|
|
||||
| `football_analyst` | Primes the assistant with football analyst context — platform description, followed teams, tool summary. Use at session start to skip manual setup. |
|
||||
|
||||
## League Aliases
|
||||
|
||||
`get_standings` accepts league aliases — useful when the underlying name is verbose.
|
||||
|
||||
| Alias | League |
|
||||
|---|---|
|
||||
| `MLS`, `Major League Soccer`, `American Major League Soccer` | MLS (ID 4346) |
|
||||
| `EPL`, `Premier League`, `English Premier League` | Premier League (ID 4328) |
|
||||
|
||||
For other leagues, pass the full name and Nike will attempt to resolve it automatically.
|
||||
|
||||
## Season Format
|
||||
|
||||
Season format varies by league:
|
||||
- **MLS:** single year — `"2026"`
|
||||
- **European leagues (Premier League, etc.):** hyphenated season — `"2025-2026"`
|
||||
|
||||
Get this wrong and the standings call returns nothing useful.
|
||||
|
||||
## Premium vs. Free Tier
|
||||
|
||||
Nike uses a TheSportsDB API key set via the `SPORTSDB_KEY` environment variable. The free key is `3`. Some tools require a premium key.
|
||||
|
||||
| Tool | Free tier | Premium required |
|
||||
|---|---|---|
|
||||
| `get_team_info` | ✓ | |
|
||||
| `get_roster` | Cached data only | Live V2 squad |
|
||||
| `get_player_info` | Basic profile | Height, weight, number, bio |
|
||||
| `get_fixtures` | ✓ | |
|
||||
| `get_standings` | ✓ | |
|
||||
| `get_match_result` | ✓ | |
|
||||
| `get_match_detail` | — | ✓ (required) |
|
||||
| `get_livescores` | — | ✓ (required) |
|
||||
|
||||
When a premium-required tool is called on a free key, it returns an error message rather than silently degrading.
|
||||
|
||||
## Who Uses Nike
|
||||
|
||||
- **Cristiano** — exclusive. Football is Cristiano's domain; Nike is his live-data source.
|
||||
|
||||
Other agents reference football work through Cristiano (via the messaging system) rather than calling Nike directly.
|
||||
|
||||
## What It's Good For
|
||||
|
||||
- Looking up the actual current standings before talking about a league
|
||||
- Pulling fixtures for a team to know what's coming up
|
||||
- Confirming a match result rather than relying on training data (which may be stale)
|
||||
- Walking through a specific match in detail — lineups, timeline, statistics (premium)
|
||||
- Live scores during active match windows (premium)
|
||||
|
||||
## What It's Not Good For
|
||||
|
||||
- Storage — Nike is read-only; what Robert thought of a match goes in Cristiano's Neo4j `Match` node, not back into Nike
|
||||
- Cross-team or cross-domain reads — Nike is single-purpose for football
|
||||
- Tactical analysis — Nike returns the data; Cristiano interprets it
|
||||
- Anything beyond football
|
||||
|
||||
## Known Gotchas
|
||||
|
||||
- **Get the season format right.** MLS uses `"2026"`; European leagues use `"2025-2026"`. Wrong format → empty results.
|
||||
- **Free tier limits.** `get_match_detail` and `get_livescores` return errors on the free key. Don't try to work around it — surface the limitation to Robert.
|
||||
- **`get_match_detail` requires an event ID.** Workflow: `get_fixtures` first to find the event ID, then `get_match_detail` with that ID.
|
||||
- **TheSportsDB data quality varies by league.** Top European leagues are well-covered; smaller leagues may have gaps or stale data. If something looks wrong, sanity-check against another source via Argos.
|
||||
- **Rosters are cached on the free tier.** If a transfer just happened, the free-tier roster may not reflect it yet. Premium has the live V2 squad data.
|
||||
- **Default `team_name` is `"Toronto FC"`.** Several tools default to TFC if no team name is given. Be explicit when asking about other teams.
|
||||
117
docs/tools/orpheus.md
Normal file
117
docs/tools/orpheus.md
Normal file
@@ -0,0 +1,117 @@
|
||||
# Orpheus
|
||||
|
||||
> Robert's Kawai piano — play music, manage the song library, review practice sessions.
|
||||
|
||||
- **MCP server name:** `orpheus`
|
||||
- **Prompt snippet:** [prompts/tools/orpheus.md](../../prompts/tools/orpheus.md)
|
||||
|
||||
## What It Is
|
||||
|
||||
Orpheus is the MCP for Robert's Kawai piano. It turns the piano into something an assistant can actually *play* — converting ABC notation to MIDI, queuing pieces for playback, managing a song library, and capturing practice sessions for review. Named for the Greek musician whose lyre could move stones; the Kawai is the modern equivalent.
|
||||
|
||||
Music isn't something David just talks about — it's something he can bring to life. Orpheus is the difference between recommending a piece and demonstrating it.
|
||||
|
||||
## MCP Tools
|
||||
|
||||
### Playback
|
||||
|
||||
| Tool | Purpose |
|
||||
|---|---|
|
||||
| `play_abc` | Play music from ABC notation. Converts to MIDI and queues for playback. **The easiest way to play a piece.** Args: `title`, `abc`, optional `tempo_bpm`. |
|
||||
| `play_midi` | Queue raw MIDI events. Each event is a dict with `type`, `time`, `note`, `velocity`, `channel`, `control`, `value`. Args: `title`, `midi_data`, `tempo_bpm` (default 72). |
|
||||
| `play_song` | Queue a library song by ID. Args: `song_id`. |
|
||||
| `stop_playback` | Stop whatever's currently playing. |
|
||||
| `playback_status` | Returns `{is_playing, is_paused, title, playback_id, progress}`. |
|
||||
|
||||
### Library
|
||||
|
||||
| Tool | Purpose |
|
||||
|---|---|
|
||||
| `export_midi` | Convert ABC to MIDI and save to the song library for future replay via `play_song`. Args: `title`, `abc`, optional `tempo_bpm`, `save_to_library=True`. |
|
||||
| `list_songs` | List all songs in the library — id, title, composer, genre, duration. |
|
||||
|
||||
### Sessions (review practice history)
|
||||
|
||||
| Tool | Purpose |
|
||||
|---|---|
|
||||
| `list_sessions` | List recent practice sessions — id, date, duration, note count. Args: `limit` (default 20). |
|
||||
| `get_session` | Full session details including all raw MIDI events. Args: `session_id`. |
|
||||
|
||||
### System
|
||||
|
||||
| Tool | Purpose |
|
||||
|---|---|
|
||||
| `get_system_info` | Returns hostname, IP, instrument, uptime, DB path, version. |
|
||||
|
||||
## Canonical Workflows
|
||||
|
||||
### Play a piece from ABC notation
|
||||
|
||||
```
|
||||
play_abc(
|
||||
title="Gymnopédie No. 1",
|
||||
abc="X:1\nT:Gymnopédie No. 1\nC:Erik Satie\nM:3/4\nL:1/4\nK:Dmaj\n...",
|
||||
tempo_bpm=60
|
||||
)
|
||||
```
|
||||
|
||||
The simplest path — composer + piece + ABC notation → live piano playback.
|
||||
|
||||
### Save a piece to the library for later
|
||||
|
||||
```
|
||||
export_midi(
|
||||
title="Gymnopédie No. 1",
|
||||
abc="...",
|
||||
tempo_bpm=60,
|
||||
save_to_library=True
|
||||
)
|
||||
# returns a song_id
|
||||
|
||||
# Later:
|
||||
play_song(song_id="...")
|
||||
```
|
||||
|
||||
Useful when David has converged on the right interpretation of a piece and wants it persistent rather than re-composed each time.
|
||||
|
||||
### Review a practice session
|
||||
|
||||
```
|
||||
list_sessions(limit=5)
|
||||
# returns recent sessions with date and note counts
|
||||
|
||||
get_session(session_id="...")
|
||||
# returns full MIDI event detail — every note played, when, how hard
|
||||
```
|
||||
|
||||
This is the diagnostic side — when Robert practiced something and wants to see what he actually played vs. what he intended.
|
||||
|
||||
## Who Uses Orpheus
|
||||
|
||||
- **David** — primary user. Music is David's domain, so the piano is most often his to play. Orpheus is how David can demonstrate rather than just describe.
|
||||
|
||||
Other agents may use Orpheus too — it just happens that David is the first one with it. If another agent's work has a legitimate reason to play something (a piece tied to a memory, a song for a mood), Orpheus is available.
|
||||
|
||||
## What It's Good For
|
||||
|
||||
- Demonstrating a piece David is recommending ("here, let me play it for you")
|
||||
- Building a library of pieces Robert is working on or wants to revisit
|
||||
- Reviewing practice sessions for analysis — what was played, tempo discipline, note accuracy
|
||||
- Setting a mood — a piece in the background while doing something else
|
||||
- Exploring music interactively — try a piece, adjust tempo, try variations
|
||||
|
||||
## What It's Not Good For
|
||||
|
||||
- Music *recommendations* alone — those don't need Orpheus; conversation is enough. Orpheus is for when David wants to *play* the recommendation, not just describe it.
|
||||
- Recording — Orpheus plays back; the piano captures sessions separately
|
||||
- Genre or artist analysis — that's interpretation work belonging in David's Neo4j `Music`, `Artist`, `Playlist` nodes
|
||||
- Songs not in ABC notation or MIDI form. To play something obscure, you need the notation first.
|
||||
|
||||
## Known Gotchas
|
||||
|
||||
- **ABC notation is the path of least resistance.** Most pieces in the public domain (classical, traditional folk) have ABC available. For other pieces, you may need to transcribe or find a MIDI source first.
|
||||
- **Tempo matters for piece identity.** Satie at 60 bpm and Satie at 90 bpm are different musical experiences. Pick deliberately and document the choice in the song-library entry if saving.
|
||||
- **Playback is queued, not instant.** `playback_status` tells you what's actually playing. Don't assume a successful queue call means the piece is currently audible.
|
||||
- **`stop_playback` is the kill switch.** Use it when something is wrong (wrong piece, wrong tempo, distraction) rather than waiting for it to finish.
|
||||
- **`get_session` returns all raw MIDI events.** For long sessions this is a lot of data. If you just want overview metrics (date, duration, count), `list_sessions` is enough.
|
||||
- **The piano is a physical object in Robert's space.** Playing something loud at 11pm has real consequences. Confirm before queueing a piece if context suggests it might be disruptive.
|
||||
118
docs/tools/periplus.md
Normal file
118
docs/tools/periplus.md
Normal file
@@ -0,0 +1,118 @@
|
||||
# Periplus
|
||||
|
||||
> Maps, bookmarks, collections, and directions — Robert's canonical store for geographic places.
|
||||
|
||||
- **MCP server name:** `periplus`
|
||||
- **Prompt snippet:** [prompts/tools/periplus.md](../../prompts/tools/periplus.md)
|
||||
|
||||
## What It Is
|
||||
|
||||
Periplus is the canonical store for **places** in Robert's life: addresses and points of interest, their actual coordinates, organized into collections (often one collection per trip or per category), with multi-hop directions between them. Backed by OpenStreetMap's Nominatim for place search and OSRM for routing.
|
||||
|
||||
Named for the ancient Greek *periplus* — the sailing manual that listed coastal landmarks in order. Same idea: the catalogue of places that matter, with the routes between them.
|
||||
|
||||
Periplus sits in the same relation to Neo4j that Kairos does for calendar and contacts: Periplus holds the **canonical geographic record** (the lat/lng, the bookmark, the collection); Neo4j holds the **interpretation and cross-domain linking** (what Robert did at the place, what restaurant Bourdain recommended, what species Cousteau observed there).
|
||||
|
||||
## ⚠️ Critical Discipline: Never Estimate Coordinates
|
||||
|
||||
> Models reliably misplace estimated coordinates — bookmarks for restaurants end up in the ocean.
|
||||
|
||||
When you need a place's coordinates, **call `search_places` to look them up.** Do not estimate or guess from memory. The typical workflow is:
|
||||
|
||||
1. `search_places("place name")` to resolve the place via Nominatim
|
||||
2. Use the returned `lat` and `lng` to `create_bookmark` or other coordinate-consuming operations
|
||||
|
||||
This rule has no exceptions. Even for "obvious" landmarks where you think you know the coordinates, look them up.
|
||||
|
||||
## MCP Tools
|
||||
|
||||
### Search
|
||||
|
||||
| Tool | Purpose |
|
||||
|---|---|
|
||||
| `search_places` | Search OSM/Nominatim for addresses and places. Returns lat/lng + metadata. **The first step for any place not already bookmarked.** |
|
||||
| `search_bookmarks` | Search saved bookmarks by name / tag / source / collection. Returns existing bookmarks before you re-create them. |
|
||||
| `get_bookmark` | Fetch a single bookmark by UUID. |
|
||||
|
||||
### Bookmarks (creation)
|
||||
|
||||
| Tool | Purpose |
|
||||
|---|---|
|
||||
| `create_bookmark` | Create a bookmark from coordinates (name, lat, lng, optional description/address/source/tags). |
|
||||
| `import_bookmarks` | Import a KML/KMZ/GPX/GeoJSON file from the server filesystem. |
|
||||
|
||||
### Geographic queries
|
||||
|
||||
| Tool | Purpose |
|
||||
|---|---|
|
||||
| `find_bookmarks_nearby` | Find bookmarks near a point, sorted by distance. Includes `distance_m`. |
|
||||
| `find_bookmarks_in_area` | Find bookmarks within a bounding box (sw_lat/lng → ne_lat/lng). |
|
||||
| `get_directions` | Multi-hop directions between waypoints (semicolon-separated `lat,lng` pairs). Returns distance, duration, GeoJSON geometry, step-by-step instructions. Modes: `car`, `bike`, `foot`. |
|
||||
|
||||
### Collections
|
||||
|
||||
| Tool | Purpose |
|
||||
|---|---|
|
||||
| `list_collections` | List all collections with bookmark and track counts. |
|
||||
| `get_collection` | Get a collection with its full bookmark list. |
|
||||
| `create_collection` | Create a new collection (name, optional description and tags). |
|
||||
| `add_bookmarks_to_collection` | Add bookmarks to a collection (comma-separated bookmark UUIDs). |
|
||||
| `remove_bookmark_from_collection` | Remove a bookmark from a collection (does not delete the bookmark). |
|
||||
|
||||
## Canonical Workflow — Find and Save a Place
|
||||
|
||||
```
|
||||
1. search_places("Rideau Canal Ottawa")
|
||||
→ [{lat: 45.4274, lng: -75.6919, name: "Rideau Canal", ...}]
|
||||
|
||||
2. create_collection("Ottawa Landmarks")
|
||||
→ {id: "coll-uuid", ...}
|
||||
|
||||
3. create_bookmark(
|
||||
name="Rideau Canal",
|
||||
lat=45.4274, lng=-75.6919,
|
||||
address="Rideau Canal, Ottawa, Ontario",
|
||||
source="nominatim"
|
||||
)
|
||||
→ {id: "bm-uuid", ...}
|
||||
|
||||
4. add_bookmarks_to_collection(
|
||||
collection_id="coll-uuid",
|
||||
bookmark_ids="bm-uuid"
|
||||
)
|
||||
```
|
||||
|
||||
Steps 1 and 3 enforce the no-estimate rule: the coordinates passed to `create_bookmark` came from `search_places`, not from the model's head.
|
||||
|
||||
## Who Uses Periplus
|
||||
|
||||
- **Nate** — heavy, primary. One collection per trip, with the destinations, lodging, day-trip points of interest. Used alongside `get_directions` for itinerary logistics.
|
||||
- **Bourdain** — restaurants, markets, shops. Collections organized by city or by type. Bourdain's Neo4j `Restaurant` and `Ingredient` nodes cross-link to Periplus bookmarks.
|
||||
- **David** — stores, theatres, studios, apothecaries — the places where culture and good taste live. Collections by city or by type.
|
||||
- **Cousteau** — site-of-interest bookmarks for nature observations (dive sites, garden suppliers, parks).
|
||||
- **Other agents** read Periplus when their work involves a place; the four above do the writing.
|
||||
|
||||
## What It's Good For
|
||||
|
||||
- Resolving "where is X" with real coordinates
|
||||
- Building a per-trip collection of places worth knowing about
|
||||
- Multi-hop routing for actual itinerary planning
|
||||
- Finding bookmarks near a point or in an area ("what's near the hotel")
|
||||
- Importing GPS tracks, KML waypoints, or other geo data
|
||||
|
||||
## What It's Not Good For
|
||||
|
||||
- Estimating coordinates without lookup. (Documented above; restating because it's the single most important rule.)
|
||||
- Cross-domain interpretation — Periplus holds the place; what Robert did or thought about the place belongs in Neo4j (Activity, Restaurant, Observation, etc.)
|
||||
- Real-time location tracking — Periplus is for places, not for "where is Robert right now"
|
||||
- Indoor navigation, building floor plans — Periplus is map-scale
|
||||
|
||||
## Known Gotchas
|
||||
|
||||
- **Never estimate coordinates.** Bears repeating because the failure mode is silent: a bookmark created with estimated lat/lng looks fine until someone tries to navigate to it and ends up at the wrong location. Always `search_places` first.
|
||||
- **Nominatim's `display_name` is verbose.** Use it for verification but pass cleaner names to `create_bookmark` (`name` field).
|
||||
- **`tags` is a JSON string, not a dict.** When passing tags to `create_bookmark` or `create_collection`, serialize the dict to a JSON string: `'{"category": "restaurant"}'`, not `{"category": "restaurant"}` directly.
|
||||
- **`waypoints` format is specific.** `get_directions` expects semicolon-separated `lat,lng` pairs: `"45.42,-75.70;45.50,-73.57"`. Get this wrong and routing fails silently.
|
||||
- **Search before create.** Before `create_bookmark` for a known place, run `search_bookmarks` to avoid duplicates. Bookmarks aren't deduplicated by coordinates automatically.
|
||||
- **Collections are organizational, not exclusive.** A bookmark can belong to multiple collections. Adding to one doesn't remove from another.
|
||||
- **`import_bookmarks` reads server filesystem paths.** The path must be absolute and accessible to the Periplus server, not the client.
|
||||
Reference in New Issue
Block a user