datanotes 2.0.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (181) hide show
  1. package/NOTICE +9 -0
  2. package/README.md +207 -28
  3. package/SECURITY.md +92 -45
  4. package/dist/THIRD-PARTY-NOTICES.txt +682 -0
  5. package/dist/api/catalog.d.cts +69 -0
  6. package/dist/api/catalog.d.ts +50 -2
  7. package/dist/api/cli-options.d.cts +39 -0
  8. package/dist/api/cli-options.d.ts +39 -0
  9. package/dist/api/client.d.cts +89 -0
  10. package/dist/api/client.d.ts +19 -30
  11. package/dist/api/docs.d.cts +211 -0
  12. package/dist/api/docs.d.ts +211 -0
  13. package/dist/api/guidance.d.cts +81 -0
  14. package/dist/api/guidance.d.ts +81 -0
  15. package/dist/api/index.cjs +6610 -2247
  16. package/dist/api/index.d.cts +13 -0
  17. package/dist/api/index.d.ts +10 -7
  18. package/dist/api/index.js +6610 -2247
  19. package/dist/api/local.cjs +118 -6
  20. package/dist/api/local.d.cts +95 -0
  21. package/dist/api/local.d.ts +70 -6
  22. package/dist/api/local.js +104 -6
  23. package/dist/api/mcp.cjs +17384 -0
  24. package/dist/api/mcp.d.cts +108 -0
  25. package/dist/api/mcp.d.ts +108 -0
  26. package/dist/api/mcp.js +17334 -0
  27. package/dist/api/otlp.d.cts +65 -0
  28. package/dist/api/redact.d.cts +17 -0
  29. package/dist/api/redact.d.ts +17 -0
  30. package/dist/api/requests.d.cts +26 -0
  31. package/dist/api/requests.d.ts +14 -16
  32. package/dist/api/results.d.cts +16 -0
  33. package/dist/api/results.d.ts +2 -1
  34. package/dist/api/tokens.d.cts +7 -0
  35. package/dist/datanotes.cjs +62911 -28409
  36. package/dist/docs/administration/configuration.md +59 -0
  37. package/dist/docs/administration/docker.md +80 -0
  38. package/dist/docs/administration/git-sync.md +71 -0
  39. package/dist/docs/administration/limits.md +69 -0
  40. package/dist/docs/administration/run-the-service.md +219 -0
  41. package/dist/docs/administration/status.md +61 -0
  42. package/dist/docs/administration/use-with-obsidian.md +75 -0
  43. package/dist/docs/api/operations/add_column.md +49 -0
  44. package/dist/docs/api/operations/add_constraint.md +55 -0
  45. package/dist/docs/api/operations/adopt_rows.md +50 -0
  46. package/dist/docs/api/operations/align_relations.md +41 -0
  47. package/dist/docs/api/operations/alter_column.md +46 -0
  48. package/dist/docs/api/operations/alter_table.md +67 -0
  49. package/dist/docs/api/operations/batch.md +48 -0
  50. package/dist/docs/api/operations/changes_stream.md +28 -0
  51. package/dist/docs/api/operations/check_table.md +29 -0
  52. package/dist/docs/api/operations/clone_table.md +48 -0
  53. package/dist/docs/api/operations/comment_on.md +42 -0
  54. package/dist/docs/api/operations/configure_database.md +52 -0
  55. package/dist/docs/api/operations/create_table.md +78 -0
  56. package/dist/docs/api/operations/create_view.md +54 -0
  57. package/dist/docs/api/operations/create_webhook.md +37 -0
  58. package/dist/docs/api/operations/define_base.md +52 -0
  59. package/dist/docs/api/operations/delete_rows.md +43 -0
  60. package/dist/docs/api/operations/delete_webhook.md +31 -0
  61. package/dist/docs/api/operations/describe_database.md +30 -0
  62. package/dist/docs/api/operations/describe_history.md +40 -0
  63. package/dist/docs/api/operations/describe_semantic_index.md +24 -0
  64. package/dist/docs/api/operations/describe_table.md +38 -0
  65. package/dist/docs/api/operations/docs.md +13 -0
  66. package/dist/docs/api/operations/drop_column.md +41 -0
  67. package/dist/docs/api/operations/drop_constraint.md +39 -0
  68. package/dist/docs/api/operations/drop_table.md +43 -0
  69. package/dist/docs/api/operations/drop_view.md +38 -0
  70. package/dist/docs/api/operations/engine_status.md +23 -0
  71. package/dist/docs/api/operations/graph_neighbors.md +32 -0
  72. package/dist/docs/api/operations/graph_path.md +32 -0
  73. package/dist/docs/api/operations/graph_traverse.md +43 -0
  74. package/dist/docs/api/operations/identify_session.md +24 -0
  75. package/dist/docs/api/operations/infer_table.md +43 -0
  76. package/dist/docs/api/operations/insert_row.md +48 -0
  77. package/dist/docs/api/operations/list_changes.md +35 -0
  78. package/dist/docs/api/operations/list_folder.md +28 -0
  79. package/dist/docs/api/operations/list_link_targets.md +44 -0
  80. package/dist/docs/api/operations/list_migrations.md +35 -0
  81. package/dist/docs/api/operations/list_tables.md +32 -0
  82. package/dist/docs/api/operations/list_webhooks.md +23 -0
  83. package/dist/docs/api/operations/manual_index.md +14 -0
  84. package/dist/docs/api/operations/manual_page.md +22 -0
  85. package/dist/docs/api/operations/merge_rows.md +44 -0
  86. package/dist/docs/api/operations/move_rows.md +52 -0
  87. package/dist/docs/api/operations/openapi.md +13 -0
  88. package/dist/docs/api/operations/openapi_post.md +20 -0
  89. package/dist/docs/api/operations/read_note.md +29 -0
  90. package/dist/docs/api/operations/recompute_columns.md +44 -0
  91. package/dist/docs/api/operations/record_tool_call.md +36 -0
  92. package/dist/docs/api/operations/rename_column.md +44 -0
  93. package/dist/docs/api/operations/rename_value.md +45 -0
  94. package/dist/docs/api/operations/restore_database.md +51 -0
  95. package/dist/docs/api/operations/restore_table.md +46 -0
  96. package/dist/docs/api/operations/search_notes.md +28 -0
  97. package/dist/docs/api/operations/select_rows.md +61 -0
  98. package/dist/docs/api/operations/semantic_search.md +34 -0
  99. package/dist/docs/api/operations/semantic_search_docs.md +26 -0
  100. package/dist/docs/api/operations/set_table_bases.md +44 -0
  101. package/dist/docs/api/operations/status.md +13 -0
  102. package/dist/docs/api/operations/stop_engine.md +23 -0
  103. package/dist/docs/api/operations/sync_semantic_index.md +33 -0
  104. package/dist/docs/api/operations/table_changes.md +31 -0
  105. package/dist/docs/api/operations/tags/auxiliary.md +14 -0
  106. package/dist/docs/api/operations/tags/change-feed.md +8 -0
  107. package/dist/docs/api/operations/tags/history.md +17 -0
  108. package/dist/docs/api/operations/tags/queries.md +15 -0
  109. package/dist/docs/api/operations/tags/rows-dml.md +16 -0
  110. package/dist/docs/api/operations/tags/schema-ddl.md +22 -0
  111. package/dist/docs/api/operations/tags/service.md +15 -0
  112. package/dist/docs/api/operations/tags/tokens.md +13 -0
  113. package/dist/docs/api/operations/tokens_create.md +34 -0
  114. package/dist/docs/api/operations/tokens_delete.md +29 -0
  115. package/dist/docs/api/operations/tokens_list.md +21 -0
  116. package/dist/docs/api/operations/tokens_me.md +20 -0
  117. package/dist/docs/api/operations/tokens_rotate.md +29 -0
  118. package/dist/docs/api/operations/tokens_update.md +34 -0
  119. package/dist/docs/api/operations/undo_migration.md +46 -0
  120. package/dist/docs/api/operations/update_row.md +60 -0
  121. package/dist/docs/api/operations/update_rows.md +46 -0
  122. package/dist/docs/api/operations/vacuum_table.md +37 -0
  123. package/dist/docs/api.md +135 -0
  124. package/dist/docs/develop/build-an-app.md +320 -0
  125. package/dist/docs/develop/build-on-datanotes.md +138 -0
  126. package/dist/docs/develop/change-feed-and-webhooks.md +70 -0
  127. package/dist/docs/develop/client.md +116 -0
  128. package/dist/docs/develop/concurrency.md +153 -0
  129. package/dist/docs/develop/http-api.md +79 -0
  130. package/dist/docs/develop/telemetry.md +86 -0
  131. package/dist/docs/guides/agents/docs-offline.md +99 -0
  132. package/dist/docs/guides/agents/how-agents-use-datanotes.md +124 -0
  133. package/dist/docs/guides/agents/prompts.md +495 -0
  134. package/dist/docs/guides/agents/reading-errors.md +112 -0
  135. package/dist/docs/guides/data-quality/check-constraints.md +379 -0
  136. package/dist/docs/guides/data-quality/check-table.md +63 -0
  137. package/dist/docs/guides/data-quality/hand-edits.md +507 -0
  138. package/dist/docs/guides/data-quality/sync-between-devices.md +51 -0
  139. package/dist/docs/guides/data-quality/validation.md +90 -0
  140. package/dist/docs/guides/database-objects/bases.md +480 -0
  141. package/dist/docs/guides/database-objects/catalogs-and-schemas.md +897 -0
  142. package/dist/docs/guides/database-objects/columns.md +1332 -0
  143. package/dist/docs/guides/database-objects/relations.md +1454 -0
  144. package/dist/docs/guides/database-objects/tables.md +1404 -0
  145. package/dist/docs/guides/database-objects/views.md +1003 -0
  146. package/dist/docs/guides/history/back-up.md +195 -0
  147. package/dist/docs/guides/history/change-data-feed.md +247 -0
  148. package/dist/docs/guides/history/journal-and-undo.md +262 -0
  149. package/dist/docs/guides/history/restore.md +341 -0
  150. package/dist/docs/guides/history/table-history.md +657 -0
  151. package/dist/docs/guides/history/vacuum.md +35 -0
  152. package/dist/docs/guides/read-and-write/automatic-links.md +768 -0
  153. package/dist/docs/guides/read-and-write/batch.md +139 -0
  154. package/dist/docs/guides/read-and-write/import-notes.md +896 -0
  155. package/dist/docs/guides/read-and-write/joins-and-aggregates.md +251 -0
  156. package/dist/docs/guides/read-and-write/read-and-filter.md +536 -0
  157. package/dist/docs/guides/read-and-write/write-rows.md +573 -0
  158. package/dist/docs/guides/search/link-graph.md +146 -0
  159. package/dist/docs/guides/search/semantic.md +133 -0
  160. package/dist/docs/guides/search/text.md +142 -0
  161. package/dist/docs/guides/security/security-model.md +110 -0
  162. package/dist/docs/guides/security/tokens.md +60 -0
  163. package/dist/docs/guides/security/who-did-what.md +42 -0
  164. package/dist/docs/index.md +113 -0
  165. package/dist/docs/llms.txt +33 -0
  166. package/dist/docs/reference/cli.md +136 -0
  167. package/dist/docs/reference/compatibility.md +63 -0
  168. package/dist/docs/reference/errors.md +72 -0
  169. package/dist/docs/reference/glossary.md +161 -0
  170. package/dist/docs/reference/operations/auxiliary.md +116 -0
  171. package/dist/docs/reference/operations/history.md +168 -0
  172. package/dist/docs/reference/operations/queries.md +169 -0
  173. package/dist/docs/reference/operations/rows.md +185 -0
  174. package/dist/docs/reference/operations/schema.md +316 -0
  175. package/dist/docs/reference/operations.md +96 -0
  176. package/dist/docs/reference/settings.md +31 -0
  177. package/dist/docs/release-notes.md +67 -0
  178. package/dist/docs/start/connect-agents.md +204 -0
  179. package/dist/docs/start/how-it-works.md +317 -0
  180. package/dist/docs/start/quick-start.md +126 -0
  181. package/package.json +59 -14
