# Neo4j Graph RAG

> Query the Neo4j knowledge graph containing Fireflies call transcripts, Mattermost threads, HubSpot emails, and GitHub issues. Use when searching for business intelligence, finding past conversations, or answering questions about company knowledge.

- Skill: `shakudo-io/neo4j-graph-rag` (Agent Skill)
- Install (CLI): `npx skillmds@latest add shakudo-io/neo4j-graph-rag`
- Raw SKILL.md: https://api.skillmd.com/api/skills/shakudo-io/neo4j-graph-rag/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: AI & ML
- License: MIT
- Author: Shakudo-io (https://skillmd.com/u/shakudo-io)
- Updated: 2026-09-22
- Page: https://skillmd.com/skills/shakudo-io/neo4j-graph-rag

---


# Neo4j Graph RAG Query Skill

This skill teaches you how to query the Neo4j knowledge graph that powers the Shakudo business intelligence system.

## Prerequisites

- Neo4j MCP tools available (`neo4j_execute_query`, etc.)
- Connection to the knowledge graph database

## Data Sources in the Knowledge Graph

The knowledge graph aggregates data from 4 sources:

| Source | Node Label | Description |
|--------|------------|-------------|
| Fireflies | `Parent` | Call transcripts with speaker/company info |
| Mattermost | `MMThread` | Team chat threads and discussions |
| HubSpot | `EmailThread` | Customer email communications |
| GitHub | `GithubThread` | Issue discussions and PR comments |

## Schema Overview

### Parent Node (Fireflies Calls)

```cypher
(:Parent {
  id: String,           # Unique identifier
  title: String,        # Call/meeting title
  call_date: DateTime,  # When the call occurred
  company: String,      # Associated company name
  transcript: String,   # Full transcript text
  summary: String,      # AI-generated summary
  embedding: [Float]    # Vector embedding for similarity search
})
```

### MMThread Node (Mattermost)

```cypher
(:MMThread {
  id: String,
  channel_name: String,
  created_at: DateTime,
  content: String,
  embedding: [Float]
})
```

### EmailThread Node (HubSpot)

```cypher
(:EmailThread {
  id: String,
  subject: String,
  from_email: String,
  to_email: String,
  sent_at: DateTime,
  body: String,
  embedding: [Float]
})
```

### GithubThread Node (GitHub Issues)

```cypher
(:GithubThread {
  id: String,
  repo: String,
  issue_number: Integer,
  title: String,
  body: String,
  created_at: DateTime,
  embedding: [Float]
})
```

## Common Query Patterns

### 1. Vector Similarity Search (Recommended)

For semantic search across all data sources:

```cypher
// Search Fireflies calls by semantic similarity
CALL db.index.vector.queryNodes('parent_embedding', 10, $queryEmbedding)
YIELD node, score
RETURN node.title, node.company, node.call_date, score
ORDER BY score DESC
```

**Note**: You need to generate the query embedding using the same embedding model (stella_en_1.5b_v5 via Ollama).

### 2. Find Calls by Company

```cypher
MATCH (p:Parent)
WHERE p.company CONTAINS $companyName
RETURN p.title, p.call_date, p.summary
ORDER BY p.call_date DESC
LIMIT 10
```

### 3. Find Calls in Date Range

```cypher
MATCH (p:Parent)
WHERE p.call_date >= datetime($startDate)
  AND p.call_date <= datetime($endDate)
RETURN p.title, p.company, p.call_date
ORDER BY p.call_date DESC
```

### 4. Search Mattermost for Topic

```cypher
MATCH (m:MMThread)
WHERE m.content CONTAINS $searchTerm
RETURN m.channel_name, m.content, m.created_at
ORDER BY m.created_at DESC
LIMIT 20
```

### 5. Find Emails from/to Contact

```cypher
MATCH (e:EmailThread)
WHERE e.from_email CONTAINS $email OR e.to_email CONTAINS $email
RETURN e.subject, e.from_email, e.to_email, e.sent_at
ORDER BY e.sent_at DESC
LIMIT 20
```

### 6. Search GitHub Issues by Repo

```cypher
MATCH (g:GithubThread)
WHERE g.repo = $repoName
RETURN g.issue_number, g.title, g.created_at
ORDER BY g.created_at DESC
LIMIT 20
```

### 7. Cross-Source Search (All Data)

```cypher
// Search across all sources with text matching
MATCH (n)
WHERE (n:Parent OR n:MMThread OR n:EmailThread OR n:GithubThread)
  AND (
    n.content CONTAINS $searchTerm OR
    n.transcript CONTAINS $searchTerm OR
    n.body CONTAINS $searchTerm OR
    n.summary CONTAINS $searchTerm OR
    n.title CONTAINS $searchTerm
  )
RETURN labels(n)[0] AS source, 
       COALESCE(n.title, n.subject, 'Thread') AS title,
       COALESCE(n.call_date, n.created_at, n.sent_at) AS date
ORDER BY date DESC
LIMIT 20
```

## Using the Graph RAG API

The Graph RAG API at `http://graph-rag-api:8000` provides a higher-level interface:

```bash
curl -X POST http://graph-rag-api:8000/query \
  -H "Content-Type: application/json" \
  -d '{"query": "What did we discuss with Acme Corp last month?"}'
```

The API uses a SmolAgents CodeAgent that:
1. Generates embeddings for your query
2. Searches across all 4 data sources
3. Uses Cypher queries for structured filtering
4. Returns synthesized answers with source citations

## Execution Examples

### Direct Neo4j Query

```javascript
neo4j_execute_query({
  query: `
    MATCH (p:Parent)
    WHERE p.company CONTAINS $company
    RETURN p.title, p.summary, p.call_date
    ORDER BY p.call_date DESC
    LIMIT 5
  `,
  params: { company: "Acme" }
})
```

### Create a Node

```javascript
neo4j_create_node({
  label: "Note",
  properties: {
    content: "Important meeting note",
    created_at: new Date().toISOString()
  }
})
```

### Create a Relationship

```javascript
neo4j_create_relationship({
  fromNodeId: 123,
  toNodeId: 456,
  type: "MENTIONED_IN",
  properties: { context: "Sales discussion" }
})
```

## Best Practices

1. **Use parameterized queries**: Always use `$paramName` syntax to prevent injection
2. **Add LIMIT clauses**: Prevent returning too much data
3. **Use indexes**: Query on indexed properties (id, company, call_date) for performance
4. **Prefer vector search**: For semantic queries, vector similarity is more accurate than text matching
5. **Filter by date**: Narrow results by time range when possible

## Common Mistakes to Avoid

1. **Wrong node label**: Use `Parent` for Fireflies, not `Call` or `Transcript`
2. **Wrong date property**: Use `call_date` for Parent nodes, `created_at` for others
3. **Missing LIMIT**: Always limit results to avoid memory issues
4. **Case sensitivity**: Use `CONTAINS` for case-insensitive search, or `toLower()`

## Troubleshooting

### No results returned

1. Check node label spelling (case-sensitive)
2. Verify property names exist
3. Try broader search terms
4. Check date formats (use ISO 8601)

### Slow queries

1. Add LIMIT clause
2. Use indexed properties in WHERE
3. Avoid `CONTAINS` on large text fields
4. Use vector search instead of text matching

