u/gimalay

How I turned three philosophy books into a 1,200-document knowledge graph

Marcus Aurelius says virtue is acting according to nature and reason, serving the common good as naturally as the eye sees. Machiavelli says a prince who acts entirely virtuously will be ruined among so much evil. Nietzsche warns against becoming enslaved to one's own virtues, noting that every virtue inclines toward stupidity.

Same word. Three completely different meanings across seventeen centuries. I wanted to see how many concepts work like this — where the surface agreement hides a deep disagreement — so I built a knowledge graph connecting Meditations (170 AD), The Prince (1513), and Beyond Good and Evil (1886).

The result: Seventeen Centuries — 838 text fragments, 340+ concept files, and category documents that let you trace how ideas evolved across time. The first article built from the graph is Virtue across seventeen centuries, which follows the concept from Stoic duty through political pragmatism to Nietzsche's genealogical critique.

Why a graph, not a database

I needed a structure where the same concept could belong to multiple contexts simultaneously. Virtue belongs under the Stoic worldview and under Machiavelli's political theory and under Nietzsche's critique of morality. Folders force single placement. A database would work but then I lose the thing I actually use — being able to open a file, read it, edit it, link from it.

IWE uses inclusion links — a markdown link on its own line defines a parent-child relationship. A document can have multiple parents. The entire graph is plain markdown files in a flat directory. No database, no special format. I edit them in my text editor, query them from the CLI, and an AI agent can read the same files.

The five-stage pipeline

Stage 1 — Fragment extraction. Parsers for Standard Ebooks XHTML split each book into atomic markdown files — one per aphorism, passage, or chapter. Nietzsche yielded 296 fragments, Marcus Aurelius 515, Machiavelli 27.

# 146

He who fights with monsters should be careful lest he thereby
become a monster. And if thou gaze long into an abyss, the abyss
will also gaze into thee.

Stage 2 — Entity extraction. An LLM read each fragment and identified 3–7 significant entities: philosophical concepts, historical figures, themes. Each entity got its own file. Fragment text was updated with inline links so the graph forms through the content itself:

...life itself is [Will to Power](will-to-power.md);
[self-preservation](self-preservation.md) is only one...

Stage 3 — Flattening and merging. Each book started in its own directory with its own virtue.md, soul.md, plato.md. This stage moved everything into a single flat directory and merged overlapping concepts. Ten concepts appeared in multiple books — virtue, soul, Plato, Socrates, truth, nature, gods, Epicurus, cruelty, free will. These became the most valuable documents in the graph because they're where the real contrasts live.

Stage 4 — Categories. With 340+ concept files floating in a flat directory, I needed entry points. Categories like philosophers, virtues, power-dynamics, and moral-systems emerged from the content. Each is a document with inclusion links to its members — and because IWE supports multiple parents, Socrates belongs to both philosophers and ancient-cultures without duplication.

Stage 5 — Summaries. An LLM analyzed the referenced fragments for each merged concept and wrote comparative summaries. This turned simple backlink indexes into the comparative analysis that makes the graph worth reading — and worth writing articles from.

Why this structure pays off

The graph is queryable from the CLI:

iwe retrieve -k virtue --depth 2    # virtue + linked fragments
iwe find --refs-to will-to-power    # everything referencing will-to-power
iwe tree -k bge                     # Beyond Good and Evil as a tree

retrieve --depth 2 pulls a concept, its backlinks to fragments, and the fragment content in one call. That's how the virtue article was written — retrieve the concept, read the fragments side by side, write the analysis. An AI agent uses the same commands and the same files.

The most surprising result was how much structure emerged from just inclusion links. No tags, no folders, no metadata beyond the links themselves. The graph has clear clusters around each book, bridges through shared concepts, and category entry points — all from markdown files linking to each other.

Browse the graph: https://iwe.pub/seventeen-centuries/ GitHub: https://github.com/iwe-org/seventeen-centuries IWE: https://github.com/iwe-org/iwe