@@ -0,0 +1,896 @@
1
+ # Import existing notes
2
+
3
+ > Turn a folder of notes you already have into a table: infer its columns, create it and adopt the notes. Then choose which new notes become rows on their own.
4
+
5
+ Your vault may already have notes with front matter, like a film diary, a reading list or meeting notes. The examples start from a `Films/` folder of classic films written by hand, each with its year, runtime and `Director`. You turn it into a table without retyping anything: you infer the columns, create the table and adopt the notes. Then you decide which new notes become rows on their own.
6
+
7
+ ## Infer a table from notes
8
+
9
+ `infer_table` reads the notes’ front matter and proposes a table, without writing anything. The proposal has:
10
+
11
+ * **A type for each key**: an enum when a few short values repeat across enough notes
12
+ * **Shared keys**: which front matter keys every note has
13
+ * **Valid column names**: a key whose name isn’t a valid column name, like `Director`, gets a valid name and a `from`
14
+
15
+ **`infer_table`**
16
+
17
+ ```json
18
+ { "folder": "Films", "name": "film" }
19
+ ```
20
+
21
+ Answer (153 lines)
22
+
23
+ ```json
24
+ {
25
+ "files": 5,
26
+ "paths": [
27
+ "Films/Charade.md",
28
+ "Films/His Girl Friday.md",
29
+ "Films/Metropolis.md",
30
+ "Films/Nosferatu.md",
31
+ "Films/The Gold Rush.md"
32
+ ],
33
+ "skipped": [],
34
+ "columns": [
35
+ {
36
+ "name": "director",
37
+ "from": "Director",
38
+ "type": "string",
39
+ "description": null,
40
+ "stats": {
41
+ "present": 5,
42
+ "filled": 5,
43
+ "distinct": 5,
44
+ "types": { "string": 5 },
45
+ "examples": ["Stanley Donen", "Howard Hawks", "Fritz Lang"]
46
+ },
47
+ "required": true,
48
+ "unique": true,
49
+ "dense": true
50
+ },
51
+ {
52
+ "name": "minutes",
53
+ "type": "integer",
54
+ "description": null,
55
+ "stats": {
56
+ "present": 5,
57
+ "filled": 5,
58
+ "distinct": 5,
59
+ "types": { "integer": 5 },
60
+ "examples": [113, 92, 153]
61
+ },
62
+ "required": true,
63
+ "unique": true,
64
+ "dense": true
65
+ },
66
+ {
67
+ "name": "status",
68
+ "type": "enum",
69
+ "description": null,
70
+ "stats": {
71
+ "present": 5,
72
+ "filled": 5,
73
+ "distinct": 2,
74
+ "types": { "string": 5 },
75
+ "examples": ["watched", "watched", "to watch"]
76
+ },
77
+ "values": ["watched", "to watch"],
78
+ "required": true,
79
+ "dense": true
80
+ },
81
+ {
82
+ "name": "year",
83
+ "type": "integer",
84
+ "description": null,
85
+ "stats": {
86
+ "present": 5,
87
+ "filled": 5,
88
+ "distinct": 5,
89
+ "types": { "integer": 5 },
90
+ "examples": [1963, 1940, 1927]
91
+ },
92
+ "required": true,
93
+ "unique": true,
94
+ "dense": true
95
+ },
96
+ {
97
+ "name": "rating",
98
+ "type": "integer",
99
+ "description": null,
100
+ "stats": {
101
+ "present": 4,
102
+ "filled": 4,
103
+ "distinct": 2,
104
+ "types": { "integer": 4 },
105
+ "examples": [4, 5, 5]
106
+ }
107
+ },
108
+ {
109
+ "name": "watched_on",
110
+ "type": "date",
111
+ "description": null,
112
+ "stats": {
113
+ "present": 4,
114
+ "filled": 4,
115
+ "distinct": 4,
116
+ "types": { "date": 4 },
117
+ "examples": ["2026-09-12", "2026-07-20", "2026-03-14"]
118
+ }
119
+ }
120
+ ],
121
+ "proposal": {
122
+ "name": "film",
123
+ "description": null,
124
+ "columns": [
125
+ {
126
+ "name": "director",
127
+ "type": "string",
128
+ "description": null,
129
+ "required": true,
130
+ "unique": true,
131
+ "dense": true
132
+ },
133
+ {
134
+ "name": "minutes",
135
+ "type": "integer",
136
+ "description": null,
137
+ "required": true,
138
+ "unique": true,
139
+ "dense": true
140
+ },
141
+ {
142
+ "name": "status",
143
+ "type": "enum",
144
+ "description": null,
145
+ "values": ["watched", "to watch"],
146
+ "required": true,
147
+ "dense": true
148
+ },
149
+ {
150
+ "name": "year",
151
+ "type": "integer",
152
+ "description": null,
153
+ "required": true,
154
+ "unique": true,
155
+ "dense": true
156
+ },
157
+ { "name": "rating", "type": "integer", "description": null },
158
+ { "name": "watched_on", "type": "date", "description": null }
159
+ ]
160
+ },
161
+ "adopt": {
162
+ "paths": [
163
+ "Films/Charade.md",
164
+ "Films/His Girl Friday.md",
165
+ "Films/Metropolis.md",
166
+ "Films/Nosferatu.md",
167
+ "Films/The Gold Rush.md"
168
+ ],
169
+ "rename": { "Director": "director" },
170
+ "relocate": false
171
+ },
172
+ "hints": [
173
+ "no column matches the file names: set filename (e.g. \"{title}\") and adopt with relocate: false to keep the current names",
174
+ "write the description of the table and of each column (null in the proposal) before create_table: it refuses them empty"
175
+ ]
176
+ }
177
+ ```
178
+
179
+ Read the proposal and its `notes` before you use it. The notes can’t say what the table and its columns mean. So `description` is `null` on the table and on every column, for you to write. Here five columns also need a fix:
180
+
181
+ * **`year`**, **`minutes`** and **`director`**: came out `unique` because no two of these films share them, which won’t stay true
182
+ * **`status`**: an enum with its values in the order the notes gave them, `watched` first, where you want an ordered enum from `to watch` to `watched`
183
+ * **`rating`**: an integer with no range, where you want 1 to 5
184
+ * **`title`**: missing, because the notes keep the title in the note’s name, not in the front matter
185
+
186
+ ## Create the table from the proposal
187
+
188
+ `create_table` refuses the proposal as it is, because its descriptions are `null`. The refusal names every one you still have to write:
189
+
190
+ **`create_table`**
191
+
192
+ ```json
193
+ {
194
+ "name": "film",
195
+ "description": null,
196
+ "columns": [
197
+ {
198
+ "name": "director",
199
+ "type": "string",
200
+ "description": null,
201
+ "required": true,
202
+ "unique": true,
203
+ "dense": true
204
+ },
205
+ {
206
+ "name": "minutes",
207
+ "type": "integer",
208
+ "description": null,
209
+ "required": true,
210
+ "unique": true,
211
+ "dense": true
212
+ },
213
+ {
214
+ "name": "status",
215
+ "type": "enum",
216
+ "description": null,
217
+ "values": ["watched", "to watch"],
218
+ "required": true,
219
+ "dense": true
220
+ },
221
+ {
222
+ "name": "year",
223
+ "type": "integer",
224
+ "description": null,
225
+ "required": true,
226
+ "unique": true,
227
+ "dense": true
228
+ },
229
+ { "name": "rating", "type": "integer", "description": null },
230
+ { "name": "watched_on", "type": "date", "description": null }
231
+ ]
232
+ }
233
+ ```
234
+
235
+ Refused:
236
+
237
+ ```text
238
+ pass "time_column" or "filename" (e.g. "{name}") so rows get file names
239
+ Hint: Check the arguments of create_table: name (string, required), description (string), columns (list of objects, required), catalog (string), schema (string), time_column (string), filename (string), partition (string), exclude (list of strings), archive (string), aliases (list of strings), history (boolean), autolink_target (boolean), row_template (string), fields (object), tags (object), dry_run (boolean).
240
+ Docs: https://datanotes.dev/reference/operations/schema.md#create_table (offline: read_docs("reference/operations/schema#create_table"))
241
+ ```
242
+
243
+ This call adds a description to the table and to each column, and corrects what the inference guessed wrong:
244
+
245
+ * **`year`**, **`minutes`** and **`director`**: no longer unique
246
+ * **`status`**: an ordered enum (`to watch` < `watched`)
247
+ * **`rating`**: from 1 to 5
248
+ * **`title`**: a new column that holds the note’s file name (`identity: "filename"`)
249
+
250
+ **`create_table`**
251
+
252
+ ```json
253
+ {
254
+ "name": "film",
255
+ "description": "Classic films I watched or want to watch",
256
+ "columns": [
257
+ {
258
+ "name": "title",
259
+ "type": "string",
260
+ "identity": "filename",
261
+ "description": "The film's title, which is also its note's name"
262
+ },
263
+ {
264
+ "name": "director",
265
+ "type": "string",
266
+ "description": "Who directed the film",
267
+ "required": true,
268
+ "unique": false,
269
+ "dense": true
270
+ },
271
+ {
272
+ "name": "minutes",
273
+ "type": "integer",
274
+ "description": "Running time in minutes",
275
+ "required": true,
276
+ "unique": false,
277
+ "dense": true
278
+ },
279
+ {
280
+ "name": "status",
281
+ "type": "enum",
282
+ "description": "Where the film is on my list",
283
+ "values": ["to watch", "watched"],
284
+ "required": true,
285
+ "dense": true,
286
+ "ordered": true
287
+ },
288
+ {
289
+ "name": "year",
290
+ "type": "integer",
291
+ "description": "Year the film first came out",
292
+ "required": true,
293
+ "unique": false,
294
+ "dense": true
295
+ },
296
+ {
297
+ "name": "rating",
298
+ "type": "integer",
299
+ "min": 1,
300
+ "max": 5,
301
+ "description": "My rating, from 1 (poor) to 5 (a masterpiece)"
302
+ },
303
+ { "name": "watched_on", "type": "date", "description": "The day I last watched it" }
304
+ ],
305
+ "filename": "{title}"
306
+ }
307
+ ```
308
+
309
+ Answer:
310
+
311
+ ```json
312
+ {
313
+ "ok": true,
314
+ "op": "create_table",
315
+ "planned_texts": ["datanotes/metastore.yaml"],
316
+ "commits": [{ "table": "main.public.film", "version": 0, "operation": "CREATE TABLE" }],
317
+ "migration_id": "20261012T071957-create_table-create-table-main-public-film"
318
+ }
319
+ ```
320
+
321
+ ## Preview the adoption with a dry run
322
+
323
+ `adopt_rows` makes existing notes rows of a table and keeps their text and links. It sets `table` and an `id` on each note, and applies these arguments:
324
+
325
+ * **`rename`**: renames front matter keys to column names
326
+ * **`set`**: sets the same values on every note
327
+ * **`drop`**: removes the front matter keys the table doesn’t have
328
+ * **`relocate`**: moves the notes to the table’s folder and rewrites the links to them
329
+
330
+ With `dry_run`, it shows what it would do and writes nothing.
331
+
332
+ **`adopt_rows`**
333
+
334
+ ```json
335
+ {
336
+ "table": "film",
337
+ "paths": [
338
+ "Films/Charade.md",
339
+ "Films/His Girl Friday.md",
340
+ "Films/Metropolis.md",
341
+ "Films/Nosferatu.md",
342
+ "Films/The Gold Rush.md"
343
+ ],
344
+ "rename": { "Director": "director" },
345
+ "relocate": true,
346
+ "dry_run": true
347
+ }
348
+ ```
349
+
350
+ Answer (70 lines)
351
+
352
+ ```json
353
+ {
354
+ "ok": true,
355
+ "op": "adopt_rows",
356
+ "dry_run": true,
357
+ "planned_edits": [
358
+ {
359
+ "path": "Films/Charade.md",
360
+ "set": {
361
+ "table": "main.public.film",
362
+ "id": "01a12efb-81a4-717d-a664-f60882bb8996",
363
+ "director": "Stanley Donen",
364
+ "title": "Charade"
365
+ },
366
+ "remove": ["Director"]
367
+ },
368
+ {
369
+ "path": "Films/His Girl Friday.md",
370
+ "set": {
371
+ "table": "main.public.film",
372
+ "id": "01a12efb-81a4-7e0e-8864-4d93d474be34",
373
+ "director": "Howard Hawks",
374
+ "title": "His Girl Friday"
375
+ },
376
+ "remove": ["Director"]
377
+ },
378
+ {
379
+ "path": "Films/Metropolis.md",
380
+ "set": {
381
+ "table": "main.public.film",
382
+ "id": "01a12efb-81a4-747e-8aef-048494381ac2",
383
+ "director": "Fritz Lang",
384
+ "title": "Metropolis"
385
+ },
386
+ "remove": ["Director"]
387
+ },
388
+ {
389
+ "path": "Films/Nosferatu.md",
390
+ "set": {
391
+ "table": "main.public.film",
392
+ "id": "01a12efb-81a4-71bf-9b8f-a28f778461db",
393
+ "director": "F. W. Murnau",
394
+ "title": "Nosferatu"
395
+ },
396
+ "remove": ["Director"]
397
+ },
398
+ {
399
+ "path": "Films/The Gold Rush.md",
400
+ "set": {
401
+ "table": "main.public.film",
402
+ "id": "01a12efb-81a4-7628-817c-ce1281d27329",
403
+ "director": "Charlie Chaplin",
404
+ "title": "The Gold Rush"
405
+ },
406
+ "remove": ["Director"]
407
+ }
408
+ ],
409
+ "planned_moves": [
410
+ { "from": "Films/Charade.md", "to": "datanotes/main/public/film/Charade.md" },
411
+ {
412
+ "from": "Films/His Girl Friday.md",
413
+ "to": "datanotes/main/public/film/His Girl Friday.md"
414
+ },
415
+ { "from": "Films/Metropolis.md", "to": "datanotes/main/public/film/Metropolis.md" },
416
+ { "from": "Films/Nosferatu.md", "to": "datanotes/main/public/film/Nosferatu.md" },
417
+ {
418
+ "from": "Films/The Gold Rush.md",
419
+ "to": "datanotes/main/public/film/The Gold Rush.md"
420
+ }
421
+ ]
422
+ }
423
+ ```
424
+
425
+ ## Adopt the notes into the table
426
+
427
+ This is the same call without `dry_run`. The engine checks every note first: a note that doesn’t fit the table stops the whole adoption, and the answer lists why.
428
+
429
+ With thousands of notes, adopt them in calls of about 1,000 `paths` each. Each call is one journal entry, so a stop or a crash interrupts less, and `undo_migration` reverts one chunk at a time.
430
+
431
+ **`adopt_rows`**
432
+
433
+ ```json
434
+ {
435
+ "table": "film",
436
+ "paths": [
437
+ "Films/Charade.md",
438
+ "Films/His Girl Friday.md",
439
+ "Films/Metropolis.md",
440
+ "Films/Nosferatu.md",
441
+ "Films/The Gold Rush.md"
442
+ ],
443
+ "rename": { "Director": "director" },
444
+ "relocate": true
445
+ }
446
+ ```
447
+
448
+ Answer (73 lines)
449
+
450
+ ```json
451
+ {
452
+ "ok": true,
453
+ "op": "adopt_rows",
454
+ "notes_changed": 5,
455
+ "files_moved": 5,
456
+ "planned_edits": [
457
+ {
458
+ "path": "Films/Charade.md",
459
+ "set": {
460
+ "table": "main.public.film",
461
+ "id": "01a12efb-81ad-7350-b6fc-3607a2c36814",
462
+ "director": "Stanley Donen",
463
+ "title": "Charade"
464
+ },
465
+ "remove": ["Director"]
466
+ },
467
+ {
468
+ "path": "Films/His Girl Friday.md",
469
+ "set": {
470
+ "table": "main.public.film",
471
+ "id": "01a12efb-81ad-76cb-a7d9-1d8bcd578f6d",
472
+ "director": "Howard Hawks",
473
+ "title": "His Girl Friday"
474
+ },
475
+ "remove": ["Director"]
476
+ },
477
+ {
478
+ "path": "Films/Metropolis.md",
479
+ "set": {
480
+ "table": "main.public.film",
481
+ "id": "01a12efb-81ad-7b8f-aa3d-16ff4a7685be",
482
+ "director": "Fritz Lang",
483
+ "title": "Metropolis"
484
+ },
485
+ "remove": ["Director"]
486
+ },
487
+ {
488
+ "path": "Films/Nosferatu.md",
489
+ "set": {
490
+ "table": "main.public.film",
491
+ "id": "01a12efb-81ad-7a1c-b7d7-c6ce93fd565e",
492
+ "director": "F. W. Murnau",
493
+ "title": "Nosferatu"
494
+ },
495
+ "remove": ["Director"]
496
+ },
497
+ {
498
+ "path": "Films/The Gold Rush.md",
499
+ "set": {
500
+ "table": "main.public.film",
501
+ "id": "01a12efb-81ad-7816-bbb2-0c7ac62d182a",
502
+ "director": "Charlie Chaplin",
503
+ "title": "The Gold Rush"
504
+ },
505
+ "remove": ["Director"]
506
+ }
507
+ ],
508
+ "planned_moves": [
509
+ { "from": "Films/Charade.md", "to": "datanotes/main/public/film/Charade.md" },
510
+ {
511
+ "from": "Films/His Girl Friday.md",
512
+ "to": "datanotes/main/public/film/His Girl Friday.md"
513
+ },
514
+ { "from": "Films/Metropolis.md", "to": "datanotes/main/public/film/Metropolis.md" },
515
+ { "from": "Films/Nosferatu.md", "to": "datanotes/main/public/film/Nosferatu.md" },
516
+ {
517
+ "from": "Films/The Gold Rush.md",
518
+ "to": "datanotes/main/public/film/The Gold Rush.md"
519
+ }
520
+ ],
521
+ "commits": [{ "table": "main.public.film", "version": 1, "operation": "ADOPT ROWS" }],
522
+ "migration_id": "20261012T071957-adopt_rows-adopt-5-notes-into-film"
523
+ }
524
+ ```
525
+
526
+ The notes keep their text and names, so `[[His Girl Friday]]` in Charade still resolves:
527
+
528
+ **`read_note`**
529
+
530
+ ```json
531
+ { "path": "datanotes/main/public/film/Charade.md" }
532
+ ```
533
+
534
+ Answer:
535
+
536
+ ```markdown
537
+ ---
538
+ table: main.public.film
539
+ id: 01a12efb-81ad-7350-b6fc-3607a2c36814
540
+ year: 1963
541
+ minutes: 113
542
+ status: watched
543
+ rating: 4
544
+ watched_on: 2026-09-12
545
+ director: Stanley Donen
546
+ title: Charade
547
+ ---
548
+ Cary Grant again, twenty years after [[His Girl Friday]], and just as quick.
549
+ ```
550
+
551
+ **`select_rows`**
552
+
553
+ ```json
554
+ { "table": "film", "columns": ["title", "status", "rating"], "order_by": "title" }
555
+ ```
556
+
557
+ Answer:
558
+
559
+ ```json
560
+ {
561
+ "table": "main.public.film",
562
+ "total": 5,
563
+ "rows": [
564
+ {
565
+ "path": "datanotes/main/public/film/Charade.md",
566
+ "title": "Charade",
567
+ "status": "watched",
568
+ "rating": 4
569
+ },
570
+ {
571
+ "path": "datanotes/main/public/film/His Girl Friday.md",
572
+ "title": "His Girl Friday",
573
+ "status": "watched",
574
+ "rating": 5
575
+ },
576
+ {
577
+ "path": "datanotes/main/public/film/Metropolis.md",
578
+ "title": "Metropolis",
579
+ "status": "to watch",
580
+ "rating": null
581
+ },
582
+ {
583
+ "path": "datanotes/main/public/film/Nosferatu.md",
584
+ "title": "Nosferatu",
585
+ "status": "watched",
586
+ "rating": 5
587
+ },
588
+ {
589
+ "path": "datanotes/main/public/film/The Gold Rush.md",
590
+ "title": "The Gold Rush",
591
+ "status": "watched",
592
+ "rating": 5
593
+ }
594
+ ]
595
+ }
596
+ ```
597
+
598
+ ## Insert new rows through the engine
599
+
600
+ `title` is the note’s file name (`identity: "filename"`). When you give it at insert, it names the new note, and the engine then keeps it equal to the note’s actual name.
601
+
602
+ **`insert_row`**
603
+
604
+ ```json
605
+ {
606
+ "table": "film",
607
+ "values": {
608
+ "title": "Battleship Potemkin",
609
+ "year": 1925,
610
+ "minutes": 75,
611
+ "director": "Sergei Eisenstein",
612
+ "status": "to watch"
613
+ }
614
+ }
615
+ ```
616
+
617
+ Answer:
618
+
619
+ ```json
620
+ {
621
+ "ok": true,
622
+ "op": "insert_row",
623
+ "files_created": 1,
624
+ "planned_creates": ["datanotes/main/public/film/Battleship Potemkin.md"],
625
+ "commits": [{ "table": "main.public.film", "version": 2, "operation": "WRITE" }],
626
+ "migration_id": "20261012T071957-insert_row-insert-into-film"
627
+ }
628
+ ```
629
+
630
+ ## Set a value for notes made by hand with `external_default`
631
+
632
+ `default` fills a column on rows the engine writes. `external_default` fills it on notes that become rows without the engine writing them, like the note in the next example. Here `added_by` tells the two apart.
633
+
634
+ **`add_column`**
635
+
636
+ ```json
637
+ {
638
+ "table": "film",
639
+ "column": {
640
+ "name": "added_by",
641
+ "type": "enum",
642
+ "values": ["agent", "by hand"],
643
+ "default": "agent",
644
+ "external_default": "by hand",
645
+ "description": "Who added the film: an agent through the engine, or a person in an editor"
646
+ }
647
+ }
648
+ ```
649
+
650
+ Answer:
651
+
652
+ ```json
653
+ {
654
+ "ok": true,
655
+ "op": "add_column",
656
+ "planned_texts": ["datanotes/metastore.yaml"],
657
+ "commits": [{ "table": "main.public.film", "version": 4, "operation": "ADD COLUMNS" }],
658
+ "migration_id": "20261012T071958-add_column-add-column-added_by-to-film"
659
+ }
660
+ ```
661
+
662
+ **`insert_row`**
663
+
664
+ ```json
665
+ {
666
+ "table": "film",
667
+ "values": {
668
+ "title": "Night of the Living Dead",
669
+ "year": 1968,
670
+ "minutes": 96,
671
+ "director": "George A. Romero",
672
+ "status": "to watch"
673
+ }
674
+ }
675
+ ```
676
+
677
+ Answer:
678
+
679
+ ```json
680
+ {
681
+ "ok": true,
682
+ "op": "insert_row",
683
+ "files_created": 1,
684
+ "planned_creates": ["datanotes/main/public/film/Night of the Living Dead.md"],
685
+ "commits": [{ "table": "main.public.film", "version": 5, "operation": "WRITE" }],
686
+ "migration_id": "20261012T071958-insert_row-insert-into-film"
687
+ }
688
+ ```
689
+
690
+ `datanotes/main/public/film/Night of the Living Dead.md` now reads:
691
+
692
+ ```markdown
693
+ ---
694
+ table: main.public.film
695
+ id: 01a12efb-87b5-7e4d-95f6-04c05995e9df
696
+ director: George A. Romero
697
+ minutes: 96
698
+ status: to watch
699
+ year: 1968
700
+ title: Night of the Living Dead
701
+ added_by: agent
702
+ ---
703
+ ```
704
+
705
+ ## A new note in a table’s folder becomes a row
706
+
707
+ The engine adopts a note you create by hand inside a table’s folder, for example with “new note” in a note editor such as Obsidian, or from a daily note template. The note gets:
708
+
709
+ * `table` and an `id`
710
+ * the values its name carries under the table’s `filename` pattern
711
+ * the column defaults and the `external_default` values
712
+
713
+ Here the note’s name gives `title`, and `added_by` is `by hand`. A note that misses a required column or has a bad value stays as it is, and the engine logs a warning.
714
+
715
+ You edit `datanotes/main/public/film/Sherlock Jr..md` by hand, outside the engine. The note now reads:
716
+
717
+ ```markdown
718
+ ---
719
+ year: 1924
720
+ minutes: 45
721
+ status: to watch
722
+ director: Buster Keaton
723
+ ---
724
+ ```
725
+
726
+ **`read_note`**
727
+
728
+ ```json
729
+ { "path": "datanotes/main/public/film/Sherlock Jr..md" }
730
+ ```
731
+
732
+ Answer:
733
+
734
+ ```markdown
735
+ ---
736
+ table: main.public.film
737
+ id: 01a12efb-8a37-7b33-bb22-169f2afb9934
738
+ year: 1924
739
+ minutes: 45
740
+ status: to watch
741
+ director: Buster Keaton
742
+ added_by: by hand
743
+ title: Sherlock Jr.
744
+ ---
745
+ ```
746
+
747
+ ## Keep a folder’s notes out of the table with `exclude`
748
+
749
+ A note is a row when its front matter key `table` names the table, and a new note in the table’s folder becomes one. `exclude` lists folders whose notes never become rows. Here it lists the editor’s templates folder. The template already says `table:`, so the notes you make from it are rows, but the template itself must not be one.
750
+
751
+ **`alter_table`**
752
+
753
+ ```json
754
+ { "table": "film", "exclude": ["datanotes/main/public/film/Templates"] }
755
+ ```
756
+
757
+ Answer:
758
+
759
+ ```json
760
+ {
761
+ "ok": true,
762
+ "op": "alter_table",
763
+ "planned_texts": ["datanotes/metastore.yaml"],
764
+ "commits": [{ "table": "main.public.film", "version": 7, "operation": "ALTER TABLE" }],
765
+ "migration_id": "20261012T072001-alter_table-alter-table-main-public-film"
766
+ }
767
+ ```
768
+
769
+ You edit `datanotes/main/public/film/Templates/New film.md` by hand, outside the engine. The note now reads:
770
+
771
+ ```markdown
772
+ ---
773
+ table: main.public.film
774
+ year:
775
+ status: to watch
776
+ ---
777
+ ## Why I want to watch it
778
+ ```
779
+
780
+ The engine leaves the template as it is, with no `id`, and it isn’t a row:
781
+
782
+ **`read_note`**
783
+
784
+ ```json
785
+ { "path": "datanotes/main/public/film/Templates/New film.md" }
786
+ ```
787
+
788
+ Answer:
789
+
790
+ ```markdown
791
+ ---
792
+ table: main.public.film
793
+ year:
794
+ status: to watch
795
+ ---
796
+ ## Why I want to watch it
797
+ ```
798
+
799
+ **`select_rows`**
800
+
801
+ ```json
802
+ {
803
+ "table": "film",
804
+ "columns": ["title"],
805
+ "where": { "path": { "contains": "Templates" } }
806
+ }
807
+ ```
808
+
809
+ Answer:
810
+
811
+ ```json
812
+ { "table": "main.public.film", "total": 0, "rows": [] }
813
+ ```
814
+
815
+ ## See the table’s definition in `metastore.yaml`
816
+
817
+ This is the table as you inferred, corrected and extended it on this page. Its definition holds:
818
+
819
+ * `title` with `identity: filename`
820
+ * the columns from the notes’ front matter
821
+ * `added_by` with its `external_default`
822
+ * the `exclude` folder under `properties`
823
+
824
+ `datanotes/metastore.yaml` now reads:
825
+
826
+ ```yaml
827
+ # Metastore (Datanotes): catalogs, schemas, tables, columns, views.
828
+ id: 01a12efb-8191-7a5c-9aee-8ffe9c6f215a
829
+ config:
830
+ history: true
831
+
832
+
833
+ catalogs:
834
+ main:
835
+ schemas:
836
+ public:
837
+ tables:
838
+ film:
839
+ description: Classic films I watched or want to watch
840
+ options:
841
+ filename: "{title}"
842
+ archive: _archive
843
+ exclude: datanotes/main/public/film/Templates
844
+ columns:
845
+ - name: id
846
+ type: string
847
+ unique: true
848
+ identity: uuid
849
+ required: true
850
+ dense: true
851
+ description: "Unique id of the row (UUIDv7): set when the row is created, never changes"
852
+ - name: title
853
+ type: string
854
+ description: The film's title, which is also its note's name
855
+ identity: filename
856
+ - name: director
857
+ type: string
858
+ required: true
859
+ description: Who directed the film
860
+ dense: true
861
+ - name: minutes
862
+ type: integer
863
+ required: true
864
+ description: Running time in minutes
865
+ dense: true
866
+ - name: status
867
+ type: enum
868
+ required: true
869
+ values:
870
+ - to watch
871
+ - watched
872
+ description: Where the film is on my list
873
+ ordered: true
874
+ dense: true
875
+ - name: year
876
+ type: integer
877
+ required: true
878
+ description: Year the film first came out
879
+ dense: true
880
+ - name: rating
881
+ type: integer
882
+ min: 1
883
+ max: 5
884
+ description: My rating, from 1 (poor) to 5 (a masterpiece)
885
+ - name: watched_on
886
+ type: date
887
+ description: The day I last watched it
888
+ - name: added_by
889
+ type: enum
890
+ default: agent
891
+ values:
892
+ - agent
893
+ - by hand
894
+ external_default: by hand
895
+ description: "Who added the film: an agent through the engine, or a person in an editor"
896
+ ```