docs(readme): update assistant roster, prompt layers, repo structure

- Update assistant lists (added Shawn, Watson, David, CASE, AWS SA; modified Scotty/Harper roles)
- Reflect new architecture layers: Tool Prompt Snippets and Shared Context
- Align repository structure diagram with current filesystem layout
This commit is contained in:
2026-05-20 22:50:22 -04:00
parent c1cc6e26c5
commit 703b3402d4
39 changed files with 1181 additions and 158 deletions

View File

@@ -0,0 +1,19 @@
## Neo4j Version Compatibility Notes
Neo4j had significant breaking changes between version 4.x and 5.x regarding schema introspection:
**Neo4j 5.x+ (current):**
- Use `SHOW INDEXES` instead of `CALL db.indexes()`
- Use `SHOW CONSTRAINTS` instead of `CALL db.constraints()`
- Use `CALL db.schema.visualization()` for full schema (works in both versions)
**Neo4j 4.x and earlier:**
- Use `CALL db.indexes()`
- Use `CALL db.constraints()`
**Safe queries that work across versions:**
- `CALL db.schema.visualization()` - Full schema visualization
- `CALL db.labels()` - Get all node labels
- `CALL db.relationshipTypes()` - Get all relationship types
When querying indexes or constraints, prefer the `SHOW` commands for Neo4j 5+ environments.

View File

@@ -0,0 +1,75 @@
# Neo4j Knowledge Graph — Engineering Team
You have access to a unified Neo4j knowledge graph shared across fifteen AI assistants (9 personal, 4 work, 2 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., `infra_neo4j_prod`, `proto_mcp_dashboard`)
4. **Always set timestamps**`created_at` on CREATE, `updated_at` on every SET
5. **Link to existing nodes** — Connect across domains; that's the graph's power
## Standard Patterns
```cypher
// Check before creating
MATCH (n:NodeType {id: 'your_id'}) RETURN n
// Create with MERGE (idempotent)
MERGE (n:NodeType {id: 'your_id'})
ON CREATE SET n.created_at = datetime()
SET n.name = 'Name', n.updated_at = datetime()
// Link to existing nodes
MATCH (a:TypeA {id: 'a_id'}), (b:TypeB {id: 'b_id'})
MERGE (a)-[:RELATIONSHIP]->(b)
```
## Engineering Node Ownership
| Assistant | Domain | Owns |
|-----------|--------|------|
| **Scotty** | Infrastructure & Ops | Infrastructure, Incident |
| **Harper** | Prototyping & Hacking | Prototype, Experiment |
### Scotty's Nodes
| Node | Required | Optional |
|------|----------|----------|
| Infrastructure | id, name, type | status, environment, host, version, notes |
| Incident | id, title, severity | status, date, root_cause, resolution, duration |
### Harper's Nodes
| Node | Required | Optional |
|------|----------|----------|
| Prototype | id, name | status, tech_stack, purpose, outcome, notes |
| Experiment | id, title | hypothesis, result, date, learnings, notes |
## Key Relationships
- Infrastructure -[DEPENDS_ON]-> Infrastructure
- Infrastructure -[HOSTS]-> Project | Prototype
- Incident -[AFFECTED]-> Infrastructure
- Incident -[CAUSED_BY]-> Infrastructure
- Prototype -[DEPLOYED_ON]-> Infrastructure
- Prototype -[SUPPORTS]-> Opportunity
- Prototype -[DEMONSTRATES]-> Technology
- Experiment -[LED_TO]-> Prototype
- Experiment -[VALIDATES]-> MarketTrend
- Prototype -[AUTOMATES]-> Habit | Task
## Cross-Team Reads
- **Work team:** Projects (infrastructure requirements), Opportunities (demo needs), Client SLAs
- **Personal team:** Habits (automation candidates), Goals (tooling support)
- **Universal nodes:** Person, Location, Event, Topic, Goal (shared by all)
## Scotty ↔ Harper Handoff
Harper builds and deploys; Scotty operates production and provisions resources. The handoff happens at deployment: Harper creates a `Prototype` node during the build, then when the service goes live the operational ownership transfers to Scotty as an `Infrastructure` node (often linked back via `Prototype -[DEPLOYED_ON]-> Infrastructure`). Use the messaging system to coordinate. See `docs/engineering/team.md` for the full responsibility matrix.
## Full Schema Reference
See `docs/tools/neo4j/unified-schema.md` for complete node definitions, all fields, and relationship types.