reddit.com
u/gimalay — 4 days ago

Markdown notes as a graph, edited in Zed, read by your AI agent

I've been using Zed as my notes editor with an LSP called IWE that turns a directory of markdown files into a graph. F12 follows a link into the target document. Shift+F12 lists every backlink. Cmd+T searches across every document title. Cmd+. opens code actions — extract a section into its own note, inline a referenced note back into its parent, sort a list. No plugin shim: Zed's built-in LSP handles it, and the official IWE extension just downloads the iwes binary on first use.

The same graph is also what my AI agent reads from. I keep seeing agent memory solved with vector databases, embedding stores, and opaque "knowledge" services, and every time I've tried one I lose the thing I actually want: being able to open the file, read it, grep it, diff it, and edit it like any other source.

IWE is a Rust LSP server that loads a directory of markdown files into an in-memory knowledge graph. No separate database, no embeddings, no sync step. Same files for you and the agent.

What the agent actually sees

IWE ships a CLI your agent calls directly:

iwe find "authentication"
iwe retrieve -k docs/auth-flow --depth 2

find is fuzzy search across the graph. retrieve returns a document and — with --depth — follows inclusion links and inlines child documents, so the agent gets transitive context in one call instead of a multi-turn crawl.

Here's what iwe retrieve -k platform --depth 2 produces when platform.md links to auth-flow.md which links to token-rotation.md:

---
document:
  key: platform
  title: Platform
---

# Platform

[Auth flow](auth-flow)

[Rate limiting](rate-limiting)


---
document:
  key: auth-flow
  title: Auth flow
  parents:
  - key: platform
    title: Platform
---

# Auth flow

[Token rotation](token-rotation)


---
document:
  key: token-rotation
  title: Token rotation
  parents:
  - key: auth-flow
    title: Auth flow
---

# Token rotation

Rotate refresh tokens every 24 hours. Access tokens expire after 15 minutes.

Just structured markdown with YAML frontmatter for identity and parent pointers. Nothing the model needs to be taught. If you use Claude Code, Cursor, or anything that can call shell commands, you can point it at these.

Structure without folders

Folders force single placement. Tags give you no structure. IWE uses inclusion links — a markdown link on its own line defines a parent-child relationship:

# Platform

[Auth flow](auth-flow.md)

[Rate limiting](rate-limiting.md)

A document can have multiple parents. "Rate limiting" lives under both Platform and Billing without duplication. You see that structure through Zed's document and workspace symbols; the agent sees it through retrieve --depth. More on inclusion links.

Keybindings

Action Keybinding
Go to definition (follow link) F12 or Cmd+Click
Find references (backlinks) Shift+F12
Code actions Cmd+.
Document symbols (outline) Cmd+Shift+O
Workspace symbols (search) Cmd+T
Rename (updates links across the graph) F2
Format document Cmd+Shift+I

The code actions you'll find in the Cmd+. menu: Extract, Extract all subsections, Inline section, Inline quote, Link, Sort A-Z, Sort Z-A. Rename is a separate LSP operation — F2 on a heading updates every incoming link automatically.

Setup

Open Zed, hit Cmd+Shift+X, search for IWE, install. The extension downloads the iwes binary from GitHub releases on first activation. Open a markdown file in your notes directory and the LSP comes up — iwes uses defaults if there's no config, so there's nothing else to run.

If you want IWE to apply only to your notes directory (not every markdown file in every project), scope it with .zed/settings.json in that directory:

{
  "lsp": {
    "iwe": {
      "binary": {
        "path": "iwes"
      }
    }
  }
}

What I'm looking for

Honest feedback on how this feels inside Zed specifically — how the code actions land in the command palette, whether the LSP surface matches what Zed users expect. Also interested in hearing from anyone wiring IWE up to Claude Code, Cursor, or similar: what worked, what you wish the CLI did differently.

GitHub: https://github.com/iwe-org/iwe Docs: https://iwe.md

u/gimalay — 4 days ago