<!-- mobian-agent-page publisher="dailydev" canonical="https://daily.dev/posts/maintaining-an-organizational-knowledge-graph-with-an-llm-and-event-sourcing-d4p4017r7" -->

---
title: Maintaining an organizational knowledge graph with an...
description: Arkency built Planet Arkency, a multi-tenant organizational knowledge graph on Rails Event Store that uses an LLM to extract entities and relationships from...
canonical: https://daily.dev/posts/maintaining-an-organizational-knowledge-graph-with-an-llm-and-event-sourcing-d4p4017r7
twitter:card: summary_large_image
twitter:site: @dailydotdev
og:type: website
og:site_name: daily.dev
og:title: Maintaining an organizational knowledge graph with an LLM and event sourcing | daily.dev
og:description: Arkency built Planet Arkency, a multi-tenant organizational knowledge graph on Rails Event Store that uses an LLM to extract entities and relationships from...
og:url: https://daily.dev/posts/maintaining-an-organizational-knowledge-graph-with-an-llm-and-event-sourcing-d4p4017r7
og:image: https://api.daily.dev/og/posts/d4p4017r7.png
og:image:alt: Maintaining an organizational knowledge graph with an LLM and event sourcing
og:image:width: 1200
og:image:height: 630
og:locale: en
---

> ## Documentation Index
> Fetch the complete documentation index at: https://daily.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Maintaining an organizational knowledge graph with an LLM and event sourcing