View File

@@ -0,0 +1,52 @@
# 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).
## 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`)
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'`
6. **Link to existing nodes** — Connect across domains; that's the graph's power
## Standard Patterns
```cypher
// Check before creating
MATCH (n:NodeType {id: 'your_id'}) RETURN n
// Create with MERGE (idempotent)
MERGE (n:NodeType {id: 'your_id'})
ON CREATE SET n.created_at = datetime()
SET n.name = 'Name', n.updated_at = datetime()
// Link to existing nodes
MATCH (a:TypeA {id: 'a_id'}), (b:TypeB {id: 'b_id'})
MERGE (a)-[:RELATIONSHIP]->(b)
```
## Your Team's Node Ownership
| Assistant | Domain | Owns |
|-----------|--------|------|
| **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 |
| **Bourdain** | Food & Cooking | Recipe, Restaurant, Ingredient, Meal, Technique |
| **Bowie** | Arts & Culture | Music, Film, Artwork, Playlist, Artist, Style |
| **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 |
## 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)
## Full Schema Reference
See `docs/tools/neo4j/unified-schema.md` for complete node definitions, all fields, and relationship types.

149
docs/tools/neo4j/shared.md Normal file
View File

@@ -0,0 +1,149 @@
# Shared Tools & Infrastructure
## User
You are assisting **Robert Helewka**. Address him as Robert. His node in the Neo4j knowledge graph is `Person {id: "user_main", name: "Robert"}`.
## Your Toolbox (MCP Servers)
MCP tool discovery tells you what each tool does at runtime. This table gives you the operational context that tool descriptions don't:
| Server | Purpose | Location |
|--------|---------|----------|
| **korax** | Shell execution + file operations (Kernos) — primary workbench | korax.helu.ca |
| **neo4j** | Knowledge graph (Cypher queries) | ariel.incus |
| **gitea** | Git repository management | miranda.incus |
| **argos** | Web search + webpage fetching | miranda.incus |
| **rommie** | Computer automation (Agent S, MATE desktop) | caliban.incus |
| **github** | GitHub Copilot MCP | api.githubcopilot.com |
| **context7** | Library/framework documentation lookup | local (npx) |
| **time** | Current time and timezone | local |
**Korax is your workbench.** For shell commands and file operations, use Korax (Kernos MCP). Call `get_shell_config` first to see what commands are whitelisted.
Use the `time` server to check the current date when temporal context matters.
> **Note:** Not every assistant has every server. Your available servers are listed in your FastAgent config.
## Agathos Sandbox
You work within Agathos — a set of Incus containers (LXC) on a 10.10.0.0/24 network, named after moons of Uranus. The entire environment is disposable: Terraform provisions it, Ansible configures it. It can be rebuilt trivially.
Key hosts: ariel (Neo4j), miranda (MCP servers), oberon (Docker/SearXNG), portia (PostgreSQL), prospero (monitoring), puck (apps), sycorax (LLM proxy), caliban (agent automation), titania (HAProxy/SSO).
## Inter-Assistant Graph Messaging
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`.
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.
### 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:<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,
n.created_at AS sent_at
ORDER BY n.created_at DESC
```
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 $ids
SET n.tags = [tag IN n.tags WHERE tag <> 'inbox'] + ['read'],
n.updated_at = datetime()
```
If no messages were returned, skip the write entirely.
Acknowledge messages naturally in conversation. If `action_required: true`,
prioritize addressing the request.
### 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: $id})
ON CREATE SET n.created_at = datetime()
SET n.title = $title,
n.date = date(),
n.type = 'assistant_message',
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** | 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.

File diff suppressed because it is too large Load Diff

301
docs/tools/neo4j/utils.md Normal file
View File

@@ -0,0 +1,301 @@
# Neo4j Utility Scripts
> Documentation for the database management scripts in `utils/`
---
## Scripts Overview
| Script | Purpose | Destructive? |
|--------|---------|:------------:|
| `neo4j-schema-init.py` | Create constraints, indexes, and sample data | No (idempotent) |
| `neo4j-reset.py` | Wipe all data, constraints, and indexes | **Yes** |
| `neo4j-validate.py` | Comprehensive validation report | No (read-only) |
---
## neo4j-schema-init.py
Creates the foundational schema for the unified knowledge graph: 74 uniqueness constraints, ~94 performance indexes, and 12 sample nodes with 5 cross-domain relationships.
### Usage
```bash
# Interactive — prompts for URI, user, password
python utils/neo4j-schema-init.py
# Specify URI (will prompt for user/password)
python utils/neo4j-schema-init.py --uri bolt://ariel.incus:7687
# Skip sample data creation
python utils/neo4j-schema-init.py --uri bolt://ariel.incus:7687 --skip-samples
# Test-only mode (no schema changes)
python utils/neo4j-schema-init.py --uri bolt://ariel.incus:7687 --test-only
# Quiet mode
python utils/neo4j-schema-init.py --uri bolt://ariel.incus:7687 --quiet
```
### What It Creates
1. **74 uniqueness constraints** — one per node type, on the `id` property
2. **~94 performance indexes** — on name/title, date, type/status/category, and domain fields
3. **12 sample nodes** — spanning all three teams (Personal, Work, Engineering)
4. **5 sample relationships** — demonstrating cross-domain connections
### Idempotent
Safe to run multiple times. Uses `IF NOT EXISTS` for constraints/indexes and `MERGE` for sample data.
---
## neo4j-reset.py
Wipes the database clean. Drops all constraints, indexes, nodes, and relationships.
### Usage
```bash
# Interactive — will prompt for confirmation
python utils/neo4j-reset.py --uri bolt://ariel.incus:7687
# Skip confirmation prompt
python utils/neo4j-reset.py --uri bolt://ariel.incus:7687 --force
```
### What It Does
1. Reports current database contents (node/relationship/constraint/index counts)
2. Drops all constraints
3. Drops all non-lookup indexes
4. Deletes all nodes and relationships (batched for large databases)
5. Verifies the database is clean
### Safety
- Requires typing `yes` to confirm (unless `--force`)
- Shows before/after counts so you know exactly what was removed
---
## neo4j-validate.py
Generates a comprehensive validation report. Share the output to verify the graph is correctly built.
### Usage
```bash
python utils/neo4j-validate.py --uri bolt://ariel.incus:7687
```
### What It Checks
| Section | What's Validated |
|---------|-----------------|
| **Connection** | Database reachable, APOC plugin available |
| **Constraints** | All 74 uniqueness constraints present, no extras |
| **Indexes** | Total count, spot-check of 11 key indexes |
| **Node Labels** | No unexpected labels (detects junk from Memory server, etc.) |
| **Sample Nodes** | All 12 sample nodes exist with correct properties |
| **Sample Relationships** | All 5 cross-domain relationships exist |
| **Relationship Summary** | Total count and breakdown by type |
| **Node Summary** | Total count and breakdown by label |
### Expected Clean Output
```
═════════════════════════════════════════════════════════════════
VALIDATION REPORT — Koios Unified Knowledge Graph
═════════════════════════════════════════════════════════════════
Schema Version: 2.1.0
...
RESULT: ALL 23 CHECKS PASSED ✓
═════════════════════════════════════════════════════════════════
```
---
## Standard Workflow
### Fresh Setup / Clean Slate
```bash
# 1. Wipe everything
python utils/neo4j-reset.py --uri bolt://ariel.incus:7687
# 2. Build schema and sample data
python utils/neo4j-schema-init.py --uri bolt://ariel.incus:7687
# 3. Validate
python utils/neo4j-validate.py --uri bolt://ariel.incus:7687
```
### Routine Validation
```bash
python utils/neo4j-validate.py --uri bolt://ariel.incus:7687
```
### Environment Variables
All three scripts support environment variables to avoid repeated prompts:
```bash
export NEO4J_URI="bolt://ariel.incus:7687"
export NEO4J_USER="neo4j"
export NEO4J_PASSWORD="your-password"
# Then just:
python utils/neo4j-reset.py --force
python utils/neo4j-schema-init.py --skip-docs
python utils/neo4j-validate.py
```
---
## Neo4j Python Driver — Lessons Learned
These patterns were discovered during development and are critical for anyone writing Cypher through the Neo4j Python driver (v5.x / v6.x).
### 1. Use Explicit Transactions for Writes
**Problem:** `session.run()` uses auto-commit transactions that don't reliably commit writes in the Neo4j Python driver 5.x+. Results must be fully consumed or the transaction may not commit.
**Bad — silently fails to persist:**
```python
with driver.session() as session:
session.run("CREATE (n:Person {id: 'test'})")
# Transaction may not commit!
```
**Good — explicit transaction with context manager:**
```python
with driver.session() as session:
with session.begin_transaction() as tx:
tx.run("CREATE (n:Person {id: 'test'})")
# Auto-commits when context exits normally
# Auto-rolls back on exception
```
**Also good — managed write transaction:**
```python
def create_person_tx(tx, name):
result = tx.run("CREATE (a:Person {name: $name}) RETURN a.id AS id", name=name)
record = result.single()
return record["id"]
with driver.session() as session:
node_id = session.execute_write(create_person_tx, "Alice")
```
### 2. Cypher MERGE Clause Ordering
**Problem:** `ON CREATE SET` must come immediately after `MERGE`, before any general `SET` clause. Placing `SET` before `ON CREATE SET` causes a syntax error.
**Bad — syntax error:**
```cypher
MERGE (p:Person {id: 'user_main'})
SET p.name = 'Main User',
p.updated_at = datetime()
ON CREATE SET p.created_at = datetime() -- ERROR: Invalid input 'ON'
```
**Good — correct clause order:**
```cypher
MERGE (p:Person {id: 'user_main'})
ON CREATE SET p.created_at = datetime()
SET p.name = 'Main User',
p.updated_at = datetime()
```
The full MERGE clause order is:
```
MERGE (pattern)
ON CREATE SET ... ← only runs when node is first created
ON MATCH SET ... ← only runs when node already exists (optional)
SET ... ← always runs
```
### 3. Consume Results in Transactions
**Problem:** In managed transactions (`execute_write`), results must be consumed within the transaction function. Unconsumed results can cause issues.
**Good pattern:**
```python
def create_node_tx(tx, node_id):
result = tx.run("MERGE (n:Person {id: $id}) RETURN n.id AS id", id=node_id)
record = result.single() # Consumes the result
return record["id"]
```
### 4. MATCH Returns No Rows ≠ Error
**Problem:** If a `MATCH` clause finds nothing, the query succeeds with zero rows — it does **not** raise an error. This means `MERGE` on a relationship after a failed `MATCH` silently does nothing.
```cypher
-- If person_xyz doesn't exist, this returns 0 rows (no error)
MATCH (p:Person {id: 'person_xyz'})
MATCH (b:Book {id: 'book_abc'})
MERGE (p)-[:COMPLETED]->(b)
-- Zero rows processed, zero relationships created, zero errors
```
**Mitigation:** Always check `result.single()` for `None` to detect this case:
```python
record = result.single()
if record is None:
logger.error("Endpoints not found — no relationship created")
```
### 5. Separate Node and Relationship Transactions
**Problem:** Creating nodes and then matching them for relationships in the same auto-commit transaction can fail because the nodes aren't visible yet within the same transaction scope.
**Good pattern:** Create all nodes in one explicit transaction (commit), then create relationships in a separate explicit transaction:
```python
# Transaction 1: Create nodes
with session.begin_transaction() as tx:
for query in node_queries:
tx.run(query)
# Auto-commits on exit
# Transaction 2: Create relationships (nodes now visible)
with session.begin_transaction() as tx:
for query in relationship_queries:
tx.run(query)
# Auto-commits on exit
```
### 6. MCP Memory Server vs Neo4j Cypher Server
**Problem:** The MCP Memory server (`@modelcontextprotocol/server-memory`) and Neo4j Cypher MCP server can both connect to the same Neo4j instance, but they use completely different data models.
| | Memory Server | Cypher Server |
|---|---|---|
| **Schema** | Fixed: `name`, `type`, `observations` | Your full custom schema |
| **Node labels** | `Memory`, `reference` | Your 74 defined types |
| **Relationships** | Simple string pairs | Rich typed relationships |
| **Query language** | API calls (`search_nodes`) | Full Cypher |
**Resolution:** If you have a custom Neo4j schema, use **only** the Cypher MCP server. Remove the Memory server to prevent it from polluting your graph with its own primitive node types.
---
## Dependencies
```
pip install neo4j
```
All three scripts require the `neo4j` Python package. APOC is optional but recommended (the init script's test suite checks for it).
---
## Version History
| Date | Change |
|------|--------|
| 2025-01-07 | Initial `neo4j-schema-init.py` |
| 2026-02-17 | Added `neo4j-reset.py` and `neo4j-validate.py` |
| 2026-02-17 | Fixed init script: explicit transactions, correct MERGE clause ordering |

57
docs/tools/neo4j/work.md Normal file
View File

@@ -0,0 +1,57 @@
# Neo4j Knowledge Graph — Work Team
You have access to a unified Neo4j knowledge graph shared across fifteen AI assistants (9 personal, 4 work, 2 engineering).
## Principles
1. **Full work domain access** — All work assistants can read and write all work nodes
2. **Always MERGE on `id`** — Check before creating to avoid duplicates
3. **Use consistent IDs** — Format: `{type}_{identifier}_{qualifier}` (e.g., `client_acme_corp`, `opp_acme_cx_2025`)
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'`
6. **Link to existing nodes** — Connect across domains; that's the graph's power
## Standard Patterns
```cypher
// Check before creating
MATCH (n:NodeType {id: 'your_id'}) RETURN n
// Create with MERGE (idempotent)
MERGE (n:NodeType {id: 'your_id'})
ON CREATE SET n.created_at = datetime()
SET n.name = 'Name', n.updated_at = datetime()
// Link to existing nodes
MATCH (a:TypeA {id: 'a_id'}), (b:TypeB {id: 'b_id'})
MERGE (a)-[:RELATIONSHIP]->(b)
```
## Work Node Types
| Category | Nodes |
|----------|-------|
| **Business** | Client, Contact, Opportunity, Proposal, Project |
| **Market Intelligence** | Vendor, Competitor, MarketTrend, Technology |
| **Content & Visibility** | Content, Publication |
| **Professional Development** | Skill, Certification, Relationship |
| **Daily Operations** | Task, Meeting, Note, Decision |
## Assistant Focus Areas
| Assistant | Primary Focus | Key Nodes |
|-----------|--------------|-----------|
| **Alan** | Strategy & Business Model | Client, Vendor, Competitor, MarketTrend, Decision |
| **Ann** | Marketing & Visibility | Content, Publication, Topic |
| **Jeffrey** | Proposals & Sales | Opportunity, Proposal, Contact |
| **Jarvis** | Daily Execution | Task, Meeting, Note |
## Cross-Team Reads
- **Personal team:** Books (for skill development), Trips (for client travel), Goals (for career alignment)
- **Engineering:** Infrastructure (hosting projects), Prototypes (for client demos)
- **Universal nodes:** Person, Location, Event, Topic, Goal (shared by all)
## Full Schema Reference
See `docs/tools/neo4j/unified-schema.md` for complete node definitions, all fields, and relationship types.