Skip to content

Commit 57bdd3c

Browse files
committed
docs(core): document relation grammar
Signed-off-by: phernandez <paul@basicmachines.co>
1 parent e73a049 commit 57bdd3c

5 files changed

Lines changed: 55 additions & 10 deletions

File tree

CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,16 @@
22

33
## Unreleased
44

5+
### Breaking Changes
6+
7+
- Relation parsing no longer treats unquoted multi-word text before a wikilink as a
8+
custom relation type. Use single-token relation types like `relates_to [[Target]]`,
9+
or quote multi-word relation types like `"relates to" [[Target]]` or
10+
`'relates to' [[Target]]`.
11+
- Bare list wikilinks like `- [[Target]]` now index as `links_to`.
12+
- Prose list items like `- some other thing [[Target]]` now index as `links_to`.
13+
- To preserve existing multi-word relation types on re-sync, quote them before upgrading.
14+
515
## v0.20.3 (2026-03-26)
616

717
### Bug Fixes

README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,8 +285,13 @@ Markdown format:
285285

286286
```markdown
287287
- relation_type [[WikiLink]] (optional context)
288+
- "multi word relation type" [[WikiLink]] (optional context)
289+
- 'multi word relation type' [[WikiLink]] (optional context)
288290
```
289291

292+
Unquoted relation types are single tokens. Use quotes when the relation type contains
293+
spaces. Bare wikilinks and prose with wikilinks are stored as `links_to` relations.
294+
290295
Examples of relations:
291296

292297
```markdown
@@ -295,6 +300,8 @@ Examples of relations:
295300
- contrasts_with [[Tea Brewing Methods]]
296301
- requires [[Burr Grinder]]
297302
- improves_with [[Fresh Beans]]
303+
- "pairs well with" [[Chocolate Desserts]]
304+
- 'documented in' [[Coffee Journal]]
298305
- relates_to [[Morning Routine]]
299306
- inspired_by [[Japanese Coffee Culture]]
300307
- documented_in [[Coffee Journal]]

docs/NOTE-FORMAT.md

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ The parser excludes these list item patterns:
106106
|---------|---------|--------|
107107
| Checkboxes | `- [ ] Todo item`, `- [x] Done`, `- [-] Cancelled` | Task list syntax |
108108
| Markdown links | `- [text](url)` | URL link syntax |
109-
| Bare wiki links | `- [[Target]]` | Treated as a relation instead |
109+
| Bare wiki links | `- [[Target]]` | Treated as a `links_to` relation instead |
110110

111111
A list item with `#tags` but no `[category]` is still parsed — the tags are extracted and the category defaults to `Note`.
112112

@@ -116,47 +116,65 @@ Relations connect documents to form the knowledge graph. There are two kinds.
116116

117117
### Explicit Relations
118118

119-
Written as list items with a relation type and a `[[wiki link]]` target.
119+
Written as list items with a relation type and a `[[wiki link]]` target. Unquoted
120+
relation types are single tokens. Quote relation types that contain spaces.
120121

121122
**Syntax:**
122123

123124
```
124125
- relation_type [[Target Entity]] (context)
126+
- "multi word relation type" [[Target Entity]] (context)
127+
- 'multi word relation type' [[Target Entity]] (context)
125128
```
126129

127130
| Part | Required | Description |
128131
|------|----------|-------------|
129-
| `relation_type` | No | Text before `[[`. Defaults to `relates_to` if omitted. |
132+
| `relation_type` | Yes | Single unquoted token before `[[`, or quoted text for multi-word labels. |
130133
| `[[Target]]` | Yes | Wiki link to the target entity. Matched by title or permalink. |
131134
| `(context)` | No | Parenthesized text after `]]`. Supporting details. |
132135

133136
### Examples
134137

138+
Explicit relations:
139+
135140
```markdown
136141
- implements [[Search Design]]
137142
- depends_on [[Database Schema]]
138143
- works_at [[Y Combinator]] (co-founder)
144+
- "based on" [[Customer Interview]]
145+
- 'in response to' [[Incident Review]]
146+
```
147+
148+
Bare wiki links and prose list items create implicit `links_to` relations:
149+
150+
```markdown
139151
- [[Some Entity]]
152+
- some other thing [[Some Entity]]
140153
```
141154

