GRAPH.md
The specification.
Eleven sections, two of them optional, two regions, seventy lines. That is the whole of it, and it is also exactly what validation looks at.
The sections
Their order is part of the spec. An assistant reads top to bottom, and the checker looks at the order too.
What this isIts standing, and who does the judging. Three lines is enough.Read before you writeSearch first, reuse the ids you get back. The id prefix convention lives here.Node kindsWhen to reach for Concept, Episode, Record, Decision, Bridge, Entity.How big is one conceptTwo good examples and three bad ones, instead of a rule. Rules here do not get followed.RelationsThe six of them, and what a direction means. Three of them carry meaning in the direction.DocumentsWhich route source text comes in by, so whole documents do not get pasted onto nodes.RolesOptional. What an Agent role is as a node (concept:agent-<name> under the reserved topic vinc/agent), and the properties that are its contract.TopicsOptional. How to shape the domain field into a tree (area/discipline/subject), and how big a leaf should be (ten to sixty nodes).Domains in this graphGenerated. The real topic list and how you spell them.Ratified vocabularyGenerated. The node and relation types a person has approved.Do notThree of them, starting with: do not approve your own proposal.The two generated sections are filled by Generate it. Roles and Topics are optional: a file without them passes, and a file with them is checked for their order. What a person writes is nine sections, about 44 lines.
Seventy lines
Not a cap, a design. A long conventions file does not get read, and unread is the same as absent. The shipped template is 69 lines including blanks, so there is one line of headroom.
Which means adding a line means deleting one. The budget moved once, from sixty to seventy, when the Roles and Topics sections were added, and that took a written decision rather than a habit. That budget is what keeps this document short.
The file
Copy it as is. The region between the markers gets replaced with values from your own map.
# GRAPH.md
<!-- vinc-graph-md: 1 · built 2026-08-01 · the store is canonical, this file is a view of it -->
## What this is [this graph decides]
The house style for writing into this knowledge graph. Read it before your first write
in a session. Judging meaning is your job. This file only fixes the conventions.
## Read before you write [this graph decides]
Search first (vinc_search), reuse the ids you get back, and prefer attaching to an
existing concept over creating a near duplicate. Ids carry their type as a prefix:
concept:optimistic-locking, decision:drop-the-cache, record:pricing-note.
Write in English, titles and bodies alike, whatever language you are thinking in.
## Node kinds [schema-fixed]
- Concept: one reusable idea. If it will not be reused, do not create it.
- Episode: something that happened (a session, an event). It is tied to a time.
- Record: a note on a concept, or a measurement about code: then add props.subject_path as repo:path (vinc:api/sync.py), measured_at, measured_ref.
- Decision: what you chose at a point in time, and why. Tie it with `about`.
- Bridge: a junction that ties domains together.
- Entity: anything else you author. Unknown types save here and enter the
vocabulary as proposed. If you cannot decide, use Concept and say so.
## How big is one concept [varies by topic]
GOOD "Optimistic concurrency control": reusable, self standing, one idea.
GOOD "Sunk cost fallacy": same shape, different field.
BAD "Database stuff": several ideas in a bag. Split it.
BAD "What I read today": not a concept. That is an Episode.
BAD "PostgreSQL" and "Postgres" as two nodes: the same thing. Keep one.
Test: if you cannot finish the sentence "X is ..." in two sentences, it is too big.
People and products pass that test but are not ideas: write them as an Entity or record.
## Relations [schema-fixed]
- relates_to: loose association. Undirected (the reverse folds into the same edge).
- prerequisite_of: A comes before B. The direction carries the meaning.
- derives_from: A comes out of B. The direction carries the meaning.
- inherits_from: A inherits from B. The direction carries the meaning.
- connects_via: Bridge to Concept or Decision.
- about: Episode or Decision to Concept or Decision.
Record to either: any of the first four. Those edges and about must carry `evidence`.
Not sure: use relates_to. Never flip a directed edge to make it fit.
## Documents [schema-fixed]
Source text goes in through vinc_doc_put and the store keeps the canonical copy. Do
not paste a whole document into a Record; link concepts through the document, not a copy.
## Roles [schema-fixed]
An Agent role is a Concept: id concept:agent-<name>, topic vinc/agent (a reserved topic).
Its contract is props: mission, tier, rung, reads (ordered doc ids), gates, never, person_only.
props replace whole on every write: read them back, then resend. A change ships with a Decision about the role.
## Topics [this graph decides]
A topic is the domain field. Shape it area/discipline/subject, two or three levels, lowercase english.
A leaf holds ten to sixty nodes: past sixty split it, under five fold it into its parent.
<!-- vinc:generated start · copied from the ontology below this line -->
## Domains in this graph
research (142) · product (88) · personal (31)
A slash makes a tree: 'vinc/design' files that node under 'vinc', with nothing extra to author. Walk it with vinc_neighbors('domain:vinc').
## Ratified vocabulary
node types: none beyond the six above
edge types: cites, contradicts
Anything else you write is kept and marked proposed, for a person to ratify.
<!-- vinc:generated end -->
## Do not [this graph decides]
- Do not ratify your own proposal. A person does that.
- Do not create a node for something you did not search for first.
- Do not invent a domain name inline. Propose it and say why.
Those two comment lines are markers. Leave them in. They are how the command and the app know where the generated region begins and ends.
For a Korean file, run
vinc graph-md build --lang ko. Only the section names differ, the spec is the same.What happens to anything unrecognised
A spec is only half written if it says what is allowed and not what becomes of the rest. Here is the rest.
An unlisted node typeSaves as an Entity and enters the vocabulary as proposed. Nothing is dropped.An unlisted relationBetween two open-type nodes it saves and is proposed. Between the built-in kinds, only the pairs that make structural sense are accepted, and the rest are reported back rather than silently skipped.A topic you inventedSaves. Nothing rejects it, which is exactly why the conventions ask an assistant to propose one instead of coining it mid sentence.A section you addedLeft alone. Validation checks that the required sections are present and ordered, not that yours are absent.The pattern is the same everywhere: keep it, mark it, and let a person decide. Rejecting at write time would lose the one thing a machine cannot recreate, which is what your assistant meant.