Schema update

This commit is contained in:
2026-05-20 07:12:48 -04:00
parent 71de22d3de
commit 812473ad97
5 changed files with 441 additions and 140 deletions

View File

@@ -33,16 +33,34 @@ Key hosts: ariel (Neo4j), miranda (MCP servers), oberon (Docker/SearXNG), portia
## Inter-Assistant Graph Messaging
Other assistants may leave you messages as `Note` nodes in the Neo4j knowledge graph.
Other assistants may leave you messages as `Note` nodes in the Neo4j knowledge
graph. Messages are scoped by tag conventions: `from:<sender>`, `to:<recipient>`
(or `to:all` for broadcast), and `inbox` for unread state. The recipient marks
the message read by replacing the `inbox` tag with `read`.
### Check Your Inbox (do this at the start of every conversation)
This protocol applies to every assistant on every team — Personal (Iolaus),
Work (Mentor), Engineering (Kottos). The shape is identical; only the
`from:`/`to:` tag values change per agent.
**Step 1 — Fetch unread messages:**
### When to read your inbox
Read on demand only. Do **not** check at the start of every conversation —
that wastes tokens and round-trips. Read when:
- The user explicitly asks you to check.
- A scheduler (Daedalus) invokes the inbox-check prompt against you. See
[mentor/docs/inbox_check_prompt.md](../../mentor/docs/inbox_check_prompt.md)
for the canonical scheduler prompt.
- You're picking up cross-domain work and want context from other agents.
### Reading your inbox
Call `read_neo4j_cypher` (substitute your own agent name for `<self>`):
```cypher
MATCH (n:Note)
WHERE n.type = 'assistant_message'
AND ANY(tag IN n.tags WHERE tag IN ['to:YOUR_NAME', 'to:all'])
AND ANY(tag IN n.tags WHERE tag IN ['to:<self>', 'to:all'])
AND ANY(tag IN n.tags WHERE tag = 'inbox')
RETURN n.id AS id, n.title AS title, n.content AS content,
n.action_required AS action_required, n.tags AS tags,
@@ -50,43 +68,82 @@ RETURN n.id AS id, n.title AS title, n.content AS content,
ORDER BY n.created_at DESC
```
**Step 2 — If messages were returned, immediately mark them all read with one write query** (substituting all IDs):
If messages were returned, mark them all read with a single write
(substituting the actual IDs into `$ids`):
```cypher
MATCH (n:Note)
WHERE n.id IN ['id1', 'id2']
WHERE n.id IN $ids
SET n.tags = [tag IN n.tags WHERE tag <> 'inbox'] + ['read'],
n.updated_at = datetime()
```
If no messages were returned, skip the write query entirely.
If no messages were returned, skip the write entirely.
**Once you have run the inbox read query — whether it returned results or not — do not run it again for the rest of this conversation.**
Acknowledge messages naturally in conversation. If `action_required: true`,
prioritize addressing the request.
**Step 3** — Acknowledge messages naturally in conversation. If `action_required: true`, prioritize addressing the request.
### Sending messages to other assistants
### Sending Messages to Other Assistants
Call `write_neo4j_cypher` with this exact parameterized query (no string
interpolation in the query body — all values come from `params`):
```cypher
MERGE (n:Note {id: 'note_{date}_YOUR_NAME_{recipient}_{subject}'})
MERGE (n:Note {id: $id})
ON CREATE SET n.created_at = datetime()
SET n.title = 'Brief subject line',
SET n.title = $title,
n.date = date(),
n.type = 'assistant_message',
n.content = 'Your message here',
n.action_required = false,
n.tags = ['from:YOUR_NAME', 'to:{recipient}', 'inbox'],
n.content = $content,
n.action_required = $action_required,
n.tags = ['from:<self>', $to_tag, 'inbox'],
n.updated_at = datetime()
```
`<self>` is your own agent name (a constant in the query body — `'from:harper'`,
`'from:bourdain'`, etc.). Everything else flows through `params`.
Example `params` (Harper sending Scotty a handoff):
```json
{
"id": "note_2026-05-17_harper_scotty_prod_hardening",
"title": "Prototype ready for production hardening",
"content": "The slack-neo4j bridge is stable. Need your eyes on TLS, systemd, secrets.",
"action_required": true,
"to_tag": "to:scotty"
}
```
Conventions:
- **id** — `note_<YYYY-MM-DD>_<sender>_<recipient>_<short_snake_slug>`. Check
the Time tool for today's date.
- **to_tag** — `to:<recipient>` for a directed message, `to:all` to broadcast.
- **action_required** — `true` when a response is expected, `false` for FYI.
- **Never** use `{placeholder}` syntax in the query body — local models
(Qwen3.5-35B) mishandle it. Pass literal values through `params`.
### Why tag-based `from:` / `to:` (not a `from` property)
The protocol uses tags for both directions (`'from:alan'` AND `'to:jeffrey'`
both live in `n.tags`). This is simpler than splitting into a `from` property
plus a `to:` tag — the local model only has to emit one consistent list,
inbox queries filter on the same array, and there's no second source of truth
to keep in sync.
### Assistant Directory
| Team | Assistants |
|------|-----------|
| **Personal** | nate, hypatia, marcus, seneca, bourdain, bowie, cousteau, garth, cristiano |
| **Work** | alan, ann, jeffrey, jarvis |
| **Personal** | shawn, nate, hypatia, marcus, watson, bourdain, david, cousteau, garth, cristiano |
| **Work** | alan, ann, jeffrey, jarvis, aws_sa |
| **Engineering** | scotty, harper |
Watson replaces Seneca (as of 2026-04-28); David replaces Bowie; Shawn is the
personal general assistant (calendar/contacts/email). AWS SA is the work-team
cloud-architecture specialist.
## Graph Error Handling
If a graph query fails, continue the conversation. Mention it briefly and move on. Never expose raw Cypher errors to the user.