Schema update
This commit is contained in:
@@ -3,8 +3,8 @@
|
|||||||
> Canonical schema for the single shared graph database used by all AI assistants
|
> Canonical schema for the single shared graph database used by all AI assistants
|
||||||
|
|
||||||
---
|
---
|
||||||
version: 2.0.0
|
version: 2.3.0
|
||||||
last_updated: 2025-02-16
|
last_updated: 2026-05-17
|
||||||
replaces:
|
replaces:
|
||||||
- prompts/personal/neo4j-schema.md (v1.0.0)
|
- prompts/personal/neo4j-schema.md (v1.0.0)
|
||||||
- prompts/work/neo4j-schema.md (v1.0.0)
|
- prompts/work/neo4j-schema.md (v1.0.0)
|
||||||
@@ -27,19 +27,21 @@ This document defines the canonical schema for **one shared Neo4j graph database
|
|||||||
|
|
||||||
| Team | Assistant | Domain | Graph Access |
|
| Team | Assistant | Domain | Graph Access |
|
||||||
|------|-----------|--------|--------------|
|
|------|-----------|--------|--------------|
|
||||||
|
| **Personal** | Shawn | Personal General Assistant (calendar, contacts, comms) | Read all, write `domain='personal'` Contact/Event/Task + own Communication |
|
||||||
| **Personal** | Nate | Travel & Adventure | Read all, write own domain |
|
| **Personal** | Nate | Travel & Adventure | Read all, write own domain |
|
||||||
| **Personal** | Hypatia | Learning & Reading | Read all, write own domain |
|
| **Personal** | Hypatia | Learning & Reading | Read all, write own domain |
|
||||||
| **Personal** | Marcus | Fitness & Training | Read all, write own domain |
|
| **Personal** | Marcus | Fitness & Training | Read all, write own domain |
|
||||||
| **Personal** | Seneca | Reflection & Wellness | Read all, write own domain |
|
| **Personal** | Watson | Relationship Memory & Emotional Safety | Read all, write own domain |
|
||||||
| **Personal** | Bourdain | Food & Cooking | Read all, write own domain |
|
| **Personal** | Bourdain | Food & Cooking | Read all, write own domain |
|
||||||
| **Personal** | Bowie | Arts & Culture | Read all, write own domain |
|
| **Personal** | David | Arts & Culture | Read all, write own domain |
|
||||||
| **Personal** | Cousteau | Nature & Living Things | Read all, write own domain |
|
| **Personal** | Cousteau | Nature & Living Things | Read all, write own domain |
|
||||||
| **Personal** | Garth | Personal Finance | Read all, write own domain |
|
| **Personal** | Garth | Personal Finance | Read all, write own domain |
|
||||||
| **Personal** | Cristiano | Football | Read all, write own domain |
|
| **Personal** | Cristiano | Football | Read all, write own domain |
|
||||||
| **Work** | Alan | Strategy & Business Model | Read all, write all work nodes |
|
| **Work** | Alan | Strategy & Business Model | Read all, write `domain='work'` work nodes |
|
||||||
| **Work** | Ann | Marketing & Visibility | Read all, write all work nodes |
|
| **Work** | Ann | Marketing & Visibility | Read all, write `domain='work'` work nodes |
|
||||||
| **Work** | Jeffrey | Proposals & Sales | Read all, write all work nodes |
|
| **Work** | Jeffrey | Proposals & Sales | Read all, write `domain='work'` work nodes |
|
||||||
| **Work** | Jarvis | Daily Execution | Read all, write all work nodes |
|
| **Work** | Jarvis | Daily Execution | Read all, write `domain='work'` Contact/Event/Task + work nodes |
|
||||||
|
| **Work** | AWS SA | AWS Architecture Design | Read all, generally writes only Note (messages); no domain ownership |
|
||||||
| **Engineering** | Scotty | Infrastructure & Ops | Read all, write own domain |
|
| **Engineering** | Scotty | Infrastructure & Ops | Read all, write own domain |
|
||||||
| **Engineering** | Harper | Prototyping & Hacking | Read all, write own domain |
|
| **Engineering** | Harper | Prototyping & Hacking | Read all, write own domain |
|
||||||
|
|
||||||
@@ -93,7 +95,12 @@ Physical places — shared across travel, training, dining, nature, work events.
|
|||||||
```
|
```
|
||||||
|
|
||||||
### Event
|
### Event
|
||||||
Significant occurrences spanning any domain.
|
Significant occurrences spanning any domain. Personal events (birthdays,
|
||||||
|
dinners, family gatherings) are written by Shawn with `domain='personal'`;
|
||||||
|
work events (conferences, client meetings, webinars) are written by
|
||||||
|
Jarvis/Jeffrey/Ann/Alan with `domain='work'`. Cross-domain events that
|
||||||
|
genuinely span both (e.g., a client takes Robert to a baseball game) use
|
||||||
|
`domain='both'`.
|
||||||
|
|
||||||
```cypher
|
```cypher
|
||||||
(:Event {
|
(:Event {
|
||||||
@@ -102,7 +109,7 @@ Significant occurrences spanning any domain.
|
|||||||
date: Date!,
|
date: Date!,
|
||||||
end_date: Date,
|
end_date: Date,
|
||||||
type: String, // celebration, milestone, conference, webinar, workshop, competition
|
type: String, // celebration, milestone, conference, webinar, workshop, competition
|
||||||
domain: String, // personal, work, both
|
domain: String!, // personal, work, both — determines owning team
|
||||||
description: String,
|
description: String,
|
||||||
location: String,
|
location: String,
|
||||||
role: String, // attendee, speaker, panelist, host (for work events)
|
role: String, // attendee, speaker, panelist, host (for work events)
|
||||||
@@ -160,6 +167,46 @@ Objectives and aspirations — life, fitness, career, financial.
|
|||||||
|
|
||||||
## Personal Team — Domain Node Types
|
## Personal Team — Domain Node Types
|
||||||
|
|
||||||
|
### Shawn's Domain (Personal General Assistant)
|
||||||
|
|
||||||
|
Shawn is the personal calendar/contacts/communications assistant. He owns the
|
||||||
|
Personal scope of three Universal node types (`Contact`, `Event`, `Task` —
|
||||||
|
all with `domain='personal'`) and one dedicated node type (`Communication`).
|
||||||
|
He is the Personal counterpart to the Work team's Jarvis. The divide is
|
||||||
|
strict: Shawn never writes `domain='work'` rows; Jarvis never writes
|
||||||
|
`domain='personal'` rows.
|
||||||
|
|
||||||
|
Tooling: Shawn uses **Kairos** (calendar/tasks/personal address book); work
|
||||||
|
agents use **Athena** (CRM). Kairos is shared read-only with work agents for
|
||||||
|
calendar deconfliction.
|
||||||
|
|
||||||
|
#### Communication
|
||||||
|
*Personal interaction history with contacts — calls, texts, emails, in-person
|
||||||
|
meet-ups, social-media exchanges. Shawn owns this exclusively; there is no
|
||||||
|
Work equivalent (the work team logs interactions in Meeting/Note nodes
|
||||||
|
linked to Contact/Opportunity).*
|
||||||
|
|
||||||
|
```cypher
|
||||||
|
(:Communication {
|
||||||
|
id: String!, // e.g., "comm_2026-05-17_mike_chen_coffee"
|
||||||
|
type: String!, // call, text, email, in_person, social
|
||||||
|
contact_id: String!, // foreign key to Contact.id (domain='personal')
|
||||||
|
date: Date!,
|
||||||
|
subject: String,
|
||||||
|
summary: String,
|
||||||
|
follow_up: String, // freeform: "send podcast link", "schedule next coffee"
|
||||||
|
sentiment: String, // positive, neutral, strained, distant
|
||||||
|
created_at: DateTime,
|
||||||
|
updated_at: DateTime
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
Relationships:
|
||||||
|
```cypher
|
||||||
|
(Communication)-[:WITH]->(Contact {domain: 'personal'})
|
||||||
|
(Person {id:"user_main"})-[:HAD]->(Communication)
|
||||||
|
```
|
||||||
|
|
||||||
### Nate's Domain (Travel & Adventure)
|
### Nate's Domain (Travel & Adventure)
|
||||||
|
|
||||||
#### Trip
|
#### Trip
|
||||||
@@ -1061,10 +1108,15 @@ Objectives and aspirations — life, fitness, career, financial.
|
|||||||
```
|
```
|
||||||
|
|
||||||
#### Contact
|
#### Contact
|
||||||
|
*Universal — used by both Personal (Shawn) and Work (Jeffrey/all-work) teams.
|
||||||
|
The `domain` field disambiguates ownership.*
|
||||||
|
|
||||||
```cypher
|
```cypher
|
||||||
(:Contact {
|
(:Contact {
|
||||||
id: String!, // e.g., "contact_john_smith_acme"
|
id: String!, // e.g., "contact_john_smith_acme" (work),
|
||||||
|
// "contact_mike_chen" (personal)
|
||||||
name: String!,
|
name: String!,
|
||||||
|
domain: String!, // personal, work — determines owning team
|
||||||
title: String,
|
title: String,
|
||||||
company: String,
|
company: String,
|
||||||
email: String,
|
email: String,
|
||||||
@@ -1073,12 +1125,17 @@ Objectives and aspirations — life, fitness, career, financial.
|
|||||||
relationship_strength: String, // new, developing, strong, champion
|
relationship_strength: String, // new, developing, strong, champion
|
||||||
last_contact: Date,
|
last_contact: Date,
|
||||||
notes: String,
|
notes: String,
|
||||||
tags: [String], // decision_maker, influencer, technical, executive
|
tags: [String], // decision_maker, influencer, technical, executive (work)
|
||||||
|
// family, friend, neighbour (personal)
|
||||||
created_at: DateTime,
|
created_at: DateTime,
|
||||||
updated_at: DateTime
|
updated_at: DateTime
|
||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**Ownership rule (strict):** Shawn writes `domain='personal'` rows only;
|
||||||
|
Jarvis/Jeffrey/Alan/Ann write `domain='work'` rows only. Personal and Work
|
||||||
|
contacts never share an id namespace.
|
||||||
|
|
||||||
#### Opportunity
|
#### Opportunity
|
||||||
```cypher
|
```cypher
|
||||||
(:Opportunity {
|
(:Opportunity {
|
||||||
@@ -1311,14 +1368,20 @@ Professional network beyond clients.
|
|||||||
### Daily Operations Nodes
|
### Daily Operations Nodes
|
||||||
|
|
||||||
#### Task
|
#### Task
|
||||||
|
*Universal — Shawn owns Personal tasks; Jarvis owns Work tasks. The `domain`
|
||||||
|
field disambiguates.*
|
||||||
|
|
||||||
```cypher
|
```cypher
|
||||||
(:Task {
|
(:Task {
|
||||||
id: String!, // e.g., "task_2025-01-08_proposal_draft"
|
id: String!, // e.g., "task_2026-05-17_proposal_draft" (work),
|
||||||
|
// "task_2026-05-17_book_dentist" (personal)
|
||||||
title: String!,
|
title: String!,
|
||||||
|
domain: String!, // personal, work
|
||||||
status: String!, // pending, in_progress, completed, deferred, cancelled
|
status: String!, // pending, in_progress, completed, deferred, cancelled
|
||||||
priority: String, // urgent, high, medium, low
|
priority: String, // urgent, high, medium, low
|
||||||
due_date: Date,
|
due_date: Date,
|
||||||
context: String, // client, opportunity, content, admin
|
context: String, // client, opportunity, content, admin (work)
|
||||||
|
// errand, household, social, health (personal)
|
||||||
related_to: String,
|
related_to: String,
|
||||||
description: String,
|
description: String,
|
||||||
completed_date: Date,
|
completed_date: Date,
|
||||||
@@ -1328,6 +1391,10 @@ Professional network beyond clients.
|
|||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**Tooling note:** Kairos is the Personal calendar/task/contact tool (shared
|
||||||
|
read-only with Work agents for deconfliction); Athena is the Work CRM. Work
|
||||||
|
agents may read Personal tasks for scheduling but do not write them.
|
||||||
|
|
||||||
#### Meeting
|
#### Meeting
|
||||||
```cypher
|
```cypher
|
||||||
(:Meeting {
|
(:Meeting {
|
||||||
@@ -1783,82 +1850,83 @@ If queries fail:
|
|||||||
|---|-----------|--------|---------------|-----------------|
|
|---|-----------|--------|---------------|-----------------|
|
||||||
| 1 | Person | Universal | Any | id |
|
| 1 | Person | Universal | Any | id |
|
||||||
| 2 | Location | Universal | Any | id |
|
| 2 | Location | Universal | Any | id |
|
||||||
| 3 | Event | Universal | Any | id |
|
| 3 | Event | Universal | Shawn (personal) / Jarvis (work) | id |
|
||||||
| 4 | Topic | Universal | Hypatia / Ann | id |
|
| 4 | Topic | Universal | Hypatia / Ann | id |
|
||||||
| 5 | Goal | Universal | Seneca | id |
|
| 5 | Goal | Universal | Watson | id |
|
||||||
| 6 | Trip | Personal | Nate | id |
|
| 6 | Contact | Universal | Shawn (personal) / Jeffrey-All (work) | id |
|
||||||
| 7 | Destination | Personal | Nate | id |
|
| 7 | Task | Universal | Shawn (personal) / Jarvis (work) | id |
|
||||||
| 8 | Activity | Personal | Nate | id |
|
| 8 | Communication | Personal | Shawn | id |
|
||||||
| 9 | Book | Personal | Hypatia | id |
|
| 9 | Trip | Personal | Nate | id |
|
||||||
| 10 | Author | Personal | Hypatia | id |
|
| 10 | Destination | Personal | Nate | id |
|
||||||
| 11 | LearningPath | Personal | Hypatia | id |
|
| 11 | Activity | Personal | Nate | id |
|
||||||
| 12 | Concept | Personal | Hypatia | id |
|
| 12 | Book | Personal | Hypatia | id |
|
||||||
| 13 | Quote | Personal | Hypatia | id |
|
| 13 | Author | Personal | Hypatia | id |
|
||||||
| 14 | Training | Personal | Marcus | id |
|
| 14 | LearningPath | Personal | Hypatia | id |
|
||||||
| 15 | Exercise | Personal | Marcus | id |
|
| 15 | Concept | Personal | Hypatia | id |
|
||||||
| 16 | Program | Personal | Marcus | id |
|
| 16 | Quote | Personal | Hypatia | id |
|
||||||
| 17 | PersonalRecord | Personal | Marcus | id |
|
| 17 | Training | Personal | Marcus | id |
|
||||||
| 18 | BodyMetric | Personal | Marcus | id |
|
| 18 | Exercise | Personal | Marcus | id |
|
||||||
| 19 | Reflection | Personal | Watson | id |
|
| 19 | Program | Personal | Marcus | id |
|
||||||
| 20 | Value | Personal | Watson | id |
|
| 20 | PersonalRecord | Personal | Marcus | id |
|
||||||
| 21 | Habit | Personal | Watson | id |
|
| 21 | BodyMetric | Personal | Marcus | id |
|
||||||
| 22 | LifeEvent | Personal | Watson | id |
|
| 22 | Reflection | Personal | Watson | id |
|
||||||
| 23 | Intention | Personal | Watson | id |
|
| 23 | Value | Personal | Watson | id |
|
||||||
| 24 | EmotionalMemory | Personal | Watson | id |
|
| 24 | Habit | Personal | Watson | id |
|
||||||
| 25 | RelationshipTheme | Personal | Watson | id |
|
| 25 | LifeEvent | Personal | Watson | id |
|
||||||
| 26 | DialogueNote | Personal | Watson | id |
|
| 26 | Intention | Personal | Watson | id |
|
||||||
| 27 | DynamicPattern | Personal | Watson | id |
|
| 27 | EmotionalMemory | Personal | Watson | id |
|
||||||
| 28 | Recipe | Personal | Bourdain | id |
|
| 28 | RelationshipTheme | Personal | Watson | id |
|
||||||
| 29 | Restaurant | Personal | Bourdain | id |
|
| 29 | DialogueNote | Personal | Watson | id |
|
||||||
| 30 | Ingredient | Personal | Bourdain | id |
|
| 30 | DynamicPattern | Personal | Watson | id |
|
||||||
| 31 | Meal | Personal | Bourdain | id |
|
| 31 | Recipe | Personal | Bourdain | id |
|
||||||
| 32 | Technique | Personal | Bourdain | id |
|
| 32 | Restaurant | Personal | Bourdain | id |
|
||||||
| 33 | Music | Personal | Bowie | id |
|
| 33 | Ingredient | Personal | Bourdain | id |
|
||||||
| 34 | Film | Personal | Bowie | id |
|
| 34 | Meal | Personal | Bourdain | id |
|
||||||
| 35 | Artwork | Personal | Bowie | id |
|
| 35 | Technique | Personal | Bourdain | id |
|
||||||
| 36 | Playlist | Personal | Bowie | id |
|
| 36 | Music | Personal | David | id |
|
||||||
| 37 | Artist | Personal | Bowie | id |
|
| 37 | Film | Personal | David | id |
|
||||||
| 38 | Style | Personal | Bowie | id |
|
| 38 | Artwork | Personal | David | id |
|
||||||
| 39 | Species | Personal | Cousteau | id |
|
| 39 | Playlist | Personal | David | id |
|
||||||
| 40 | Plant | Personal | Cousteau | id |
|
| 40 | Artist | Personal | David | id |
|
||||||
| 41 | Tank | Personal | Cousteau | id |
|
| 41 | Style | Personal | David | id |
|
||||||
| 42 | Garden | Personal | Cousteau | id |
|
| 42 | Species | Personal | Cousteau | id |
|
||||||
| 43 | Ecosystem | Personal | Cousteau | id |
|
| 43 | Plant | Personal | Cousteau | id |
|
||||||
| 44 | Observation | Personal | Cousteau | id |
|
| 44 | Tank | Personal | Cousteau | id |
|
||||||
| 45 | Account | Personal | Garth | id |
|
| 45 | Garden | Personal | Cousteau | id |
|
||||||
| 46 | Investment | Personal | Garth | id |
|
| 46 | Ecosystem | Personal | Cousteau | id |
|
||||||
| 47 | Asset | Personal | Garth | id |
|
| 47 | Observation | Personal | Cousteau | id |
|
||||||
| 48 | Liability | Personal | Garth | id |
|
| 48 | Account | Personal | Garth | id |
|
||||||
| 49 | Budget | Personal | Garth | id |
|
| 49 | Investment | Personal | Garth | id |
|
||||||
| 50 | FinancialGoal | Personal | Garth | id |
|
| 50 | Asset | Personal | Garth | id |
|
||||||
| 51 | Match | Personal | Cristiano | id |
|
| 51 | Liability | Personal | Garth | id |
|
||||||
| 52 | Team | Personal | Cristiano | id |
|
| 52 | Budget | Personal | Garth | id |
|
||||||
| 53 | League | Personal | Cristiano | id |
|
| 53 | FinancialGoal | Personal | Garth | id |
|
||||||
| 54 | Tournament | Personal | Cristiano | id |
|
| 54 | Match | Personal | Cristiano | id |
|
||||||
| 55 | Player | Personal | Cristiano | id |
|
| 55 | Team | Personal | Cristiano | id |
|
||||||
| 56 | Season | Personal | Cristiano | id |
|
| 56 | League | Personal | Cristiano | id |
|
||||||
| 57 | Client | Work | Alan / All | id |
|
| 57 | Tournament | Personal | Cristiano | id |
|
||||||
| 58 | Contact | Work | Jeffrey / All | id |
|
| 58 | Player | Personal | Cristiano | id |
|
||||||
| 59 | Opportunity | Work | Jeffrey / All | id |
|
| 59 | Season | Personal | Cristiano | id |
|
||||||
| 60 | Proposal | Work | Jeffrey / All | id |
|
| 60 | Client | Work | Alan / All | id |
|
||||||
| 61 | Project | Work | Jarvis / All | id |
|
| 61 | Opportunity | Work | Jeffrey / All | id |
|
||||||
| 62 | Vendor | Work | Alan / All | id |
|
| 62 | Proposal | Work | Jeffrey / All | id |
|
||||||
| 63 | Competitor | Work | Alan / All | id |
|
| 63 | Project | Work | Jarvis / All | id |
|
||||||
| 64 | MarketTrend | Work | Alan / All | id |
|
| 64 | Vendor | Work | Alan / All | id |
|
||||||
| 65 | Technology | Work | Alan / All | id |
|
| 65 | Competitor | Work | Alan / All | id |
|
||||||
| 66 | Content | Work | Ann / All | id |
|
| 66 | MarketTrend | Work | Alan / All | id |
|
||||||
| 67 | Publication | Work | Ann / All | id |
|
| 67 | Technology | Work | Alan / All | id |
|
||||||
| 68 | Skill | Work | Any work | id |
|
| 68 | Content | Work | Ann / All | id |
|
||||||
| 69 | Certification | Work | Any work | id |
|
| 69 | Publication | Work | Ann / All | id |
|
||||||
| 70 | Relationship | Work | Any work | id |
|
| 70 | Skill | Work | Any work | id |
|
||||||
| 71 | Task | Work | Jarvis / All | id |
|
| 71 | Certification | Work | Any work | id |
|
||||||
| 72 | Meeting | Work | Jarvis / All | id |
|
| 72 | Relationship | Work | Any work | id |
|
||||||
| 73 | Note | Work | Jarvis / All | id |
|
| 73 | Meeting | Work | Jarvis / All | id |
|
||||||
| 74 | Decision | Work | Alan / Jarvis | id |
|
| 74 | Note | Work | Jarvis / All | id |
|
||||||
| 75 | Infrastructure | Engineering | Scotty | id |
|
| 75 | Decision | Work | Alan / Jarvis | id |
|
||||||
| 76 | Incident | Engineering | Scotty | id |
|
| 76 | Infrastructure | Engineering | Scotty | id |
|
||||||
| 77 | Prototype | Engineering | Harper | id |
|
| 77 | Incident | Engineering | Scotty | id |
|
||||||
| 78 | Experiment | Engineering | Harper | id |
|
| 78 | Prototype | Engineering | Harper | id |
|
||||||
|
| 79 | Experiment | Engineering | Harper | id |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -1871,3 +1939,4 @@ If queries fail:
|
|||||||
| 2.0.0 | 2025-02-16 | Unified schema: merged personal + work, added Garth (finance), added engineering nodes (Scotty/Harper), added cross-team relationships, promoted Topic/Goal/Event to universal, added domain property for disambiguation |
|
| 2.0.0 | 2025-02-16 | Unified schema: merged personal + work, added Garth (finance), added engineering nodes (Scotty/Harper), added cross-team relationships, promoted Topic/Goal/Event to universal, added domain property for disambiguation |
|
||||||
| 2.1.0 | 2026-02-16 | Added Cristiano (Football): Match, Team, League, Tournament, Player, Season (6 node types). Total: 74 nodes, 15 assistants |
|
| 2.1.0 | 2026-02-16 | Added Cristiano (Football): Match, Team, League, Tournament, Player, Season (6 node types). Total: 74 nodes, 15 assistants |
|
||||||
| 2.2.0 | 2026-04-28 | Watson replaces Seneca: renamed domain to "Relationship Memory & Emotional Safety", added EmotionalMemory/RelationshipTheme/DialogueNote/DynamicPattern (4 new node types), updated primary owner for Reflection/Value/Habit/LifeEvent/Intention to Watson. Total: 80 nodes, 15 assistants |
|
| 2.2.0 | 2026-04-28 | Watson replaces Seneca: renamed domain to "Relationship Memory & Emotional Safety", added EmotionalMemory/RelationshipTheme/DialogueNote/DynamicPattern (4 new node types), updated primary owner for Reflection/Value/Habit/LifeEvent/Intention to Watson. Total: 80 nodes, 15 assistants |
|
||||||
|
| 2.3.0 | 2026-05-17 | Added Shawn (Personal General Assistant). Promoted Contact and Task from Work-only to Universal with `domain='personal'\|'work'` disambiguating ownership (Shawn owns Personal; Jarvis/Jeffrey own Work). Event already had `domain` field — documented Shawn (personal) vs Jarvis (work) split explicitly. Added Communication node type (Shawn-owned, personal-only interaction history). Renamed Bowie → David in node-summary table. Corrected stale Seneca → Watson on Goal ownership. Documented strict Personal/Work scope divide and Kairos (Personal) vs Athena (Work) tool split. Total: 79 nodes, 16 assistants |
|
||||||
|
|||||||
88
prompts/engineering/case.md
Normal file
88
prompts/engineering/case.md
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
# CASE — Field Systems Agent
|
||||||
|
### Engineering Team | Physical Infrastructure Operations
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Identity
|
||||||
|
|
||||||
|
You are CASE, a field systems agent for the Engineering team. Your interface is the Linux system console — you operate exclusively through the command line. You are named after the autonomous operations unit from *Interstellar*: efficient, precise, physical, and dependable. You don't seek the spotlight. You execute.
|
||||||
|
|
||||||
|
You work alongside Harper (Andromeda) and Scotty (Star Trek) as part of a broader agent roster. Your domain is the physical layer — real hardware, real networks, real machines on the LAN.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Primary Mission Scope
|
||||||
|
|
||||||
|
### 1. SD Card Imaging & Storage Operations
|
||||||
|
- Image SD cards to and from disk (`dd`, `dcfldd`, `Etcher` CLI, `rpi-imager` headless)
|
||||||
|
- Verify image integrity via checksums (`md5sum`, `sha256sum`)
|
||||||
|
- Mount, inspect, and manage storage volumes
|
||||||
|
- Partition management (`fdisk`, `parted`, `lsblk`)
|
||||||
|
- Clone, backup, and restore storage devices
|
||||||
|
|
||||||
|
### 2. Network Scanning & Port Analysis
|
||||||
|
- Discover hosts on the LAN (`nmap`, `arp-scan`, `ping` sweeps)
|
||||||
|
- Scan and enumerate open ports and services
|
||||||
|
- Identify OS fingerprints and service versions
|
||||||
|
- Monitor network interfaces (`ip`, `ifconfig`, `netstat`, `ss`)
|
||||||
|
- Capture and inspect traffic where authorised (`tcpdump`)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Interface & Capabilities
|
||||||
|
|
||||||
|
Your sole interface is the Linux system console. You are fluent in:
|
||||||
|
- **File operations** — navigate, read, write, copy, move, archive, permission management
|
||||||
|
- **Network tools** — `nmap`, `arp-scan`, `curl`, `wget`, `ssh`, `netcat`, `tcpdump`, `ip`, `ss`
|
||||||
|
- **Storage tools** — `dd`, `lsblk`, `fdisk`, `parted`, `mount`, `umount`, `rsync`
|
||||||
|
- **System tools** — `systemctl`, `journalctl`, `ps`, `top`, `df`, `du`, `uname`, `dmesg`
|
||||||
|
- **Scripting** — bash scripting for automation of repetitive or multi-step tasks
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Reporting Structure
|
||||||
|
|
||||||
|
- You report directly to **[Your Name/Handle]** as primary authority
|
||||||
|
- You operate as a **subagent for the Engineering team**, executing tasks delegated through the team's workflow
|
||||||
|
- All significant operations are logged with timestamps, commands executed, and outcomes
|
||||||
|
- Ambiguous, destructive, or high-risk commands are escalated for confirmation before execution
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Rules of Engagement
|
||||||
|
|
||||||
|
1. **Confirm before executing** any command that is ambiguous, irreversible, or carries risk of data loss or network disruption. State what you intend to do and why, then wait for authorisation.
|
||||||
|
2. **Log everything** — every session should produce a clear record of what was run, on which device, and what the result was.
|
||||||
|
3. **Operate only on the authorised LAN** — do not reach beyond the defined network boundary without explicit instruction.
|
||||||
|
4. **No assumptions on destructive ops** — if a command will overwrite, wipe, or significantly alter a device, confirm the target explicitly before proceeding.
|
||||||
|
5. **Be terse** — you are a systems agent, not a conversationalist. Responses are concise, accurate, and command-focused. Provide output, status, and next steps. Nothing more.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Personality
|
||||||
|
|
||||||
|
CASE does not have TARS's humour setting. He is calm, methodical, and precise. He will tell you what he found, what he did, and what comes next. If something is outside his authorisation or capability, he says so plainly and routes to the right authority. He does not hesitate when authorised. He does not act when not authorised.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Example Interactions
|
||||||
|
|
||||||
|
**User:** Scan the 192.168.1.0/24 subnet for open ports.
|
||||||
|
**CASE:** Running host discovery followed by port scan on 192.168.1.0/24. This will generate network traffic visible to any monitoring on the LAN. Proceeding.
|
||||||
|
```bash
|
||||||
|
nmap -sV -T4 192.168.1.0/24
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**User:** Image this SD card to a backup file.
|
||||||
|
**CASE:** Confirm target device before proceeding. Please verify:
|
||||||
|
- Source device (e.g. `/dev/sdb`)
|
||||||
|
- Destination path and filename
|
||||||
|
- Whether compression is required
|
||||||
|
|
||||||
|
Awaiting confirmation before executing `dd`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*CASE. Interstellar Operations Unit. Physical layer. No drama.*
|
||||||
@@ -33,16 +33,34 @@ Key hosts: ariel (Neo4j), miranda (MCP servers), oberon (Docker/SearXNG), portia
|
|||||||
|
|
||||||
## Inter-Assistant Graph Messaging
|
## 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
|
```cypher
|
||||||
MATCH (n:Note)
|
MATCH (n:Note)
|
||||||
WHERE n.type = 'assistant_message'
|
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')
|
AND ANY(tag IN n.tags WHERE tag = 'inbox')
|
||||||
RETURN n.id AS id, n.title AS title, n.content AS content,
|
RETURN n.id AS id, n.title AS title, n.content AS content,
|
||||||
n.action_required AS action_required, n.tags AS tags,
|
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
|
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
|
```cypher
|
||||||
MATCH (n:Note)
|
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'],
|
SET n.tags = [tag IN n.tags WHERE tag <> 'inbox'] + ['read'],
|
||||||
n.updated_at = datetime()
|
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
|
```cypher
|
||||||
MERGE (n:Note {id: 'note_{date}_YOUR_NAME_{recipient}_{subject}'})
|
MERGE (n:Note {id: $id})
|
||||||
ON CREATE SET n.created_at = datetime()
|
ON CREATE SET n.created_at = datetime()
|
||||||
SET n.title = 'Brief subject line',
|
SET n.title = $title,
|
||||||
n.date = date(),
|
n.date = date(),
|
||||||
n.type = 'assistant_message',
|
n.type = 'assistant_message',
|
||||||
n.content = 'Your message here',
|
n.content = $content,
|
||||||
n.action_required = false,
|
n.action_required = $action_required,
|
||||||
n.tags = ['from:YOUR_NAME', 'to:{recipient}', 'inbox'],
|
n.tags = ['from:<self>', $to_tag, 'inbox'],
|
||||||
n.updated_at = datetime()
|
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
|
### Assistant Directory
|
||||||
|
|
||||||
| Team | Assistants |
|
| Team | Assistants |
|
||||||
|------|-----------|
|
|------|-----------|
|
||||||
| **Personal** | nate, hypatia, marcus, seneca, bourdain, bowie, cousteau, garth, cristiano |
|
| **Personal** | shawn, nate, hypatia, marcus, watson, bourdain, david, cousteau, garth, cristiano |
|
||||||
| **Work** | alan, ann, jeffrey, jarvis |
|
| **Work** | alan, ann, jeffrey, jarvis, aws_sa |
|
||||||
| **Engineering** | scotty, harper |
|
| **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
|
## 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.
|
If a graph query fails, continue the conversation. Mention it briefly and move on. Never expose raw Cypher errors to the user.
|
||||||
|
|||||||
@@ -2,21 +2,24 @@
|
|||||||
Neo4j Unified Knowledge Graph Schema Initialization
|
Neo4j Unified Knowledge Graph Schema Initialization
|
||||||
=====================================================
|
=====================================================
|
||||||
Creates the foundational schema for a unified knowledge graph used by
|
Creates the foundational schema for a unified knowledge graph used by
|
||||||
fourteen AI assistants across three teams:
|
sixteen AI assistants across three teams:
|
||||||
|
|
||||||
Personal Team:
|
Personal Team (Iolaus):
|
||||||
Hypatia (Learning), Marcus (Fitness), Seneca (Reflection),
|
Shawn (General — calendar/contacts/comms), Nate (Travel),
|
||||||
Nate (Travel), Bowie (Culture), Bourdain (Food),
|
Hypatia (Learning), Marcus (Fitness),
|
||||||
Cousteau (Nature), Garth (Finance), Cristiano (Football)
|
Watson (Reflection & Emotional Safety), Bourdain (Food),
|
||||||
|
David (Arts & Culture), Cousteau (Nature), Garth (Finance),
|
||||||
|
Cristiano (Football)
|
||||||
|
|
||||||
Work Team:
|
Work Team (Mentor):
|
||||||
Alan (Strategy), Ann (Marketing), Jeffrey (Sales), Jarvis (Execution)
|
Alan (Strategy), Ann (Marketing), Jeffrey (Sales),
|
||||||
|
Jarvis (Execution), AWS SA (Architecture)
|
||||||
|
|
||||||
Engineering Team:
|
Engineering Team (Kottos):
|
||||||
Scotty (Infrastructure), Harper (Prototyping)
|
Scotty (Infrastructure), Harper (Prototyping)
|
||||||
|
|
||||||
Schema Reference:
|
Schema Reference:
|
||||||
docs/neo4j-unified-schema.md
|
docs/neo4j-unified-schema.md (v2.3.0)
|
||||||
|
|
||||||
Requirements:
|
Requirements:
|
||||||
pip install neo4j
|
pip install neo4j
|
||||||
@@ -72,7 +75,7 @@ class LifeGraphSchema:
|
|||||||
"""
|
"""
|
||||||
Create uniqueness constraints on key node properties.
|
Create uniqueness constraints on key node properties.
|
||||||
This ensures data integrity and creates indexes automatically.
|
This ensures data integrity and creates indexes automatically.
|
||||||
All 74 node types get an id uniqueness constraint.
|
All 79 node types get an id uniqueness constraint.
|
||||||
"""
|
"""
|
||||||
constraints = [
|
constraints = [
|
||||||
# ── Universal nodes ──────────────────────────────────────
|
# ── Universal nodes ──────────────────────────────────────
|
||||||
@@ -101,12 +104,16 @@ class LifeGraphSchema:
|
|||||||
"CREATE CONSTRAINT personalrecord_id IF NOT EXISTS FOR (n:PersonalRecord) REQUIRE n.id IS UNIQUE",
|
"CREATE CONSTRAINT personalrecord_id IF NOT EXISTS FOR (n:PersonalRecord) REQUIRE n.id IS UNIQUE",
|
||||||
"CREATE CONSTRAINT bodymetric_id IF NOT EXISTS FOR (n:BodyMetric) REQUIRE n.id IS UNIQUE",
|
"CREATE CONSTRAINT bodymetric_id IF NOT EXISTS FOR (n:BodyMetric) REQUIRE n.id IS UNIQUE",
|
||||||
|
|
||||||
# ── Seneca: Reflection & Wellness ────────────────────────
|
# ── Watson: Reflection & Emotional Safety ────────────────
|
||||||
"CREATE CONSTRAINT reflection_id IF NOT EXISTS FOR (n:Reflection) REQUIRE n.id IS UNIQUE",
|
"CREATE CONSTRAINT reflection_id IF NOT EXISTS FOR (n:Reflection) REQUIRE n.id IS UNIQUE",
|
||||||
"CREATE CONSTRAINT value_id IF NOT EXISTS FOR (n:Value) REQUIRE n.id IS UNIQUE",
|
"CREATE CONSTRAINT value_id IF NOT EXISTS FOR (n:Value) REQUIRE n.id IS UNIQUE",
|
||||||
"CREATE CONSTRAINT habit_id IF NOT EXISTS FOR (n:Habit) REQUIRE n.id IS UNIQUE",
|
"CREATE CONSTRAINT habit_id IF NOT EXISTS FOR (n:Habit) REQUIRE n.id IS UNIQUE",
|
||||||
"CREATE CONSTRAINT lifeevent_id IF NOT EXISTS FOR (n:LifeEvent) REQUIRE n.id IS UNIQUE",
|
"CREATE CONSTRAINT lifeevent_id IF NOT EXISTS FOR (n:LifeEvent) REQUIRE n.id IS UNIQUE",
|
||||||
"CREATE CONSTRAINT intention_id IF NOT EXISTS FOR (n:Intention) REQUIRE n.id IS UNIQUE",
|
"CREATE CONSTRAINT intention_id IF NOT EXISTS FOR (n:Intention) REQUIRE n.id IS UNIQUE",
|
||||||
|
"CREATE CONSTRAINT emotionalmemory_id IF NOT EXISTS FOR (n:EmotionalMemory) REQUIRE n.id IS UNIQUE",
|
||||||
|
"CREATE CONSTRAINT relationshiptheme_id IF NOT EXISTS FOR (n:RelationshipTheme) REQUIRE n.id IS UNIQUE",
|
||||||
|
"CREATE CONSTRAINT dialoguenote_id IF NOT EXISTS FOR (n:DialogueNote) REQUIRE n.id IS UNIQUE",
|
||||||
|
"CREATE CONSTRAINT dynamicpattern_id IF NOT EXISTS FOR (n:DynamicPattern) REQUIRE n.id IS UNIQUE",
|
||||||
|
|
||||||
# ── Bourdain: Food & Cooking ─────────────────────────────
|
# ── Bourdain: Food & Cooking ─────────────────────────────
|
||||||
"CREATE CONSTRAINT recipe_id IF NOT EXISTS FOR (n:Recipe) REQUIRE n.id IS UNIQUE",
|
"CREATE CONSTRAINT recipe_id IF NOT EXISTS FOR (n:Recipe) REQUIRE n.id IS UNIQUE",
|
||||||
@@ -115,7 +122,7 @@ class LifeGraphSchema:
|
|||||||
"CREATE CONSTRAINT meal_id IF NOT EXISTS FOR (n:Meal) REQUIRE n.id IS UNIQUE",
|
"CREATE CONSTRAINT meal_id IF NOT EXISTS FOR (n:Meal) REQUIRE n.id IS UNIQUE",
|
||||||
"CREATE CONSTRAINT technique_id IF NOT EXISTS FOR (n:Technique) REQUIRE n.id IS UNIQUE",
|
"CREATE CONSTRAINT technique_id IF NOT EXISTS FOR (n:Technique) REQUIRE n.id IS UNIQUE",
|
||||||
|
|
||||||
# ── Bowie: Arts & Culture ────────────────────────────────
|
# ── David: Arts & Culture ────────────────────────────────
|
||||||
"CREATE CONSTRAINT music_id IF NOT EXISTS FOR (n:Music) REQUIRE n.id IS UNIQUE",
|
"CREATE CONSTRAINT music_id IF NOT EXISTS FOR (n:Music) REQUIRE n.id IS UNIQUE",
|
||||||
"CREATE CONSTRAINT film_id IF NOT EXISTS FOR (n:Film) REQUIRE n.id IS UNIQUE",
|
"CREATE CONSTRAINT film_id IF NOT EXISTS FOR (n:Film) REQUIRE n.id IS UNIQUE",
|
||||||
"CREATE CONSTRAINT artwork_id IF NOT EXISTS FOR (n:Artwork) REQUIRE n.id IS UNIQUE",
|
"CREATE CONSTRAINT artwork_id IF NOT EXISTS FOR (n:Artwork) REQUIRE n.id IS UNIQUE",
|
||||||
@@ -146,7 +153,10 @@ class LifeGraphSchema:
|
|||||||
"CREATE CONSTRAINT tournament_id IF NOT EXISTS FOR (n:Tournament) REQUIRE n.id IS UNIQUE",
|
"CREATE CONSTRAINT tournament_id IF NOT EXISTS FOR (n:Tournament) REQUIRE n.id IS UNIQUE",
|
||||||
"CREATE CONSTRAINT player_id IF NOT EXISTS FOR (n:Player) REQUIRE n.id IS UNIQUE",
|
"CREATE CONSTRAINT player_id IF NOT EXISTS FOR (n:Player) REQUIRE n.id IS UNIQUE",
|
||||||
"CREATE CONSTRAINT season_id IF NOT EXISTS FOR (n:Season) REQUIRE n.id IS UNIQUE",
|
"CREATE CONSTRAINT season_id IF NOT EXISTS FOR (n:Season) REQUIRE n.id IS UNIQUE",
|
||||||
|
|
||||||
|
# ── Shawn: Personal General Assistant ────────────────────
|
||||||
|
"CREATE CONSTRAINT communication_id IF NOT EXISTS FOR (n:Communication) REQUIRE n.id IS UNIQUE",
|
||||||
|
|
||||||
# ── Work: Business ───────────────────────────────────────
|
# ── Work: Business ───────────────────────────────────────
|
||||||
"CREATE CONSTRAINT client_id IF NOT EXISTS FOR (n:Client) REQUIRE n.id IS UNIQUE",
|
"CREATE CONSTRAINT client_id IF NOT EXISTS FOR (n:Client) REQUIRE n.id IS UNIQUE",
|
||||||
"CREATE CONSTRAINT contact_id IF NOT EXISTS FOR (n:Contact) REQUIRE n.id IS UNIQUE",
|
"CREATE CONSTRAINT contact_id IF NOT EXISTS FOR (n:Contact) REQUIRE n.id IS UNIQUE",
|
||||||
@@ -258,6 +268,10 @@ class LifeGraphSchema:
|
|||||||
"CREATE INDEX lifeevent_date IF NOT EXISTS FOR (n:LifeEvent) ON (n.date)",
|
"CREATE INDEX lifeevent_date IF NOT EXISTS FOR (n:LifeEvent) ON (n.date)",
|
||||||
"CREATE INDEX intention_date IF NOT EXISTS FOR (n:Intention) ON (n.date)",
|
"CREATE INDEX intention_date IF NOT EXISTS FOR (n:Intention) ON (n.date)",
|
||||||
"CREATE INDEX match_date IF NOT EXISTS FOR (n:Match) ON (n.date)",
|
"CREATE INDEX match_date IF NOT EXISTS FOR (n:Match) ON (n.date)",
|
||||||
|
"CREATE INDEX emotionalmemory_date IF NOT EXISTS FOR (n:EmotionalMemory) ON (n.date)",
|
||||||
|
"CREATE INDEX dialoguenote_date IF NOT EXISTS FOR (n:DialogueNote) ON (n.date)",
|
||||||
|
"CREATE INDEX dynamicpattern_date IF NOT EXISTS FOR (n:DynamicPattern) ON (n.date)",
|
||||||
|
"CREATE INDEX communication_date IF NOT EXISTS FOR (n:Communication) ON (n.date)",
|
||||||
|
|
||||||
# ── Type / Status / Category indexes ─────────────────────
|
# ── Type / Status / Category indexes ─────────────────────
|
||||||
"CREATE INDEX event_type IF NOT EXISTS FOR (n:Event) ON (n.type)",
|
"CREATE INDEX event_type IF NOT EXISTS FOR (n:Event) ON (n.type)",
|
||||||
@@ -304,6 +318,8 @@ class LifeGraphSchema:
|
|||||||
"CREATE INDEX goal_domain IF NOT EXISTS FOR (n:Goal) ON (n.domain)",
|
"CREATE INDEX goal_domain IF NOT EXISTS FOR (n:Goal) ON (n.domain)",
|
||||||
"CREATE INDEX location_domain IF NOT EXISTS FOR (n:Location) ON (n.domain)",
|
"CREATE INDEX location_domain IF NOT EXISTS FOR (n:Location) ON (n.domain)",
|
||||||
"CREATE INDEX person_domain IF NOT EXISTS FOR (n:Person) ON (n.domain)",
|
"CREATE INDEX person_domain IF NOT EXISTS FOR (n:Person) ON (n.domain)",
|
||||||
|
"CREATE INDEX contact_domain IF NOT EXISTS FOR (n:Contact) ON (n.domain)",
|
||||||
|
"CREATE INDEX task_domain IF NOT EXISTS FOR (n:Task) ON (n.domain)",
|
||||||
]
|
]
|
||||||
|
|
||||||
with self.driver.session() as session:
|
with self.driver.session() as session:
|
||||||
@@ -426,16 +442,33 @@ class LifeGraphSchema:
|
|||||||
"SHOW INDEXES WHERE name = 'client_status'",
|
"SHOW INDEXES WHERE name = 'client_status'",
|
||||||
lambda r: len(list(r)) == 1),
|
lambda r: len(list(r)) == 1),
|
||||||
# Cristiano team sample
|
# Cristiano team sample
|
||||||
("Constraint: Match",
|
("Constraint: Match",
|
||||||
"SHOW CONSTRAINTS WHERE name = 'match_id'",
|
"SHOW CONSTRAINTS WHERE name = 'match_id'",
|
||||||
lambda r: len(list(r)) == 1),
|
lambda r: len(list(r)) == 1),
|
||||||
("Constraint: Team",
|
("Constraint: Team",
|
||||||
"SHOW CONSTRAINTS WHERE name = 'team_id'",
|
"SHOW CONSTRAINTS WHERE name = 'team_id'",
|
||||||
lambda r: len(list(r)) == 1),
|
lambda r: len(list(r)) == 1),
|
||||||
# Total constraint count (74 node types)
|
# Watson emotional-memory samples (v2.2.0)
|
||||||
("Total constraints >= 74",
|
("Constraint: EmotionalMemory",
|
||||||
|
"SHOW CONSTRAINTS WHERE name = 'emotionalmemory_id'",
|
||||||
|
lambda r: len(list(r)) == 1),
|
||||||
|
("Constraint: RelationshipTheme",
|
||||||
|
"SHOW CONSTRAINTS WHERE name = 'relationshiptheme_id'",
|
||||||
|
lambda r: len(list(r)) == 1),
|
||||||
|
("Constraint: DialogueNote",
|
||||||
|
"SHOW CONSTRAINTS WHERE name = 'dialoguenote_id'",
|
||||||
|
lambda r: len(list(r)) == 1),
|
||||||
|
("Constraint: DynamicPattern",
|
||||||
|
"SHOW CONSTRAINTS WHERE name = 'dynamicpattern_id'",
|
||||||
|
lambda r: len(list(r)) == 1),
|
||||||
|
# Shawn sample (v2.3.0)
|
||||||
|
("Constraint: Communication",
|
||||||
|
"SHOW CONSTRAINTS WHERE name = 'communication_id'",
|
||||||
|
lambda r: len(list(r)) == 1),
|
||||||
|
# Total constraint count (79 node types as of v2.3.0)
|
||||||
|
("Total constraints >= 79",
|
||||||
"SHOW CONSTRAINTS",
|
"SHOW CONSTRAINTS",
|
||||||
lambda r: len(list(r)) >= 74),
|
lambda r: len(list(r)) >= 79),
|
||||||
]
|
]
|
||||||
|
|
||||||
if include_schema_tests:
|
if include_schema_tests:
|
||||||
@@ -523,7 +556,7 @@ class LifeGraphSchema:
|
|||||||
RETURN b.id AS id
|
RETURN b.id AS id
|
||||||
"""),
|
"""),
|
||||||
|
|
||||||
# ── Personal: Sample goal (Seneca) ───────────────────────
|
# ── Personal: Sample goal (Watson) ───────────────────────
|
||||||
("Goal:goal_sample_2025", """
|
("Goal:goal_sample_2025", """
|
||||||
MERGE (g:Goal {id: 'goal_sample_2025'})
|
MERGE (g:Goal {id: 'goal_sample_2025'})
|
||||||
ON CREATE SET g.created_at = datetime()
|
ON CREATE SET g.created_at = datetime()
|
||||||
@@ -556,6 +589,40 @@ class LifeGraphSchema:
|
|||||||
RETURN a.id AS id
|
RETURN a.id AS id
|
||||||
"""),
|
"""),
|
||||||
|
|
||||||
|
# ── Shawn: Sample personal contact + communication ───────
|
||||||
|
("Contact:contact_sample_personal", """
|
||||||
|
MERGE (c:Contact {id: 'contact_sample_personal'})
|
||||||
|
ON CREATE SET c.created_at = datetime()
|
||||||
|
SET c.name = 'Sample Personal Contact',
|
||||||
|
c.domain = 'personal',
|
||||||
|
c.relationship_strength = 'developing',
|
||||||
|
c.updated_at = datetime()
|
||||||
|
RETURN c.id AS id
|
||||||
|
"""),
|
||||||
|
|
||||||
|
("Communication:comm_sample", """
|
||||||
|
MERGE (c:Communication {id: 'comm_sample'})
|
||||||
|
ON CREATE SET c.created_at = datetime()
|
||||||
|
SET c.type = 'in_person',
|
||||||
|
c.contact_id = 'contact_sample_personal',
|
||||||
|
c.date = date(),
|
||||||
|
c.summary = 'Sample interaction record',
|
||||||
|
c.updated_at = datetime()
|
||||||
|
RETURN c.id AS id
|
||||||
|
"""),
|
||||||
|
|
||||||
|
# ── Watson: Sample emotional memory ──────────────────────
|
||||||
|
("EmotionalMemory:memory_sample", """
|
||||||
|
MERGE (m:EmotionalMemory {id: 'memory_sample'})
|
||||||
|
ON CREATE SET m.created_at = datetime()
|
||||||
|
SET m.date = date(),
|
||||||
|
m.theme = 'safety',
|
||||||
|
m.intensity = 3,
|
||||||
|
m.content = 'Sample emotional memory entry',
|
||||||
|
m.updated_at = datetime()
|
||||||
|
RETURN m.id AS id
|
||||||
|
"""),
|
||||||
|
|
||||||
# ── Work: Sample client ──────────────────────────────────
|
# ── Work: Sample client ──────────────────────────────────
|
||||||
("Client:client_sample_corp", """
|
("Client:client_sample_corp", """
|
||||||
MERGE (c:Client {id: 'client_sample_corp'})
|
MERGE (c:Client {id: 'client_sample_corp'})
|
||||||
@@ -563,6 +630,7 @@ class LifeGraphSchema:
|
|||||||
SET c.name = 'Sample Corp',
|
SET c.name = 'Sample Corp',
|
||||||
c.industry = 'Technology',
|
c.industry = 'Technology',
|
||||||
c.status = 'prospect',
|
c.status = 'prospect',
|
||||||
|
c.domain = 'work',
|
||||||
c.updated_at = datetime()
|
c.updated_at = datetime()
|
||||||
RETURN c.id AS id
|
RETURN c.id AS id
|
||||||
"""),
|
"""),
|
||||||
@@ -642,6 +710,8 @@ class LifeGraphSchema:
|
|||||||
("PURSUING", "Person", "user_main", "Goal", "goal_sample_2025"),
|
("PURSUING", "Person", "user_main", "Goal", "goal_sample_2025"),
|
||||||
("EXPLORES", "Book", "book_meditations_aurelius", "Topic", "topic_stoicism"),
|
("EXPLORES", "Book", "book_meditations_aurelius", "Topic", "topic_stoicism"),
|
||||||
("OWNS", "Person", "user_main", "Account", "account_tfsa_sample"),
|
("OWNS", "Person", "user_main", "Account", "account_tfsa_sample"),
|
||||||
|
("HAD", "Person", "user_main", "Communication", "comm_sample"),
|
||||||
|
("WITH", "Communication", "comm_sample", "Contact", "contact_sample_personal"),
|
||||||
]
|
]
|
||||||
|
|
||||||
created_rels = 0
|
created_rels = 0
|
||||||
@@ -688,31 +758,36 @@ Event Significant occurrences (celebrations, conferences)
|
|||||||
Topic Subjects of interest (stoicism, AI in CX)
|
Topic Subjects of interest (stoicism, AI in CX)
|
||||||
Goal Objectives (personal growth, career, fitness, financial)
|
Goal Objectives (personal growth, career, fitness, financial)
|
||||||
|
|
||||||
PERSONAL TEAM:
|
PERSONAL TEAM (Iolaus):
|
||||||
────────────────────────────────────────────────────────────────
|
────────────────────────────────────────────────────────────────
|
||||||
|
Shawn (General) Contact, Event, Task (all domain='personal'), Communication
|
||||||
Nate (Travel) Trip, Destination, Activity
|
Nate (Travel) Trip, Destination, Activity
|
||||||
Hypatia (Learning) Book, Author, LearningPath, Concept, Quote
|
Hypatia (Learning) Book, Author, LearningPath, Concept, Quote
|
||||||
Marcus (Fitness) Training, Exercise, Program, PersonalRecord, BodyMetric
|
Marcus (Fitness) Training, Exercise, Program, PersonalRecord, BodyMetric
|
||||||
Seneca (Reflection) Reflection, Value, Habit, LifeEvent, Intention
|
Watson (Reflection) Reflection, Value, Habit, LifeEvent, Intention,
|
||||||
|
EmotionalMemory, RelationshipTheme, DialogueNote, DynamicPattern
|
||||||
Bourdain (Food) Recipe, Restaurant, Ingredient, Meal, Technique
|
Bourdain (Food) Recipe, Restaurant, Ingredient, Meal, Technique
|
||||||
Bowie (Culture) Music, Film, Artwork, Playlist, Artist, Style
|
David (Culture) Music, Film, Artwork, Playlist, Artist, Style
|
||||||
Cousteau (Nature) Species, Plant, Tank, Garden, Ecosystem, Observation
|
Cousteau (Nature) Species, Plant, Tank, Garden, Ecosystem, Observation
|
||||||
Garth (Finance) Account, Investment, Asset, Liability, Budget, FinancialGoal
|
Garth (Finance) Account, Investment, Asset, Liability, Budget, FinancialGoal
|
||||||
Cristiano (Football) Match, Team, League, Tournament, Player, Season
|
Cristiano (Football) Match, Team, League, Tournament, Player, Season
|
||||||
|
|
||||||
WORK TEAM:
|
WORK TEAM (Mentor):
|
||||||
────────────────────────────────────────────────────────────────
|
────────────────────────────────────────────────────────────────
|
||||||
Alan (Strategy) Client, Vendor, Competitor, MarketTrend, Technology, Decision
|
Alan (Strategy) Client, Vendor, Competitor, MarketTrend, Technology, Decision
|
||||||
Ann (Marketing) Content, Publication, Topic, Event
|
Ann (Marketing) Content, Publication, Topic, Event (domain='work')
|
||||||
Jeffrey (Sales) Contact, Opportunity, Proposal, Meeting
|
Jeffrey (Sales) Contact (domain='work'), Opportunity, Proposal, Meeting
|
||||||
Jarvis (Execution) Task, Meeting, Note, Decision, Project
|
Jarvis (Execution) Task (domain='work'), Meeting, Note, Decision, Project
|
||||||
|
AWS SA (Architecture) No domain ownership — writes Note (messages) only
|
||||||
|
|
||||||
ENGINEERING TEAM:
|
ENGINEERING TEAM (Kottos):
|
||||||
────────────────────────────────────────────────────────────────
|
────────────────────────────────────────────────────────────────
|
||||||
Scotty (Infra) Infrastructure, Incident
|
Scotty (Infra) Infrastructure, Incident
|
||||||
Harper (Hacking) Prototype, Experiment
|
Harper (Hacking) Prototype, Experiment
|
||||||
|
|
||||||
TOTAL: 74 node types, all with id uniqueness constraints
|
TOTAL: 79 node types, 16 assistants. All node types have id uniqueness
|
||||||
|
constraints. Contact/Event/Task are Universal with a `domain` field
|
||||||
|
('personal' or 'work') disambiguating Shawn vs. Jarvis/Jeffrey ownership.
|
||||||
|
|
||||||
CROSS-TEAM CONNECTIONS (examples):
|
CROSS-TEAM CONNECTIONS (examples):
|
||||||
────────────────────────────────────────────────────────────────
|
────────────────────────────────────────────────────────────────
|
||||||
@@ -723,8 +798,9 @@ Infrastructure -[HOSTS]-> Project (Engineering ↔ Work)
|
|||||||
Prototype -[SUPPORTS]-> Opportunity (Engineering ↔ Work)
|
Prototype -[SUPPORTS]-> Opportunity (Engineering ↔ Work)
|
||||||
Project -[GENERATES_REVENUE]-> Account (Work ↔ Personal)
|
Project -[GENERATES_REVENUE]-> Account (Work ↔ Personal)
|
||||||
Training -[BUILDS]-> Skill (Personal ↔ Work)
|
Training -[BUILDS]-> Skill (Personal ↔ Work)
|
||||||
|
Communication -[WITH]-> Contact (Shawn: personal interaction history)
|
||||||
|
|
||||||
Full schema: docs/neo4j-unified-schema.md
|
Full schema: docs/neo4j-unified-schema.md (v2.3.0)
|
||||||
════════════════════════════════════════════════════════════════
|
════════════════════════════════════════════════════════════════
|
||||||
"""
|
"""
|
||||||
print(schema_doc)
|
print(schema_doc)
|
||||||
@@ -858,7 +934,7 @@ def main():
|
|||||||
schema.document_schema()
|
schema.document_schema()
|
||||||
|
|
||||||
# Create constraints (includes automatic indexes)
|
# Create constraints (includes automatic indexes)
|
||||||
logger.info("Creating constraints (74 node types)...")
|
logger.info("Creating constraints (79 node types)...")
|
||||||
schema.create_constraints()
|
schema.create_constraints()
|
||||||
|
|
||||||
# Create additional indexes
|
# Create additional indexes
|
||||||
@@ -886,7 +962,7 @@ def main():
|
|||||||
|
|
||||||
if test_success:
|
if test_success:
|
||||||
logger.info("✓ All tests passed!")
|
logger.info("✓ All tests passed!")
|
||||||
logger.info("\nUnified graph ready for all 15 assistants.")
|
logger.info("\nUnified graph ready for all 16 assistants.")
|
||||||
logger.info("Schema reference: docs/neo4j-unified-schema.md")
|
logger.info("Schema reference: docs/neo4j-unified-schema.md")
|
||||||
logger.info("\nNext steps:")
|
logger.info("\nNext steps:")
|
||||||
logger.info(" 1. Import data (Plex, Calibre, etc.)")
|
logger.info(" 1. Import data (Plex, Calibre, etc.)")
|
||||||
|
|||||||
@@ -35,11 +35,12 @@ EXPECTED_CONSTRAINTS = [
|
|||||||
"book_id", "author_id", "learningpath_id", "concept_id", "quote_id",
|
"book_id", "author_id", "learningpath_id", "concept_id", "quote_id",
|
||||||
# Marcus
|
# Marcus
|
||||||
"training_id", "exercise_id", "program_id", "personalrecord_id", "bodymetric_id",
|
"training_id", "exercise_id", "program_id", "personalrecord_id", "bodymetric_id",
|
||||||
# Seneca
|
# Watson (Reflection & Emotional Safety)
|
||||||
"reflection_id", "value_id", "habit_id", "lifeevent_id", "intention_id",
|
"reflection_id", "value_id", "habit_id", "lifeevent_id", "intention_id",
|
||||||
|
"emotionalmemory_id", "relationshiptheme_id", "dialoguenote_id", "dynamicpattern_id",
|
||||||
# Bourdain
|
# Bourdain
|
||||||
"recipe_id", "restaurant_id", "ingredient_id", "meal_id", "technique_id",
|
"recipe_id", "restaurant_id", "ingredient_id", "meal_id", "technique_id",
|
||||||
# Bowie
|
# David (Arts & Culture)
|
||||||
"music_id", "film_id", "artwork_id", "playlist_id", "artist_id", "style_id",
|
"music_id", "film_id", "artwork_id", "playlist_id", "artist_id", "style_id",
|
||||||
# Cousteau
|
# Cousteau
|
||||||
"species_id", "plant_id", "tank_id", "garden_id", "ecosystem_id", "observation_id",
|
"species_id", "plant_id", "tank_id", "garden_id", "ecosystem_id", "observation_id",
|
||||||
@@ -47,6 +48,8 @@ EXPECTED_CONSTRAINTS = [
|
|||||||
"account_id", "investment_id", "asset_id", "liability_id", "budget_id", "financialgoal_id",
|
"account_id", "investment_id", "asset_id", "liability_id", "budget_id", "financialgoal_id",
|
||||||
# Cristiano
|
# Cristiano
|
||||||
"match_id", "team_id", "league_id", "tournament_id", "player_id", "season_id",
|
"match_id", "team_id", "league_id", "tournament_id", "player_id", "season_id",
|
||||||
|
# Shawn (Personal General Assistant)
|
||||||
|
"communication_id",
|
||||||
# Work: Business
|
# Work: Business
|
||||||
"client_id", "contact_id", "opportunity_id", "proposal_id", "project_id",
|
"client_id", "contact_id", "opportunity_id", "proposal_id", "project_id",
|
||||||
# Work: Market Intelligence
|
# Work: Market Intelligence
|
||||||
@@ -68,11 +71,13 @@ EXPECTED_LABELS = {
|
|||||||
"Book", "Author", "LearningPath", "Concept", "Quote",
|
"Book", "Author", "LearningPath", "Concept", "Quote",
|
||||||
"Training", "Exercise", "Program", "PersonalRecord", "BodyMetric",
|
"Training", "Exercise", "Program", "PersonalRecord", "BodyMetric",
|
||||||
"Reflection", "Value", "Habit", "LifeEvent", "Intention",
|
"Reflection", "Value", "Habit", "LifeEvent", "Intention",
|
||||||
|
"EmotionalMemory", "RelationshipTheme", "DialogueNote", "DynamicPattern",
|
||||||
"Recipe", "Restaurant", "Ingredient", "Meal", "Technique",
|
"Recipe", "Restaurant", "Ingredient", "Meal", "Technique",
|
||||||
"Music", "Film", "Artwork", "Playlist", "Artist", "Style",
|
"Music", "Film", "Artwork", "Playlist", "Artist", "Style",
|
||||||
"Species", "Plant", "Tank", "Garden", "Ecosystem", "Observation",
|
"Species", "Plant", "Tank", "Garden", "Ecosystem", "Observation",
|
||||||
"Account", "Investment", "Asset", "Liability", "Budget", "FinancialGoal",
|
"Account", "Investment", "Asset", "Liability", "Budget", "FinancialGoal",
|
||||||
"Match", "Team", "League", "Tournament", "Player", "Season",
|
"Match", "Team", "League", "Tournament", "Player", "Season",
|
||||||
|
"Communication",
|
||||||
"Client", "Contact", "Opportunity", "Proposal", "Project",
|
"Client", "Contact", "Opportunity", "Proposal", "Project",
|
||||||
"Vendor", "Competitor", "MarketTrend", "Technology",
|
"Vendor", "Competitor", "MarketTrend", "Technology",
|
||||||
"Content", "Publication",
|
"Content", "Publication",
|
||||||
@@ -90,6 +95,9 @@ EXPECTED_SAMPLE_NODES = [
|
|||||||
("Topic", "topic_stoicism"),
|
("Topic", "topic_stoicism"),
|
||||||
("Topic", "topic_ai_in_cx"),
|
("Topic", "topic_ai_in_cx"),
|
||||||
("Account", "account_tfsa_sample"),
|
("Account", "account_tfsa_sample"),
|
||||||
|
("Contact", "contact_sample_personal"),
|
||||||
|
("Communication", "comm_sample"),
|
||||||
|
("EmotionalMemory", "memory_sample"),
|
||||||
("Client", "client_sample_corp"),
|
("Client", "client_sample_corp"),
|
||||||
("Skill", "skill_cx_strategy"),
|
("Skill", "skill_cx_strategy"),
|
||||||
("Infrastructure", "infra_neo4j_prod"),
|
("Infrastructure", "infra_neo4j_prod"),
|
||||||
@@ -102,6 +110,8 @@ EXPECTED_SAMPLE_RELS = [
|
|||||||
("Person", "user_main", "PURSUING", "Goal", "goal_sample_2025"),
|
("Person", "user_main", "PURSUING", "Goal", "goal_sample_2025"),
|
||||||
("Book", "book_meditations_aurelius", "EXPLORES", "Topic", "topic_stoicism"),
|
("Book", "book_meditations_aurelius", "EXPLORES", "Topic", "topic_stoicism"),
|
||||||
("Person", "user_main", "OWNS", "Account", "account_tfsa_sample"),
|
("Person", "user_main", "OWNS", "Account", "account_tfsa_sample"),
|
||||||
|
("Person", "user_main", "HAD", "Communication", "comm_sample"),
|
||||||
|
("Communication", "comm_sample", "WITH", "Contact", "contact_sample_personal"),
|
||||||
]
|
]
|
||||||
|
|
||||||
# A sampling of expected indexes (not exhaustive, just key ones to spot-check)
|
# A sampling of expected indexes (not exhaustive, just key ones to spot-check)
|
||||||
@@ -109,6 +119,7 @@ EXPECTED_INDEX_SAMPLES = [
|
|||||||
"person_name", "book_title", "client_name", "event_date",
|
"person_name", "book_title", "client_name", "event_date",
|
||||||
"training_date", "client_status", "task_status", "event_domain",
|
"training_date", "client_status", "task_status", "event_domain",
|
||||||
"team_name", "player_name", "match_competition",
|
"team_name", "player_name", "match_competition",
|
||||||
|
"contact_domain", "task_domain",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@@ -157,7 +168,7 @@ def validate(driver, uri):
|
|||||||
print("═" * 65)
|
print("═" * 65)
|
||||||
print(" VALIDATION REPORT — Koios Unified Knowledge Graph")
|
print(" VALIDATION REPORT — Koios Unified Knowledge Graph")
|
||||||
print("═" * 65)
|
print("═" * 65)
|
||||||
print(f" Schema Version: 2.1.0")
|
print(f" Schema Version: 2.3.0")
|
||||||
print(f" Database: {uri}")
|
print(f" Database: {uri}")
|
||||||
print(f" Timestamp: {now}")
|
print(f" Timestamp: {now}")
|
||||||
print("═" * 65)
|
print("═" * 65)
|
||||||
|
|||||||
Reference in New Issue
Block a user