Engineering teams already have the facts. They are just split across Discord, GitHub, and docs. Someone says Priya will take the frontend. A pull request lands. An issue mentions billing. A week later nobody can answer "what is blocked?" or "who actually knows authentication?" without scrolling.

SigmaAgent is a Discord bot that treats that mess as one graph. Mention it in plain language. It answers from tasks, people, commits, issues, docs, and chat that live in FalkorDB, one graph per server.

A few posts on DEV pushed me toward a graph instead of another vector index. Prabhu used FalkorDB so an agent could remember interactions as edges and walk them with Cypher. sznimperial made the same move for ownership: chunks guess, edges say who owns what. Razeef Shaikh put it in one line I kept coming back to: search finds documents, a graph finds consequences.

That last one is the product. "What is blocked?" is a consequence question.

What the graph stores

Each Discord server gets its own FalkorDB graph. Ingest writes the same kinds of facts every time:

  • A developer is ASSIGNED_TO a task.
  • A task BLOCKED_BY another task. The edge points at the work it is waiting on.
  • A commit TOUCHES a file. An issue MENTIONS a task.
  • A Discord message SUPPORTS a claim, so chat is evidence, not a second source of truth.

GitHub webhooks and a background sync keep commits, issues, and pull requests current. Discord messages are extracted as they arrive. Full-text indexes on nodes let a question like "billing" hit docs and chat, then hop back to the people and tasks those nodes connect to.

Questions that are traversals

The bot does not invent a dashboard for each question. Gemini reads a report that FalkorDB already computed.

The critical path is the longest chain of unfinished tasks:

MATCH p = (:Task)-[:BLOCKED_BY*1..20]->(:Task) WHERE all(n IN nodes(p) WHERE coalesce(n.status, 'todo') <> 'done') WITH [n IN nodes(p) | n.id] AS chain, length(p) AS hops RETURN chain, hops ORDER BY hops DESC LIMIT 1 

Bottlenecks are PageRank on the same edge. Rank flows toward the open tasks that other open tasks are waiting on:

CALL algo.pageRank('Task', 'BLOCKED_BY') YIELD node, score WITH node, score WHERE coalesce(node.status, 'todo') <> 'done' OPTIONAL MATCH (waiting:Task)-[:BLOCKED_BY*1..20]->(node) WHERE coalesce(waiting.status, 'todo') <> 'done' RETURN node.id, node.title, score, count(DISTINCT waiting) AS waiting_count ORDER BY score DESC 

Impact is the other direction: given one task id, which unfinished tasks reach it within 20 hops, and how far away they are. Weakly connected components on Task / BLOCKED_BY split work that can proceed in parallel.

Expertise is a separate walk. "Who knows authentication?" ranks developers from task ownership, commits, issues, docs, chat mentions, and team membership, then writes EXPERT_IN edges so the next question can start from the ranking instead of recomputing it from scratch.

Why a graph, for this bot

A vector store would have retrieved the message where someone said the billing API was stuck. It would not have told me that three open tasks wait on that one, that the same person also owns the highest-PageRank node, or that the docs mentioning auth were written by someone who has not touched the repo in a month.

select_graph made multi-tenant isolation boring, which is what I wanted. The API, the Discord client, and the GitHub ingest all call FalkorDB(...).select_graph(name) and run Cypher. There is no separate query service.

Two things I still want from the database: errors that name the bad label when algo.pageRank or a full-text index call fails, and vector search beside full-text so keyword hits and embedding similarity land on the same nodes.

Try it

The repo is Sumit884-byte/sigmaAgent. In a server, mention the bot:

  • "What is blocked?"
  • "Who knows about billing?"
  • "Priya will do the frontend"

The first two read the graph. The third writes it.