142-
The last example — a bare `[[wiki link]]` in a list item — gets relation type `relates_to`.
155+
Both examples above create `links_to [[Some Entity]]`. Use quotes when the words before
156+
`[[` are meant to be a multi-word relation type.
143157

144158
Common relation types:
145159
- `implements`, `depends_on`, `relates_to`, `inspired_by`
146160
- `extends`, `part_of`, `contains`, `pairs_with`
147161
- `works_at`, `authored`, `collaborated_with`
148162

149-
Any text works as a relation type. These are conventions, not a fixed set.
163+
Any single-token text or quoted text works as a relation type. These are conventions,
164+
not a fixed set.
150165

151166
### Inline References
152167

153-
Wiki links appearing in regular prose (not as list items) create implicit `links_to` relations.
168+
Wiki links appearing in regular prose create implicit `links_to` relations. This includes
169+
list items that do not match the explicit relation grammar above.
154170

155171
```markdown
156172
This builds on [[Core Design]] and uses [[Utility Functions]].
173+
- We should revisit [[Search Design]] after the API changes.
157174
```
158175

159-
This creates two relations: `links_to [[Core Design]]` and `links_to [[Utility Functions]]`.
176+
This creates three relations: `links_to [[Core Design]]`, `links_to [[Utility Functions]]`,
177+
and `links_to [[Search Design]]`.
160178

161179
### Forward References
162180

src/basic_memory/mcp/tools/write_note.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,10 +66,14 @@ async def write_note(
6666
6767
Relations format:
6868
- Explicit: `- relation_type [[Entity]] (optional context)`
69-
- Inline: Any `[[Entity]]` reference creates a relation
69+
- Quoted: `- "multi word relation type" [[Entity]] (optional context)`
70+
- Quoted: `- 'multi word relation type' [[Entity]] (optional context)`
71+
- Inline: Any other `[[Entity]]` reference creates a `links_to` relation
7072
7173
Examples:
7274
`- depends_on [[Content Parser]] (Need for semantic extraction)`
75+
`- "based on" [[Design Notes]]`
76+
`- 'in response to' [[Incident Review]]`
7377
`- implements [[Search Spec]] (Initial implementation)`
7478
`- This feature extends [[Base Design]] and uses [[Core Utils]]`
7579

tests/mcp/test_tool_write_note.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
from basic_memory import config as config_module
99
from basic_memory.mcp.tools import write_note, read_note, delete_note
10+
from basic_memory.repository.relation_repository import RelationRepository
1011
from basic_memory.utils import normalize_newlines
1112

1213

@@ -309,7 +310,7 @@ async def test_write_note_with_tag_array_from_bug_report(app, test_project):
309310

310311

311312
@pytest.mark.asyncio
312-
async def test_write_note_verbose(app, test_project):
313+
async def test_write_note_verbose(app, test_project, engine_factory):
313314
"""Test creating a new note.
314315
315316
Should:
@@ -326,7 +327,7 @@ async def test_write_note_verbose(app, test_project):
326327
# Test\nThis is a test note
327328
328329
- [note] First observation
329-
- relates to [[Knowledge]]
330+
- "relates to" [[Knowledge]]
330331
331332
""",
332333
tags=["test", "documentation"],
@@ -343,6 +344,11 @@ async def test_write_note_verbose(app, test_project):
343344
assert "- test, documentation" in result
344345
assert f"[Session: Using project '{test_project.name}']" in result
345346

347+
_, session_maker = engine_factory
348+
relation_repository = RelationRepository(session_maker, project_id=test_project.id)
349+
relations = await relation_repository.find_by_type("relates to")
350+
assert any(relation.to_name == "Knowledge" for relation in relations)
351+
346352

347353
@pytest.mark.asyncio
348354
async def test_write_note_preserves_custom_metadata(app, project_config, test_project):

0 commit comments

Comments
 (0)