cd /news/ai-agents/knowledge-graphs-explained-for-ai-me… Β· home β€Ί topics β€Ί ai-agents β€Ί article
[ARTICLE Β· art-163217] src=dev.to β†— pub= topic=ai-agents verified=true sentiment=↑ positive

Knowledge graphs, explained for AI memory (and how Palace uses one)

A developer built Palace, an open-source memory server for coding agents that combines vector search with a temporal knowledge graph to answer fact-based questions like which database a service currently uses. The writeup explains that embeddings excel at similarity but not truth, while typed triples with validity intervals track current state and preserve history, and it notes Palace keeps its graph deliberately simple.

by read7 min views3 publishedNov 3, 2026

Most AI memory systems today come down to the same recipe. Split text into chunks, turn each chunk into an embedding, store the vectors, and when a question comes in, return the chunks closest to it. That recipe works well, and it's the backbone of Palace, the memory server I build for coding agents.

Some questions, though, it answers badly. "What database does the billing service use now?" "Who owns the deploy pipeline?" "Which services depend on this queue?" Those are questions about facts: things with one current answer, a history of past answers, and connections to other things.

That's what knowledge graphs are for. This post covers what a knowledge graph is, why it complements vector search instead of replacing it, what adding time to it changes, and what it costs. It ends with how Palace uses one, including where Palace keeps it deliberately simple.

A knowledge graph stores knowledge as entities and the relationships between them.

depends_on, owned_by, uses_queue, replaced_by. The basic unit is a triple: subject, predicate, object.

billing_service  β†’  uses_database  β†’  Postgres
billing_service  β†’  owned_by       β†’  payments_team
payments_team    β†’  reports_to     β†’  Dana

Put enough triples together and you get a graph: entities are the nodes, relationships are the edges. Since every edge has a type, you can ask precise questions, like "follow owned_by out of billing_service" or "find everything with a uses_database edge pointing at Postgres."

The idea isn't new. The W3C's RDF standard has modeled data as triples for over two decades, and Wikidata stores its facts that way. Google introduced its Knowledge Graph in 2012 under the slogan "things, not strings." That slogan is the core idea: a knowledge graph stores things and how they relate, not text that happens to mention them.

There are two common styles:

For agent memory, the distinction matters less than the core idea: knowledge as explicit, typed, queryable links.

To see why a graph helps, be clear about what embeddings do.

An embedding model maps text to a point in a high-dimensional space, so that text with similar meaning lands close together. Vector search finds the stored chunks nearest to your question. It's very good at:

Its weaknesses all follow from one property: similarity isn't truth.

A knowledge graph covers exactly these weak spots. It doesn't replace search, because a triple keeps no nuance and no reasoning. Search gives you the evidence. The graph gives you the state.

A plain knowledge graph has a problem of its own: facts change. If you just overwrite uses_queue β†’ Redis with uses_queue β†’ SQLite, you lose the history. Worse, you lose the context that makes old evidence readable. A future reader who finds the March Redis thread can't tell it describes the past.

A temporal knowledge graph gives each fact a validity interval:

my_api β†’ uses_queue β†’ Redis    valid 2026-03-02 … 2026-10-12
my_api β†’ uses_queue β†’ SQLite   valid 2026-10-12 … (still true)

Three things follow:

The database world calls this valid time: when a fact was true in reality. It's different from transaction time: when the system recorded it. Systems that track both are called bitemporal. Valid time is usually what an agent needs, because the question is "what's true?", not "when did someone write it down?"

Put vector search and a temporal graph side by side, and an agent gets several things it didn't have before:

A direct answer for state questions. "Which queue does my_api use?" turns into an exact lookup that returns one current fact. There's no similarity ranking to second-guess.

Context for interpreting search results. The graph also says Redis was in use until October 12. When search turns up the March thread, the agent knows it's history, not instructions.

Reverse and complete lookups. Following an edge backwards ("what points at SQLite?") returns every match, not the top k.

Contradiction detection. Two current facts with the same subject and predicate but different objects are a structural signal. Something changed and nobody closed out the old fact, or two sources disagree.

Compactness. A triple is a handful of tokens. Stating a fact as a triple is far cheaper to put in a model's context than the paragraphs that originally established it.

Multi-hop questions. Graphs make it natural to chain relationships: billing β†’ owned_by β†’ payments team β†’ reports_to β†’ Dana. Each hop is a precise step, not another fuzzy search.

