The knowledge base your agent can actually read.

ugraph turns what you read and watch into plain markdown an agent navigates by following links: articles, transcripts, scraped pages, pasted text. Every claim is traceable to a verbatim quote in the original capture. No database. No embeddings. No vector store.

Python CLI Open Knowledge Format Any CLI input Apache-2.0
10
CLI commands
init · ingest · index · lint · verify · status · graph · ledger · extract · skills
8
typed edge kinds
bidirectionality enforced by the linter
6
graph export formats
json · graphml · dot · canvas · obsidian-groups · d3
0
databases required
a knowledge base is a directory; the graph is a derived view

An agent can read a folder. It cannot read your trust.

The usual answer to "give my agent knowledge" is a vector store: chunk everything, embed it, retrieve the top-k, hope the model paraphrases honestly. You get a system nobody can inspect, that cannot be diffed, and whose citations are approximately true. ugraph makes the opposite bet.

Every quote is checked, not trusted

A verbatim_quote that is not a literal substring of the captured source is rejected and retried. Where the source carries time markers, a timestamp that does not resolve to a real one is rejected too. That turns an unreliable generator into a reliable pipeline, which is why a small local model is safe here.

# verify.py — the check the whole format rests on
quote in the capture         → pass
quote paraphrased            → reject, retry
timestamp [00:14:02] exists      → pass
quote inside that marker     → pass

The filesystem is the whole API

Markdown files, YAML frontmatter, relative links. An agent reads an index, follows two or three links, and cites a timestamp. It works in Obsidian, in git diff, in grep, and in a model context, because there is nothing to query.

knowledge/
├─ concepts/            the ideas
├─ entities/
│  ├─ tools/ people/ organizations/
├─ sources/             one page per item
├─ raw/                 immutable captures
├─ _mocs/               maps of content
├─ index.md             generated, byte-identical
└─ SCHEMA.md            the contract lint enforces

Gates that fail a build

lint, verify and index --check exit non-zero and stay quiet on success, so they drop into a pre-commit hook or CI unchanged. Index rebuilds are byte-identical: if a rebuild would change a file, the working tree is lying about what the KB contains.

# .github/workflows/kb.yml
- run: ugraph index --check
- run: ugraph lint --warnings
- run: ugraph verify

Bring the model you already pay for

The deterministic core calls no model at all. Extraction is opt-in and pluggable: hand the work to the agent you are already in, run it free and private on your own machine, or point it at an API key.

BackendWhat it is
claude-codeGuidance only — the agent does the work through the installed skill
ollamaLocal, free, private. Plain HTTP, no new dependency
apiAnthropic or OpenAI, via the [api] extra

Six stages, and the tool never lies about which one you are in

Lifecycle state is derived from the files on every run, never stored in frontmatter, so it cannot drift the first time somebody edits a page by hand. Transitions are appended to a log, because derivation can tell you where a source is but not how long it has been stuck there.

discovered
ugraph ingest

Known to the knowledge base, nothing captured yet.

pulled
ugraph ingest

Fetched or pasted, normalized to markdown, written immutably to raw/.

extracted
ugraph extract

Phase A. Candidate concepts with verbatim quotes and their anchors. Mechanical work.

synthesized
you + your agent

Phase B. Ten sources about one idea become one page. Deliberately not automated.

linked
ugraph index · lint

Typed edges resolve, indexes regenerate, everything is reachable.

verified
ugraph verify

Every quote verbatim, every anchor real. Now an agent may cite it.

deterministic — no model involved model-driven, output machine-checked human in the loop, on purpose

Phase B is the one step ugraph refuses to automate. Deciding which ten candidates collapse into one canonical page needs every candidate in view at once, it is where the entire value of the format lives, and there is no mechanical check for getting it wrong. That earns a good model and your judgement, not a batch job.

The Open Knowledge Format, made executable

Seven page types, each with a contract the linter enforces, and eight relationship headings that make the markdown a real graph. SCHEMA.md is the spec; model.py is the executable half of it.

prerequisites builds on implemented by tools sources context engineering context window eval harness Claude Code entity · tool DSPy entity · tool AIE Summit — talk source · video raw/ · immutable · [00:14:02]
A fragment of a knowledge base. Solid edges are reciprocated and the linter says so; the dashed sources edge is one-way by design, ending at the immutable capture that verify checks every quote against. Illustrative content; the shapes and the rules are the format's.
Page typeWhat it holdsRequired frontmatter
concept One idea, canonicalized across every source that discusses it type · title · description · domain · status · created · updated
entity A tool, a person, or an organization type · subtype · title · description · created · updated
source One article, talk, post or page, with its provenance type · source_type · title · description · slug · created · updated
raw-transcript The immutable capture every quote is checked against, whatever it came from type · immutable · slug
moc A map of content — the hand-curated route into a cluster type · title
overview A domain's front door type · title
note Human-facing scratch outside the traversable graph — held to almost no contract, on purpose type · title

