Get started
Ten minutes, one command, and a question your docset could not answer before. Nothing here reaches a model or the network.
This is the first half of Maya’s M18. The second half is Explore the graph.
Before you start
Section titled “Before you start”Node.js 24 or newer, and the package you may already have:
npm install -D @hawkeyexl/manniGit is useful but not required. History is detected, not declared: where git can run over a repository, commit dates and authors become triples. Where it cannot, the run says so once and builds the rest.
1. Build the graph
Section titled “1. Build the graph”Point it at your docs:
$ npx @hawkeyexl/manni graph build docs/Wrote graph/graph.ttl (3 docs, 157 triples, 3 concepts)That is the whole first step. You now have a Turtle file: one node per document, one per heading, one per concept, plus the agents and activities that produced them.
Two runs over unchanged inputs produce a byte-identical file. That is a product contract rather than a happy accident, and it is why the graph is safe to commit, diff, and cache.
2. Ask what shape the docset is in
Section titled “2. Ask what shape the docset is in”$ npx @hawkeyexl/manni graph statsTriples: 157Documents: 3Sections: 8Concepts: 3References: 2
Most connected: docs/configuration.md (2) docs/getting-started.md (2)
Orphan docs (1): docs/troubleshooting.md
Broken internal links (1): docs/troubleshooting.md -> missing.md
Broken section refs (1): docs/getting-started.md -> #renamed-headingThe orphan is a page nothing links to. The broken section ref is a link to an anchor that no longer exists, which is what a renamed heading leaves behind. Neither is visible from any single file.
stats on its own always exits 0. --check makes it a gate.
3. Ask a question
Section titled “3. Ask a question”$ npx @hawkeyexl/manni graph query --predicate dcterms:subject<https://example.com/dd/doc/docs/configuration.md> dcterms:subject <https://example.com/dd/concept/reference><https://example.com/dd/doc/docs/getting-started.md> dcterms:subject <https://example.com/dd/concept/onboarding>
2 match(es)Omit a term and it is a wildcard, so that reads “everything the corpus says
about subject”. --subject and --object narrow the other two positions.
4. Check the graph
Section titled “4. Check the graph”$ npx @hawkeyexl/manni graph checkwarning: docs/configuration.md, docs/getting-started.md: Pages spell this concept two ways: "Installation" and "installation". Use one spelling on every page that names it. at https://example.com/dd/concept/installation skos:prefLabel manni:graph-shapes:1.3.0 Concept-prefLabel-collision: One name per language, so search and the glossary agree on a spelling. Guide: https://hawkeyexl.github.io/manni/graph/fix/
0 errors, 1 warning, 0 noticesTwo pages named one concept with different spellings, so they collided on a
single node. That finding does not exist in either file: it exists only in the
graph. This is the class of failure check is for, and the reason a graph gate
is not a second linter.
A warning reports and exits 0. An error exits 1.
5. Write the config down
Section titled “5. Write the config down”You can keep typing paths, but the point of a config is that CI and your laptop agree:
$ npx @hawkeyexl/manni graph initCreated manni.config.yamlIt writes a commented starter graph: section into manni.config.yaml, appending
to the file if it already exists and leaving every sibling tool’s keys alone. A
file that already has a graph: key is refused rather than overwritten.
Then declare the documents once, at the top level, where every tool reads them:
collections: - name: site paths: - "docs/**/*.{md,mdx}"
graph: baseIri: https://docs.example.com/graph/ out: graph/graph.ttlWith that in place, manni graph build with no paths reads the collection. The
same collection feeds manni meta validate and manni cite check, which is
the point of declaring it once.
Set baseIri to a namespace you control. Without it, node IRIs fall back to
urn:manni:graph:, which identifies without promising to resolve. That is fine
for a graph that stays in CI. It is unhelpful for one you hand to someone
else.
What you have now
Section titled “What you have now”- A deterministic graph of the docset, rebuildable in one command.
- A list of orphans, broken links and broken anchors that no per-file check produces.
- A corpus-level contract, enforced by
check.
Where next
Section titled “Where next”| Goal | Page |
|---|---|
| Ask the graph more questions | Explore the graph |
| Know what a change to one page affects | See what a change affects |
| Understand what becomes a triple, and what never does | How manni graph works |
| Categorize a corpus nobody annotated | Fill the vocabulary |
| Make this a gate on every pull request | Run it in CI |