Rules & Relations
Rules are declarative specifications that create relationships between entities across different systems in your graph. They run automatically on triggers or on demand, and are the primary way SixDegree connects data from separate tools.
Where relations come from
SixDegree creates relations from two distinct sources.
Intra-molecule relations are created automatically by molecules within their own domain. You don't configure these. They're intrinsic to the source system:
- Salesforce molecule:
SalesforceOpportunity --belongs_to--> SalesforceAccount - Zendesk molecule:
ZendeskTicket --assigned_to--> ZendeskUser - PagerDuty molecule:
PagerDutyIncident --on_escalation_policy--> PagerDutyEscalationPolicy
Inter-molecule relations are created by rules you configure. These cross system boundaries:
ZendeskTicket --escalated_to--> PagerDutyIncidentStripeSubscription --renews--> SalesforceAccountZendeskTicket --affects--> SalesforceAccountPagerDutyIncident --affects--> KubernetesDeployment
This separation keeps molecules loosely coupled. A Stripe molecule doesn't need to understand Salesforce; you configure the cross-system relationship using a rule that matches your conventions.
Molecules may suggest inter-molecule rules based on common patterns, but you decide which cross-system relationships are created.
Rule structure
Rules use a Kubernetes-style YAML format with five main sections: trigger, source, target, relation, and lifecycle.
apiVersion: sixdegree.ai/v1
kind: Rule
metadata:
name: ticket-affects-account
spec:
enabled: true
priority: 100
trigger:
on: discovery.completed
source:
kind: ZendeskTicket
match: all
target:
kind: SalesforceAccount
match: pattern
query: 'target.spec.name == source.labels["organization"]'
relation:
type: AFFECTS
attributes:
inferred: "true"
onDelete: keep
Triggers
Triggers define when a rule is evaluated.
| Trigger | When it fires |
|---|---|
discovery.completed | After a molecule finishes a discovery run |
entity.created | When a new entity is added to the graph |
entity.updated | When an entity's attributes change |
entity.deleted | When an entity is removed |
relation.created | When a new relation is created |
relation.deleted | When a relation is removed |
manual | Only when explicitly triggered via CLI |
Event-based trigger
trigger:
on: entity.created
match:
kind: ZendeskTicket
labels:
status: open
Manual trigger
trigger:
on: manual
Most pattern-based rules should use discovery.completed. Use manual for explicit mappings that rarely change, such as an account managing a fixed set of subscriptions.
Source matching
The source section defines which entities the rule starts from.
| Mode | Description |
|---|---|
all | Every entity of the specified kind |
pattern | Entities matching a CEL expression |
specific | An explicitly listed set of entities |
All entities of a kind
source:
kind: ZendeskTicket
match: all
Pattern matching
source:
kind: SalesforceAccount
match: pattern
query: 'source.labels["segment"] == "enterprise"'
Specific entities
source:
kind: SalesforceAccount
match: specific
entities:
- name: Acme Corp
- name: Globex
Target matching
The target section defines which entities to link to. It uses the same three match modes as source.
Pattern-based target
target:
kind: SalesforceAccount
match: pattern
query: 'target.spec.name == source.labels["organization"]'
Specific targets
target:
kind: StripeSubscription
match: specific
entities:
- name: sub_acme_platform
- name: sub_acme_support
- name: sub_acme_usage
Relations
The relation section defines what relationship to create between matched source and target entities.
Relation types
| Type | Meaning |
|---|---|
OWNS | Ownership or management |
BELONGS_TO | Membership in a parent record |
RENEWS | A subscription renews an account |
ESCALATED_TO | A ticket escalates to an incident |
AFFECTS | One record affects another |
DEPENDS_ON | Dependency |
RELATED_TO | General association |
You can define custom relation types based on your domain conventions.
Static attributes
Relations can carry arbitrary attributes for context:
relation:
type: OWNS
attributes:
since: "2024-01-15"
priority: high
notes: "Primary account for the enterprise segment"
Every relation automatically gets created_at (timestamp) and created_by (one of rule:{name}, user:{id}, or molecule:{name}).
Computed attributes
Attribute values can be computed from source or target entity fields using CEL template expressions:
relation:
type: AFFECTS
attributes:
ticket_id: '{{ source.labels["id"] }}'
account_name: '{{ target.spec.name }}'
Lifecycle
onDelete behavior
When a rule is deleted, the onDelete field controls what happens to the relations it created.
| Value | Behavior |
|---|---|
keep | Relations persist after rule deletion |
cascade | Relations are deleted with the rule |
onDelete: cascade
Using cascade on a rule that matched thousands of entity pairs will delete all those relations when the rule is removed. Use keep for inferred relations you want to retain as permanent facts in the graph.
Idempotency
Rules are idempotent by default. Running a rule multiple times won't create duplicate relations.
RuleSets
A RuleSet groups related rules together. Use RuleSets when rules belong to the same integration, should be enabled or disabled together, or are versioned as a unit.
apiVersion: sixdegree.ai/v1
kind: RuleSet
metadata:
name: revenue-health-rules
labels:
source: molecule/salesforce
version: "1.2.0"
rules:
- name: ticket-affects-account
spec:
trigger:
on: discovery.completed
source:
kind: ZendeskTicket
match: all
target:
kind: SalesforceAccount
match: pattern
query: 'target.spec.name == source.labels["organization"]'
relation:
type: AFFECTS
- name: subscription-renews-account
spec:
trigger:
on: discovery.completed
source:
kind: StripeSubscription
match: all
target:
kind: SalesforceAccount
match: pattern
query: 'target.metadata.name == source.spec.account'
relation:
type: RENEWS
Molecule-provided rules
Molecules can ship default RuleSets that are installed when the molecule is configured. You can enable or disable the whole set, and they upgrade when the molecule updates. User-defined rules always take precedence.
CEL expressions
Rules use CEL (Common Expression Language) for pattern matching and computed attribute values.
Available variables
| Variable | Available in | Description |
|---|---|---|
source | Source queries, target queries, attributes | The source entity |
target | Target queries, attributes | The target entity |
entity | Trigger conditions | The entity that fired the trigger |
Entity field paths
// Metadata
entity.metadata.name
entity.metadata.createdAt
// Labels
entity.labels["key"]
// Spec (entity-specific fields)
entity.spec.title
entity.spec.url
entity.spec.status
String functions
// Substring check
target.spec.name.contains("Acme")
// Prefix / suffix
source.metadata.name.startsWith("enterprise-")
target.spec.plan.endsWith("-annual")
// Regex matching (RE2 syntax)
source.labels["id"].matches("^TICKET-[0-9]+$")
target.spec.name.matches(".*Corp$")
Comparison and logic
// Equality
source.labels["segment"] == "enterprise"
// Numeric comparison
entity.spec.priority > 5
// Boolean logic
source.spec.status == "open" && target.spec.renewed == false
Common patterns
Link tickets to accounts by organization name:
target.spec.name == source.labels["organization"]
Match records by naming convention:
target.metadata.name.startsWith(source.spec.prefix + "-")
Match by shared label:
target.labels["segment"] == source.labels["segment"]
Test CEL expressions with sixdegree apply --dry-run before applying them. The dry-run output shows which entity pairs would be matched without writing any relations.
Full examples
Pattern-based: ticket to account
Link Zendesk tickets to Salesforce accounts where the account name matches the ticket's organization.
apiVersion: sixdegree.ai/v1
kind: Rule
metadata:
name: ticket-affects-account
spec:
enabled: true
trigger:
on: discovery.completed
source:
kind: ZendeskTicket
match: all
target:
kind: SalesforceAccount
match: pattern
query: 'target.spec.name == source.labels["organization"]'
relation:
type: AFFECTS
attributes:
inferred: "true"
onDelete: keep
Explicit: account owns subscriptions
An account explicitly owns a fixed set of subscriptions.
apiVersion: sixdegree.ai/v1
kind: Rule
metadata:
name: account-owns-subscriptions
spec:
trigger:
on: manual
source:
kind: SalesforceAccount
match: specific
entities:
- name: Acme Corp
target:
kind: StripeSubscription
match: specific
entities:
- name: sub_acme_platform
- name: sub_acme_support
- name: sub_acme_usage
relation:
type: OWNS
attributes:
notes: "Core enterprise subscriptions"
onDelete: cascade
Direct link: single relation
A single service is owned by a specific account.
apiVersion: sixdegree.ai/v1
kind: Rule
metadata:
name: payments-service-owned-by-acme
spec:
trigger:
on: manual
source:
kind: KubernetesDeployment
match: specific
entities:
- name: payments-service
target:
kind: SalesforceAccount
match: specific
entities:
- name: Acme Corp
relation:
type: OWNED_BY
onDelete: cascade
CLI usage
# Apply rules from a file
sixdegree apply -f rules.yaml
# Preview what relations would be created without writing them
sixdegree apply --dry-run -f rules.yaml
# List all rules
sixdegree get rules
# Get a specific rule
sixdegree get rule ticket-affects-account
# Run a manual rule
sixdegree run rule account-owns-subscriptions
# Delete a rule
sixdegree delete rule ticket-affects-account
# List rulesets
sixdegree get rulesets
# Disable a ruleset
sixdegree disable ruleset revenue-health-rules
Best practices
- Name rules descriptively. The name should explain what relationship the rule creates, not how it works.
- Prefer pattern matching over explicit lists. Pattern-based rules scale automatically as new entities are discovered.
- Group with RuleSets. Rules that belong to the same integration or should be toggled together should live in a RuleSet.
- Match
onDeleteto intent. Usecascadefor explicit mappings; usekeepfor inferred relations you want to survive rule changes. - Comment complex CEL. Add a YAML comment above any non-obvious query expression.
Next steps
- Entities: understand the entity model that rules operate on
- Molecules: see how molecules provide the intra-molecule relations that rules extend
- Ontology: explore how entity kinds and relation types are defined
- Graph: see how rules and relations build the connected graph
- CLI reference: full command reference for
sixdegree apply,get,run, anddelete