Sagittarius Knowledge Graph
Sagittarius is the built-in knowledge graph that automatically builds a persistent model of your organization as you use the API. Every API operation enriches the graph with entities and relationships.
Why a Knowledge Graph?
Traditional APIs are transactional - you ask for data, you get data, it's forgotten. But understanding your organization requires context:
- Who authored this PR?
- What issues are assigned to Alice?
- Which repos had deployments this week?
- How do these projects relate to each other?
Sagittarius answers these questions by maintaining a persistent graph of entities and their relationships.
How It Works
┌─────────────────────────────────────────────────────────────────┐
│ API Request │
│ POST /mcp/jira/execute {"tool": "list_issues"} │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────┐
│ Jira Adapter │
│ Fetches data │
└────────┬────────┘
│
┌──────────────┴──────────────┐
▼ ▼
┌─────────────────┐ ┌─────────────────────┐
│ Return response │ │ Sagittarius Bridge │
│ to caller │ │ │
└─────────────────┘ │ For each issue: │
│ → Create Issue node │
│ → Create User nodes │
│ → Create edges │
│ → Log activity │
└──────────┬──────────┘
│
▼
┌─────────────────────┐
│ Redis (DB 1) │
│ Persistent storage │
└─────────────────────┘
Key insight: The graph builds passively as you use the API. No separate sync jobs, no ETL pipelines.
Entity Types
| Node Type | Source | Key Properties |
|---|---|---|
user | GitHub, Jira | login, name, email, account_id |
repository | GitHub | full_name, language, description |
pull_request | GitHub | number, title, state, author |
issue | Jira | key, summary, status, priority |
project | Jira | key, name, lead |
page | Confluence | id, title, space_key |
deployment | GitHub | id, environment, status |
notion_page | Notion | id, title, database_id |
notion_database | Notion | id, title |
Relationship Types
| Edge Type | From | To | Meaning |
|---|---|---|---|
AUTHORED_BY | PR, Issue, Page | User | Who created it |
ASSIGNED_TO | Issue | User | Who's working on it |
BELONGS_TO | PR, Issue, Page | Repo, Project, Space | Containment |
DEPLOYED_TO | Deployment | Repository | Where deployed |
CREATED_BY | Project | User | Project lead |
CONTRIBUTES_TO | User | Repo, Project | Contribution |
LINKED_TO | Issue, Page | Issue, PR | Cross-references |
API Endpoints
Get Entity
POST /graph/entity
{
"entity_type": "user",
"entity_id": "alice"
}
Returns the node with all properties.
Traverse Graph
POST /graph/traverse
{
"entity_type": "user",
"entity_id": "alice",
"depth": 2,
"direction": "both"
}
Returns all nodes and edges within N hops of the starting node.
Response:
{
"success": true,
"data": {
"nodes": [
{"node_type": "user", "node_id": "alice", "properties": {...}},
{"node_type": "pull_request", "node_id": "org/repo/123", "properties": {...}},
{"node_type": "repository", "node_id": "org/repo", "properties": {...}}
],
"edges": [
{"from_node": "pull_request:org/repo/123", "to_node": "user:alice", "edge_type": "AUTHORED_BY"},
{"from_node": "pull_request:org/repo/123", "to_node": "repository:org/repo", "edge_type": "BELONGS_TO"}
]
}
}
Search Entities
POST /graph/search
{
"entity_type": "issue",
"filters": {"status": "In Progress"},
"limit": 50
}
Returns entities matching the filter criteria.
Find Path
POST /graph/find-path
{
"from_type": "user",
"from_id": "alice",
"to_type": "repository",
"to_id": "org/api",
"max_depth": 5
}
Returns the shortest path between two entities.
Activity Feed
GET /graph/feed?limit=50
Returns recent activity across all entities.
Entity Activity
POST /graph/activity
{
"entity_type": "user",
"entity_id": "alice",
"limit": 20
}
Returns activity timeline for a specific entity.
Graph Stats
GET /graph/stats
Returns counts by entity type and total edges.
Response:
{
"success": true,
"data": {
"total_nodes": 156,
"total_edges": 423,
"nodes_by_type": {
"user": 15,
"repository": 8,
"pull_request": 45,
"issue": 67,
"project": 5,
"deployment": 16
}
}
}
Graph Visualizer
Interactive web UI for exploring the knowledge graph.
URL: http://localhost:3007/graph/visualizer
Features
- Entity Type Selection: Pick one type or "All Types"
- Entity ID Modes: All, Single, or Multi-select
- Depth Control: 1-3 hops or all connections
- Quick Actions: Toggle entity types to combine
- Cypher-like Queries: Write graph queries
- Activity Feed: See recent operations
- Stats Dashboard: Node and edge counts
Query Syntax
// Find user with relationships
MATCH (u:user) WHERE u.id = 'alice'
// Find all entities of type
MATCH (n:repository)
// Relationship query
MATCH (u:user)-[r]-(e) WHERE u.id = 'bob'
// Path finding
PATH FROM user:alice TO repository:acme/api
Activity Logging
Every MCP execution is automatically logged:
# Automatic logging in MCP layer
await bridge.record_activity(
action="mcp.create_issue",
actor_type="user",
actor_id="alice@company.com", # From JWT
target_type="issue",
target_id="PROJ-123",
context_type="tenant",
context_id="tenant-abc",
properties={
"system": "jira",
"tool": "create_issue",
"success": True
}
)
This creates a complete audit trail of who did what, when.
Persistence
Sagittarius uses Redis with full persistence:
# docker-compose.yml
redis:
command: redis-server --appendonly yes --save 60 1
volumes:
- ./data/redis:/data
Storage location: ./data/redis/
appendonly.aof- Transaction logdump.rdb- Periodic snapshots
Data survives container restarts and host reboots.
Bridge Methods
The Sagittarius Bridge provides typed methods for each entity:
from app.integrations.sagittarius_bridge import get_sagittarius_bridge
bridge = await get_sagittarius_bridge()
# Ingest entities
await bridge.on_user_fetched(user_data, source="github")
await bridge.on_repository_fetched(repo_data)
await bridge.on_pull_request_fetched(pr_data, repo_id)
await bridge.on_issue_fetched(issue_data)
await bridge.on_project_fetched(project_data)
await bridge.on_page_fetched(page_data)
await bridge.on_deployment_fetched(deploy_data, repo_id)
# Record activity
await bridge.record_activity(
action="reviewed",
actor_type="user",
actor_id="alice",
target_type="pull_request",
target_id="org/repo/123"
)
Auto-Entity Creation
When ingesting entities with relationships, Sagittarius automatically creates related entities to ensure relationship targets exist:
# When ingesting an issue:
# 1. Creates reporter user (if data available)
# 2. Creates assignee user (if data available)
# 3. Creates issue node
# 4. Creates edges: AUTHORED_BY, ASSIGNED_TO, BELONGS_TO
This ensures the graph is always consistent, even if you haven't explicitly fetched all related entities.
Use Cases
1. Context for AI Agents
"What PRs has Alice authored in the last week?"
→ Query: MATCH (u:user)-[:AUTHORED_BY]-(pr:pull_request) WHERE u.id = 'alice'
2. Impact Analysis
"What's connected to this repository?"
→ Traverse from repository with depth=2
3. Audit Trail
"Who modified this project's issues?"
→ GET /graph/activity for project entity
4. Cross-System Correlation
"Show all entities related to user alice across all systems"
→ Traverse from user node, includes GitHub PRs, Jira issues, Confluence pages
5. Onboarding Context
"What does the new hire need to know about?"
→ Traverse from their user node to see assigned issues, relevant repos
Architecture
/sagittarius # Standalone package
├── core/
│ ├── models.py # Node, Edge, NodeRef, Activity
│ ├── schema.py # NodeType, EdgeType enums
│ └── exceptions.py # Custom errors
├── storage/
│ ├── base.py # Storage interface
│ ├── redis_storage.py # Redis implementation
│ └── memory_storage.py # In-memory (for tests)
├── ingest/
│ ├── event_types.py # EntityCreated, ActivityRecorded
│ └── handlers.py # Event processing
├── service/
│ └── graph_service.py # Query operations, SagittariusClient
└── config.py # Configuration
Sagittarius is designed to be spun off as its own service - it has zero dependencies on the main app.
Configuration
Environment variables:
| Variable | Default | Description |
|---|---|---|
SAGITTARIUS_REDIS_URL | redis://localhost:6380/1 | Redis connection |
SAGITTARIUS_KEY_PREFIX | sag | Key prefix for all Redis keys |
SAGITTARIUS_FRESHNESS_TTL | 300 | Freshness check TTL (seconds) |
SAGITTARIUS_SYNC_INTERVAL | 900 | Background sync interval |
Related
- Architecture Overview - How Sagittarius fits in
- MCP Protocol - Tool execution that feeds the graph
- Deployment - Production setup with persistence