A link takes a reader somewhere. A relationship also says why the connection matters. Keep that extra meaning clear enough to use, not elaborate enough to require a second framework.

Store the assertion at its source

Suppose a fictional project uses a fictional tool. The project stores:

relationships:
  - predicate: uses
    target: example-tool

The target is an ID, not a path. A renderer can later resolve it to a URL. Moving the tool’s file does not change the assertion.

This is an illustrative fragment. A real graph must register uses in its ontology and contain a node with ID example-tool before accepting the edge.

Keep the vocabulary small

Prefer a precise, reusable predicate such as depends-on to a growing collection of near synonyms. Write one sentence defining a new predicate before adopting it. If two predicates mean the same thing, choose one.

Do not invent a relationship merely because two words occur in the same article. A connection is an assertion that needs justification, not a decorative line.

Derive the reverse view

If A depends on B, the system can show A in B’s incoming connections. It does not need a second manually maintained assertion. The incoming view retains the source and original predicate; it does not pretend to prove the converse.

Cycles are not inherently invalid. A cycle in depends-on might be a problem for an execution order; a cycle of conceptual references might be entirely useful. Define the rule for the meaning, not for the shape alone.

Use a simple review test

For each edge, ask: can I read “source — predicate → target” as a clear statement? Does the target exist? Is the assertion supported? Would it still mean the same thing after either page moves?

Try it: add just one justified relationship. Build an incoming view before adding more predicates. Seeing how the edge will be used often reveals whether it was worth storing.