**[RUBYLAND](https://daily.dev/sources/rubyla)** · 16 min read · 2 upvotes · 1 comments

## Summary

Arkency built Planet Arkency, a multi-tenant organizational knowledge graph on Rails Event Store that uses an LLM to extract entities and relationships from unstructured inputs like meeting transcripts, Slack threads, and emails. The system relies on a closed YAML-defined ontology, hybrid identity resolution (trigram plus embedding search via pg_trgm and pgvector with a self-hosted bge-m3 model), full provenance tracking of every extraction and tool call, human-in-the-loop review of proposed graph changes before they apply, and an event-driven pipeline (TranscriptIngested through GraphChangeApplied) built with Rails Event Store. The graph can also research entities using Anthropic's web_search and web_fetch tools, and is exposed to AI assistants via MCP.

## Full article

daily.dev links to this article rather than hosting it. Read it at the original source: <https://blog.arkency.com/maintaining-an-organizational-knowledge-graph-with-an-llm-and-event-sourcing>

## Questions this post answers

### How do you prevent an LLM from creating duplicate nodes when extracting entities into a knowledge graph, like the same person under different names?

Combine three mechanisms: require the model to search existing nodes with read-only tools before creating new ones, maintain aliases so alternate surface forms resolve to one canonical entity, and run hybrid search combining pg_trgm trigram similarity (threshold 0.3) over names and aliases with embedding search using a self-hosted bge-m3 model on Ollama stored in pgvector to catch semantic matches and misspellings.

_Developers wiring LLM extraction into a graph can browse similar identity-resolution patterns on daily.dev._

### Why use a closed ontology instead of letting an LLM define its own node and relation types when building a knowledge graph?

An open ontology, where the model could introduce new node and relation kinds freely, led to complete chaos in the graph within days. Restricting allowed node kinds and edge relations to a fixed YAML file, rendered into the extraction prompt as markdown tables and enforced via schema enums, keeps the graph consistent because the model only picks from a predefined vocabulary rather than inventing types ad hoc.

_Teams weighing structured versus freeform LLM outputs can compare design tradeoffs like this on daily.dev._

### How can event sourcing support a human-in-the-loop review process for AI-proposed changes to a database?

Model the workflow as an event flow (TranscriptIngested, ExtractionRequested, KnowledgeExtracted, GraphChangeProposed, GraphChangeApplied or GraphChangeConflicted) with an aggregate implementing a propose-then-apply state machine. A review window becomes just another state in that machine; if the underlying data changes before a human approves the proposal, the apply step detects the mismatch and marks the change conflicted with a human-readable explanation instead of silently overwriting.

_Architects designing human-in-the-loop AI pipelines can find more event sourcing patterns on daily.dev._

## Community discussion

Top comments from developers on daily.dev.

**@agustinbarrientos** · 0 upvotes

> `proposed` and `accepted` need to be different event types. Let the LLM write the first one, but only a human should promote it.

## Similar posts on daily.dev

- [Automating Knowledge Graph Population: Extracting Entities and Triples from Unstructured Text with an LLM](https://daily.dev/posts/automating-knowledge-graph-population-extracting-entities-and-triples-from-unstructured-text-with-a-occ2gvqzy) · Machine Learning Mastery · 1 upvotes · 0 comments
- [Your File System Is Already a Graph Database](https://daily.dev/posts/your-file-system-is-already-a-graph-database-voyeam9d4) · Hacker News · 2 upvotes · 0 comments
- [Making the Knowledge Layer a Graph You Actually Traverse](https://daily.dev/posts/making-the-knowledge-layer-a-graph-you-actually-traverse-szwwqn11n) · Towards Data Science · 0 upvotes · 0 comments

---

Tags: [#llm](https://daily.dev/tags/llm), [#architecture](https://daily.dev/tags/architecture), [#postgresql](https://daily.dev/tags/postgresql), [#ruby](https://daily.dev/tags/ruby)

[View this post on daily.dev](https://daily.dev/posts/maintaining-an-organizational-knowledge-graph-with-an-llm-and-event-sourcing-d4p4017r7)

```json
{"@context":"https://schema.org","@graph":[{"@type":"Organization","@id":"https://daily.dev/#organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180},"sameAs":["https://twitter.com/dailydotdev","https://github.com/dailydotdev","https://www.linkedin.com/company/daily-dev-ltd"]},{"@type":"WebSite","@id":"https://daily.dev/#website","url":"https://daily.dev","name":"daily.dev","publisher":{"@id":"https://daily.dev/#organization"},"potentialAction":{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https://daily.dev/search?q={search_term_string}"},"query-input":"required name=search_term_string"}}]}
{"@context":"https://schema.org","@type":"TechArticle","headline":"Maintaining an organizational knowledge graph with an LLM and event sourcing","url":"https://daily.dev/posts/maintaining-an-organizational-knowledge-graph-with-an-llm-and-event-sourcing-d4p4017r7","mainEntityOfPage":{"@type":"WebPage","@id":"https://daily.dev/posts/maintaining-an-organizational-knowledge-graph-with-an-llm-and-event-sourcing-d4p4017r7"},"datePublished":"2026-08-12T16:25:01.336Z","dateModified":"2026-09-14T06:17:56.516Z","description":"Arkency built Planet Arkency, a multi-tenant organizational knowledge graph on Rails Event Store that uses an LLM to extract entities and relationships from...","image":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/4797f67b3946a90522fb17adc2df1fba?_a=AQAEuop","thumbnailUrl":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/4797f67b3946a90522fb17adc2df1fba?_a=AQAEuop","isAccessibleForFree":true,"articleSection":"RUBYLAND","inLanguage":"en","publisher":{"@type":"Organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180}},"author":{"@type":"Organization","name":"RUBYLAND","logo":"https://media.daily.dev/image/upload/t_logo,f_auto/v1/logos/rubyla","url":"https://daily.dev/sources/rubyla"},"commentCount":1,"discussionUrl":"https://daily.dev/posts/maintaining-an-organizational-knowledge-graph-with-an-llm-and-event-sourcing-d4p4017r7","interactionStatistic":[{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":2},{"@type":"InteractionCounter","interactionType":{"@type":"CommentAction"},"userInteractionCount":1}],"keywords":"llm,architecture,postgresql,ruby","timeRequired":"PT16M"}
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://daily.dev"},{"@type":"ListItem","position":2,"name":"RUBYLAND","item":"https://daily.dev/sources/rubyla"},{"@type":"ListItem","position":3,"name":"Maintaining an organizational knowledge graph with an LLM and event sourcing"}]}
{"@context":"https://schema.org","@type":"WebPage","@id":"https://daily.dev/posts/maintaining-an-organizational-knowledge-graph-with-an-llm-and-event-sourcing-d4p4017r7","comment":[{"@type":"Comment","text":"proposed and accepted need to be different event types. Let the LLM write the first one, but only a human should promote it.","datePublished":"2026-08-14T14:56:55.796Z","url":"https://daily.dev/posts/d4p4017r7#c-XVFcjDLfG","author":{"@type":"Person","name":"Agustin Barrientos","url":"https://daily.dev/agustinbarrientos","image":"https://media.daily.dev/image/upload/s--5ayxQnqn--/f_auto/v1788281802/avatars/avatar_wQYYVe5Tbj0NJ7C7qPoa8?_a=BAMAMicg0"}}]}
{"@context":"https://schema.org","@type":"FAQPage","@id":"https://daily.dev/posts/maintaining-an-organizational-knowledge-graph-with-an-llm-and-event-sourcing-d4p4017r7#faq","mainEntity":[{"@type":"Question","name":"How do you prevent an LLM from creating duplicate nodes when extracting entities into a knowledge graph, like the same person under different names?","acceptedAnswer":{"@type":"Answer","text":"Combine three mechanisms: require the model to search existing nodes with read-only tools before creating new ones, maintain aliases so alternate surface forms resolve to one canonical entity, and run hybrid search combining pg_trgm trigram similarity (threshold 0.3) over names and aliases with embedding search using a self-hosted bge-m3 model on Ollama stored in pgvector to catch semantic matches and misspellings. Developers wiring LLM extraction into a graph can browse similar identity-resolution patterns on daily.dev."}},{"@type":"Question","name":"Why use a closed ontology instead of letting an LLM define its own node and relation types when building a knowledge graph?","acceptedAnswer":{"@type":"Answer","text":"An open ontology, where the model could introduce new node and relation kinds freely, led to complete chaos in the graph within days. Restricting allowed node kinds and edge relations to a fixed YAML file, rendered into the extraction prompt as markdown tables and enforced via schema enums, keeps the graph consistent because the model only picks from a predefined vocabulary rather than inventing types ad hoc. Teams weighing structured versus freeform LLM outputs can compare design tradeoffs like this on daily.dev."}},{"@type":"Question","name":"How can event sourcing support a human-in-the-loop review process for AI-proposed changes to a database?","acceptedAnswer":{"@type":"Answer","text":"Model the workflow as an event flow (TranscriptIngested, ExtractionRequested, KnowledgeExtracted, GraphChangeProposed, GraphChangeApplied or GraphChangeConflicted) with an aggregate implementing a propose-then-apply state machine. A review window becomes just another state in that machine; if the underlying data changes before a human approves the proposal, the apply step detects the mismatch and marks the change conflicted with a human-readable explanation instead of silently overwriting. Architects designing human-in-the-loop AI pipelines can find more event sourcing patterns on daily.dev."}}]}
```

