Revenue Operations
Build an AI-powered revenue operations layer — pipeline intelligence, account scoring, deal risk, and rep coaching — all backed by a typed knowledge graph.
Your CRM holds records. Your data warehouse holds metrics. Your agents need a world model that connects them: accounts to signals, signals to deals, deals to people, people to interactions. That's a graph.
This guide walks through building a RevOps intelligence layer where specialized agents ingest signals, score accounts, flag deal risk, and surface coaching opportunities — each on its own branch, each auditable, each mergeable.
The ontology
node Account {
slug: String @key
name: String @index
domain: String? @unique
tier: enum(enterprise, mid_market, smb)
industry: enum(saas, fintech, health, infra, consumer, other)
arr: F64?
employee_count: I32?
health_score: F64?
}
node Contact {
slug: String @key
name: String @index
title: String? @index
email: String? @unique
seniority: enum(c_level, vp, director, manager, ic)
persona: enum(champion, evaluator, blocker, economic_buyer, end_user)
}
node Deal {
slug: String @key
name: String @index
stage: enum(prospecting, discovery, evaluation, negotiation, closed_won, closed_lost)
amount: F64?
close_date: Date?
risk: enum(low, medium, high, critical)?
created_at: Date
}
node Activity {
slug: String @key
type: enum(email, call, meeting, demo, proposal, follow_up)
subject: String @index
body: String? @index
sentiment: enum(positive, neutral, negative)?
occurred_at: DateTime
embedding: Vector(768)? @index
}
node Signal {
slug: String @key
type: enum(product_usage, intent_data, news, job_change, funding, churn_indicator, expansion_signal)
title: String @index
body: String?
strength: enum(strong, moderate, weak)
source: String
detected_at: DateTime
}
node Rep {
slug: String @key
name: String @index
role: enum(ae, sdr, csm, se, manager)
team: String
}
// Relationships
edge BelongsTo: Contact -> Account
edge Owns: Rep -> Deal @card(1..1)
edge Involves: Deal -> Account @card(1..1)
edge Participants: Deal -> Contact
edge Performed: Rep -> Activity
edge Regarding: Activity -> Contact
edge AboutDeal: Activity -> Deal
edge Indicates: Signal -> Account
edge TriggeredDeal: Signal -> Deal
// Competitive & organizational
edge ReportsTo: Contact -> Contact @card(0..1)
edge Champions: Contact -> Deal @card(0..1)Read this schema and the domain is self-evident. An agent seeing this ontology immediately understands: accounts have contacts, reps own deals, deals involve accounts, activities connect reps to contacts about deals, and signals flow from external sources into accounts and deals.
Load your data
{"type": "Account", "data": {"slug": "acme-corp", "name": "Acme Corp", "domain": "acme.com", "tier": "enterprise", "industry": "saas", "arr": 240000, "employee_count": 850}}
{"type": "Account", "data": {"slug": "globex", "name": "Globex Inc", "domain": "globex.io", "tier": "mid_market", "industry": "fintech", "arr": 48000, "employee_count": 120}}
{"type": "Contact", "data": {"slug": "jane-cto", "name": "Jane Torres", "title": "CTO", "email": "jane@acme.com", "seniority": "c_level", "persona": "champion"}}
{"type": "Contact", "data": {"slug": "mike-vpe", "name": "Mike Chen", "title": "VP Engineering", "email": "mike@acme.com", "seniority": "vp", "persona": "evaluator"}}
{"type": "Contact", "data": {"slug": "sarah-cfo", "name": "Sarah Kim", "title": "CFO", "email": "sarah@acme.com", "seniority": "c_level", "persona": "economic_buyer"}}
{"type": "Rep", "data": {"slug": "alex-ae", "name": "Alex Rivera", "role": "ae", "team": "enterprise-west"}}
{"type": "Deal", "data": {"slug": "acme-expansion", "name": "Acme Platform Expansion", "stage": "negotiation", "amount": 480000, "close_date": "2026-04-30", "risk": "medium", "created_at": "2026-01-15"}}
{"edge": "BelongsTo", "from": "jane-cto", "to": "acme-corp", "data": {}}
{"edge": "BelongsTo", "from": "mike-vpe", "to": "acme-corp", "data": {}}
{"edge": "BelongsTo", "from": "sarah-cfo", "to": "acme-corp", "data": {}}
{"edge": "Involves", "from": "acme-expansion", "to": "acme-corp", "data": {}}
{"edge": "Owns", "from": "alex-ae", "to": "acme-expansion", "data": {}}
{"edge": "Champions", "from": "jane-cto", "to": "acme-expansion", "data": {}}
{"edge": "Participants", "from": "acme-expansion", "to": "jane-cto", "data": {}}
{"edge": "Participants", "from": "acme-expansion", "to": "mike-vpe", "data": {}}
{"type": "Signal", "data": {"slug": "acme-hiring-surge", "type": "expansion_signal", "title": "Acme posted 12 engineering roles in 2 weeks", "strength": "strong", "source": "linkedin-monitor", "detected_at": "2026-03-25T10:00:00"}}
{"edge": "Indicates", "from": "acme-hiring-surge", "to": "acme-corp", "data": {}}
{"edge": "TriggeredDeal", "from": "acme-hiring-surge", "to": "acme-expansion", "data": {}}omnigraph init --schema revops.pg ./revops-graph
omnigraph load ./revops-graph --data revops.jsonlQueries your agents run
Pipeline risk dashboard
An analyst agent assesses which deals need attention:
query at_risk_pipeline() {
match {
$d: Deal
$d.stage != "closed_won"
$d.stage != "closed_lost"
$d involves $a
$rep owns $d
}
return {
$d.name, $d.stage, $d.amount, $d.close_date, $d.risk,
$a.name as account, $a.tier,
$rep.name as owner
}
order { $d.amount desc }
}[
{
"name": "Acme Platform Expansion",
"stage": "negotiation",
"amount": 480000,
"close_date": "2026-04-30",
"risk": "medium",
"account": "Acme Corp",
"tier": "enterprise",
"owner": "Alex Rivera"
}
]Missing champion detection
Deals without a champion are 3x more likely to stall:
query deals_without_champion() {
match {
$d: Deal
$d.stage != "closed_won"
$d.stage != "closed_lost"
$d.amount > 100000
$d involves $a
not { $_ champions $d }
}
return { $d.name, $d.stage, $d.amount, $a.name as account }
order { $d.amount desc }
}Good — the Acme deal has Jane Torres as champion. If she leaves or goes silent, the deal shows up here immediately.
Contact gap analysis
Which enterprise accounts are missing economic buyer engagement?
query accounts_without_economic_buyer() {
match {
$a: Account { tier: "enterprise" }
$d involves $a
$d.stage != "closed_won"
$d.stage != "closed_lost"
not {
$d participants $c
$c.persona = "economic_buyer"
}
}
return { $a.name, $d.name, $d.stage, $d.amount }
order { $d.amount desc }
}An SDR agent reads this result and knows exactly where to focus outreach.
Signal-enriched deal context
When a rep opens a deal, give them everything — the account, the contacts, the signals, the activity trail:
query deal_briefing($deal: String) {
match {
$d: Deal { slug: $deal }
$d involves $a
$d participants $c
$s triggeredDeal $d
}
return {
$d.name, $d.stage, $d.amount, $d.close_date,
$a.name as account, $a.arr, $a.tier,
$c.name as contact, $c.title, $c.persona,
$s.title as signal, $s.type as signal_type, $s.strength
}
}[
{
"name": "Acme Platform Expansion",
"stage": "negotiation",
"amount": 480000,
"close_date": "2026-04-30",
"account": "Acme Corp",
"arr": 240000,
"tier": "enterprise",
"contact": "Jane Torres",
"title": "CTO",
"persona": "champion",
"signal": "Acme posted 12 engineering roles in 2 weeks",
"signal_type": "expansion_signal",
"strength": "strong"
}
]One query. Full deal context. Typed and traceable.
Engagement velocity
How recently has the rep engaged with deal contacts?
query recent_activity($deal: String) {
match {
$d: Deal { slug: $deal }
$act aboutDeal $d
$rep performed $act
$act regarding $contact
}
return {
$act.type, $act.subject, $act.sentiment, $act.occurred_at,
$rep.name as rep,
$contact.name as contact, $contact.persona
}
order { $act.occurred_at desc }
limit 20
}An engagement scoring agent reads this and computes: days since last champion contact, ratio of positive to negative sentiment, meeting cadence. All from graph traversal.
Semantic activity search
Find past interactions about specific topics:
query find_relevant_conversations($deal: String, $topic: Vector(768)) {
match {
$d: Deal { slug: $deal }
$act aboutDeal $d
}
return { $act.subject, $act.type, $act.occurred_at }
order { nearest($act.embedding, $topic) }
limit 5
}"What conversations has the rep had about pricing?" — structure scopes to this deal, vector similarity finds the semantic match.
Multi-agent architecture
+----------+
| main |
+----+-----+
|
+-------------------+-------------------+
| | |
+------+------+ +-----+------+ +-------+-------+
| signal-agent| | risk-agent | | coaching-agent|
| | | | | |
| Reads: | | Reads: | | Reads: |
| - RSS feeds | | - Deals | | - Activities |
| - LinkedIn | | - Signals | | - Deal stage |
| - Intent | | - Contacts | | - Contact |
| | | | | engagement |
| Writes: | | Writes: | | |
| - Signal | | - Deal.risk| | Writes: |
| - Indicates | | - Account | | - Coaching |
| - Triggered | | .health | | notes |
+-------------+ +------------+ +---------------+Each agent works on its own branch:
# Signal agent ingests external data
omnigraph branch create ./revops-graph signal-ingest-20260330
# ... agent writes Signals, Indicates edges, TriggeredDeal edges
omnigraph branch merge ./revops-graph --source signal-ingest-20260330 --into main
# Risk agent scores deals
omnigraph branch create ./revops-graph risk-scoring-20260330
# ... agent reads deals + signals, updates Deal.risk
omnigraph branch merge ./revops-graph --source risk-scoring-20260330 --into main
# Coaching agent surfaces insights
omnigraph branch create ./revops-graph coaching-20260330
# ... agent reads activity patterns, writes coaching notes
omnigraph branch merge ./revops-graph --source coaching-20260330 --into mainThe signal agent doesn't know about the risk agent. The risk agent doesn't know about the coaching agent. They coordinate through the graph: signals appear, risk scores update, coaching insights reference the risk context. No orchestrator.
What you can build from here
- Forecast agent — Read deal stages, amounts, close dates, and signal strength. Predict weighted pipeline and flag deals where velocity has dropped.
- Territory mapping — Add
Regionnodes andCovers: Rep -> Regionedges. Auto-balance territories by querying account distribution and deal load per rep. - Competitive intelligence — Add
Competitornodes andCompetesWith: Deal -> Competitoredges. Track win/loss patterns per competitor. - Renewal risk — Combine ARR data, support ticket volume, product usage signals, and contact engagement to predict churn before the renewal date.