datanotes 2.0.1 → 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 +62511 -28069
  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 +58 -14
@@ -0,0 +1,262 @@
1
+ # Journal and undo
2
+
3
+ > Every write through the engine is journaled with who made it: list the writes, undo them, and see what undo can't take back.
4
+
5
+ The journal records every write to rows and to the schema, with the data to undo it and who made it. `list_migrations` lists the writes, newest first, and `undo_migration` reverts one, batches included. An undo is itself a write, so you can undo it too.
6
+
7
+ The journal works on every table, whatever its history setting. Reading a table as it was and restoring it need its transaction log too. A database the engine creates keeps one for every table: see [Table history and time travel](https://datanotes.dev/guides/history/table-history/).
8
+
9
+ The examples work on a small diary of five classic films.
10
+
11
+ ## The engine rolls back a write it cannot finish
12
+
13
+ A write can touch many notes, and the engine changes them one at a time. Sometimes it can’t change one of them halfway through:
14
+
15
+ * Another program holds the file, such as an editor, an antivirus or a sync tool
16
+ * Someone edits the note between the check and the change
17
+ * Someone deletes or moves the note meanwhile
18
+
19
+ The engine then puts back what it had already changed. It undoes the journal entry of the interrupted operation, as `undo_migration` would, so the database stays as it was. You don’t need to undo anything yourself.
20
+
21
+ The answer has `ok: false`, the files it couldn’t change in `failed` and `rolled_back: true`. The HTTP API answers with status 503, which means nothing changed and you can retry. Its `hint` tells you to free the file and send the operation again:
22
+
23
+ ```json
24
+ {
25
+ "ok": false,
26
+ "op": "update_rows",
27
+ "migration_id": "20261011T101500-update_rows-update-film",
28
+ "failed": [
29
+ {
30
+ "path": "datanotes/main/public/film/Nosferatu.md",
31
+ "error": "EBUSY: resource busy or locked"
32
+ }
33
+ ],
34
+ "rolled_back": true,
35
+ "notes_changed": 0
36
+ }
37
+ ```
38
+
39
+ Through the MCP server, the agent reads the same answer as text, which says that nothing is left changed.
40
+
41
+ The journal keeps both steps. `list_migrations` shows the interrupted operation as undone, and a `rollback` entry that undid it. You can’t undo a rollback: send the operation again instead. The table history gets no version of the interrupted operation.
42
+
43
+ Inside a [batch](https://datanotes.dev/guides/read-and-write/batch/), the engine rolls back the interrupted step first. The batch then undoes the steps before it, so the whole batch leaves nothing behind.
44
+
45
+ On Windows, a file another program has open can’t be renamed for a moment. The engine retries a move for about three seconds before it gives up.
46
+
47
+ ### When the rollback can’t finish either
48
+
49
+ The rollback can stop too, for example when the same program still holds a file. The answer then has `rolled_back: false`. `failed` lists the file that stopped the operation and each file the rollback left, with the error `not rolled back: …`.
50
+
51
+ To finish the rollback:
52
+
53
+ 1. Close the program that holds the files.
54
+ 2. Call `undo_migration` with the operation’s `migration_id`.
55
+ 3. Send the operation again.
56
+
57
+ `undo_migration` skips the files the rollback already put back, so you can call it again until it succeeds.
58
+
59
+ ## What undo can’t take back
60
+
61
+ `undo_migration` reverts the writes the journal holds. Some changes never reach the journal, so no undo brings them back:
62
+
63
+ * **`vacuum_table`**: it deletes old versions of a table’s history for good. Its `dry_run` is on by default.
64
+ * **`configure_database`**: the database settings aren’t journaled. Set the old value again with `configure_database`.
65
+ * **Webhooks**: `create_webhook` and `delete_webhook` aren’t journaled. Delete or create the webhook again.
66
+ * **`sync_semantic_index`**: it rebuilds the semantic index, which the engine can build again at any time.
67
+ * **Hand edits**: the journal doesn’t record a note you edit outside the engine. With history on, the table’s log records it, and `restore_table` brings back the version before it. Without history, nothing can.
68
+ * **Old entries**: when the engine starts, it drops journal entries older than `journalRetentionDays`, 90 days by default. `list_migrations` no longer lists them, and they can’t be undone.
69
+ * **A crash or `kill -9`**: a write cut short this way may leave some notes written and no journal entry. Find the rows it left with `check_table`, and repair them with a new write.
70
+
71
+ `restore_database` doesn’t fill these gaps either: it goes back only through tables with history on. To revert one operation, use `undo_migration`.
72
+
73
+ ## Undo a write
74
+
75
+ Every write returns a `migration_id`. `list_migrations` lists them, newest first, with who made each one, and `undo_migration` reverts one.
76
+
77
+ **`list_migrations`**
78
+
79
+ ```json
80
+ { "table": "film", "limit": 3 }
81
+ ```
82
+
83
+ Answer:
84
+
85
+ ```json
86
+ {
87
+ "total": 13,
88
+ "migrations": [
89
+ {
90
+ "migration_id": "20261012T071951-delete_rows-archive-1-rows-of-film",
91
+ "op": "delete_rows",
92
+ "summary": "archive 1 rows of film",
93
+ "table": "main.public.film",
94
+ "executed_at": "2026-10-12T07:19:51.705Z",
95
+ "notes_changed": 0,
96
+ "files_changed": 1,
97
+ "undone": false,
98
+ "files_failed": 0,
99
+ "by": "docs-example"
100
+ },
101
+ {
102
+ "migration_id": "20261012T071951-merge_rows-merge-2-rows-into-film",
103
+ "op": "merge_rows",
104
+ "summary": "merge 2 rows into film",
105
+ "table": "main.public.film",
106
+ "executed_at": "2026-10-12T07:19:51.690Z",
107
+ "notes_changed": 1,
108
+ "files_changed": 1,
109
+ "undone": false,
110
+ "files_failed": 0,
111
+ "by": "docs-example"
112
+ },
113
+ {
114
+ "migration_id": "20261012T071951-update_rows-update-film",
115
+ "op": "update_rows",
116
+ "summary": "update film",
117
+ "table": "main.public.film",
118
+ "executed_at": "2026-10-12T07:19:51.674Z",
119
+ "notes_changed": 3,
120
+ "files_changed": 0,
121
+ "undone": false,
122
+ "files_failed": 0,
123
+ "by": "docs-example"
124
+ }
125
+ ]
126
+ }
127
+ ```
128
+
129
+ **`undo_migration`**
130
+
131
+ ```json
132
+ { "migration_id": "20261012T071951-delete_rows-archive-1-rows-of-film" }
133
+ ```
134
+
135
+ Answer:
136
+
137
+ ```json
138
+ {
139
+ "ok": true,
140
+ "op": "undo_migration",
141
+ "undoes": "20261012T071951-delete_rows-archive-1-rows-of-film",
142
+ "migration_id": "20261012T071951-undo_migration-undo-20261012t071951-delete_ro",
143
+ "conflicts": [],
144
+ "failed": []
145
+ }
146
+ ```
147
+
148
+ Battleship Potemkin is back:
149
+
150
+ **`select_rows`**
151
+
152
+ ```json
153
+ { "table": "film", "columns": ["title"], "where": { "title": "Battleship Potemkin" } }
154
+ ```
155
+
156
+ Answer:
157
+
158
+ ```json
159
+ {
160
+ "table": "main.public.film",
161
+ "total": 1,
162
+ "rows": [
163
+ {
164
+ "path": "datanotes/main/public/film/Battleship Potemkin.md",
165
+ "title": "Battleship Potemkin"
166
+ }
167
+ ]
168
+ }
169
+ ```
170
+
171
+ ## Undo refuses to overwrite later changes
172
+
173
+ An undo never overwrites later work. The engine compares the values the operation wrote with the notes as they are now. If one of those values changed since, the engine refuses the undo and lists the changes. Changes to other columns don’t block the undo, and the engine keeps them.
174
+
175
+ **`update_row`**
176
+
177
+ ```json
178
+ {
179
+ "table": "film",
180
+ "path": "datanotes/main/public/film/Sherlock Jr..md",
181
+ "set": { "rating": 5 }
182
+ }
183
+ ```
184
+
185
+ Answer:
186
+
187
+ ```json
188
+ {
189
+ "ok": true,
190
+ "op": "update_row",
191
+ "notes_changed": 1,
192
+ "planned_edits": [
193
+ {
194
+ "path": "datanotes/main/public/film/Sherlock Jr..md",
195
+ "set": { "rating": 5 },
196
+ "remove": []
197
+ }
198
+ ],
199
+ "commits": [{ "table": "main.public.film", "version": 14, "operation": "UPDATE" }],
200
+ "migration_id": "20261012T071951-update_row-update-film-5"
201
+ }
202
+ ```
203
+
204
+ Then someone changes the rating again:
205
+
206
+ **`update_row`**
207
+
208
+ ```json
209
+ {
210
+ "table": "film",
211
+ "path": "datanotes/main/public/film/Sherlock Jr..md",
212
+ "set": { "rating": 4 }
213
+ }
214
+ ```
215
+
216
+ **`undo_migration`**
217
+
218
+ ```json
219
+ { "migration_id": "20261012T071951-update_row-update-film-5" }
220
+ ```
221
+
222
+ Refused:
223
+
224
+ ```text
225
+ undo_migration refused — nothing was written:
226
+ conflict datanotes/main/public/film/Sherlock Jr..md: "rating" changed since the operation
227
+ Hint: Later changes touched the same notes: undo those first (list_migrations lists them, newest first), or change the rows with update_row.
228
+ Docs: https://datanotes.dev/guides/history/journal-and-undo.md#undo-refuses-to-overwrite-later-changes (offline: read_docs("guides/history/journal-and-undo#undo-refuses-to-overwrite-later-changes"))
229
+ ```
230
+
231
+ The undo of an insert trashes the new note only while it’s as the insert left it:
232
+
233
+ **`insert_row`**
234
+
235
+ ```json
236
+ { "table": "film", "values": { "title": "The General", "year": 1926 } }
237
+ ```
238
+
239
+ **`update_row`**
240
+
241
+ ```json
242
+ {
243
+ "table": "film",
244
+ "path": "datanotes/main/public/film/The General.md",
245
+ "body": "Buster Keaton drives a locomotive.\n"
246
+ }
247
+ ```
248
+
249
+ **`undo_migration`**
250
+
251
+ ```json
252
+ { "migration_id": "20261012T071951-insert_row-insert-into-film-6" }
253
+ ```
254
+
255
+ Refused:
256
+
257
+ ```text
258
+ undo_migration refused — nothing was written:
259
+ conflict datanotes/main/public/film/The General.md: created note changed since the operation
260
+ Hint: Later changes touched the same notes: undo those first (list_migrations lists them, newest first), or change the rows with update_row.
261
+ Docs: https://datanotes.dev/guides/history/journal-and-undo.md#undo-refuses-to-overwrite-later-changes (offline: read_docs("guides/history/journal-and-undo#undo-refuses-to-overwrite-later-changes"))
262
+ ```
@@ -0,0 +1,341 @@
1
+ # Restore a table or the database
2
+
3
+ > Bring a table back to an old version, or every table back to a time or to the moment before an operation.
4
+
5
+ `restore_table` brings a table back to an old version, and `restore_database` brings every table that keeps a transaction log back to a time, or to the moment before an operation. Each restore is one write: it’s journaled, and `undo_migration` reverts it.
6
+
7
+ The same history lets you time travel before you restore: `select_rows` with `timestamp` reads a table, a view, a join or a base as it was at that time.
8
+
9
+ ## Restore a table to an old version
10
+
11
+ `restore_table` brings the rows and the definition back to a version:
12
+
13
+ * it removes the rows added since
14
+ * it gives changed rows their old values
15
+ * it brings removed rows back
16
+
17
+ The restore doesn’t rewrite history: it’s a new version, and you can undo it. Run it with `dry_run` first.
18
+
19
+ The dry run names the version by its time, with a `timestamp` from the history read above:
20
+
21
+ **`restore_table`**
22
+
23
+ ```json
24
+ { "table": "film", "timestamp": "2026-10-12T07:20:04.642Z", "dry_run": true }
25
+ ```
26
+
27
+ Answer:
28
+
29
+ ```json
30
+ {
31
+ "ok": true,
32
+ "op": "restore_table",
33
+ "dry_run": true,
34
+ "planned_creates": ["datanotes/main/public/film/Metropolis.md"]
35
+ }
36
+ ```
37
+
38
+ **`restore_table`**
39
+
40
+ ```json
41
+ { "table": "film", "version": 5 }
42
+ ```
43
+
44
+ Answer:
45
+
46
+ ```json
47
+ {
48
+ "ok": true,
49
+ "op": "restore_table",
50
+ "files_created": 1,
51
+ "planned_creates": ["datanotes/main/public/film/Metropolis.md"],
52
+ "commits": [{ "table": "main.public.film", "version": 7, "operation": "RESTORE" }],
53
+ "migration_id": "20261012T072004-restore_table-restore-main-public-film-to-ve"
54
+ }
55
+ ```
56
+
57
+ **`select_rows`**
58
+
59
+ ```json
60
+ { "table": "film", "columns": ["title", "status"] }
61
+ ```
62
+
63
+ Answer:
64
+
65
+ ```json
66
+ {
67
+ "table": "main.public.film",
68
+ "total": 2,
69
+ "rows": [
70
+ {
71
+ "path": "datanotes/main/public/film/Metropolis.md",
72
+ "title": "Metropolis",
73
+ "status": "watched"
74
+ },
75
+ {
76
+ "path": "datanotes/main/public/film/Nosferatu.md",
77
+ "title": "Nosferatu",
78
+ "status": "watched"
79
+ }
80
+ ]
81
+ }
82
+ ```
83
+
84
+ ## Time travel and restore the whole database
85
+
86
+ An agent can change several tables in one call: here one batch adds an actor and rates a film. `describe_history` without `table` lists the commits of every table, newest first, each with its `table`. In that list:
87
+
88
+ * the commits of one operation share its `migration_id`
89
+ * the commits of a batch carry the batch’s id as `batch`
90
+ * `tables` names every table the change touched
91
+
92
+ **`batch`**
93
+
94
+ ```json
95
+ {
96
+ "summary": "add Cary Grant, rate His Girl Friday",
97
+ "operations": [
98
+ {
99
+ "op": "insert_row",
100
+ "table": "actor",
101
+ "values": { "name": "Cary Grant", "born": "1904-01-18" }
102
+ },
103
+ {
104
+ "op": "update_row",
105
+ "table": "film",
106
+ "path": "datanotes/main/public/film/His Girl Friday.md",
107
+ "set": { "rating": 5, "watched_on": "2026-10-08" }
108
+ }
109
+ ]
110
+ }
111
+ ```
112
+
113
+ Answer:
114
+
115
+ ```json
116
+ { "ok": true, "migration_id": "20261012T072013-batch-add-cary-grant-rate-his-girl-f" }
117
+ ```
118
+
119
+ **`describe_history`**
120
+
121
+ ```json
122
+ { "limit": 3 }
123
+ ```
124
+
125
+ Answer (62 lines)
126
+
127
+ ```json
128
+ {
129
+ "tables": [
130
+ "main.public.actor",
131
+ "main.public.film",
132
+ "main.public.film_at",
133
+ "main.public.film_before"
134
+ ],
135
+ "history": [
136
+ {
137
+ "table": "main.public.film",
138
+ "version": 11,
139
+ "timestamp": "2026-10-12T07:20:13.321Z",
140
+ "operation": "UPDATE",
141
+ "operation_parameters": { "summary": "update film" },
142
+ "migration_id": "20261012T072013-update_row-update-film",
143
+ "operation_metrics": {
144
+ "num_added_files": 1,
145
+ "num_removed_files": 1,
146
+ "metadata_changed": false
147
+ },
148
+ "engine_info": "datanotes",
149
+ "user_name": "docs-example",
150
+ "actor": { "session": "history", "harness": "docs-example", "auth": "owner" },
151
+ "batch": "20261012T072013-batch-add-cary-grant-rate-his-girl-f",
152
+ "tables": ["main.public.actor", "main.public.film"]
153
+ },
154
+ {
155
+ "table": "main.public.actor",
156
+ "version": 2,
157
+ "timestamp": "2026-10-12T07:20:13.314Z",
158
+ "operation": "WRITE",
159
+ "operation_parameters": { "summary": "insert into actor" },
160
+ "migration_id": "20261012T072013-insert_row-insert-into-actor-2",
161
+ "operation_metrics": {
162
+ "num_added_files": 1,
163
+ "num_removed_files": 0,
164
+ "metadata_changed": false
165
+ },
166
+ "engine_info": "datanotes",
167
+ "user_name": "docs-example",
168
+ "actor": { "session": "history", "harness": "docs-example", "auth": "owner" },
169
+ "batch": "20261012T072013-batch-add-cary-grant-rate-his-girl-f",
170
+ "tables": ["main.public.actor", "main.public.film"]
171
+ },
172
+ {
173
+ "table": "main.public.film_at",
174
+ "version": 1,
175
+ "timestamp": "2026-10-12T07:20:13.304Z",
176
+ "operation": "ALTER TABLE",
177
+ "operation_parameters": { "summary": "alter table main.public.film_at" },
178
+ "migration_id": "20261012T072013-alter_table-alter-table-main-public-film_a",
179
+ "operation_metrics": {
180
+ "num_added_files": 0,
181
+ "num_removed_files": 0,
182
+ "metadata_changed": true
183
+ },
184
+ "engine_info": "datanotes",
185
+ "user_name": "docs-example",
186
+ "actor": { "session": "history", "harness": "docs-example", "auth": "owner" }
187
+ }
188
+ ]
189
+ }
190
+ ```
191
+
192
+ `restore_database` brings every table that keeps a log back to a moment, as one operation. `before_migration` names the moment by an operation, here the batch, and means the state immediately before it. The dry run lists what would change in each table, and shows a table without history, like `film_before`, as `skipped` with the reason.
193
+
194
+ **`restore_database`**
195
+
196
+ ```json
197
+ {
198
+ "before_migration": "20261012T072013-batch-add-cary-grant-rate-his-girl-f",
199
+ "dry_run": true
200
+ }
201
+ ```
202
+
203
+ Answer:
204
+
205
+ ```json
206
+ {
207
+ "ok": true,
208
+ "op": "restore_database",
209
+ "dry_run": true,
210
+ "planned_deletes": ["datanotes/main/public/actor/Cary Grant.md"],
211
+ "planned_texts": ["datanotes/main/public/film/His Girl Friday.md"],
212
+ "restored_to": "2026-10-12T07:20:13.313Z",
213
+ "tables": [
214
+ {
215
+ "table": "main.public.actor",
216
+ "action": "restore",
217
+ "version": 1,
218
+ "definition_changed": false,
219
+ "creates": [],
220
+ "texts": [],
221
+ "deletes": ["datanotes/main/public/actor/Cary Grant.md"],
222
+ "archived": []
223
+ },
224
+ {
225
+ "table": "main.public.film",
226
+ "action": "restore",
227
+ "version": 10,
228
+ "definition_changed": false,
229
+ "creates": [],
230
+ "texts": ["datanotes/main/public/film/His Girl Friday.md"],
231
+ "deletes": [],
232
+ "archived": []
233
+ }
234
+ ],
235
+ "unchanged": ["main.public.film_at"],
236
+ "skipped": [
237
+ {
238
+ "table": "main.public.film_before",
239
+ "reason": "history is off for it: it keeps no transaction log to go back with (alter_table history=true, or configure_database history=true, keeps one from then on)"
240
+ }
241
+ ]
242
+ }
243
+ ```
244
+
245
+ **`restore_database`**
246
+
247
+ ```json
248
+ { "before_migration": "20261012T072013-batch-add-cary-grant-rate-his-girl-f" }
249
+ ```
250
+
251
+ Answer:
252
+
253
+ ```json
254
+ {
255
+ "ok": true,
256
+ "migration_id": "20261012T072013-restore_database-restore-database-to-before-202",
257
+ "restored_to": "2026-10-12T07:20:13.313Z",
258
+ "tables": ["main.public.actor: restore", "main.public.film: restore"]
259
+ }
260
+ ```
261
+
262
+ **`select_rows`**
263
+
264
+ ```json
265
+ { "table": "actor", "columns": ["name"] }
266
+ ```
267
+
268
+ Answer:
269
+
270
+ ```json
271
+ {
272
+ "table": "main.public.actor",
273
+ "total": 1,
274
+ "rows": [
275
+ {
276
+ "path": "datanotes/main/public/actor/Rosalind Russell.md",
277
+ "name": "Rosalind Russell"
278
+ }
279
+ ]
280
+ }
281
+ ```
282
+
283
+ The restore has one `migration_id` for every table, so `undo_migration` puts them all back as they were.
284
+
285
+ A `timestamp` names the moment by its time, as it does for a table. `restored_to` is that time for the restore above: the last millisecond before the batch, so passing it as `timestamp` names the same moment. A restore to that time would drop a table created after it and archive its rows. It would also bring back a table dropped since.
286
+
287
+ **`undo_migration`**
288
+
289
+ ```json
290
+ { "migration_id": "20261012T072013-restore_database-restore-database-to-before-202" }
291
+ ```
292
+
293
+ **`restore_database`**
294
+
295
+ ```json
296
+ { "timestamp": "2026-10-12T07:20:13.313Z", "dry_run": true }
297
+ ```
298
+
299
+ Answer:
300
+
301
+ ```json
302
+ {
303
+ "ok": true,
304
+ "dry_run": true,
305
+ "tables": [
306
+ "main.public.actor: restore to version 1",
307
+ "main.public.film: restore to version 10"
308
+ ],
309
+ "skipped": [
310
+ {
311
+ "table": "main.public.film_before",
312
+ "reason": "history is off for it: it keeps no transaction log to go back with (alter_table history=true, or configure_database history=true, keeps one from then on)"
313
+ }
314
+ ]
315
+ }
316
+ ```
317
+
318
+ Time travel reads several tables the same way. `select_rows` with `timestamp` on a join, a view or `base:<name>` reads each table as of that time, and `versions` says which version of each it read.
319
+
320
+ **`select_rows`**
321
+
322
+ ```json
323
+ { "table": "actor", "columns": ["name"], "timestamp": "2026-10-12T07:20:13.313Z" }
324
+ ```
325
+
326
+ Answer:
327
+
328
+ ```json
329
+ {
330
+ "table": "main.public.actor",
331
+ "total": 1,
332
+ "rows": [
333
+ {
334
+ "path": "datanotes/main/public/actor/Rosalind Russell.md",
335
+ "name": "Rosalind Russell"
336
+ }
337
+ ],
338
+ "version": 1,
339
+ "timestamp": "2026-10-12T07:20:13.272Z"
340
+ }
341
+ ```