Graphs aren't free, and pretending otherwise is how graph projects fail.

uses_db, uses_database and database_is, all meaning the same thing. Palace stores memory in two complementary forms. By default, both live in the same local SQLite file:

valid_from / valid_to dates. This is the state. The two don't feed into each other. Search doesn't read the graph, and the graph doesn't rank drawers. Instead, the memory protocol Palace gives agents asks for both before answering anything about past decisions:

β†’ palace_search + palace_kg_query β€” never answer from training data alone.

Here's how the queue example plays out in practice.

Writing a fact. After the agent learns that my_api uses Redis, it records that:

palace_kg_add  my_api β†’ uses queue β†’ Redis   (valid_from 2026-03-02)

Palace normalizes names on the way in. My API, my api and my_api all resolve to the same entity, and uses queue is the same relationship as uses_queue. Adding a fact that's already current returns the existing one instead of a duplicate. It's a lightweight form of entity resolution: it covers case and spacing, not synonyms.

Changing a fact. In October the agent closes out the old fact and adds the new one:

palace_kg_invalidate  my_api β†’ uses_queue β†’ Redis    (ended 2026-10-12)
palace_kg_add         my_api β†’ uses_queue β†’ SQLite   (valid_from 2026-10-12)

Nothing is deleted. The Redis fact gets an end date and stays as history.

Confidence is binary on purpose. Graphs built by automatic extraction often attach a probability to each fact, and then every reader has to decide what a 0.6 means. Palace stores every fact at full confidence (1.0). When an agent decides a fact is no longer true, it doesn't lower a score. It invalidates the fact. So the graph never holds half-believed facts: a fact is either current or ended, and the dates record when it changed.

Reading it back. palace_kg_query on my_api returns both facts, each flagged:

my_api β†’ uses_queue β†’ Redis    2026-03-02 … 2026-10-12   current: false
my_api β†’ uses_queue β†’ SQLite   2026-10-12 …              current: true

The agent now has the current answer and the context to read older search results correctly. The same tool takes:

direction to follow edges backwards ("what uses SQLite?")as_of date for point-in-time questions. Both ends of the interval count, so on the switch day itself, both facts come back. Catching contradictions. palace_conflicts lists every subject and predicate pair with more than one distinct object. It includes properly closed-out history like the example above, so it's a review list, not a verdict. The case to act on is a group where more than one fact is still marked current.

Linking state to evidence. A fact can store an optional source_closet pointing at the stored memory that justifies it, so the short triple can lead back to the full discussion.

This is the cost that sinks most graph efforts, so it's worth being specific. Palace doesn't extract triples from text automatically. Agents add them on purpose, and Palace works to make sure they do:

palace_kg_add for stable facts, and palace_kg_invalidate plus palace_kg_query and The agent writing the fact is already an LLM, and it has the full task context, so there's no need for a second model reading raw messages after the fact. The graph contains what agents decided was worth stating as a fact, not whatever an extractor guessed.

The graph is deliberately small. These are its current limits:

Postgres and PostgreSQL are two entities. Search is the fuzzy layer. It finds the memories that say "PostgreSQL" when the question says "Postgres", and the agent then queries the graph under that name. If two agents record the same fact with different object names, palace_conflicts flags the pair. Vector search answers "what have we said about this?" A temporal knowledge graph answers "what is true about this, and since when?" Agent memory needs both. Without the graph, an agent can't tell current facts from history. Without search, it has facts but no reasoning behind them.

Palace pairs the two in one local file and gets agents to keep the graph up to date. Every connected agent reads and writes the same palace, so a fact Claude Code records today is there for Cursor or Codex in their next session, with the same history of what changed and when.

Palace is open source (MIT) at github.com/AncientiCe/palace-rs. palace install connects 11 agents over MCP: Claude Code, Codex, Cursor, Gemini CLI, VS Code, OpenCode, Cline, Zed, Goose, Windsurf and Claude Desktop.

If you want one shared memory across a whole team, that's what we're building at palacememory.com.

── more in #ai-agents 4 stories Β· sorted by recency
── more on @palace 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain β€” perfect for shipping the agent you just read about.

$git push zahid main
β†’ Live at https://your-agent.zahid.host βœ“
Get free account β†’ Pricing
from €0/mo Β· no card required
LIVE [news/knowledge-graphs-exp…] indexed:0 read:7min 2026-11-03 Β· β€”