Typed edges

A relationship is an ## heading with links under it. If A links to B under a typed heading, B must link back under some typed heading, and the linter checks it. sources is the deliberate exception: a transcript never links forward to its readers.

prerequisites builds on part of contrasts with implemented by tools related sources · one-way

Maturity, not vibes

Every concept declares a status and every claim a confidence, from a closed vocabulary. ugraph status --thin lists concepts still resting on a single source, the ones an agent should hedge on.

status: seed status: growing status: evergreen confidence: high confidence: medium confidence: low

Credit where it is due. The Open Knowledge Format was originated by Cole Medin (github.com/coleam00/cole-medin-knowledge-base). ugraph is an independent implementation of it as a reusable tool; every divergence is marked OKF-v in SCHEMA.md.

Ten commands, one job each

The CLI is deliberately thin: every subcommand resolves a config, calls one library function, and formats the result. Anything importable is importable: from ugraph import lint, verify, status.

CommandWhat it doesWorth knowing
ugraph initScaffold a new knowledge baseRun it bare for the interactive wizard; it refuses to scatter itself across an existing vault
ugraph ingestPull source material automatically--limit · --newest N · --retry-failed · --dry-run · resumable, checkpointed per item
ugraph extractModel-driven candidate extraction (Phase A)--backend claude-code|ollama|api · --model · --since 2w
ugraph indexRegenerate every index.md--check exits 1 if stale and writes nothing
ugraph lintThe conformance gate--warnings promotes warnings to failure · --report PATH · --json
ugraph verifyEvery quote verbatim, every timestamp real--candidates-only (strict) · --pages-only (deliberately timid)
ugraph statusExtraction progress and graph health--clusters · --pending · --thin · --json
ugraph ledgerLifecycle state of every source--stuck DAYS · --pending · --slug · record SLUG STAGE · --write
ugraph graphExport the KB as a graph (derived view)--format d3 opens a standalone interactive page · --concepts-only
ugraph skillsInstall the agent instructionsskills install --dest .claude/skills

From nothing to a citable knowledge base

ugraph init with no arguments walks a stranger through it: where the KB lives, which extraction backend to use, and the one thing a first-timer cannot undo: where not to scaffold it.

Requirements

Python 3.10+ python-frontmatter tomli · Python < 3.11 clipboard / pipe / file input anthropic / openai / ollama · optional

The KB root resolves in order: --kb, then $UGRAPH_KB, then the nearest ugraph.toml, then the current directory if it looks like a KB. Nothing is hardcoded, which is what makes the same commands work against someone else's vault.

quickstart
# 1 — scaffold (or run bare for the wizard)
ugraph init ./knowledge

# 2 — capture any input. deterministic, no model.
ugraph
#     clipboard · paste · pipe · file · URL
ugraph ingest file ./notes.md
printf 'a claim you care about' | ugraph --yes

# 3 — teach your agent the format
ugraph skills install

# 4 — Phase A: candidates with checked quotes
ugraph extract --newest 10

# 5 — Phase B is yours. then close the loop:
ugraph index && ugraph lint && ugraph verify

# see it: a standalone interactive graph
ugraph graph --format d3 --concepts-only \
  --out graph.html

What ugraph is not

Where the tool stops is as load-bearing as what it does. None of these are oversights.

Not a query engine

The graph export is a derived, disposable view. Markdown stays the source of truth, because a graph database in the loop is a second system that drifts from the files and turns git diff into something you cannot read. At a few hundred nodes the whole export fits in one model context anyway.

Not a RAG pipeline

There are no chunks and no embeddings. An agent gets the index, follows the two or three links it needs, and cites the timestamp it landed on. Retrieval quality is a property of the links you wrote, which you can read and fix.

Not tied to one kind of source

The CLI accepts any input you can land as text — clipboard, paste, pipe, file, or URL. Each capture becomes the same pair of files: an immutable copy in raw/ and a page in sources/. Downstream commands treat every source identically because the ledger keys on the slug, not on the input channel. More fetch adapters are on the backlog.

Not a repair tool

Nothing in verify ever rewrites your text. Machine captions carry their own disfluencies and mistranscriptions, and those are preserved inside quotes deliberately, because normalizing them away would destroy the evidence.

Point it at the sources you already trust.

Twenty-five captures, an afternoon of Phase B, and your agent stops guessing. It cites. Then read where this is going next.

Open source under Apache-2.0. Paid support is available for teams that need an SLA, and nothing in the tool is held back for it.

Product backlog Versions & updates