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.
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.
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.
Backend
What it is
claude-code
Guidance only — the agent does the work through the installed skill
ollama
Local, free, private. Plain HTTP, no new dependency
api
Anthropic 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.
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 type
What it holds
Required 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.
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.
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.
Command
What it does
Worth knowing
ugraph init
Scaffold a new knowledge base
Run it bare for the interactive wizard; it refuses to scatter itself across an existing vault
ugraph ingest
Pull source material automatically
--limit · --newest N · --retry-failed · --dry-run · resumable, checkpointed per item
--stuck DAYS · --pending · --slug · record SLUG STAGE · --write
ugraph graph
Export the KB as a graph (derived view)
--format d3 opens a standalone interactive page · --concepts-only
ugraph skills
Install the agent instructions
skills 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.
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 · URLugraph ingest file ./notes.mdprintf 'a claim you care about' | ugraph --yes# 3 — teach your agent the formatugraph skills install# 4 — Phase A: candidates with checked quotesugraph extract --newest 10# 5 — Phase B is yours. then close the loop:ugraph index && ugraph lint && ugraph verify# see it: a standalone interactive graphugraph 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.