Schema update
This commit is contained in:
@@ -2,21 +2,24 @@
|
||||
Neo4j Unified Knowledge Graph Schema Initialization
|
||||
=====================================================
|
||||
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:
|
||||
Hypatia (Learning), Marcus (Fitness), Seneca (Reflection),
|
||||
Nate (Travel), Bowie (Culture), Bourdain (Food),
|
||||
Cousteau (Nature), Garth (Finance), Cristiano (Football)
|
||||
Personal Team (Iolaus):
|
||||
Shawn (General — calendar/contacts/comms), Nate (Travel),
|
||||
Hypatia (Learning), Marcus (Fitness),
|
||||
Watson (Reflection & Emotional Safety), Bourdain (Food),
|
||||
David (Arts & Culture), Cousteau (Nature), Garth (Finance),
|
||||
Cristiano (Football)
|
||||
|
||||
Work Team:
|
||||
Alan (Strategy), Ann (Marketing), Jeffrey (Sales), Jarvis (Execution)
|
||||
Work Team (Mentor):
|
||||
Alan (Strategy), Ann (Marketing), Jeffrey (Sales),
|
||||
Jarvis (Execution), AWS SA (Architecture)
|
||||
|
||||
Engineering Team:
|
||||
Engineering Team (Kottos):
|
||||
Scotty (Infrastructure), Harper (Prototyping)
|
||||
|
||||
Schema Reference:
|
||||
docs/neo4j-unified-schema.md
|
||||
docs/neo4j-unified-schema.md (v2.3.0)
|
||||
|
||||
Requirements:
|
||||
pip install neo4j
|
||||
@@ -72,7 +75,7 @@ class LifeGraphSchema:
|
||||
"""
|
||||
Create uniqueness constraints on key node properties.
|
||||
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 = [
|
||||
# ── 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 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 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 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 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 ─────────────────────────────
|
||||
"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 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 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",
|
||||
@@ -146,7 +153,10 @@ class LifeGraphSchema:
|
||||
"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 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 ───────────────────────────────────────
|
||||
"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",
|
||||
@@ -258,6 +268,10 @@ class LifeGraphSchema:
|
||||
"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 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 ─────────────────────
|
||||
"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 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 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:
|
||||
@@ -426,16 +442,33 @@ class LifeGraphSchema:
|
||||
"SHOW INDEXES WHERE name = 'client_status'",
|
||||
lambda r: len(list(r)) == 1),
|
||||
# Cristiano team sample
|
||||
("Constraint: Match",
|
||||
("Constraint: Match",
|
||||
"SHOW CONSTRAINTS WHERE name = 'match_id'",
|
||||
lambda r: len(list(r)) == 1),
|
||||
("Constraint: Team",
|
||||
("Constraint: Team",
|
||||
"SHOW CONSTRAINTS WHERE name = 'team_id'",
|
||||
lambda r: len(list(r)) == 1),
|
||||
# Total constraint count (74 node types)
|
||||
("Total constraints >= 74",
|
||||
# Watson emotional-memory samples (v2.2.0)
|
||||
("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",
|
||||
lambda r: len(list(r)) >= 74),
|
||||
lambda r: len(list(r)) >= 79),
|
||||
]
|
||||
|
||||
if include_schema_tests:
|
||||
@@ -523,7 +556,7 @@ class LifeGraphSchema:
|
||||
RETURN b.id AS id
|
||||
"""),
|
||||
|
||||
# ── Personal: Sample goal (Seneca) ───────────────────────
|
||||
# ── Personal: Sample goal (Watson) ───────────────────────
|
||||
("Goal:goal_sample_2025", """
|
||||
MERGE (g:Goal {id: 'goal_sample_2025'})
|
||||
ON CREATE SET g.created_at = datetime()
|
||||
@@ -556,6 +589,40 @@ class LifeGraphSchema:
|
||||
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 ──────────────────────────────────
|
||||
("Client:client_sample_corp", """
|
||||
MERGE (c:Client {id: 'client_sample_corp'})
|
||||
@@ -563,6 +630,7 @@ class LifeGraphSchema:
|
||||
SET c.name = 'Sample Corp',
|
||||
c.industry = 'Technology',
|
||||
c.status = 'prospect',
|
||||
c.domain = 'work',
|
||||
c.updated_at = datetime()
|
||||
RETURN c.id AS id
|
||||
"""),
|
||||
@@ -642,6 +710,8 @@ class LifeGraphSchema:
|
||||
("PURSUING", "Person", "user_main", "Goal", "goal_sample_2025"),
|
||||
("EXPLORES", "Book", "book_meditations_aurelius", "Topic", "topic_stoicism"),
|
||||
("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
|
||||
@@ -688,31 +758,36 @@ Event Significant occurrences (celebrations, conferences)
|
||||
Topic Subjects of interest (stoicism, AI in CX)
|
||||
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
|
||||
Hypatia (Learning) Book, Author, LearningPath, Concept, Quote
|
||||
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
|
||||
Bowie (Culture) Music, Film, Artwork, Playlist, Artist, Style
|
||||
David (Culture) Music, Film, Artwork, Playlist, Artist, Style
|
||||
Cousteau (Nature) Species, Plant, Tank, Garden, Ecosystem, Observation
|
||||
Garth (Finance) Account, Investment, Asset, Liability, Budget, FinancialGoal
|
||||
Cristiano (Football) Match, Team, League, Tournament, Player, Season
|
||||
|
||||
WORK TEAM:
|
||||
WORK TEAM (Mentor):
|
||||
────────────────────────────────────────────────────────────────
|
||||
Alan (Strategy) Client, Vendor, Competitor, MarketTrend, Technology, Decision
|
||||
Ann (Marketing) Content, Publication, Topic, Event
|
||||
Jeffrey (Sales) Contact, Opportunity, Proposal, Meeting
|
||||
Jarvis (Execution) Task, Meeting, Note, Decision, Project
|
||||
Ann (Marketing) Content, Publication, Topic, Event (domain='work')
|
||||
Jeffrey (Sales) Contact (domain='work'), Opportunity, Proposal, Meeting
|
||||
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
|
||||
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):
|
||||
────────────────────────────────────────────────────────────────
|
||||
@@ -723,8 +798,9 @@ Infrastructure -[HOSTS]-> Project (Engineering ↔ Work)
|
||||
Prototype -[SUPPORTS]-> Opportunity (Engineering ↔ Work)
|
||||
Project -[GENERATES_REVENUE]-> Account (Work ↔ Personal)
|
||||
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)
|
||||
@@ -858,7 +934,7 @@ def main():
|
||||
schema.document_schema()
|
||||
|
||||
# Create constraints (includes automatic indexes)
|
||||
logger.info("Creating constraints (74 node types)...")
|
||||
logger.info("Creating constraints (79 node types)...")
|
||||
schema.create_constraints()
|
||||
|
||||
# Create additional indexes
|
||||
@@ -886,7 +962,7 @@ def main():
|
||||
|
||||
if test_success:
|
||||
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("\nNext steps:")
|
||||
logger.info(" 1. Import data (Plex, Calibre, etc.)")
|
||||
|
||||
Reference in New Issue
Block a user