An on-call knowledge graph that keeps document curation, technical responsibility, and policy history explicit.
A new on-call engineer can retrieve the right document and still make the wrong decision. The name beside a runbook might belong to its editor. A timeout setting might have been replaced. A confident chat message might contradict the operating procedure.
Those are the problems behind OnCall Brain, a project for FalkorDB Graph Hacks. It joins operations documents, organisation records, chats, and support tickets in a knowledge graph, then answers questions with source-line evidence.
All examples below come from the project's synthetic corpus for the fictional company AetherPulse. They are reproducible test cases, not reports from a production deployment.
The engineering question is specific. Can we make the relationships needed for an operational decision explicit enough that an answer can be inspected?
Where the data comes from
Picture a platform operations team. Users report problems through a ticketing system, here called Sentinel Desk: each ticket records the module, the first-line engineer it was assigned to, and how it was resolved. The real work happens elsewhere, in a dedicated channel on the company's internal instant-messaging tool, where first-line and Tier 2 engineers ask each other questions, claim tickets, hand them over, and announce rule changes. Around both sit formal documents (SOPs, a module registry, an escalation policy) and an organisation roster.
The synthetic corpus mirrors that setup: 10 formal documents, 18 days of channel logs, 95 tickets, and the org records.
Chat and tickets meet on the ticket ID. The ticket system says TCK-1014 was assigned to Alan Cox. The channel log adds two lines: Dominic Shaw writes, "I am transferring TCK-1014 to Colin on Sentinel Desk right now", and later Colin Marsh writes, "Verified TCK-1014 closure". Extraction turns those lines into HANDLED_BY edges on the same Ticket node, each citing its chat line and marked observation, next to the ticket system's own record. Across the corpus, the ticket system contributes 95 handler edges and chat adds 26 more; 21 tickets end up with handlers from both sources. That is what lets the graph answer "who has actually fixed this?" with people the ticket system alone would miss.
This join depends on someone typing the ticket ID. In practice, people often discuss a problem without naming the ticket, describing a symptom that resembles one ("the certificate handshake is timing out again"). OnCall Brain does not link those today: entities align only on identical IDs, so a resemblance never becomes a graph fact. At query time, keyword search over all evidence lines, ticket records included, can still surface the similar ticket and the chat thread side by side, but only as retrieved context, not as an edge, and not in the "who has fixed it" count. The natural extension is a similarity pass that proposes candidate SIMILAR_TO edges between chat threads and tickets, kept out of answers until a person approves them.
Chat also carries rules. The change of the default step timeout from 120 to 60 minutes, used below, was announced in the channel, not in a document, so it enters the graph as a SUPERSEDES edge with chat evidence.
The runbook editor is the wrong escalation target
One test asks whether Wesley Tate should log into a backend server and terminate a zombie worker when a Pipeline runner deadlocks.
Wesley is a plausible search result. He reviews Knowledge Hub articles and coordinates submissions. His name belongs near Pipeline documentation. But the module's technical lead is Colin Marsh.
The distinction is encoded directly in the graph. A Resource points to its curator through MAINTAINED_BY. A Person points to a Module through TECH_LEAD_OF. The ontology explicitly forbids deriving technical responsibility from document maintenance. Unregistered predicates are rejected, and each assertion's domain and range are validated.
The answer should correct the question's premise, direct the ticket to the Pipeline queue, and identify Colin. The walkthrough demonstrates that correction; the frozen evaluation also records this trap as a pass.
A text or vector search can retrieve the supporting passages. Similarity alone does not establish what Wesley's relationship to Pipeline permits him to do. A model could reason correctly from those passages, but it would have to reconstruct the responsibility distinction during generation. Here, that distinction is part of the retrieval contract.
Ticket history adds a second view. Someone who handled a module's tickets may offer practical help without being its official owner. OnCall Brain joins tickets to modules and handlers, then presents that history alongside ownership. It does not treat past handling as proof of current availability or authority.
The graph behind those distinctions
The relationships are not invented on top of the data; they are read off the structure the sources already have. The module registry is a table with a header note, "Review Cadence: Weekly review by Wesley Tate", and rows such as:
| Module ID | Module Name | Tier 2 Lead | Content Platform |
|---|---|---|---|
| MOD-01 | Pipeline Orchestration Engine | Colin Marsh | Knowledge Hub |
A deterministic parser, with no LLM involved, maps one column to one relationship. The Tier 2 Lead column, defined in the same file as the technical owner accountable for runbook accuracy, becomes Colin Marsh -TECH_LEAD_OF-> MOD-01. The platform column becomes MOD-01 -HAS_RESOURCE-> Knowledge Hub. The review note becomes Knowledge Hub -MAINTAINED_BY-> Wesley Tate. Rosters and team tables are handled the same way: a Team Lead column becomes a HOLDS_ROLE edge to a role node.
What about a title the schema does not know, such as "Support Lead"? Nothing is inferred from it. A new column in a structured source is ignored until someone decides which relationship it means. In free text, the model must pick from the nineteen registered relationships, so "Ava is the support lead for Pipeline" can at most become a role assignment, and a role never implies TECH_LEAD_OF. Adding a relationship type is a schema decision with an explicit domain, range, and meaning. That is deliberate: "support lead" means escalation owner in one company and shift coordinator in another.
The free-text path has a limit worth stating. Quote validation proves that the cited line exists and says what the assertion quotes; it does not prove the model chose the right relationship type. That choice is guided by the predicate definitions in the extraction prompt, not checked by code.
This abbreviated model uses concrete source-line locators on its domain edges. registry means 08-module-knowledge-base-registry.md; chat and ticket locators name their files directly.
Colin Marsh (Person) --TECH_LEAD_OF [registry L17]--> MOD-01 (Module)
MOD-01 (Module) --HAS_RESOURCE [registry L17]--> Knowledge Hub (Resource)
Knowledge Hub (Resource) --MAINTAINED_BY [registry L9]--> Wesley Tate (Person)
TCK-1017 (Ticket) --ABOUT [tickets.jsonl L17]--> MOD-01 (Module)
TCK-1017 (Ticket) --HANDLED_BY [tickets.jsonl L17]--> Robert Coleman (Person)
Notice: 60-minute timeout --SUPERSEDES [chat_2026-08-20.md L28]--> Rule: 120-minute timeout
Evidence is not drawn above because it is not wired into the business graph. Each Evidence node stores a source file, line, and quoted text; each relationship stores the IDs of its Evidence nodes in an evidence property, and citations are resolved through those IDs. Business nodes carry Entity; Evidence nodes do not, keeping evidence records out of business traversals.
Every assertion carries an ID, authority, validity dates, state, and evidence references. Answer citations pair assertion IDs with file:line. That makes the unit of inspection a supported relationship, rather than an unexplained connection between names.
Yesterday's correct timeout can be today's wrong answer
The original corpus contains a change in the default Pipeline step timeout from 120 minutes to 60 minutes, effective 2026-08-20. Both values remain useful evidence. Only one belongs in the current default answer.
SUPERSEDES preserves that history. A visible replacement excludes its target from current answers while retaining the old rule, replacement, and effective date for inspection.
The freshness demo extends the example in an isolated graph. It copies the loaded graph, injects a notice replacing the 60-minute timeout with 30 minutes, and repeats the same read. The old card becomes superseded; the new notice and evidence appear. The resulting chain is 120 → 60 → 30.
The 30-minute rule is an injected demonstration, not an original AetherPulse policy. The documented verification covers graph reads and reset; it does not establish that generated answers or browser layout were tested. The demo page reads the graph without an LLM.
Retrieval by similarity can return every version of a timeout policy. Ranking the newest passage can help, but it still leaves questions about replacement scope and effective dates. A replacement edge records which rule changed. Future notices remain invisible until their effective date.
Visibility is enforced server-side at every traversal hop. A relationship must be approved, its start date must have arrived, and its end date must be absent or still ahead of the query time. A matching sentence cannot bypass those conditions.
A chat message confuses claiming with diagnosis
Another test starts with Luke Fischer's belief that a P3 ticket can remain unclaimed for four hours. The formal workflow training guide penalizes tickets left unassigned beyond 15 minutes. Sophia Evans's chat correction separates the deadlines explicitly. Claim within 15 minutes, provide an initial technical response within 30 minutes, and understand four hours as the initial diagnostic window.
These passages share the same vocabulary while describing different stages. A retrieved “P3, four hours” snippet can therefore reinforce the wrong premise even when it is topically relevant.
The graph's assertions retain authority and semantic slots. Its authority order is formal_rule, then practice, then observation. Chat defaults to observation; an announced policy can be practice, but chat is never automatically promoted to a formal rule.
Conflict checks require claims about the same subject and slot, mutually exclusive values, compatible conditions, and overlapping validity intervals. This matters because a claim deadline and a diagnostic deadline can coexist. The mistaken claim-window belief needs correction; the diagnostic window does not need deletion.
The answer can lay out the disagreement and cite both the mistaken chat statement and the governing evidence. The frozen Q13 result records that behavior as a pass. This is a useful retrieval advantage, not proof that vector search could never answer the question.
The model selects tools; the server owns Cypher
The model never writes executable Cypher. It selects tool arguments, registered predicates, direction, and hop count. Server-owned templates perform the queries.
For example, the following is copied verbatim from the README's query for oncall_brain/tools.py:module_expertise.
MATCH (k:Entity)-[a:ABOUT]->(m:Entity {id: $id}), (k)-[h:HANDLED_BY]->(p:Entity) WHERE a.state = 'approved' AND a.valid_from <= $now AND (a.valid_to IS NULL OR a.valid_to > $now) AND h.state = 'approved' AND h.valid_from <= $now AND (h.valid_to IS NULL OR h.valid_to > $now) RETURN k.id, k.kind, k.name, m.kind, m.name, p.id, p.kind, p.name, a.aid, a.authority, a.evidence, h.aid, h.authority, h.evidence
Both ticket relationships receive visibility checks, and both return evidence. My reason for preferring this boundary is reviewability. Predicate semantics and filtering can be checked in a fixed query rather than trusted to each generated query. The evaluation reports also record executed template names and tool arguments.
Ingest has a similar boundary. Structured organisation and ticket records are parsed without an LLM. Free text goes through model proposal, schema and evidence validation, entity alignment, and semantic annotation. Accepted assertions begin as candidates. A quoted evidence line that does not match its source causes rejection.
What the measurements actually support
The frozen deep-mode evaluation passed 15 of 17 gold questions. The walkthrough reports 14 of 17 for fast mode; the frozen report is specifically a deep-agent run. These are project test results on synthetic data, not a production accuracy claim or a measured victory over vector retrieval.
The failures are informative. Q1 lost required-point coverage. Q7 included all required points but returned insufficient_context where the card expected applicable. Retrieving facts and presenting the correct answer state remain separate problems.
A cold-cache full ingest took about 2 hours 10 minutes in the documented clean-checkout test, including provider timeouts. Cached completed slices help resume extraction, but they do not remove cold-start cost.
Conflict validation also has a limit. The Web check accepts a graph conflict record or at least two distinct source-line references in the Conflicts section. Counting locators does not independently prove that the passages contradict. Evidence makes an answer inspectable; it still needs interpretation.
Try the ownership trap, inspect its citations, then follow a replaced rule through its history. Those checks show what this graph contributes to an on-call decision.
Repository: OnCall Brain
Demo video: https://youtu.be/gifjF3u3s0c
AI development assistance included Claude Code for implementation, review, and fixes; Codex for features and documentation; Antigravity CLI for frontend pages; and Hunyuan hy4-preview, driven through Claude Code, for backend KB health and a conflict fix.
1
Top comments (0)